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 @@ -67,7 +66,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 +152,21 @@ # 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") + "Test -rpcwait option successfully waits for RPC connection") # 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()) + # 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,35 @@ 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 so we continue polling until + # RPC credentials are retrieved + pass + 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`")