Coverage reporting utilities for test_runner. Coverage calculation works by having each test script subprocess write coverage files into a particular directory. These files contain the RPC commands invoked during testing, as well as a complete listing of RPC commands per `bitco
| 588 | |
| 589 | |
| 590 | class RPCCoverage(): |
| 591 | """ |
| 592 | Coverage reporting utilities for test_runner. |
| 593 | |
| 594 | Coverage calculation works by having each test script subprocess write |
| 595 | coverage files into a particular directory. These files contain the RPC |
| 596 | commands invoked during testing, as well as a complete listing of RPC |
| 597 | commands per `bitcoin-cli help` (`rpc_interface.txt`). |
| 598 | |
| 599 | After all tests complete, the commands run are combined and diff'd against |
| 600 | the complete list to calculate uncovered RPC commands. |
| 601 | |
| 602 | See also: test/functional/test_framework/coverage.py |
| 603 | |
| 604 | """ |
| 605 | def __init__(self): |
| 606 | self.dir = tempfile.mkdtemp(prefix="coverage") |
| 607 | self.flag = '--coveragedir=%s' % self.dir |
| 608 | |
| 609 | def report_rpc_coverage(self): |
| 610 | """ |
| 611 | Print out RPC commands that were unexercised by tests. |
| 612 | |
| 613 | """ |
| 614 | uncovered = self._get_uncovered_rpc_commands() |
| 615 | |
| 616 | if uncovered: |
| 617 | print("Uncovered RPC commands:") |
| 618 | print("".join((" - %s\n" % command) for command in sorted(uncovered))) |
| 619 | else: |
| 620 | print("All RPC commands covered.") |
| 621 | |
| 622 | def cleanup(self): |
| 623 | return shutil.rmtree(self.dir) |
| 624 | |
| 625 | def _get_uncovered_rpc_commands(self): |
| 626 | """ |
| 627 | Return a set of currently untested RPC commands. |
| 628 | |
| 629 | """ |
| 630 | # This is shared from `test/functional/test-framework/coverage.py` |
| 631 | reference_filename = 'rpc_interface.txt' |
| 632 | coverage_file_prefix = 'coverage.' |
| 633 | |
| 634 | coverage_ref_filename = os.path.join(self.dir, reference_filename) |
| 635 | coverage_filenames = set() |
| 636 | all_cmds = set() |
| 637 | covered_cmds = set() |
| 638 | |
| 639 | if not os.path.isfile(coverage_ref_filename): |
| 640 | raise RuntimeError("No coverage reference found") |
| 641 | |
| 642 | with open(coverage_ref_filename, 'r', encoding="utf8") as coverage_ref_file: |
| 643 | all_cmds.update([line.strip() for line in coverage_ref_file.readlines()]) |
| 644 | |
| 645 | for root, _, files in os.walk(self.dir): |
| 646 | for filename in files: |
| 647 | if filename.startswith(coverage_file_prefix): |