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.

coverage.py 2.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. #!/usr/bin/env python3
  2. # Copyright (c) 2015-2016 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. """Utilities for doing coverage analysis on the RPC interface.
  6. Provides a way to track which RPC commands are exercised during
  7. testing.
  8. """
  9. import os
  10. REFERENCE_FILENAME = 'rpc_interface.txt'
  11. class AuthServiceProxyWrapper(object):
  12. """
  13. An object that wraps AuthServiceProxy to record specific RPC calls.
  14. """
  15. def __init__(self, auth_service_proxy_instance, coverage_logfile=None):
  16. """
  17. Kwargs:
  18. auth_service_proxy_instance (AuthServiceProxy): the instance
  19. being wrapped.
  20. coverage_logfile (str): if specified, write each service_name
  21. out to a file when called.
  22. """
  23. self.auth_service_proxy_instance = auth_service_proxy_instance
  24. self.coverage_logfile = coverage_logfile
  25. def __getattr__(self, *args, **kwargs):
  26. return_val = self.auth_service_proxy_instance.__getattr__(
  27. *args, **kwargs)
  28. return AuthServiceProxyWrapper(return_val, self.coverage_logfile)
  29. def __call__(self, *args, **kwargs):
  30. """
  31. Delegates to AuthServiceProxy, then writes the particular RPC method
  32. called to a file.
  33. """
  34. return_val = self.auth_service_proxy_instance.__call__(*args, **kwargs)
  35. rpc_method = self.auth_service_proxy_instance._service_name
  36. if self.coverage_logfile:
  37. with open(self.coverage_logfile, 'a+', encoding='utf8') as f:
  38. f.write("%s\n" % rpc_method)
  39. return return_val
  40. @property
  41. def url(self):
  42. return self.auth_service_proxy_instance.url
  43. def get_filename(dirname, n_node):
  44. """
  45. Get a filename unique to the test process ID and node.
  46. This file will contain a list of RPC commands covered.
  47. """
  48. pid = str(os.getpid())
  49. return os.path.join(
  50. dirname, "coverage.pid%s.node%s.txt" % (pid, str(n_node)))
  51. def write_all_rpc_commands(dirname, node):
  52. """
  53. Write out a list of all RPC functions available in `bitcoin-cli` for
  54. coverage comparison. This will only happen once per coverage
  55. directory.
  56. Args:
  57. dirname (str): temporary test dir
  58. node (AuthServiceProxy): client
  59. Returns:
  60. bool. if the RPC interface file was written.
  61. """
  62. filename = os.path.join(dirname, REFERENCE_FILENAME)
  63. if os.path.isfile(filename):
  64. return False
  65. help_output = node.help().split('\n')
  66. commands = set()
  67. for line in help_output:
  68. line = line.strip()
  69. # Ignore blanks and headers
  70. if line and not line.startswith('='):
  71. commands.add("%s\n" % line.split()[0])
  72. with open(filename, 'w', encoding='utf8') as f:
  73. f.writelines(list(commands))
  74. return True