diff --git a/test/functional/interface_bitcoin_cli.py b/test/functional/interface_bitcoin_cli.py --- a/test/functional/interface_bitcoin_cli.py +++ b/test/functional/interface_bitcoin_cli.py @@ -19,7 +19,6 @@ class TestBitcoinCli(BitcoinTestFramework): - def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 @@ -40,16 +39,35 @@ user, password = get_auth_cookie(self.nodes[0].datadir, self.chain) self.log.info("Test -stdinrpcpass option") - assert_equal(BLOCKS, self.nodes[0].cli( - '-rpcuser={}'.format(user), '-stdinrpcpass', input=password).getblockcount()) - assert_raises_process_error(1, "Incorrect rpcuser or rpcpassword", self.nodes[0].cli( - '-rpcuser={}'.format(user), '-stdinrpcpass', input="foo").echo) + assert_equal( + BLOCKS, + self.nodes[0].cli( + '-rpcuser={}'.format(user), + '-stdinrpcpass', + input=password).getblockcount()) + assert_raises_process_error( + 1, + 'Incorrect rpcuser or rpcpassword', + self.nodes[0].cli( + '-rpcuser={}'.format(user), + '-stdinrpcpass', + input='foo').echo) self.log.info("Test -stdin and -stdinrpcpass") - assert_equal(["foo", "bar"], self.nodes[0].cli('-rpcuser={}'.format(user), - '-stdin', '-stdinrpcpass', input=password + "\nfoo\nbar").echo()) - assert_raises_process_error(1, "Incorrect rpcuser or rpcpassword", self.nodes[0].cli( - '-rpcuser={}'.format(user), '-stdin', '-stdinrpcpass', input="foo").echo) + assert_equal(['foo', + 'bar'], + self.nodes[0].cli('-rpcuser={}'.format(user), + '-stdin', + '-stdinrpcpass', + input=password + '\nfoo\nbar').echo()) + assert_raises_process_error( + 1, + 'Incorrect rpcuser or rpcpassword', + self.nodes[0].cli( + '-rpcuser={}'.format(user), + '-stdin', + '-stdinrpcpass', + input='foo').echo) self.log.info("Test connecting to a non-existing server") assert_raises_process_error( @@ -67,7 +85,7 @@ "Test -getinfo returns expected network and blockchain info") if self.is_wallet_compiled(): self.nodes[0].encryptwallet(password) - cli_get_info = self.nodes[0].cli('-getinfo').send_cli() + cli_get_info = self.nodes[0].cli().send_cli('-getinfo') network_info = self.nodes[0].getnetworkinfo() blockchain_info = self.nodes[0].getblockchaininfo() assert_equal(cli_get_info['version'], network_info['version']) @@ -153,28 +171,20 @@ # maintain block parity with the wallet_compiled conditional branch self.nodes[0].generate(1) - self.stop_node(0) - self.log.info("Test -version with node stopped") - cli_response = self.nodes[0].cli("-version").send_cli() + self.stop_node(0) + cli_response = self.nodes[0].cli().send_cli('-version') assert "{} RPC client version".format( self.config['environment']['PACKAGE_NAME']) in cli_response self.log.info( - "Test -rpcwait option waits for RPC connection instead of failing") - # Start node without RPC connection. - self.nodes[0].start() - # Verify failure without -rpcwait. - assert_raises_process_error(1, - "Could not connect to the server", - self.nodes[0].cli('getblockcount').echo) - # Verify success using -rpcwait. - assert_equal( - BLOCKS + 1, - self.nodes[0].cli( - '-rpcwait', - 'getblockcount').send_cli()) + "Test -rpcwait option successfully waits for RPC connection") + self.nodes[0].start() # start node without RPC connection + # ensure cookie file is available to avoid race condition + self.nodes[0].wait_for_cookie_credentials() + blocks = self.nodes[0].cli('-rpcwait').send_cli('getblockcount') self.nodes[0].wait_for_rpc_connection() + assert_equal(blocks, BLOCKS + 1) if __name__ == '__main__': diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py --- a/test/functional/test_framework/test_node.py +++ b/test/functional/test_framework/test_node.py @@ -28,6 +28,7 @@ MAX_NODES, append_config, delete_cookie_file, + get_auth_cookie, get_rpc_proxy, p2p_port, rpc_url, @@ -344,12 +345,29 @@ except OSError as e: if e.errno != errno.ECONNREFUSED: # Port not yet open? raise # unknown OS error - except ValueError as e: # cookie file not found and no rpcuser or rpcassword. bitcoind still starting + except ValueError as e: # cookie file not found and no rpcuser or rpcpassword; bitcoind is still starting if "No RPC credentials" not in str(e): raise time.sleep(1.0 / poll_per_s) self._raise_assertion_error("Unable to connect to bitcoind") + def wait_for_cookie_credentials(self): + """Ensures auth cookie credentials can be read, e.g. for testing CLI with -rpcwait before RPC connection is up.""" + self.log.debug("Waiting for cookie credentials") + # Poll at a rate of four times per second. + poll_per_s = 4 + for _ in range(poll_per_s * self.rpc_timeout): + try: + get_auth_cookie(self.datadir, self.chain) + self.log.debug("Cookie credentials successfully retrieved") + return + except ValueError: # cookie file not found and no rpcuser or rpcpassword; bitcoind is still starting + pass # so we continue polling until RPC credentials are retrieved + time.sleep(1.0 / poll_per_s) + self._raise_assertion_error( + "Unable to retrieve cookie credentials after {}s".format( + self.rpc_timeout)) + def generate(self, nblocks, maxtries=1000000): self.log.debug( "TestNode.generate() dispatches `generate` call to `generatetoaddress`")