#!/usr/bin/env python3 """ test.daemontest_d.exec: unit test for the MMGen suite's Daemon class """ from subprocess import run, PIPE from collections import namedtuple from mmgen.cfg import gc from mmgen.color import orange, red from mmgen.util import fmt_list, in_nix_environment from mmgen.daemon import CoinDaemon from ..include.common import cfg, qmsg, qmsg_r, vmsg, msg, msg_r def test_flags(coin): d = CoinDaemon(cfg, network_id=coin) vmsg(f'Available opts: {fmt_list(d.avail_opts, fmt="bare")}') vmsg(f'Available flags: {fmt_list(d.avail_flags, fmt="bare")}') vals = namedtuple('vals', ['online', 'no_daemonize', 'keep_cfg_file']) def gen(): for opts, flags, val in ( (None, None, vals(False, False, False)), (None, ['keep_cfg_file'], vals(False, False, True)), (['online'], ['keep_cfg_file'], vals(True, False, True)), (['online', 'no_daemonize'], ['keep_cfg_file'], vals(True, True, True)), ): d = CoinDaemon(cfg, network_id=coin, opts=opts, flags=flags) assert d.flag.keep_cfg_file == val.keep_cfg_file assert d.opt.online == val.online assert d.opt.no_daemonize == val.no_daemonize d.flag.keep_cfg_file = not val.keep_cfg_file d.flag.keep_cfg_file = val.keep_cfg_file yield d return tuple(gen()) def test_flags_err(ut, d): def bad1(): d[0].flag.foo = False def bad2(): d[0].opt.foo = False def bad3(): d[0].opt.no_daemonize = True def bad4(): d[0].flag.keep_cfg_file = 'x' def bad5(): d[0].opt.no_daemonize = 'x' def bad6(): d[0].flag.keep_cfg_file = False def bad7(): d[1].flag.keep_cfg_file = True ut.process_bad_data(( ('flag (1)', 'ClassFlagsError', 'unrecognized flag', bad1), ('opt (1)', 'ClassFlagsError', 'unrecognized opt', bad2), ('opt (2)', 'AttributeError', 'is read-only', bad3), ('flag (2)', 'AssertionError', 'not boolean', bad4), ('opt (3)', 'AttributeError', 'is read-only', bad5), ('flag (3)', 'ClassFlagsError', 'not set', bad6), ('flag (4)', 'ClassFlagsError', 'already set', bad7), )) class unit_tests: win_skip = ('start', 'status', 'stop') altcoin_deps = ('flags_eth',) def _pre(self): self.daemon_ctrl_args = ['btc', 'btc_tn', 'btc_rt'] if cfg.no_altcoin_deps else ['all'] def _test_cmd(self, cmd, *, opts=[], network_ids=[], ok=True): args = ( ['python3', f'test/{cmd}-coin-daemons.py'] + opts + (network_ids or self.daemon_ctrl_args)) vmsg('\n' + orange(f"Running '{' '.join(args)}':")) redir = None if cfg.verbose else PIPE cp = run(args, stdout=redir, stderr=redir, text=True) if cp.returncode != 0: if cp.stdout: msg(cp.stdout) if cp.stderr: msg(red(cp.stderr)) return False if ok: vmsg('') qmsg('OK') return True def _test_daemons(self, cmd, *, msg, opts=[]): qmsg_r(msg + ' coin daemons...') test_reth = not (cfg.no_altcoin_deps or cfg.fast) test_parity = not ( cfg.no_altcoin_deps or gc.machine in ('riscv64', 'aarch64', 'armv7l') or in_nix_environment()) ret1 = self._test_cmd( cmd, opts = opts, network_ids = ['btc'] if cfg.no_altcoin_deps else ['btc', 'ltc', 'bch', 'xmr', 'eth'], ok = not (test_reth or test_parity)) ret2 = self._test_cmd( cmd, opts = opts + ['--daemon-id=reth'], network_ids = ['eth'], ok = not test_parity) if test_reth else True ret3 = self._test_cmd( cmd, opts = opts, network_ids = ['etc'], ok = True) if test_parity else True return ret1 and ret2 and ret3 def flags(self, name, ut): qmsg_r('Testing flags and opts (BTC)...') vmsg('') daemons = test_flags(coin='btc') qmsg('OK') qmsg_r('Testing error handling for flags and opts...') vmsg('') test_flags_err(ut, daemons) qmsg('OK') return True def flags_eth(self, name, ut): qmsg_r('Testing flags and opts (ETH)...') vmsg('') daemons = test_flags(coin='eth') qmsg('OK') qmsg_r('Testing error handling for flags and opts...') vmsg('') test_flags_err(ut, daemons) qmsg('OK') return True def avail(self, name, ut): return self._test_daemons( 'start', msg = 'Testing availability of', opts = ['--print-version', '--mainnet-only']) def versions(self, name, ut): qmsg_r('Displaying coin daemon versions...') ret1 = self._test_cmd('start', opts=['--print-version'], ok=False) ret2 = self._test_cmd('start', opts=['--print-version', '--mainnet-only']) return ret1 and ret2 def cmds(self, name, ut): qmsg_r('Testing start commands for coin daemons...') return self._test_cmd('start', opts=['--testing']) def start(self, name, ut): return self._test_daemons('start', msg='Starting') def status(self, name, ut): return self._test_daemons('start', msg='Checking status of') def stop(self, name, ut): return self._test_daemons('stop', msg='Stopping', opts=['--remove-datadir'])