You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
109 lines
3.3 KiB
109 lines
3.3 KiB
#!/usr/bin/env python3 |
|
# Copyright (c) 2015-2018 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(): |
|
""" |
|
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
|
|
|