From 89c3e0e8a9f8d853377ca34488f478665ac11d06 Mon Sep 17 00:00:00 2001 From: The MMGen Project Date: Fri, 3 Oct 2025 10:34:04 +0000 Subject: [PATCH] cmdtest.py: various cleanups (4 files) --- test/cmdtest_d/base.py | 1 + test/cmdtest_d/include/group_mgr.py | 42 +++++++++---------- test/cmdtest_d/include/runner.py | 63 ++++++++++++++--------------- test/cmdtest_d/main.py | 8 ++-- 4 files changed, 56 insertions(+), 58 deletions(-) diff --git a/test/cmdtest_d/base.py b/test/cmdtest_d/base.py index afe2b8f3..eef7f754 100755 --- a/test/cmdtest_d/base.py +++ b/test/cmdtest_d/base.py @@ -38,6 +38,7 @@ class CmdTestBase: need_daemon = False platform_skip = () tmpdir_nums = [] + skip_cmds = () test_name = None is_helper = False diff --git a/test/cmdtest_d/include/group_mgr.py b/test/cmdtest_d/include/group_mgr.py index 4e1b78f5..ce4486d4 100755 --- a/test/cmdtest_d/include/group_mgr.py +++ b/test/cmdtest_d/include/group_mgr.py @@ -13,6 +13,7 @@ cmdtest_d.include.group_mgr: Command group manager for the MMGen Wallet cmdtest """ import sys, os, time +from collections import namedtuple from mmgen.color import yellow, green, cyan from mmgen.util import Msg, die @@ -102,34 +103,33 @@ class CmdGroupMgr: without touching 'cmd_list' """ - cls = self.load_mod(gname, modname) - cdata = [] - def get_shared_deps(cmdname, tmpdir_idx): """ shared_deps are "implied" dependencies for all cmds in cmd_group that don't appear in the cmd_group data or cmds' argument lists. Supported only for 3seed tests at present. """ - if not hasattr(cls, 'shared_deps'): - return [] - return [k for k, v in cfgs[str(tmpdir_idx)]['dep_generators'].items() - if k in cls.shared_deps and v != cmdname] + if k in cls.shared_deps and v != cmdname] if hasattr(cls, 'shared_deps') else [] + + cls = self.load_mod(gname, modname) if not 'cmd_group' in cls.__dict__ and hasattr(cls, 'cmd_group_in'): cls.cmd_group = self.create_cmd_group(cls, sg_name) - for a, b in cls.cmd_group: - if is3seed: - for n, (i, j) in enumerate(zip(cls.tmpdir_nums, (128, 192, 256))): - k = f'{a}_{n+1}' - if hasattr(cls, 'skip_cmds') and k in cls.skip_cmds: - continue - cdata.append((k, (i, f'{b} ({j}-bit)', [[[] + get_shared_deps(k, i), i]]))) - elif full_data: - cdata.append((a, b)) - else: - cdata.append((a, (cls.tmpdir_nums[0], b, [[[], cls.tmpdir_nums[0]]]))) + def gen_cdata(): + cgd = namedtuple('cmd_group_data', ['tmpdir_num', 'desc', 'dpy_list']) + for a, b in cls.cmd_group: + if is3seed: + for n, (i, j) in enumerate(zip(cls.tmpdir_nums, [128, 192, 256])): + k = f'{a}_{n + 1}' + if not k in cls.skip_cmds: + yield (k, cgd(i, f'{b} ({j}-bit)', [[get_shared_deps(k, i), i]])) + elif full_data: + yield (a, cgd(*b)) + else: + yield (a, cgd(cls.tmpdir_nums[0], b, [[[], cls.tmpdir_nums[0]]])) + + cdata = tuple(gen_cdata()) # cannot use dict() here because of repeated keys if add_dpy: self.dpy_data.update(dict(cdata)) @@ -192,9 +192,7 @@ class CmdGroupMgr: name_w = max(len(name) for name in ginfo) for name, cls in ginfo.items(): if not cls.is_helper: - yield ' {} - {}'.format( - yellow(name.ljust(name_w)), - (cls.__doc__.strip() if cls.__doc__ else cls.__name__)) + yield ' {} - {}'.format(yellow(name.ljust(name_w)), cls.__doc__.strip()) if 'cmd_subgroups' in cls.__dict__: subgroups = {k:v for k, v in cls.cmd_subgroups.items() if not k.startswith('_')} max_w = max(len(k) for k in subgroups) @@ -211,7 +209,7 @@ class CmdGroupMgr: and return it as a string. Loads modules but alters no global variables. """ if group: - if not group in [e[0] for e in self.cmd_groups]: + if not group in self.cmd_groups: die(1, f'{group!r}: unrecognized group') groups = [self.cmd_groups[group]] else: diff --git a/test/cmdtest_d/include/runner.py b/test/cmdtest_d/include/runner.py index 78b8e599..1b3bc227 100755 --- a/test/cmdtest_d/include/runner.py +++ b/test/cmdtest_d/include/runner.py @@ -13,10 +13,11 @@ test.cmdtest_d.include.runner: test runner for the MMGen Wallet cmdtest suite """ import sys, os, time, asyncio +from collections import namedtuple from mmgen.cfg import gc from mmgen.color import red, yellow, green, blue, cyan, gray, nocolor -from mmgen.util import msg, Msg, rmsg, ymsg, bmsg, die, suf, make_timestr, isAsync +from mmgen.util import msg, Msg, rmsg, ymsg, bmsg, die, suf, make_timestr, isAsync, capfirst from ...include.common import ( cmdtest_py_log_fn, @@ -30,7 +31,7 @@ from ...include.common import ( ) from .common import get_file_with_ext, confirm_continue -from .cfg import cfgs, cmd_groups_dfl +from .cfg import cfgs from .group_mgr import CmdGroupMgr def format_args(args): @@ -141,7 +142,8 @@ class CmdTestRunner: self.exit_val = exit_val - desc = self.tg.test_name if self.cfg.names else self.gm.dpy_data[self.tg.test_name][1] + desc = self.tg.test_name if self.cfg.names else self.gm.dpy_data[self.tg.test_name].desc + if extra_desc: desc += ' ' + extra_desc @@ -347,8 +349,9 @@ class CmdTestRunner: except Exception as e: # allow calling of functions not in cmd_group if isinstance(e, KeyError) and e.args[0] == cmdname: func = getattr(self.tg, cmdname) - ret = asyncio.run(func()) if isAsync(func) else func() - self.process_retval(cmdname, ret) + self.process_retval( + cmdname, + asyncio.run(func()) if isAsync(func) else func()) else: raise self.do_between() @@ -385,16 +388,16 @@ class CmdTestRunner: fns = [] if force_delete or not root: - # does cmd produce a needed dependency(ies)? - ret = self.get_num_exts_for_cmd(cmd) - if ret: - for ext in ret[1]: - fn = get_file_with_ext(cfgs[ret[0]]['tmpdir'], ext, delete=build) - if fn: + # does cmd produce a required dependency(ies)? + if deps := self.get_cmd_deps(cmd): + for ext in deps.exts: + if fn := get_file_with_ext(cfgs[deps.cfgnum]['tmpdir'], ext, delete=build): if force_delete: os.unlink(fn) - else: fns.append(fn) - else: rerun = True + else: + fns.append(fn) + else: + rerun = True fdeps = self.generate_file_deps(cmd) cdeps = self.generate_cmd_deps(fdeps) @@ -419,10 +422,8 @@ class CmdTestRunner: self.run_test(cmd) if not root: self.do_between() - else: - # If prog produces multiple files: - if cmd not in self.rebuild_list or rerun is True: - self.rebuild_list[cmd] = (rerun, fns[0] if fns else '') # FIX + elif rerun or cmd not in self.rebuild_list: + self.rebuild_list[cmd] = 'rebuild' if rerun and fns else 'build' if rerun else 'OK' return rerun @@ -432,9 +433,9 @@ class CmdTestRunner: sys.exit(0) if self.tg.full_data: - d = [(str(num), ext) for exts, num in self.gm.dpy_data[cmd][2] for ext in exts] + d = [(num, ext) for exts, num in self.gm.dpy_data[cmd].dpy_list for ext in exts] # delete files depended on by this cmd - arg_list = [get_file_with_ext(cfgs[num]['tmpdir'], ext) for num, ext in d] + arg_list = [get_file_with_ext(cfgs[str(num)]['tmpdir'], ext) for num, ext in d] # remove shared_deps from arg list if hasattr(self.tg, 'shared_deps'): @@ -456,7 +457,7 @@ class CmdTestRunner: self.tg.test_name = cmd # NB: Do not remove, this needs to be set twice if self.tg.full_data: - tmpdir_num = self.gm.dpy_data[cmd][0] + tmpdir_num = self.gm.dpy_data[cmd].tmpdir_num self.tg.tmpdir_num = tmpdir_num for k in (test_cfg := cfgs[str(tmpdir_num)]): if k in self.gm.cfg_attrs: @@ -532,33 +533,31 @@ class CmdTestRunner: self.check_needs_rerun(cmd) w = max(map(len, self.rebuild_list)) + 1 - for cmd in self.rebuild_list: - c = self.rebuild_list[cmd] - m = 'Rebuild' if (c[0] and c[1]) else 'Build' if c[0] else 'OK' - omsg('cmd {:<{w}} {}'.format(cmd+':', m, w=w)) + for cmd, desc in self.rebuild_list.items(): + omsg('cmd {:<{w}} {}'.format(cmd+':', capfirst(desc), w=w)) def generate_file_deps(self, cmd): - return [(str(n), e) for exts, n in self.gm.dpy_data[cmd][2] for e in exts] + return [(str(n), e) for exts, n in self.gm.dpy_data[cmd].dpy_list for e in exts] def generate_cmd_deps(self, fdeps): return [cfgs[str(n)]['dep_generators'][ext] for n, ext in fdeps] - def get_num_exts_for_cmd(self, cmd): + def get_cmd_deps(self, cmd): try: - num = str(self.gm.dpy_data[cmd][0]) + self.gm.dpy_data[cmd] except KeyError: qmsg_r(f'Missing dependency {cmd!r}') if gname := self.gm.find_cmd_in_groups(cmd): kwargs = self.gm.cmd_groups[gname].params | {'add_dpy': True} self.gm.create_group(gname, None, **kwargs) - num = str(self.gm.dpy_data[cmd][0]) qmsg(f' found in group {gname!r}') else: qmsg(' not found in any command group!') raise - dgl = cfgs[num]['dep_generators'] - if cmd in dgl.values(): - exts = [k for k in dgl if dgl[k] == cmd] - return (num, exts) + num = str(self.gm.dpy_data[cmd].tmpdir_num) + dep_gens = cfgs[num]['dep_generators'] + if cmd in dep_gens.values(): + cd = namedtuple('cmd_deps', ['cfgnum', 'exts']) + return cd(num, [k for k in dep_gens if dep_gens[k] == cmd]) else: return None diff --git a/test/cmdtest_d/main.py b/test/cmdtest_d/main.py index 54f0951f..9ef09bf4 100755 --- a/test/cmdtest_d/main.py +++ b/test/cmdtest_d/main.py @@ -241,13 +241,13 @@ class CmdTestMain(CmdTestBase, CmdTestShared): (3, 'tx signing with inputs and outputs from two wallets', [[['mmdat'], 1], [['mmdat', 'rawtx'], 3]]) ), ('walletgen14', - (14, 'wallet generation (14)', [[['del_dw_run'], 15]], 14) + (14, 'wallet generation (14)', [[['del_dw_run'], 15]]) ), ('addrgen14', (14, 'address generation (14)', [[['mmdat'], 14]]) ), ('keyaddrgen14', - (14, 'key-address file generation (14)', [[['mmdat'], 14]], 14) + (14, 'key-address file generation (14)', [[['mmdat'], 14]]) ), ('walletgen4', (4, 'wallet generation (4) (brainwallet)', [[['del_dw_run'], 15]]) @@ -310,7 +310,7 @@ class CmdTestMain(CmdTestBase, CmdTestShared): ]) ), # must go after txsign4 ('walletgen5', - (20, 'wallet generation (5)', [[['del_dw_run'], 15]], 20) + (20, 'wallet generation (5)', [[['del_dw_run'], 15]]) ), ('addrgen5', (20, 'address generation (5)', [[['mmdat'], 20]]) @@ -322,7 +322,7 @@ class CmdTestMain(CmdTestBase, CmdTestShared): (20, 'transaction signing with bad vsize', [[['mmdat', 'rawtx'], 20]]) ), ('walletgen6', - (21, 'wallet generation (6)', [[['del_dw_run'], 15]], 21) + (21, 'wallet generation (6)', [[['del_dw_run'], 15]]) ), ('addrgen6', (21, 'address generation (6)', [[['mmdat'], 21]])