test.py: support command subgroups

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
This commit is contained in:
The MMGen Project 2022-07-29 16:45:31 +00:00
commit 170a9eadad
Signed by: mmgen
GPG key ID: 3F8B1861E32B7DA2
4 changed files with 471 additions and 337 deletions

View file

@ -1 +1 @@
13.2.dev10
13.2.dev11

View file

@ -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 scripts available commands
-L, --list-cmd-groups Output a list of command groups with descriptions
-L, --list-cmd-groups List the test scripts 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:

View file

@ -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):

View file

@ -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):