@ -10,6 +10,7 @@ import http.client
@@ -10,6 +10,7 @@ import http.client
import json
import logging
import os
import re
import subprocess
import time
@ -22,6 +23,9 @@ from .util import (
@@ -22,6 +23,9 @@ from .util import (
p2p_port ,
)
# For Python 3.4 compatibility
JSONDecodeError = getattr ( json , " JSONDecodeError " , ValueError )
BITCOIND_PROC_WAIT_TIMEOUT = 60
class TestNode ( ) :
@ -38,7 +42,7 @@ class TestNode():
@@ -38,7 +42,7 @@ class TestNode():
To make things easier for the test writer , any unrecognised messages will
be dispatched to the RPC connection . """
def __init__ ( self , i , dirname , extra_args , rpchost , timewait , binary , stderr , mocktime , coverage_dir ) :
def __init__ ( self , i , dirname , extra_args , rpchost , timewait , binary , stderr , mocktime , coverage_dir , use_cli = False ) :
self . index = i
self . datadir = os . path . join ( dirname , " node " + str ( i ) )
self . rpchost = rpchost
@ -58,6 +62,7 @@ class TestNode():
@@ -58,6 +62,7 @@ class TestNode():
self . args = [ self . binary , " -datadir= " + self . datadir , " -server " , " -keypool=1 " , " -discover=0 " , " -rest " , " -logtimemicros " , " -debug " , " -debugexclude=libevent " , " -debugexclude=leveldb " , " -mocktime= " + str ( mocktime ) , " -uacomment=testnode %d " % i ]
self . cli = TestNodeCLI ( os . getenv ( " BITCOINCLI " , " bitcoin-cli " ) , self . datadir )
self . use_cli = use_cli
self . running = False
self . process = None
@ -69,9 +74,12 @@ class TestNode():
@@ -69,9 +74,12 @@ class TestNode():
self . p2ps = [ ]
def __getattr__ ( self , name ) :
""" Dispatches any unrecognised messages to the RPC connection. """
assert self . rpc_connected and self . rpc is not None , " Error: no RPC connection "
return getattr ( self . rpc , name )
""" Dispatches any unrecognised messages to the RPC connection or a CLI instance. """
if self . use_cli :
return getattr ( self . cli , name )
else :
assert self . rpc_connected and self . rpc is not None , " Error: no RPC connection "
return getattr ( self . rpc , name )
def start ( self , extra_args = None , stderr = None ) :
""" Start the node. """
@ -110,10 +118,13 @@ class TestNode():
@@ -110,10 +118,13 @@ class TestNode():
raise AssertionError ( " Unable to connect to bitcoind " )
def get_wallet_rpc ( self , wallet_name ) :
assert self . rpc_connected
assert self . rpc
wallet_path = " wallet/ %s " % wallet_name
return self . rpc / wallet_path
if self . use_cli :
return self . cli ( " -rpcwallet= {} " . format ( wallet_name ) )
else :
assert self . rpc_connected
assert self . rpc
wallet_path = " wallet/ %s " % wallet_name
return self . rpc / wallet_path
def stop_node ( self ) :
""" Stop the node. """
@ -187,6 +198,16 @@ class TestNode():
@@ -187,6 +198,16 @@ class TestNode():
p . peer_disconnect ( )
del self . p2ps [ : ]
class TestNodeCLIAttr :
def __init__ ( self , cli , command ) :
self . cli = cli
self . command = command
def __call__ ( self , * args , * * kwargs ) :
return self . cli . send_cli ( self . command , * args , * * kwargs )
def get_request ( self , * args , * * kwargs ) :
return lambda : self ( * args , * * kwargs )
class TestNodeCLI ( ) :
""" Interface to bitcoin-cli for an individual node """
@ -196,17 +217,26 @@ class TestNodeCLI():
@@ -196,17 +217,26 @@ class TestNodeCLI():
self . binary = binary
self . datadir = datadir
self . input = None
self . log = logging . getLogger ( ' TestFramework.bitcoincli ' )
def __call__ ( self , * args , input = None ) :
# TestNodeCLI is callable with bitcoin-cli command-line args
self . args = [ str ( arg ) for arg in args ]
self . input = input
return self
cli = TestNodeCLI ( self . binary , self . datadir )
cli . args = [ str ( arg ) for arg in args ]
cli . input = input
return cli
def __getattr__ ( self , command ) :
def dispatcher ( * args , * * kwargs ) :
return self . send_cli ( command , * args , * * kwargs )
return dispatcher
return TestNodeCLIAttr ( self , command )
def batch ( self , requests ) :
results = [ ]
for request in requests :
try :
results . append ( dict ( result = request ( ) ) )
except JSONRPCException as e :
results . append ( dict ( error = e ) )
return results
def send_cli ( self , command , * args , * * kwargs ) :
""" Run bitcoin-cli command. Deserializes returned string as python object. """
@ -218,10 +248,18 @@ class TestNodeCLI():
@@ -218,10 +248,18 @@ class TestNodeCLI():
if named_args :
p_args + = [ " -named " ]
p_args + = [ command ] + pos_args + named_args
self . log . debug ( " Running bitcoin-cli command: %s " % command )
process = subprocess . Popen ( p_args , stdin = subprocess . PIPE , stdout = subprocess . PIPE , stderr = subprocess . PIPE , universal_newlines = True )
cli_stdout , cli_stderr = process . communicate ( input = self . input )
returncode = process . poll ( )
if returncode :
match = re . match ( r ' error code: ([-0-9]+) \ nerror message: \ n(.*) ' , cli_stderr )
if match :
code , message = match . groups ( )
raise JSONRPCException ( dict ( code = int ( code ) , message = message ) )
# Ignore cli_stdout, raise with cli_stderr
raise subprocess . CalledProcessError ( returncode , self . binary , output = cli_stderr )
return json . loads ( cli_stdout , parse_float = decimal . Decimal )
try :
return json . loads ( cli_stdout , parse_float = decimal . Decimal )
except JSONDecodeError :
return cli_stdout . rstrip ( " \n " )