interface_rpc.py
1 #!/usr/bin/env python3 2 # Copyright (c) 2018-2022 The Bitcoin Core developers 3 # Distributed under the MIT software license, see the accompanying 4 # file COPYING or http://www.opensource.org/licenses/mit-license.php. 5 """Tests some generic aspects of the RPC interface.""" 6 7 import os 8 from test_framework.authproxy import JSONRPCException 9 from test_framework.test_framework import BitcoinTestFramework 10 from test_framework.util import assert_equal, assert_greater_than_or_equal 11 from threading import Thread 12 import subprocess 13 14 15 def expect_http_status(expected_http_status, expected_rpc_code, 16 fcn, *args): 17 try: 18 fcn(*args) 19 raise AssertionError(f"Expected RPC error {expected_rpc_code}, got none") 20 except JSONRPCException as exc: 21 assert_equal(exc.error["code"], expected_rpc_code) 22 assert_equal(exc.http_status, expected_http_status) 23 24 25 def test_work_queue_getblock(node, got_exceeded_error): 26 while not got_exceeded_error: 27 try: 28 node.cli("waitfornewblock", "500").send_cli() 29 except subprocess.CalledProcessError as e: 30 assert_equal(e.output, 'error: Server response: Work queue depth exceeded\n') 31 got_exceeded_error.append(True) 32 33 34 class RPCInterfaceTest(BitcoinTestFramework): 35 def set_test_params(self): 36 self.num_nodes = 1 37 self.setup_clean_chain = True 38 self.supports_cli = False 39 40 def test_getrpcinfo(self): 41 self.log.info("Testing getrpcinfo...") 42 43 info = self.nodes[0].getrpcinfo() 44 assert_equal(len(info['active_commands']), 1) 45 46 command = info['active_commands'][0] 47 assert_equal(command['method'], 'getrpcinfo') 48 assert_greater_than_or_equal(command['duration'], 0) 49 assert_equal(info['logpath'], os.path.join(self.nodes[0].chain_path, 'debug.log')) 50 51 def test_batch_request(self): 52 self.log.info("Testing basic JSON-RPC batch request...") 53 54 results = self.nodes[0].batch([ 55 # A basic request that will work fine. 56 {"method": "getblockcount", "id": 1}, 57 # Request that will fail. The whole batch request should still 58 # work fine. 59 {"method": "invalidmethod", "id": 2}, 60 # Another call that should succeed. 61 {"method": "getblockhash", "id": 3, "params": [0]}, 62 ]) 63 64 result_by_id = {} 65 for res in results: 66 result_by_id[res["id"]] = res 67 68 assert_equal(result_by_id[1]['error'], None) 69 assert_equal(result_by_id[1]['result'], 0) 70 71 assert_equal(result_by_id[2]['error']['code'], -32601) 72 assert_equal(result_by_id[2]['result'], None) 73 74 assert_equal(result_by_id[3]['error'], None) 75 assert result_by_id[3]['result'] is not None 76 77 def test_http_status_codes(self): 78 self.log.info("Testing HTTP status codes for JSON-RPC requests...") 79 80 expect_http_status(404, -32601, self.nodes[0].invalidmethod) 81 expect_http_status(500, -8, self.nodes[0].getblockhash, 42) 82 83 def test_work_queue_exceeded(self): 84 self.log.info("Testing work queue exceeded...") 85 self.restart_node(0, ['-rpcworkqueue=1', '-rpcthreads=1']) 86 got_exceeded_error = [] 87 threads = [] 88 for _ in range(3): 89 t = Thread(target=test_work_queue_getblock, args=(self.nodes[0], got_exceeded_error)) 90 t.start() 91 threads.append(t) 92 for t in threads: 93 t.join() 94 95 def run_test(self): 96 self.test_getrpcinfo() 97 self.test_batch_request() 98 self.test_http_status_codes() 99 self.test_work_queue_exceeded() 100 101 102 if __name__ == '__main__': 103 RPCInterfaceTest().main()