Changeset View
Changeset View
Standalone View
Standalone View
test/functional/test_framework/test_framework.py
Show All 35 Lines | |||||
class TestStatus(Enum): | class TestStatus(Enum): | ||||
PASSED = 1 | PASSED = 1 | ||||
FAILED = 2 | FAILED = 2 | ||||
SKIPPED = 3 | SKIPPED = 3 | ||||
TEST_EXIT_PASSED = 0 | |||||
TEST_EXIT_FAILED = 1 | |||||
TEST_EXIT_SKIPPED = 77 | |||||
class BitcoinTestFramework(): | class BitcoinTestFramework(): | ||||
"""Base class for a bitcoin test script. | """Base class for a bitcoin test script. | ||||
Individual bitcoin test scripts should subclass this class and override the set_test_params() and run_test() methods. | Individual bitcoin test scripts should subclass this class and override the set_test_params() and run_test() methods. | ||||
Individual tests can also override the following methods to customize the test setup: | Individual tests can also override the following methods to customize the test setup: | ||||
- add_options() | - add_options() | ||||
- setup_chain() | - setup_chain() | ||||
- setup_network() | - setup_network() | ||||
- setup_nodes() | - setup_nodes() | ||||
The __init__() and main() methods should not be overridden. | The __init__() and main() methods should not be overridden. | ||||
This class also contains various public and private helper methods.""" | This class also contains various public and private helper methods.""" | ||||
def __init__(self): | def __init__(self): | ||||
"""Sets test framework defaults. Do not override this method. Instead, override the set_test_params() method""" | """Sets test framework defaults. Do not override this method. Instead, override the set_test_params() method""" | ||||
self.setup_clean_chain = False | self.setup_clean_chain = False | ||||
self.nodes = [] | self.nodes = [] | ||||
self.mocktime = 0 | self.mocktime = 0 | ||||
def main(self): | def main(self, args=None): | ||||
"""Main function. This should not be overridden by the subclass test scripts.""" | """Main function. This should not be overridden by the subclass test scripts.""" | ||||
parser = argparse.ArgumentParser(usage="%(prog)s [options]") | parser = argparse.ArgumentParser(usage="%(prog)s [options]") | ||||
parser.add_argument("--nocleanup", dest="nocleanup", default=False, action="store_true", | parser.add_argument("--nocleanup", dest="nocleanup", default=False, action="store_true", | ||||
help="Leave bitcoinds and test.* datadir on exit or error") | help="Leave bitcoinds and test.* datadir on exit or error") | ||||
parser.add_argument("--noshutdown", dest="noshutdown", default=False, action="store_true", | parser.add_argument("--noshutdown", dest="noshutdown", default=False, action="store_true", | ||||
help="Don't stop bitcoinds after the test execution") | help="Don't stop bitcoinds after the test execution") | ||||
parser.add_argument("--srcdir", dest="srcdir", default=os.path.normpath(os.path.dirname(os.path.realpath(__file__)) + "/../../../src"), | parser.add_argument("--srcdir", dest="srcdir", default=os.path.normpath(os.path.dirname(os.path.realpath(__file__)) + "/../../../src"), | ||||
Show All 10 Lines | def main(self, args=None): | ||||
help="The seed to use for assigning port numbers (default: current process id)") | help="The seed to use for assigning port numbers (default: current process id)") | ||||
parser.add_argument("--coveragedir", dest="coveragedir", | parser.add_argument("--coveragedir", dest="coveragedir", | ||||
help="Write tested RPC commands into this directory") | help="Write tested RPC commands into this directory") | ||||
parser.add_argument("--configfile", dest="configfile", | parser.add_argument("--configfile", dest="configfile", | ||||
help="Location of the test framework config file") | help="Location of the test framework config file") | ||||
parser.add_argument("--pdbonfailure", dest="pdbonfailure", default=False, action="store_true", | parser.add_argument("--pdbonfailure", dest="pdbonfailure", default=False, action="store_true", | ||||
help="Attach a python debugger if test fails") | help="Attach a python debugger if test fails") | ||||
self.add_options(parser) | self.add_options(parser) | ||||
self.options = parser.parse_args() | self.options = parser.parse_args(args) | ||||
self.set_test_params() | self.set_test_params() | ||||
assert hasattr( | assert hasattr( | ||||
self, "num_nodes"), "Test must set self.num_nodes in set_test_params()" | self, "num_nodes"), "Test must set self.num_nodes in set_test_params()" | ||||
PortSeed.n = self.options.port_seed | PortSeed.n = self.options.port_seed | ||||
os.environ['PATH'] = self.options.srcdir + ":" + \ | os.environ['PATH'] = self.options.srcdir + ":" + \ | ||||
▲ Show 20 Lines • Show All 63 Lines • ▼ Show 20 Lines | def main(self, args=None): | ||||
print("From", fn, ":") | print("From", fn, ":") | ||||
print("".join(deque(f, MAX_LINES_TO_PRINT))) | print("".join(deque(f, MAX_LINES_TO_PRINT))) | ||||
except OSError: | except OSError: | ||||
print("Opening file %s failed." % fn) | print("Opening file %s failed." % fn) | ||||
traceback.print_exc() | traceback.print_exc() | ||||
if success == TestStatus.PASSED: | if success == TestStatus.PASSED: | ||||
self.log.info("Tests successful") | self.log.info("Tests successful") | ||||
sys.exit(TEST_EXIT_PASSED) | |||||
elif success == TestStatus.SKIPPED: | elif success == TestStatus.SKIPPED: | ||||
self.log.info("Test skipped") | self.log.info("Test skipped") | ||||
sys.exit(TEST_EXIT_SKIPPED) | |||||
else: | else: | ||||
self.log.error( | self.log.error( | ||||
"Test failed. Test logging available at %s/test_framework.log", self.options.tmpdir) | "Test failed. Test logging available at %s/test_framework.log", self.options.tmpdir) | ||||
logging.shutdown() | |||||
sys.exit(TEST_EXIT_FAILED) | # Manually close our handlers as we may be sharing logging with another test. | ||||
handlers = logging._handlers.copy() | |||||
for handler in handlers: | |||||
log.removeHandler(handler) | |||||
handler.flush() | |||||
handler.close() | |||||
return success | |||||
# Methods to override in subclass test scripts. | # Methods to override in subclass test scripts. | ||||
def set_test_params(self): | def set_test_params(self): | ||||
"""Tests must this method to change default values for number of nodes, topology, etc""" | """Tests must this method to change default values for number of nodes, topology, etc""" | ||||
raise NotImplementedError | raise NotImplementedError | ||||
def add_options(self, parser): | def add_options(self, parser): | ||||
"""Override this method to add command-line options to the test""" | """Override this method to add command-line options to the test""" | ||||
▲ Show 20 Lines • Show All 159 Lines • ▼ Show 20 Lines | class BitcoinTestFramework(): | ||||
def disable_mocktime(self): | def disable_mocktime(self): | ||||
self.mocktime = 0 | self.mocktime = 0 | ||||
# Private helper methods. These should not be accessed by the subclass test scripts. | # Private helper methods. These should not be accessed by the subclass test scripts. | ||||
def _start_logging(self): | def _start_logging(self): | ||||
# Add logger and logging handlers | # Add logger and logging handlers | ||||
self.log = logging.getLogger('TestFramework') | self.log = logging.getLogger(self.options.tmpdir) | ||||
self.log.setLevel(logging.DEBUG) | self.log.setLevel(logging.DEBUG) | ||||
# Create file handler to log all messages | # Create file handler to log all messages | ||||
fh = logging.FileHandler(self.options.tmpdir + '/test_framework.log') | fh = logging.FileHandler(self.options.tmpdir + '/test_framework.log') | ||||
fh.setLevel(logging.DEBUG) | fh.setLevel(logging.DEBUG) | ||||
# Create console handler to log messages to stderr. By default this | # Create console handler to log messages to stderr. By default this | ||||
# logs only error messages, but can be configured with --loglevel. | # logs only error messages, but can be configured with --loglevel. | ||||
ch = logging.StreamHandler(sys.stdout) | ch = logging.StreamHandler(sys.stdout) | ||||
# User can provide log level as a number or string (eg DEBUG). loglevel | # User can provide log level as a number or string (eg DEBUG). loglevel | ||||
▲ Show 20 Lines • Show All 138 Lines • Show Last 20 Lines |