/ test / functional / interface_rpc.py
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()