d7119e6487
4526d21 Add test for multiwallet batch RPC calls (Russell Yanofsky) 74182f2 Add missing batch rpc calls to python coverage logs (Russell Yanofsky) 505530c Add missing multiwallet rpc calls to python coverage logs (Russell Yanofsky) 9f67646 Make AuthServiceProxy._batch method usable (Russell Yanofsky) e02007a Limit AuthServiceProxyWrapper.__getattr__ wrapping (Russell Yanofsky) edafc71 Fix uninitialized URI in batch RPC requests (Russell Yanofsky) Pull request description: This fixes "Wallet file not specified" errors when making batch wallet RPC calls with more than one wallet loaded. This issue was reported by @NicolasDorier in https://github.com/bitcoin/bitcoin/issues/11257 Request URI is not used for anything except multiwallet request dispatching, so this change has no other effect. Tree-SHA512: b3907af48a6323f864bb045ee2fa56b604188b835025ef82ba3d81673244c04228d796323cec208a676e7cd578a95ec7c7ba1e84d0158b93844d5dda8f6589b9
110 lines
3.3 KiB
Python
110 lines
3.3 KiB
Python
#!/usr/bin/env python3
|
|
# Copyright (c) 2015-2016 The Bitcoin Core developers
|
|
# Distributed under the MIT software license, see the accompanying
|
|
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
"""Utilities for doing coverage analysis on the RPC interface.
|
|
|
|
Provides a way to track which RPC commands are exercised during
|
|
testing.
|
|
"""
|
|
|
|
import os
|
|
|
|
|
|
REFERENCE_FILENAME = 'rpc_interface.txt'
|
|
|
|
|
|
class AuthServiceProxyWrapper(object):
|
|
"""
|
|
An object that wraps AuthServiceProxy to record specific RPC calls.
|
|
|
|
"""
|
|
def __init__(self, auth_service_proxy_instance, coverage_logfile=None):
|
|
"""
|
|
Kwargs:
|
|
auth_service_proxy_instance (AuthServiceProxy): the instance
|
|
being wrapped.
|
|
coverage_logfile (str): if specified, write each service_name
|
|
out to a file when called.
|
|
|
|
"""
|
|
self.auth_service_proxy_instance = auth_service_proxy_instance
|
|
self.coverage_logfile = coverage_logfile
|
|
|
|
def __getattr__(self, name):
|
|
return_val = getattr(self.auth_service_proxy_instance, name)
|
|
if not isinstance(return_val, type(self.auth_service_proxy_instance)):
|
|
# If proxy getattr returned an unwrapped value, do the same here.
|
|
return return_val
|
|
return AuthServiceProxyWrapper(return_val, self.coverage_logfile)
|
|
|
|
def __call__(self, *args, **kwargs):
|
|
"""
|
|
Delegates to AuthServiceProxy, then writes the particular RPC method
|
|
called to a file.
|
|
|
|
"""
|
|
return_val = self.auth_service_proxy_instance.__call__(*args, **kwargs)
|
|
self._log_call()
|
|
return return_val
|
|
|
|
def _log_call(self):
|
|
rpc_method = self.auth_service_proxy_instance._service_name
|
|
|
|
if self.coverage_logfile:
|
|
with open(self.coverage_logfile, 'a+', encoding='utf8') as f:
|
|
f.write("%s\n" % rpc_method)
|
|
|
|
def __truediv__(self, relative_uri):
|
|
return AuthServiceProxyWrapper(self.auth_service_proxy_instance / relative_uri,
|
|
self.coverage_logfile)
|
|
|
|
def get_request(self, *args, **kwargs):
|
|
self._log_call()
|
|
return self.auth_service_proxy_instance.get_request(*args, **kwargs)
|
|
|
|
def get_filename(dirname, n_node):
|
|
"""
|
|
Get a filename unique to the test process ID and node.
|
|
|
|
This file will contain a list of RPC commands covered.
|
|
"""
|
|
pid = str(os.getpid())
|
|
return os.path.join(
|
|
dirname, "coverage.pid%s.node%s.txt" % (pid, str(n_node)))
|
|
|
|
|
|
def write_all_rpc_commands(dirname, node):
|
|
"""
|
|
Write out a list of all RPC functions available in `bitcoin-cli` for
|
|
coverage comparison. This will only happen once per coverage
|
|
directory.
|
|
|
|
Args:
|
|
dirname (str): temporary test dir
|
|
node (AuthServiceProxy): client
|
|
|
|
Returns:
|
|
bool. if the RPC interface file was written.
|
|
|
|
"""
|
|
filename = os.path.join(dirname, REFERENCE_FILENAME)
|
|
|
|
if os.path.isfile(filename):
|
|
return False
|
|
|
|
help_output = node.help().split('\n')
|
|
commands = set()
|
|
|
|
for line in help_output:
|
|
line = line.strip()
|
|
|
|
# Ignore blanks and headers
|
|
if line and not line.startswith('='):
|
|
commands.add("%s\n" % line.split()[0])
|
|
|
|
with open(filename, 'w', encoding='utf8') as f:
|
|
f.writelines(list(commands))
|
|
|
|
return True
|