test: add functional test for getopenrpcinfo

Cover the new RPC with a lightweight functional test that verifies the result is JSON serializable and exposes the expected top-level OpenRPC document fields.
This commit is contained in:
will
2026-03-02 10:09:34 +00:00
committed by willcl-ark
parent 672dd42d14
commit 1fb6b60560
2 changed files with 98 additions and 0 deletions

97
test/functional/rpc_openrpc.py Executable file
View File

@@ -0,0 +1,97 @@
#!/usr/bin/env python3
# Copyright (c) 2026 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Check that getopenrpcinfo RPC is callable and serializable as valid json."""
import json
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
def find_method(openrpc, name):
return next(method for method in openrpc["methods"] if method["name"] == name)
def find_param(method, name):
return next(param for param in method["params"] if param["name"] == name)
class OpenRPCDocTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
def run_test(self):
self.log.info("Calling getopenrpcinfo")
openrpc = self.nodes[0].getopenrpcinfo()
json.dumps(openrpc)
assert_equal(openrpc["openrpc"], "1.4.1")
assert_equal(type(openrpc["openrpc"]).__name__, "str")
assert_equal(type(openrpc["info"]).__name__, "dict")
assert_equal(type(openrpc["methods"]).__name__, "list")
stop = find_method(openrpc, "stop")
assert "wait" not in [param["name"] for param in stop["params"]]
self.log.info("Calling getopenrpcinfo with hidden commands")
openrpc_with_hidden = self.nodes[0].getopenrpcinfo(True)
stop_with_hidden = find_method(openrpc_with_hidden, "stop")
wait = find_param(stop_with_hidden, "wait")
assert_equal(wait["schema"]["type"], "number")
self.log.info("Checking type_str override schemas")
getblockstats = find_method(openrpc, "getblockstats")
hash_or_height = find_param(getblockstats, "hash_or_height")
assert_equal(hash_or_height["schema"], {"oneOf": [{"type": "number"}, {"type": "string"}]})
self.log.info("Checking fixed-length array schemas")
deriveaddresses = find_method(openrpc, "deriveaddresses")
range_array = find_param(deriveaddresses, "range")["schema"]["oneOf"][1]
assert_equal(range_array, {
"type": "array",
"items": [{"type": "number"}, {"type": "number"}],
"additionalItems": False,
"minItems": 2,
"maxItems": 2,
})
feerate_percentiles = getblockstats["result"]["schema"]["properties"]["feerate_percentiles"]
assert_equal(feerate_percentiles["type"], "array")
assert_equal(feerate_percentiles["items"], [{"type": "number"}] * 5)
assert_equal(feerate_percentiles["additionalItems"], False)
assert_equal(feerate_percentiles["minItems"], 5)
assert_equal(feerate_percentiles["maxItems"], 5)
self.log.info("Checking relaxed schemas for unchecked RPC types")
createrawtransaction = find_method(openrpc, "createrawtransaction")
outputs = find_param(createrawtransaction, "outputs")
assert_equal(outputs["schema"], {"oneOf": [{"type": "array"}, {"type": "object"}]})
getdescriptoractivity = find_method(openrpc, "getdescriptoractivity")
activity = getdescriptoractivity["result"]["schema"]["properties"]["activity"]
assert_equal(activity["type"], "array")
if "getwalletinfo" in [method["name"] for method in openrpc["methods"]]:
getwalletinfo = find_method(openrpc, "getwalletinfo")
scanning = getwalletinfo["result"]["schema"]["properties"]["scanning"]
assert_equal(scanning["oneOf"][0]["type"], "object")
assert_equal(scanning["oneOf"][1], {"const": False})
self.log.info("Checking argument fallback annotations")
getblock = find_method(openrpc, "getblock")
verbosity = find_param(getblock, "verbosity")
assert_equal(verbosity["schema"]["default"], 1)
stats = find_param(getblockstats, "stats")
assert_equal(stats["schema"]["x-bitcoin-default-hint"], "all values")
self.log.info("Checking string amount result annotations")
analyzepsbt = find_method(openrpc, "analyzepsbt")
result_schema = analyzepsbt["result"]["schema"]
estimated_feerate = result_schema["properties"]["estimated_feerate"]
assert_equal(estimated_feerate["type"], "string")
assert_equal(estimated_feerate["x-bitcoin-unit"], "amount")
if __name__ == "__main__":
OpenRPCDocTest(__file__).main()

View File

@@ -393,6 +393,7 @@ BASE_SCRIPTS = [
'wallet_migration.py',
'p2p_ibd_txrelay.py',
'p2p_seednode.py',
'rpc_openrpc.py',
# Don't append tests at the end to avoid merge conflicts
# Put them in a random line within the section that fits their approximate run-time
]