From 170a9eadad704afc99d96f4479988ff7ae882af9 Mon Sep 17 00:00:00 2001 From: The MMGen Project Date: Fri, 29 Jul 2022 16:45:31 +0000 Subject: [PATCH] `test.py`: support command subgroups MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Example: # List available command groups and subgroups $ test/test.py -L # Run the ‘msg’ subgroup of ‘regtest’, leaving the daemon running: $ test/test.py -D regtest.msg # Re-run the subgroup, skipping dependencies and viewing output: $ test/test.py -Se regtest.msg # Re-run the individual test ‘bob_msgverify’ in the subgroup: $ test/test.py -Se regtest.msg:bob_msgverify # Same as above: $ test/test.py -Se regtest:bob_msgverify --- mmgen/data/version | 2 +- test/test.py | 116 +++++++++--- test/test_py_d/ts_ethdev.py | 343 +++++++++++++++++++---------------- test/test_py_d/ts_regtest.py | 287 ++++++++++++++++------------- 4 files changed, 441 insertions(+), 307 deletions(-) diff --git a/mmgen/data/version b/mmgen/data/version index d5e021ec..ba6c1d2f 100644 --- a/mmgen/data/version +++ b/mmgen/data/version @@ -1 +1 @@ -13.2.dev10 +13.2.dev11 diff --git a/test/test.py b/test/test.py index 2c5ea72b..d5440e6e 100755 --- a/test/test.py +++ b/test/test.py @@ -96,7 +96,7 @@ opts_data = { 'sets': [('list_current_cmd_groups',True,'list_cmd_groups',True)], 'text': { 'desc': 'Test suite for the MMGen suite', - 'usage':'[options] [command(s) or metacommand(s)]', + 'usage':'[options] [command [..command]] | [command_group[.command_subgroup][:command]]', 'options': """ -h, --help Print this help message --, --longhelp Print help message for long options (common options) @@ -114,7 +114,7 @@ opts_data = { -e, --exact-output Show the exact output of the MMGen script(s) being run -G, --exclude-groups=G Exclude the specified command groups (comma-separated) -l, --list-cmds List the test script’s available commands --L, --list-cmd-groups Output a list of command groups with descriptions +-L, --list-cmd-groups List the test script’s command groups and subgroups -g, --list-current-cmd-groups List command groups for current configuration -n, --names Display command names instead of descriptions -N, --no-timings Suppress display of timing information @@ -345,6 +345,36 @@ class CmdGroupMgr(object): cmd_groups = cmd_groups_dfl.copy() cmd_groups.update(cmd_groups_extra) + @staticmethod + def create_cmd_group(cls,sg_name=None): + + cmd_group_in = dict(cls.cmd_group_in) + + if sg_name and 'subgroup.' + sg_name not in cmd_group_in: + die(1,f'{sg_name!r}: no such subgroup in test group {cls.__name__}') + + def add_entries(key,add_deps=True): + if add_deps: + for dep in cmd_group_in['subgroup.'+key]: + for e in add_entries(dep): + yield e + for e in cls.cmd_subgroups[key][1:]: + yield e + + def gen(): + for name,data in cls.cmd_group_in: + if name.startswith('subgroup.'): + sg_key = name.removeprefix('subgroup.') + if sg_name in (None,sg_key): + for e in add_entries( + sg_key, + add_deps = sg_name and not skipping_deps ): + yield e + elif not skipping_deps: + yield (name,data) + + return tuple(gen()) + def load_mod(self,gname,modname=None): clsname,kwargs = self.cmd_groups[gname] if modname == None and 'modname' in kwargs: @@ -353,7 +383,7 @@ class CmdGroupMgr(object): modpath = f'test.test_py_d.ts_{modname or gname}' return getattr(importlib.import_module(modpath),clsname) - def create_group(self,gname,full_data=False,modname=None,is3seed=False,add_dpy=False): + def create_group(self,gname,sg_name,full_data=False,modname=None,is3seed=False,add_dpy=False): """ Initializes the list 'cmd_list' and dict 'dpy_data' from module's cmd_group data. Alternatively, if called with 'add_dpy=True', updates 'dpy_data' from module data @@ -374,6 +404,9 @@ class CmdGroupMgr(object): return [k for k,v in cfgs[str(tmpdir_idx)]['dep_generators'].items() if k in cls.shared_deps and v != cmdname] + if not hasattr(cls,'cmd_group'): + 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))): @@ -396,9 +429,9 @@ class CmdGroupMgr(object): return cls - def gm_init_group(self,trunner,gname,spawn_prog): + def gm_init_group(self,trunner,gname,sg_name,spawn_prog): kwargs = self.cmd_groups[gname][1] - cls = self.create_group(gname,**kwargs) + cls = self.create_group(gname,sg_name,**kwargs) cls.group_name = gname return cls(trunner,cfgs,spawn_prog) @@ -415,12 +448,23 @@ class CmdGroupMgr(object): if network_id in g[1].networks and not g[0] in exclude and g[0] in tuple(self.cmd_groups_dfl) + tuple(usr_args) ] + desc = 'CONFIGURED' + else: + desc = 'AVAILABLE' - for name,cls in ginfo: - msg('{:17} - {}'.format( - name, - cls.__doc__.strip() if cls.__doc__ else cls.__name__ - )) + def gen_output(): + yield green(f'{desc} COMMAND GROUPS AND SUBGROUPS:') + yield '' + for name,cls in ginfo: + yield ' {} - {}'.format( + yellow(name.ljust(13)), + (cls.__doc__.strip() if cls.__doc__ else cls.__name__) ) + if hasattr(cls,'cmd_subgroups'): + max_w = max(len(k) for k in cls.cmd_subgroups) + for k,v in cls.cmd_subgroups.items(): + yield ' + {} · {}'.format( cyan(k.ljust(max_w+1)), v[0] ) + + do_pager('\n'.join(gen_output())) Msg( '\n' + ' '.join(e[0] for e in ginfo) ) sys.exit(0) @@ -441,6 +485,9 @@ class CmdGroupMgr(object): clsname,kwargs = self.cmd_groups[gname] cls = self.load_mod(gname,kwargs['modname'] if 'modname' in kwargs else None) + if not hasattr(cls,'cmd_group'): + cls.cmd_group = self.create_cmd_group(cls) + if cmd in cls.cmd_group: # first search the class return gname @@ -559,7 +606,7 @@ class TestSuiteRunner(object): ('\n' if opt.no_timings else f'. Elapsed time: {t//60:02d}:{t%60:02d}\n') )) - def init_group(self,gname,cmd=None,quiet=False,do_clean=True): + def init_group(self,gname,sg_name=None,cmd=None,quiet=False,do_clean=True): ts_cls = CmdGroupMgr().load_mod(gname) @@ -607,7 +654,7 @@ class TestSuiteRunner(object): os.environ['MMGEN_BOGUS_UNSPENT_DATA'] = '' # zero this here, so test groups don't have to - self.ts = self.gm.gm_init_group(self,gname,self.spawn_wrapper) + self.ts = self.gm.gm_init_group(self,gname,sg_name,self.spawn_wrapper) self.ts_clsname = type(self.ts).__name__ self.passthru_opts = ['--{}{}'.format( @@ -641,24 +688,37 @@ class TestSuiteRunner(object): self.check_needs_rerun(cmd,build=True) do_between() else: - if ':' in arg: - gname,arg = arg.split(':') - else: - gname = self.gm.find_cmd_in_groups(arg) + def parse_arg(arg): + if '.' in arg: + a,b = arg.split('.') + return [a] + b.split(':') if ':' in b else [a,b,None] + elif ':' in arg: + a,b = arg.split(':') + return [a,None,b] + else: + return [self.gm.find_cmd_in_groups(arg),None,arg] + + gname,sg_name,cmdname = parse_arg(arg) + if gname: same_grp = gname == gname_save # same group as previous cmd: don't clean, suppress blue msg - if not self.init_group(gname,arg,quiet=same_grp,do_clean=not same_grp): + if not self.init_group(gname,sg_name,cmdname,quiet=same_grp,do_clean=not same_grp): continue - try: - self.check_needs_rerun(arg,build=True) - except Exception as e: # allow calling of functions not in cmd_group - if isinstance(e,KeyError) and e.args[0] == arg: - ret = getattr(self.ts,arg)() - if type(ret).__name__ == 'coroutine': - run_session(ret) - else: - raise - do_between() + if cmdname: + try: + self.check_needs_rerun(cmdname,build=True) + except Exception as e: # allow calling of functions not in cmd_group + if isinstance(e,KeyError) and e.args[0] == cmdname: + ret = getattr(self.ts,cmdname)() + if type(ret).__name__ == 'coroutine': + run_session(ret) + else: + raise + do_between() + else: + for cmd in self.gm.cmd_list: + self.check_needs_rerun(cmd,build=True) + do_between() gname_save = gname else: die(1,f'{arg!r}: command not recognized') @@ -838,7 +898,7 @@ class TestSuiteRunner(object): if gname: kwargs = self.gm.cmd_groups[gname][1] kwargs.update({'add_dpy':True}) - self.gm.create_group(gname,**kwargs) + self.gm.create_group(gname,None,**kwargs) num = str(self.gm.dpy_data[cmd][0]) qmsg(f' found in group {gname!r}') else: diff --git a/test/test_py_d/ts_ethdev.py b/test/test_py_d/ts_ethdev.py index 0c8be194..275837fb 100755 --- a/test/test_py_d/ts_ethdev.py +++ b/test/test_py_d/ts_ethdev.py @@ -56,7 +56,8 @@ vbal2 = '99.997088755' vbal3 = '1.23142525' vbal4 = '127.0287909' vbal5 = '1000126.14828654512345678' -vbal6 = '1000124.91944564512345678' +vbal6 = '1000126.14933654512345678' +vbal7 = '1000124.91944564512345678' bals = { '1': [ ('98831F3A:E:1','123.456')], @@ -130,148 +131,195 @@ class TestSuiteEthdev(TestSuiteBase,TestSuiteShared): extra_spawn_args = ['--regtest=1'] tmpdir_nums = [22] color = True - cmd_group = ( - ('setup', f'dev mode tests for coin {coin} (start daemon)'), - ('daemon_version', 'mmgen-tool daemon_version'), - ('wallet_upgrade1', 'upgrading the tracking wallet (v1 -> v2)'), - ('wallet_upgrade2', 'upgrading the tracking wallet (v2 -> v3)'), - ('addrgen', 'generating addresses'), - ('addrimport', 'importing addresses'), - ('addrimport_dev_addr', "importing dev faucet address 'Ox00a329c..'"), + cmd_group_in = ( + ('setup', f'dev mode tests for coin {coin} (start daemon)'), + ('subgroup.misc', []), + ('subgroup.init', []), + ('subgroup.msg', ['init']), + ('subgroup.main', ['init']), + ('subgroup.contract', ['main']), + ('subgroup.token', ['contract']), + ('subgroup.twexport', ['token']), + ('subgroup.cached', ['token']), + ('subgroup.view', ['cached']), + ('subgroup.label', ['cached']), + ('subgroup.remove', ['cached']), + ('stop', 'stopping daemon'), + ) + cmd_subgroups = { + 'misc': ( + 'miscellaneous commands', + ('daemon_version', 'mmgen-tool daemon_version'), + ), + 'init': ( + 'initializing wallets', + ('wallet_upgrade1', 'upgrading the tracking wallet (v1 -> v2)'), + ('wallet_upgrade2', 'upgrading the tracking wallet (v2 -> v3)'), + ('addrgen', 'generating addresses'), + ('addrimport', 'importing addresses'), + ('addrimport_dev_addr', "importing dev faucet address 'Ox00a329c..'"), + ('fund_dev_address', 'funding the default (Parity dev) address'), + ), + 'msg': ( + 'message signing', + ('msgsign_chk', "signing a message (low-level, check against 'eth_sign' RPC call)"), + ('msgcreate', 'creating a message file'), + ('msgsign', 'signing the message file'), + ('msgverify', 'verifying the message file'), + ('msgexport', 'exporting the message file data to JSON for third-party verifier'), + ('msgverify_export', 'verifying the exported JSON data'), - ('fund_dev_address', 'funding the default (Parity dev) address'), + ('msgcreate_raw', 'creating a message file (--msghash-type=raw)'), + ('msgsign_raw', 'signing the message file (msghash_type=raw)'), + ('msgverify_raw', 'verifying the message file (msghash_type=raw)'), + ('msgexport_raw', 'exporting the message file data to JSON (msghash_type=raw)'), + ('msgverify_export_raw', 'verifying the exported JSON data (msghash_type=raw)'), + ), + 'main': ( + 'creating, signing, sending and bumping Ethereum transactions', + ('txcreate1', 'creating a transaction (spend from dev address to address :1)'), + ('txview1_raw', 'viewing the raw transaction'), + ('txsign1', 'signing the transaction'), + ('txview1_sig', 'viewing the signed transaction'), + ('tx_status0_bad', 'getting the transaction status'), + ('txsign1_ni', 'signing the transaction (non-interactive)'), + ('txsend1', 'sending the transaction'), + ('bal1', f'the {coin} balance'), - ('msgsign_chk', "signing a message (low-level, check against 'eth_sign' RPC call)"), - ('msgcreate', 'creating a message file'), - ('msgsign', 'signing the message file'), - ('msgverify', 'verifying the message file'), - ('msgexport', 'exporting the message file data to JSON for third-party verifier'), - ('msgverify_export', 'verifying the exported JSON data'), + ('txcreate2', 'creating a transaction (spend from dev address to address :11)'), + ('txsign2', 'signing the transaction'), + ('txsend2', 'sending the transaction'), + ('bal2', f'the {coin} balance'), - ('msgcreate_raw', 'creating a message file (--msghash-type=raw)'), - ('msgsign_raw', 'signing the message file (msghash_type=raw)'), - ('msgverify_raw', 'verifying the message file (msghash_type=raw)'), - ('msgexport_raw', 'exporting the message file data to JSON (msghash_type=raw)'), - ('msgverify_export_raw', 'verifying the exported JSON data (msghash_type=raw)'), + ('txcreate3', 'creating a transaction (spend from dev address to address :21)'), + ('txsign3', 'signing the transaction'), + ('txsend3', 'sending the transaction'), + ('bal3', f'the {coin} balance'), - ('txcreate1', 'creating a transaction (spend from dev address to address :1)'), - ('txview1_raw', 'viewing the raw transaction'), - ('txsign1', 'signing the transaction'), - ('txview1_sig', 'viewing the signed transaction'), - ('tx_status0_bad', 'getting the transaction status'), - ('txsign1_ni', 'signing the transaction (non-interactive)'), - ('txsend1', 'sending the transaction'), - ('bal1', f'the {coin} balance'), + ('tx_status1', 'getting the transaction status'), - ('txcreate2', 'creating a transaction (spend from dev address to address :11)'), - ('txsign2', 'signing the transaction'), - ('txsend2', 'sending the transaction'), - ('bal2', f'the {coin} balance'), + ('txcreate4', 'creating a transaction (spend from MMGen address, low TX fee)'), + ('txbump', 'bumping the transaction fee'), - ('txcreate3', 'creating a transaction (spend from dev address to address :21)'), - ('txsign3', 'signing the transaction'), - ('txsend3', 'sending the transaction'), - ('bal3', f'the {coin} balance'), + ('txsign4', 'signing the transaction'), + ('txsend4', 'sending the transaction'), + ('tx_status1a', 'getting the transaction status'), + ('bal4', f'the {coin} balance'), - ('tx_status1', 'getting the transaction status'), + ('txcreate5', 'creating a transaction (fund burn address)'), + ('txsign5', 'signing the transaction'), + ('txsend5', 'sending the transaction'), - ('txcreate4', 'creating a transaction (spend from MMGen address, low TX fee)'), - ('txbump', 'bumping the transaction fee'), + ('addrimport_burn_addr', 'importing burn address'), + ('bal5', f'the {coin} balance'), - ('txsign4', 'signing the transaction'), - ('txsend4', 'sending the transaction'), - ('tx_status1a', 'getting the transaction status'), - ('bal4', f'the {coin} balance'), + ('add_label1', 'adding a UTF-8 label (zh)'), + ('chk_label1', 'checking the label'), + ('add_label2', 'adding a UTF-8 label (lat+cyr+gr)'), + ('chk_label2', 'checking the label'), + ('remove_label', 'removing the label'), + ), + 'contract': ( + 'creating and deploying ERC20 tokens', + ('token_compile1', 'compiling ERC20 token #1'), + ('token_deploy1a', 'deploying ERC20 token #1 (SafeMath)'), + ('token_deploy1b', 'deploying ERC20 token #1 (Owned)'), + ('token_deploy1c', 'deploying ERC20 token #1 (Token)'), - ('txcreate5', 'creating a transaction (fund burn address)'), - ('txsign5', 'signing the transaction'), - ('txsend5', 'sending the transaction'), + ('tx_status2', 'getting the transaction status'), + ('bal6', f'the {coin} balance'), - ('addrimport_burn_addr', 'importing burn address'), - ('bal5', f'the {coin} balance'), + ('token_compile2', 'compiling ERC20 token #2'), + ('token_deploy2a', 'deploying ERC20 token #2 (SafeMath)'), + ('token_deploy2b', 'deploying ERC20 token #2 (Owned)'), + ('token_deploy2c', 'deploying ERC20 token #2 (Token)'), - ('add_label1', 'adding a UTF-8 label (zh)'), - ('chk_label1', 'the label'), - ('add_label2', 'adding a UTF-8 label (lat+cyr+gr)'), - ('chk_label2', 'the label'), - ('remove_label', 'removing the label'), + ('contract_deploy', 'deploying contract (create,sign,send)'), + ), + 'token': ( + 'creating, signing, sending and bumping ERC20 token transactions', - ('token_compile1', 'compiling ERC20 token #1'), + ('token_fund_users', 'transferring token funds from dev to user'), + ('token_user_bals', 'show balances after transfer'), + ('token_addrgen', 'generating token addresses'), + ('token_addrimport_badaddr1', 'importing token addresses (no token address)'), + ('token_addrimport_badaddr2', 'importing token addresses (bad token address)'), + ('token_addrimport_addr1', 'importing token addresses using token address (MM1)'), + ('token_addrimport_addr2', 'importing token addresses using token address (MM2)'), + ('token_addrimport_batch', 'importing token addresses (dummy batch mode) (MM1)'), + ('token_addrimport_sym', 'importing token addresses using token symbol (MM2)'), - ('token_deploy1a', 'deploying ERC20 token #1 (SafeMath)'), - ('token_deploy1b', 'deploying ERC20 token #1 (Owned)'), - ('token_deploy1c', 'deploying ERC20 token #1 (Token)'), + ('bal7', f'the {coin} balance'), + ('token_bal1', f'the {coin} balance and token balance'), - ('tx_status2', 'getting the transaction status'), - ('bal6', f'the {coin} balance'), + ('token_txcreate1', 'creating a token transaction'), + ('token_txview1_raw', 'viewing the raw transaction'), + ('token_txsign1', 'signing the transaction'), + ('token_txsend1', 'sending the transaction'), + ('token_txview1_sig', 'viewing the signed transaction'), + ('tx_status3', 'getting the transaction status'), + ('token_bal2', f'the {coin} balance and token balance'), - ('token_compile2', 'compiling ERC20 token #2'), + ('token_txcreate2', 'creating a token transaction (to burn address)'), + ('token_txbump', 'bumping the transaction fee'), - ('token_deploy2a', 'deploying ERC20 token #2 (SafeMath)'), - ('token_deploy2b', 'deploying ERC20 token #2 (Owned)'), - ('token_deploy2c', 'deploying ERC20 token #2 (Token)'), + ('token_txsign2', 'signing the transaction'), + ('token_txsend2', 'sending the transaction'), + ('token_bal3', f'the {coin} balance and token balance'), - ('contract_deploy', 'deploying contract (create,sign,send)'), + ('del_dev_addr', 'deleting the dev address'), - ('token_fund_users', 'transferring token funds from dev to user'), - ('token_user_bals', 'show balances after transfer'), - ('token_addrgen', 'generating token addresses'), - ('token_addrimport_badaddr1', 'importing token addresses (no token address)'), - ('token_addrimport_badaddr2', 'importing token addresses (bad token address)'), - ('token_addrimport_addr1', 'importing token addresses using token address (MM1)'), - ('token_addrimport_addr2', 'importing token addresses using token address (MM2)'), - ('token_addrimport_batch', 'importing token addresses (dummy batch mode) (MM1)'), - ('token_addrimport_sym', 'importing token addresses using token symbol (MM2)'), + ('bal1_getbalance', f'the {coin} balance (getbalance)'), - ('bal7', f'the {coin} balance'), - ('token_bal1', f'the {coin} balance and token balance'), + ('addrimport_token_burn_addr', 'importing the token burn address'), - ('token_txcreate1', 'creating a token transaction'), - ('token_txview1_raw', 'viewing the raw transaction'), - ('token_txsign1', 'signing the transaction'), - ('token_txsend1', 'sending the transaction'), - ('token_txview1_sig', 'viewing the signed transaction'), - ('tx_status3', 'getting the transaction status'), - ('token_bal2', f'the {coin} balance and token balance'), + ('token_bal4', f'the {coin} balance and token balance'), + ('token_bal_getbalance', 'the token balance (getbalance)'), - ('token_txcreate2', 'creating a token transaction (to burn address)'), - ('token_txbump', 'bumping the transaction fee'), + ('txcreate_noamt', 'creating a transaction (full amount send)'), + ('txsign_noamt', 'signing the transaction'), + ('txsend_noamt', 'sending the transaction'), - ('token_txsign2', 'signing the transaction'), - ('token_txsend2', 'sending the transaction'), - ('token_bal3', f'the {coin} balance and token balance'), + ('bal8', f'the {coin} balance'), + ('token_bal5', 'the token balance'), - ('del_dev_addr', 'deleting the dev address'), + ('token_txcreate_noamt', 'creating a token transaction (full amount send)'), + ('token_txsign_noamt', 'signing the transaction'), + ('token_txsend_noamt', 'sending the transaction'), - ('bal1_getbalance', f'the {coin} balance (getbalance)'), + ('bal9', f'the {coin} balance'), + ('token_bal6', 'the token balance'), - ('addrimport_token_burn_addr', 'importing the token burn address'), + ('listaddresses1', 'listaddresses'), + ('listaddresses2', 'listaddresses minconf=999999999 (ignored)'), + ('listaddresses3', 'listaddresses sort=age (ignored)'), + ('listaddresses4', 'listaddresses showempty=1 sort=age (ignored)'), - ('token_bal4', f'the {coin} balance and token balance'), - ('token_bal_getbalance', 'the token balance (getbalance)'), - - ('txcreate_noamt', 'creating a transaction (full amount send)'), - ('txsign_noamt', 'signing the transaction'), - ('txsend_noamt', 'sending the transaction'), - - ('bal8', f'the {coin} balance'), - ('token_bal5', 'the token balance'), - - ('token_txcreate_noamt', 'creating a token transaction (full amount send)'), - ('token_txsign_noamt', 'signing the transaction'), - ('token_txsend_noamt', 'sending the transaction'), - - ('bal9', f'the {coin} balance'), - ('token_bal6', 'the token balance'), - - ('listaddresses1', 'listaddresses'), - ('listaddresses2', 'listaddresses minconf=999999999 (ignored)'), - ('listaddresses3', 'listaddresses sort=age (ignored)'), - ('listaddresses4', 'listaddresses showempty=1 sort=age (ignored)'), - - ('token_listaddresses1', 'listaddresses --token=mm1'), - ('token_listaddresses2', 'listaddresses --token=mm1 showempty=1'), + ('token_listaddresses1', 'listaddresses --token=mm1'), + ('token_listaddresses2', 'listaddresses --token=mm1 showempty=1'), + ), + 'twexport': ( + 'exporting and importing tracking wallet to JSON', + ('twexport_noamt', 'exporting the tracking wallet (include_amts=0)'), + ('twmove', 'moving the tracking wallet'), + ('twimport', 'importing the tracking wallet'), + ('twview7', 'twview (cached_balances=1)'), + ('twview8', 'twview'), + ('twexport', 'exporting the tracking wallet'), + ('tw_chktotal', 'checking total value in tracking wallet dump'), + ('twmove', 'moving the tracking wallet'), + ('twimport', 'importing the tracking wallet'), + ('twcompare', 'comparing imported tracking wallet with original'), + ('edit_json_twdump', 'editing the tracking wallet JSON dump'), + ('twmove', 'moving the tracking wallet'), + ('twimport_nochksum', 'importing the edited tracking wallet JSON dump (ignore_checksum=1)'), + ('token_listaddresses3', 'listaddresses --token=mm1 showempty=1'), + ('token_listaddresses4', 'listaddresses --token=mm2 showempty=1'), + ('twview9', 'twview (check balance)'), + ), + 'cached': ( + 'creating and sending transactions using cached balances', ('twview_cached_balances', 'twview (cached balances)'), ('token_twview_cached_balances', 'token twview (cached balances)'), ('txcreate_cached_balances', 'txcreate (cached balances)'), @@ -279,54 +327,39 @@ class TestSuiteEthdev(TestSuiteBase,TestSuiteShared): ('txdo_cached_balances', 'txdo (cached balances)'), ('txcreate_refresh_balances', 'refreshing balances'), - ('bal10', f'the {coin} balance'), + ('bal10', f'the {coin} balance'), ('token_txdo_cached_balances', 'token txdo (cached balances)'), ('token_txcreate_refresh_balances', 'refreshing token balances'), ('token_bal7', 'the token balance'), - - ('twview1', 'twview'), - ('twview2', 'twview wide=1'), - ('twview3', 'twview wide=1 sort=age (ignored)'), - ('twview4', 'twview wide=1 minconf=999999999 (ignored)'), - ('twview5', 'twview wide=1 minconf=0 (ignored)'), - - ('token_twview1', 'twview --token=mm1'), - ('token_twview2', 'twview --token=mm1 wide=1'), - ('token_twview3', 'twview --token=mm1 wide=1 sort=age (ignored)'), - - ('edit_label1', f'adding label to addr #{del_addrs[0]} in {coin} tracking wallet (zh)'), - ('edit_label2', f'adding label to addr #{del_addrs[1]} in {coin} tracking wallet (lat+cyr+gr)'), - ('edit_label3', f'removing label from addr #{del_addrs[0]} in {coin} tracking wallet'), - - ('token_edit_label1', f'adding label to addr #{del_addrs[0]} in {coin} token tracking wallet'), - + ), + 'view': ( + 'viewing addresses and unspent outputs', + ('twview1', 'twview'), + ('twview2', 'twview wide=1'), + ('twview3', 'twview wide=1 sort=age (ignored)'), + ('twview4', 'twview wide=1 minconf=999999999 (ignored)'), + ('twview5', 'twview wide=1 minconf=0 (ignored)'), + ('token_twview1', 'twview --token=mm1'), + ('token_twview2', 'twview --token=mm1 wide=1'), + ('token_twview3', 'twview --token=mm1 wide=1 sort=age (ignored)'), + ), + 'label': ( + 'creating, editing and removing labels', + ('edit_label1', f'adding label to addr #{del_addrs[0]} in {coin} tracking wallet (zh)'), + ('edit_label2', f'adding label to addr #{del_addrs[1]} in {coin} tracking wallet (lat+cyr+gr)'), + ('edit_label3', f'removing label from addr #{del_addrs[0]} in {coin} tracking wallet'), + ('token_edit_label1', f'adding label to addr #{del_addrs[0]} in {coin} token tracking wallet'), + ), + 'remove': ( + 'removing addresses from tracking wallet', ('remove_addr1', f'removing addr #{del_addrs[0]} from {coin} tracking wallet'), ('twview6', 'twview (balance reduced after address removal)'), ('remove_addr2', f'removing addr #{del_addrs[1]} from {coin} tracking wallet'), ('token_remove_addr1', f'removing addr #{del_addrs[0]} from {coin} token tracking wallet'), ('token_remove_addr2', f'removing addr #{del_addrs[1]} from {coin} token tracking wallet'), - - ('twexport_noamt', 'exporting the tracking wallet (include_amts=0)'), - ('twmove', 'moving the tracking wallet'), - ('twimport', 'importing the tracking wallet'), - ('twview7', 'twview (cached_balances=1)'), - ('twview8', 'twview'), - ('twexport', 'exporting the tracking wallet'), - ('tw_chktotal', 'checking total value in tracking wallet dump'), - ('twmove', 'moving the tracking wallet'), - ('twimport', 'importing the tracking wallet'), - ('twcompare', 'comparing imported tracking wallet with original'), - ('edit_json_twdump', 'editing the tracking wallet JSON dump'), - ('twmove', 'moving the tracking wallet'), - ('twimport_nochksum', 'importing the edited tracking wallet JSON dump (ignore_checksum=1)'), - - ('token_listaddresses3','listaddresses --token=mm1 showempty=1'), - ('token_listaddresses4','listaddresses --token=mm2 showempty=1'), - ('twview9', 'twview (check balance)'), - - ('stop', 'stopping daemon'), - ) + ), + } def __init__(self,trunner,cfgs,spawn): TestSuiteBase.__init__(self,trunner,cfgs,spawn) @@ -1223,7 +1256,7 @@ class TestSuiteEthdev(TestSuiteBase,TestSuiteShared): def twview5(self): return self.twview(tool_args=['wide=1','minconf=0']) def twview6(self): - return self.twview(expect_str=vbal6) + return self.twview(expect_str=vbal7) def twview7(self): return self.twview(args=['--cached-balances']) def twview8(self): diff --git a/test/test_py_d/ts_regtest.py b/test/test_py_d/ts_regtest.py index 08e1e3e3..3313e02a 100755 --- a/test/test_py_d/ts_regtest.py +++ b/test/test_py_d/ts_regtest.py @@ -151,90 +151,140 @@ class TestSuiteRegtest(TestSuiteBase,TestSuiteShared): color = True deterministic = False test_rbf = False - cmd_group = ( - ('setup', 'regtest (Bob and Alice) mode setup'), - ('daemon_version', 'mmgen-tool daemon_version'), - ('halving_calculator_bob', 'halving calculator (Bob)'), - ('walletgen_bob', 'wallet generation (Bob)'), - ('walletgen_alice', 'wallet generation (Alice)'), - ('addrgen_bob', 'address generation (Bob)'), - ('addrgen_alice', 'address generation (Alice)'), - ('addrimport_bob', "importing Bob's addresses"), - ('addrimport_alice', "importing Alice's addresses"), - ('bob_import_miner_addr', "importing miner’s coinbase addr into Bob’s wallet"), - ('fund_bob_deterministic', "funding Bob’s first MMGen address (deterministic method)"), - ('fund_alice_deterministic', "funding Alice’s first MMGen address (deterministic method)"), - ('bob_recreate_tracking_wallet','creation of new tracking wallet (Bob)'), - ('addrimport_bob2', "reimporting Bob's addresses"), - ('fund_bob', "funding Bob's wallet"), - ('fund_alice', "funding Alice's wallet"), - ('generate', 'mining a block'), - ('bob_bal1', "Bob's balance"), - ('bob_add_label', "adding an 80-screen-width label (lat+cyr+gr)"), - ('bob_twview1', "viewing Bob's tracking wallet"), - ('bob_split1', "splitting Bob's funds"), - ('generate', 'mining a block'), - ('bob_bal2', "Bob's balance"), - ('bob_rbf_1output_create', 'creating RBF tx with one output'), - ('bob_rbf_1output_bump', 'bumping RBF tx with one output'), - ('bob_bal2a', "Bob's balance (age_fmt=confs)"), - ('bob_bal2b', "Bob's balance (showempty=1)"), - ('bob_bal2c', "Bob's balance (showempty=1 minconf=2 age_fmt=days)"), - ('bob_bal2d', "Bob's balance (minconf=2)"), - ('bob_bal2e', "Bob's balance (showempty=1 sort=age)"), - ('bob_bal2f', "Bob's balance (showempty=1 sort=age,reverse)"), - ('bob_send_maybe_rbf', 'sending funds to Alice (RBF, if supported)'), - ('get_mempool1', 'mempool (before RBF bump)'), - ('bob_rbf_status1', 'getting status of transaction'), - ('bob_rbf_bump', 'bumping RBF transaction'), - ('get_mempool2', 'mempool (after RBF bump)'), - ('bob_rbf_status2', 'getting status of transaction after replacement'), - ('bob_rbf_status3', 'getting status of replacement transaction (mempool)'), - ('generate', 'mining a block'), - ('bob_rbf_status4', 'getting status of transaction after confirmed (1) replacement'), - ('bob_rbf_status5', 'getting status of replacement transaction (confirmed)'), - ('generate', 'mining a block'), - ('bob_rbf_status6', 'getting status of transaction after confirmed (2) replacement'), - ('bob_bal3', "Bob's balance"), - ('bob_pre_import', 'sending to non-imported address'), - ('generate', 'mining a block'), - ('bob_import_addr', 'importing non-MMGen address'), - ('bob_bal4', "Bob's balance (after import)"), - ('bob_import_list', 'importing flat address list'), - ('bob_import_list_rescan', 'importing flat address list with --rescan'), - ('bob_import_list_rescan_aio','importing flat address list with --rescan (aiohttp backend)'), - ('bob_resolve_addr', 'resolving an address in the tracking wallet'), - ('bob_rescan_addr', 'rescanning an address'), - ('bob_rescan_blockchain_all','rescanning the blockchain (full rescan)'), - ('bob_rescan_blockchain_gb', 'rescanning the blockchain (Genesis block)'), - ('bob_rescan_blockchain_one','rescanning the blockchain (single block)'), - ('bob_rescan_blockchain_ss', 'rescanning the blockchain (range of blocks)'), + cmd_group_in = ( + ('setup', 'regtest (Bob and Alice) mode setup'), + ('subgroup.misc', []), + ('subgroup.init_bob', []), + ('subgroup.init_alice', []), + ('subgroup.fund_users', ['init_bob','init_alice']), + ('subgroup.msg', ['init_bob']), + ('subgroup.twexport', ['fund_users']), + ('subgroup.rescan', ['fund_users']), + ('subgroup.main', ['fund_users']), + ('subgroup.txhist', ['main']), + ('subgroup.label', ['main']), + ('subgroup.view', ['label']), + ('stop', 'stopping regtest daemon'), + ) + cmd_subgroups = { + 'misc': ( + 'miscellaneous commands', + ('daemon_version', 'mmgen-tool daemon_version'), + ('halving_calculator_bob', 'halving calculator (Bob)'), + ), + 'init_bob': ( + 'creating Bob’s MMGen wallet and tracking wallet', + ('walletgen_bob', 'wallet generation (Bob)'), + ('addrgen_bob', 'address generation (Bob)'), + ('addrimport_bob', "importing Bob's addresses"), + ), + 'init_alice': ( + 'creating Alice’s MMGen wallet and tracking wallet', + ('walletgen_alice', 'wallet generation (Alice)'), + ('addrgen_alice', 'address generation (Alice)'), + ('addrimport_alice', "importing Alice's addresses"), + ), + 'fund_users': ( + 'funding Bob and Alice’s wallets', + ('bob_import_miner_addr', "importing miner’s coinbase addr into Bob’s wallet"), + ('fund_bob_deterministic', "funding Bob’s first MMGen address (deterministic method)"), + ('fund_alice_deterministic', "funding Alice’s first MMGen address (deterministic method)"), + ('bob_recreate_tracking_wallet', 'creation of new tracking wallet (Bob)'), + ('addrimport_bob2', "reimporting Bob's addresses"), + ('fund_bob', "funding Bob's wallet"), + ('fund_alice', "funding Alice's wallet"), + ('generate', 'mining a block'), + ('bob_bal1', "Bob's balance"), + ), + 'msg': ( + 'message signing', + ('bob_msgcreate', 'creating a message file for signing'), + ('bob_msgsign', 'signing the message file (default wallet)'), + ('bob_walletconv_words', 'creating an MMGen mnemonic wallet'), + ('bob_subwalletgen_bip39', 'creating a BIP39 mnemonic subwallet'), + ('bob_msgsign_userwallet', 'signing the message file (user-specified wallet)'), + ('bob_msgsign_userwallets', 'signing the message file (user-specified wallets)'), + ('bob_msgverify', 'verifying the message file (all addresses)'), + ('bob_msgverify_raw', 'verifying the raw message file (all addresses)'), + ('bob_msgverify_single', 'verifying the message file (single address)'), + ('bob_msgexport_single', 'exporting the message file (single address)'), + ('bob_msgexport', 'exporting the message file (all addresses)'), + ('bob_msgverify_export', 'verifying the exported JSON data (all addresses)'), + ('bob_msgverify_export_single', 'verifying the exported JSON data (single address)'), + ), + 'twexport': ( + 'exporting and importing tracking wallet to JSON', + ('bob_twexport', 'exporting a tracking wallet to JSON'), + ('carol_twimport', 'importing a tracking wallet JSON dump'), + ('carol_delete_wallet', 'unloading and deleting Carol’s tracking wallet'), + ('bob_twexport_noamt', 'exporting a tracking wallet to JSON (include_amts=0)'), + ('carol_twimport_nochksum', 'importing a tracking wallet JSON dump (ignore_checksum=1)'), + ('carol_delete_wallet', 'unloading and deleting Carol’s tracking wallet'), + ('carol_twimport_batch', 'importing a tracking wallet JSON dump (batch=1)'), + ('bob_twexport_pretty', 'exporting a tracking wallet to JSON (pretty=1)'), + ('bob_edit_json_twdump', 'editing a tracking wallet JSON dump'), + ('carol_delete_wallet', 'unloading and deleting Carol’s tracking wallet'), + ('carol_twimport_pretty', 'importing an edited tracking wallet JSON dump (ignore_checksum=1)'), + ('carol_listaddresses', 'viewing Carol’s tracking wallet'), + ('carol_delete_wallet', 'unloading and deleting Carol’s tracking wallet'), + ), + 'rescan': ( + 'rescanning address and blockchain', + ('bob_resolve_addr', 'resolving an address in the tracking wallet'), + ('bob_rescan_addr', 'rescanning an address'), + ('bob_rescan_blockchain_all', 'rescanning the blockchain (full rescan)'), + ('bob_rescan_blockchain_gb', 'rescanning the blockchain (Genesis block)'), + ('bob_rescan_blockchain_one', 'rescanning the blockchain (single block)'), + ('bob_rescan_blockchain_ss', 'rescanning the blockchain (range of blocks)'), + ), + 'main': ( + 'creating, signing, sending and bumping transactions', + ('bob_add_label', "adding an 80-screen-width label (lat+cyr+gr)"), + ('bob_twview1', "viewing Bob's tracking wallet"), + ('bob_split1', "splitting Bob's funds"), + ('generate', 'mining a block'), + ('bob_bal2', "Bob's balance"), + ('bob_rbf_1output_create', 'creating RBF tx with one output'), + ('bob_rbf_1output_bump', 'bumping RBF tx with one output'), + ('bob_bal2a', "Bob's balance (age_fmt=confs)"), + ('bob_bal2b', "Bob's balance (showempty=1)"), + ('bob_bal2c', "Bob's balance (showempty=1 minconf=2 age_fmt=days)"), + ('bob_bal2d', "Bob's balance (minconf=2)"), + ('bob_bal2e', "Bob's balance (showempty=1 sort=age)"), + ('bob_bal2f', "Bob's balance (showempty=1 sort=age,reverse)"), + ('bob_send_maybe_rbf', 'sending funds to Alice (RBF, if supported)'), + ('get_mempool1', 'mempool (before RBF bump)'), + ('bob_rbf_status1', 'getting status of transaction'), + ('bob_rbf_bump', 'bumping RBF transaction'), + ('get_mempool2', 'mempool (after RBF bump)'), + ('bob_rbf_status2', 'getting status of transaction after replacement'), + ('bob_rbf_status3', 'getting status of replacement transaction (mempool)'), + ('generate', 'mining a block'), + ('bob_rbf_status4', 'getting status of transaction after confirmed (1) replacement'), + ('bob_rbf_status5', 'getting status of replacement transaction (confirmed)'), + ('generate', 'mining a block'), + ('bob_rbf_status6', 'getting status of transaction after confirmed (2) replacement'), + ('bob_bal3', "Bob's balance"), + ('bob_pre_import', 'sending to non-imported address'), + ('generate', 'mining a block'), + ('bob_import_addr', 'importing non-MMGen address'), + ('bob_bal4', "Bob's balance (after import)"), + ('bob_import_list', 'importing flat address list'), + ('bob_import_list_rescan', 'importing flat address list with --rescan'), + ('bob_import_list_rescan_aio', 'importing flat address list with --rescan (aiohttp backend)'), - ('bob_twexport', 'exporting a tracking wallet to JSON'), - ('carol_twimport', 'importing a tracking wallet JSON dump'), - ('carol_delete_wallet', 'unloading and deleting Carol’s tracking wallet'), - ('bob_twexport_noamt', 'exporting a tracking wallet to JSON (include_amts=0)'), - ('carol_twimport_nochksum', 'importing a tracking wallet JSON dump (ignore_checksum=1)'), - ('carol_delete_wallet', 'unloading and deleting Carol’s tracking wallet'), - ('carol_twimport_batch', 'importing a tracking wallet JSON dump (batch=1)'), - ('bob_twexport_pretty', 'exporting a tracking wallet to JSON (pretty=1)'), - ('bob_edit_json_twdump', 'editing a tracking wallet JSON dump'), - ('carol_delete_wallet', 'unloading and deleting Carol’s tracking wallet'), - ('carol_twimport_pretty', 'importing an edited tracking wallet JSON dump (ignore_checksum=1)'), - ('carol_listaddresses', 'viewing Carol’s tracking wallet'), - - ('bob_split2', "splitting Bob's funds"), - ('bob_0conf0_getbalance', "Bob's balance (unconfirmed, minconf=0)"), - ('bob_0conf1_getbalance', "Bob's balance (unconfirmed, minconf=1)"), - ('generate', 'mining a block'), - ('bob_1conf1_getbalance', "Bob's balance (confirmed, minconf=1)"), - ('bob_1conf2_getbalance', "Bob's balance (confirmed, minconf=2)"), - ('bob_bal5', "Bob's balance"), - ('bob_send_non_mmgen', 'sending funds to Alice (from non-MMGen addrs)'), - ('generate', 'mining a block'), - ('alice_send_estimatefee', 'tx creation with no fee on command line'), - ('generate', 'mining a block'), - ('bob_bal6', "Bob's balance"), + ('bob_split2', "splitting Bob's funds"), + ('bob_0conf0_getbalance', "Bob's balance (unconfirmed, minconf=0)"), + ('bob_0conf1_getbalance', "Bob's balance (unconfirmed, minconf=1)"), + ('generate', 'mining a block'), + ('bob_1conf1_getbalance', "Bob's balance (confirmed, minconf=1)"), + ('bob_1conf2_getbalance', "Bob's balance (confirmed, minconf=2)"), + ('bob_bal5', "Bob's balance"), + ('bob_send_non_mmgen', 'sending funds to Alice (from non-MMGen addrs)'), + ('generate', 'mining a block'), + ('alice_send_estimatefee', 'tx creation with no fee on command line'), + ('generate', 'mining a block'), + ('bob_bal6', "Bob's balance"), ('bob_subwallet_addrgen1', "generating Bob's addrs from subwallet 29L"), ('bob_subwallet_addrgen2', "generating Bob's addrs from subwallet 127S"), @@ -250,19 +300,22 @@ class TestSuiteRegtest(TestSuiteBase,TestSuiteShared): ('generate', 'mining a block'), ('bob_twview4', "viewing Bob's tracking wallet"), - ('bob_alice_bal', "Bob and Alice's balances"), - - ('bob_nochg_burn', 'zero-change transaction to burn address'), - ('generate', 'mining a block'), - - ('bob_txhist1', "viewing Bob's transaction history (sort=age)"), - ('bob_txhist2', "viewing Bob's transaction history (sort=blockheight reverse=1)"), - ('bob_txhist3', "viewing Bob's transaction history (sort=blockheight sinceblock=-7)"), - ('bob_txhist4', "viewing Bob's transaction history (sinceblock=399 detail=1)"), - ('bob_txhist_interactive', "viewing Bob's transaction history (age_fmt=date_time interactive=true)"), + ('bob_alice_bal', "Bob and Alice's balances"), + ('bob_nochg_burn', 'zero-change transaction to burn address'), + ('generate', 'mining a block'), + ), + 'txhist': ( + 'viewing transaction history', + ('bob_txhist1', "viewing Bob's transaction history (sort=age)"), + ('bob_txhist2', "viewing Bob's transaction history (sort=blockheight reverse=1)"), + ('bob_txhist3', "viewing Bob's transaction history (sort=blockheight sinceblock=-7)"), + ('bob_txhist4', "viewing Bob's transaction history (sinceblock=399 detail=1)"), + ('bob_txhist_interactive', "viewing Bob's transaction history (age_fmt=date_time interactive=true)"), + ), + 'label': ( + 'adding, removing and editing labels', ('alice_bal2', "Alice's balance"), - ('alice_add_label1', 'adding a label'), ('alice_chk_label1', 'the label'), ('alice_add_label2', 'adding a label'), @@ -278,32 +331,20 @@ class TestSuiteRegtest(TestSuiteBase,TestSuiteShared): ('alice_add_label_badaddr2', 'adding a label with invalid address for this chain'), ('alice_add_label_badaddr3', 'adding a label with wrong MMGen address'), ('alice_add_label_badaddr4', 'adding a label with wrong coin address'), - ('alice_listaddresses1', 'listaddresses'), - ('alice_listaddresses_days', 'listaddresses (age_fmt=days)'), - ('alice_listaddresses_date', 'listaddresses (age_fmt=date)'), - ('alice_listaddresses_date_time', 'listaddresses (age_fmt=date_time)'), - ('alice_twview1', 'twview'), - ('alice_twview_days', 'twview (age_fmt=days)'), - ('alice_twview_date', 'twview (age_fmt=date)'), - ('alice_twview_date_time', 'twview (age_fmt=date_time)'), - ('alice_txcreate_info', 'txcreate -i'), - - ('bob_msgcreate', 'creating a message file for signing'), - ('bob_msgsign', 'signing the message file (default wallet)'), - ('bob_walletconv_words', 'creating an MMGen mnemonic wallet'), - ('bob_subwalletgen_bip39', 'creating a BIP39 mnemonic subwallet'), - ('bob_msgsign_userwallet', 'signing the message file (user-specified wallet)'), - ('bob_msgsign_userwallets', 'signing the message file (user-specified wallets)'), - ('bob_msgverify', 'verifying the message file (all addresses)'), - ('bob_msgverify_raw', 'verifying the raw message file (all addresses)'), - ('bob_msgverify_single', 'verifying the message file (single address)'), - ('bob_msgexport_single', 'exporting the message file (single address)'), - ('bob_msgexport', 'exporting the message file (all addresses)'), - ('bob_msgverify_export', 'verifying the exported JSON data (all addresses)'), - ('bob_msgverify_export_single','verifying the exported JSON data (single address)'), - - ('stop', 'stopping regtest daemon'), - ) + ), + 'view': ( + 'viewing addresses and unspent outputs', + ('alice_listaddresses1', 'listaddresses'), + ('alice_listaddresses_days', 'listaddresses (age_fmt=days)'), + ('alice_listaddresses_date', 'listaddresses (age_fmt=date)'), + ('alice_listaddresses_date_time', 'listaddresses (age_fmt=date_time)'), + ('alice_twview1', 'twview'), + ('alice_twview_days', 'twview (age_fmt=days)'), + ('alice_twview_date', 'twview (age_fmt=date)'), + ('alice_twview_date_time', 'twview (age_fmt=date_time)'), + ('alice_txcreate_info', 'txcreate -i'), + ), + } def __init__(self,trunner,cfgs,spawn): TestSuiteBase.__init__(self,trunner,cfgs,spawn) @@ -974,7 +1015,7 @@ class TestSuiteRegtest(TestSuiteBase,TestSuiteShared): return t def bob_rescan_blockchain_all(self): - return self.bob_rescan_blockchain([],'400-400') + return self.bob_rescan_blockchain([],'300-396') def bob_rescan_blockchain_gb(self): return self.bob_rescan_blockchain(['start_block=0','stop_block=0'],'0-0') @@ -1013,10 +1054,10 @@ class TestSuiteRegtest(TestSuiteBase,TestSuiteShared): if expect_str: t.expect(expect_str) elif 'batch=true' in add_parms: - t.expect('{} addresses imported'.format(15 if self.proto.coin == 'BCH' else 25)) + t.expect('{} addresses imported'.format(10 if self.proto.coin == 'BCH' else 20)) else: t.expect('import completed OK') - t.expect('Found 3 unspent outputs') + t.expect('Found 1 unspent output') return t def carol_twimport_nochksum(self):