From cb113ffc8293d02cfe06e6c8a90aa783b5ac76ee Mon Sep 17 00:00:00 2001 From: The MMGen Project Date: Sun, 29 Sep 2024 11:59:56 +0000 Subject: [PATCH] test suite: cleanups --- test/cmdtest.py | 5 +-- test/cmdtest_py_d/ct_base.py | 7 ++-- test/cmdtest_py_d/ct_main.py | 16 ++++---- test/cmdtest_py_d/ct_ref.py | 2 +- test/cmdtest_py_d/ct_ref_3seed.py | 43 +++++++++++----------- test/cmdtest_py_d/ct_regtest.py | 61 ++++++++++++++++++------------- test/cmdtest_py_d/ct_shared.py | 52 +++++++++++++++----------- test/tooltest2.py | 4 +- test/tooltest2_d/data.py | 2 +- 9 files changed, 105 insertions(+), 87 deletions(-) diff --git a/test/cmdtest.py b/test/cmdtest.py index 4a06ac71..4f117129 100755 --- a/test/cmdtest.py +++ b/test/cmdtest.py @@ -685,12 +685,11 @@ class CmdTestRunner: nws = [(e.split('_')[0],'testnet') if '_' in e else (e,'mainnet') for e in ct_cls.networks] if nws: coin = proto.coin.lower() - nw = ('mainnet','testnet')[proto.testnet] for a,b in nws: - if a == coin and b == nw: + if a == coin and b == proto.network: break else: - iqmsg(gray(f'INFO → skipping {m} (network={nw})')) + iqmsg(gray(f'INFO → skipping {m} for {proto.coin} {proto.network}')) return None if do_clean and not cfg.skipping_deps: diff --git a/test/cmdtest_py_d/ct_base.py b/test/cmdtest_py_d/ct_base.py index 0dc3d71c..1a7c96a8 100755 --- a/test/cmdtest_py_d/ct_base.py +++ b/test/cmdtest_py_d/ct_base.py @@ -52,10 +52,11 @@ class CmdTestBase: self.have_dfl_wallet = False self.usr_rand_chars = (5,30)[bool(cfg.usr_random)] self.usr_rand_arg = f'-r{self.usr_rand_chars}' - self.altcoin_pfx = '' if self.proto.base_coin == 'BTC' else '-'+self.proto.base_coin self.tn_ext = ('','.testnet')[self.proto.testnet] - d = {'bch':'btc','btc':'btc','ltc':'ltc'} - self.fork = d[self.proto.coin.lower()] if self.proto.coin.lower() in d else None + self.coin = self.proto.coin.lower() + self.bch_legacy = self.coin == 'bch' + self.fork = 'btc' if self.bch_legacy else self.coin + self.altcoin_pfx = '' if self.fork == 'btc' else f'-{self.proto.coin}' if len(self.tmpdir_nums) == 1: self.tmpdir_num = self.tmpdir_nums[0] if self.tr: diff --git a/test/cmdtest_py_d/ct_main.py b/test/cmdtest_py_d/ct_main.py index fa2f1845..83b2aab0 100755 --- a/test/cmdtest_py_d/ct_main.py +++ b/test/cmdtest_py_d/ct_main.py @@ -307,11 +307,11 @@ class CmdTestMain(CmdTestBase,CmdTestShared): def __init__(self,trunner,cfgs,spawn): CmdTestBase.__init__(self,trunner,cfgs,spawn) - if trunner is None or self.proto.coin.lower() not in self.networks: + if trunner is None or self.coin not in self.networks: return - if self.proto.coin in ('BTC','BCH','LTC'): - self.tx_fee = {'btc':'0.0001','bch':'0.001','ltc':'0.01'}[self.proto.coin.lower()] - self.txbump_fee = {'btc':'123s','bch':'567s','ltc':'12345s'}[self.proto.coin.lower()] + if self.coin in ('btc','bch','ltc'): + self.tx_fee = {'btc':'0.0001','bch':'0.001','ltc':'0.01'}[self.coin] + self.txbump_fee = {'btc':'123s','bch':'567s','ltc':'12345s'}[self.coin] self.unspent_data_file = joinpath('test','trash','unspent.json') self.spawn_env['MMGEN_BOGUS_UNSPENT_DATA'] = self.unspent_data_file @@ -342,8 +342,8 @@ class CmdTestMain(CmdTestBase,CmdTestShared): def export_seed_dfl_wallet(self,pf,out_fmt='seed'): return self.export_seed(wf=None,out_fmt=out_fmt,pf=pf) - def addrgen_dfl_wallet(self,pf=None,check_ref=False): - return self.addrgen(wf=None,check_ref=check_ref,dfl_wallet=True) + def addrgen_dfl_wallet(self, pf): + return self.addrgen(wf=None, dfl_wallet=True) def txcreate_dfl_wallet(self,addrfile): return self.txcreate_common(sources=['15']) @@ -475,7 +475,7 @@ class CmdTestMain(CmdTestBase,CmdTestShared): s_beg,s_end = { 'p2pkh': ('76a914','88ac'), 'p2sh': ('a914','87'), 'bech32': (self.proto.witness_vernum_hex + '14','') }[k] - amt1,amt2 = {'btc':(10,40),'bch':(10,40),'ltc':(1000,4000)}[self.proto.coin.lower()] + amt1,amt2 = {'btc':(10,40),'bch':(10,40),'ltc':(1000,4000)}[self.coin] ret = { self.lbl_id: ( f'{self.proto.base_coin.lower()}:{coinaddr}' if non_mmgen @@ -558,7 +558,7 @@ class CmdTestMain(CmdTestBase,CmdTestShared): ) # total of two outputs must be < 10 BTC (<1000 LTC) - mods = {'btc':(6,4),'bch':(6,4),'ltc':(600,400)}[self.proto.coin.lower()] + mods = {'btc':(6,4),'bch':(6,4),'ltc':(600,400)}[self.coin] for k in self.cfgs: self.cfgs[k]['amts'] = [None,None] for idx,mod in enumerate(mods): diff --git a/test/cmdtest_py_d/ct_ref.py b/test/cmdtest_py_d/ct_ref.py index c2d95781..53fb8376 100755 --- a/test/cmdtest_py_d/ct_ref.py +++ b/test/cmdtest_py_d/ct_ref.py @@ -297,7 +297,7 @@ class CmdTestRef(CmdTestBase,CmdTestShared): return self.ref_passwdfile_chk(key='hex2bip39_12',pat=r'BIP39.*len.* 12\b') def ref_tx_chk(self): - fn = self.sources['ref_tx_file'][self.proto.coin.lower()][bool(self.tn_ext)] + fn = self.sources['ref_tx_file'][self.coin][bool(self.tn_ext)] if not fn: return tf = joinpath(ref_dir,self.ref_subdir,fn) diff --git a/test/cmdtest_py_d/ct_ref_3seed.py b/test/cmdtest_py_d/ct_ref_3seed.py index 9cae7950..45a7b27a 100755 --- a/test/cmdtest_py_d/ct_ref_3seed.py +++ b/test/cmdtest_py_d/ct_ref_3seed.py @@ -214,10 +214,10 @@ class CmdTestRef3Seed(CmdTestBase,CmdTestShared): class CmdTestRef3Addr(CmdTestRef3Seed): 'generated reference address, key and password files for 128-, 192- and 256-bit seeds' - networks = ('btc','btc_tn','ltc','ltc_tn') - passthru_opts = ('coin','testnet') - tmpdir_nums = [26,27,28] - shared_deps = ['mmdat',pwfile] + networks = ('btc', 'btc_tn', 'ltc', 'ltc_tn') + passthru_opts = ('coin', 'testnet') + tmpdir_nums = [26, 27, 28] + shared_deps = ['mmdat', pwfile] chk_data = { 'lens': (128, 192, 256), @@ -370,9 +370,9 @@ class CmdTestRef3Addr(CmdTestRef3Seed): ('ref_hex2bip39_24_passwdgen',([],'new refwallet passwd file chksum (hex-to-BIP39, up to 24 words)')), ) - def call_addrgen(self,mmtype,pfx='addr'): + def call_addrgen(self, mmtype, name='addrgen'): wf = self.get_file_with_ext('mmdat') - return getattr(self,pfx+'gen')(wf,check_ref=True,mmtype=mmtype) + return getattr(self, name)(wf, check_ref=True, mmtype=mmtype) def refaddrgen_legacy(self): return self.call_addrgen('legacy') @@ -384,24 +384,24 @@ class CmdTestRef3Addr(CmdTestRef3Seed): return self.call_addrgen('bech32') def refkeyaddrgen_legacy(self): - return self.call_addrgen('legacy','keyaddr') + return self.call_addrgen('legacy', 'keyaddrgen') def refkeyaddrgen_compressed(self): - return self.call_addrgen('compressed','keyaddr') + return self.call_addrgen('compressed', 'keyaddrgen') def refkeyaddrgen_segwit(self): - return self.call_addrgen('segwit','keyaddr') + return self.call_addrgen('segwit', 'keyaddrgen') def refkeyaddrgen_bech32(self): - return self.call_addrgen('bech32','keyaddr') + return self.call_addrgen('bech32', 'keyaddrgen') - def pwgen(self, ftype, id_str, pwfmt=None, pwlen=None, extra_args=[], stdout=False): + def pwgen(self, ftype, id_str, pwfmt=None, pwlen=None, extra_opts=[], stdout=False): wf = self.get_file_with_ext('mmdat') - pwfmt = (['--passwd-fmt='+pwfmt] if pwfmt else []) - pwlen = (['--passwd-len='+str(pwlen)] if pwlen else []) + pwfmt = ([f'--passwd-fmt={pwfmt}'] if pwfmt else []) + pwlen = ([f'--passwd-len={pwlen}'] if pwlen else []) return self.addrgen( wf, check_ref = True, ftype = ftype, id_str = id_str, - extra_args = pwfmt + pwlen + extra_args, + extra_opts = pwfmt + pwlen + extra_opts, stdout = stdout) def refpasswdgen(self): @@ -416,22 +416,21 @@ class CmdTestRef3Addr(CmdTestRef3Seed): return self.pwgen('passhex','фубар@crypto.org','hex',pwlen) def ref_hexpasswdgen_half(self): - ea = ['--accept-defaults'] - return self.pwgen('passhex','фубар@crypto.org','hex','h',ea,stdout=True) + return self.pwgen('passhex', 'фубар@crypto.org', 'hex', 'h', ['--accept-defaults'], stdout=True) - def mn_pwgen(self,req_pw_len,pwfmt,ftype='passbip39',stdout=False): - pwlen = min(req_pw_len,{'1':12,'2':18,'3':24}[self.test_name[-1]]) + def mn_pwgen(self, pwlen, pwfmt, ftype='passbip39'): + if pwlen > {'1':12, '2':18, '3':24}[self.test_name[-1]]: + return 'skip' if pwfmt == 'xmrseed': if cfg.no_altcoin: return 'skip' pwlen += 1 - ea = ['--accept-defaults'] - return self.pwgen(ftype,'фубар@crypto.org',pwfmt,pwlen,ea,stdout=stdout) + return self.pwgen(ftype, 'фубар@crypto.org', pwfmt, pwlen, ['--accept-defaults']) def ref_bip39_12_passwdgen(self): - return self.mn_pwgen(12,'bip39',stdout=True) + return self.mn_pwgen(12,'bip39') def ref_bip39_18_passwdgen(self): - return self.mn_pwgen(18,'bip39',stdout=True) + return self.mn_pwgen(18,'bip39') def ref_bip39_24_passwdgen(self): return self.mn_pwgen(24,'bip39') def ref_hex2bip39_24_passwdgen(self): diff --git a/test/cmdtest_py_d/ct_regtest.py b/test/cmdtest_py_d/ct_regtest.py index 810b1a45..726eace2 100755 --- a/test/cmdtest_py_d/ct_regtest.py +++ b/test/cmdtest_py_d/ct_regtest.py @@ -471,18 +471,19 @@ class CmdTestRegtest(CmdTestBase,CmdTestShared): if self.proto.testnet: die(2,'--testnet and --regtest options incompatible with regtest test suite') - self.proto = init_proto( cfg, self.proto.coin, network='regtest', need_amt=True ) - coin = self.proto.coin.lower() + coin = self.coin + + self.proto = init_proto(cfg, coin, network='regtest', need_amt=True) gldict = globals() for k in rt_data: gldict[k] = rt_data[k][coin] if coin in rt_data[k] else None - self.use_bdb_wallet = self.bdb_wallet or self.proto.coin != 'BTC' + self.use_bdb_wallet = self.bdb_wallet or coin != 'btc' - self.rt = MMGenRegtest(cfg, self.proto.coin, bdb_wallet=self.use_bdb_wallet) + self.rt = MMGenRegtest(cfg, coin, bdb_wallet=self.use_bdb_wallet) - if self.proto.coin == 'BTC': + if coin == 'btc': self.test_rbf = True # tests are non-coin-dependent, so run just once for BTC if cfg.test_suite_deterministic: self.deterministic = True @@ -490,7 +491,7 @@ class CmdTestRegtest(CmdTestBase,CmdTestShared): self.spawn_env['MMGEN_BOGUS_SEND'] = '' self.write_to_tmpfile('wallet_password',rt_pw) - self.dfl_mmtype = 'C' if self.proto.coin == 'BCH' else 'B' + self.dfl_mmtype = 'C' if coin == 'bch' else 'B' self.burn_addr = make_burn_addr(self.proto) self.user_sids = {} @@ -553,8 +554,8 @@ class CmdTestRegtest(CmdTestBase,CmdTestShared): def walletgen_alice(self): return self.walletgen('alice') - def _user_dir(self,user,coin=None): - return joinpath(self.tr.data_dir,'regtest',coin or self.proto.coin.lower(),user) + def _user_dir(self, user, coin=None): + return joinpath(self.tr.data_dir, 'regtest', coin or self.coin, user) def _user_sid(self,user): if user in self.user_sids: @@ -723,33 +724,34 @@ class CmdTestRegtest(CmdTestBase,CmdTestShared): user, chk = None, expect = None, - cmdline = ['twview'], + cmd = 'twview', + opts = [], sort = 'age', exit_val = None): - t = self.spawn('mmgen-tool',[f'--{user}'] + cmdline + ['sort='+sort], exit_val=exit_val) + t = self.spawn('mmgen-tool', [f'--{user}'] + opts + [cmd] + [f'sort={sort}'], exit_val=exit_val) if chk: t.expect(r'{}\b.*\D{}\b'.format(*chk),regex=True) if expect: - t.expect(expect) + t.expect(expect, regex=True) return t def bob_twview_noaddrs(self): return self.user_twview('bob', expect='No spendable', exit_val=1) def bob_listaddrs_noaddrs(self): - return self.user_twview('bob', cmdline=['listaddresses'], expect='No addresses', exit_val=1) + return self.user_twview('bob', cmd='listaddresses', expect='No addresses', exit_val=1) def bob_twview_nobal(self): return self.user_twview('bob', expect='No spendable', exit_val=1) def bob_listaddrs_nobal(self): - return self.user_twview('bob', cmdline=['listaddresses'], expect='TOTAL:') + return self.user_twview('bob', cmd='listaddresses', expect='TOTAL:') def bob_twview1(self): return self.user_twview('bob', chk=('1', rtAmts[0])) - def user_bal(self,user,bal,args=['showempty=1'],skip_check=False): - t = self.spawn('mmgen-tool',['--'+user,'listaddresses'] + args) + def user_bal(self, user, bal, opts=[], args=['showempty=1'], skip_check=False): + t = self.spawn('mmgen-tool', opts + [f'--{user}', 'listaddresses'] + args) if not skip_check: cmp_or_die(f'{bal} {self.proto.coin}',strip_ansi_escapes(t.expect_getend('TOTAL: '))) return t @@ -860,10 +862,13 @@ class CmdTestRegtest(CmdTestBase,CmdTestShared): sid = self._user_sid('bob') return self.user_twview('bob',chk=(sid+':L:5',rtBals[9]),sort='twmmid') - def user_txhist(self,user,args,expect): - t = self.spawn('mmgen-tool',['--'+user,'txhist'] + args) - m = re.search( expect, t.read(strip_color=True), re.DOTALL ) - assert m, f'Expected: {expect}' + def user_txhist(self, user, args, expect, opts=[], expect2=None): + t = self.spawn('mmgen-tool', opts + [f'--{user}', 'txhist'] + args) + text = t.read(strip_color=True) + for s in (expect, expect2): + if s: + m = re.search(s, text, re.DOTALL) + assert m, f'Expected: {s}' return t def bob_txhist1(self): @@ -1483,6 +1488,8 @@ class CmdTestRegtest(CmdTestBase,CmdTestShared): async def carol_delete_wallet(self): imsg('Unloading Carol’s tracking wallet') + if self.proto.coin == 'BCH': + time.sleep(0.2) t = self.spawn('mmgen-regtest',['cli','unloadwallet','carol']) t.ok() wdir = joinpath((await self.rt.rpc).daemon.network_datadir, 'wallets', 'carol') @@ -1642,26 +1649,28 @@ class CmdTestRegtest(CmdTestBase,CmdTestShared): 'interactive=1', ] ) - t.expect('abel:\b','p') - ret = t.expect([ 'abel:\b', 'to confirm: ' ]) + prompt = 'abel:\b' + t.expect(prompt, 'p') + ret = t.expect([prompt, 'to confirm: ']) if ret == 1: t.send('YES\n') - t.expect('abel:\b') + t.expect(prompt) t.send('l') t.expect( 'main menu): ', '{}\n'.format(2 if self.proto.coin == 'BCH' else 1) ) t.expect('for address.*: ','\n',regex=True) t.expect('unchanged') - t.expect('abel:\b','q') + t.expect(prompt, 'q') return t def _alice_listaddresses_interactive(self,expect=(),expect_menu=()): t = self.spawn('mmgen-tool',['--alice','listaddresses','interactive=1']) + prompt = 'abel:\b' + for e in expect: + t.expect(*e, regex=True) for s in expect_menu: - t.expect('abel:\b',s) - for p,s in expect: - t.expect(p,s) + t.expect(prompt, s) return t def alice_listaddresses_empty(self): diff --git a/test/cmdtest_py_d/ct_shared.py b/test/cmdtest_py_d/ct_shared.py index 0ac19c25..06cc5012 100755 --- a/test/cmdtest_py_d/ct_shared.py +++ b/test/cmdtest_py_d/ct_shared.py @@ -22,8 +22,10 @@ test.cmdtest_py_d.ct_shared: Shared methods for the cmdtest.py test suite from mmgen.util import get_extension from mmgen.wallet import get_wallet_cls +from mmgen.addrlist import AddrList +from mmgen.passwdlist import PasswordList -from ..include.common import cfg,cmp_or_die,strip_ansi_escapes,joinpath +from ..include.common import cfg, cmp_or_die, strip_ansi_escapes, joinpath, silence, end_silence from .common import ref_bw_file,ref_bw_hash_preset,ref_dir class CmdTestShared: @@ -238,9 +240,9 @@ class CmdTestShared: if wcls.enc and wcls.type != 'brain': t.passphrase(wcls.desc,self.wpasswd) t.expect(['Passphrase is OK', 'Passphrase.* are correct'],regex=True) - chk = t.expect_getend(f'Valid {wcls.desc} for Seed ID ')[:8] + chksum = t.expect_getend(f'Valid {wcls.desc} for Seed ID ')[:8] if sid: - cmp_or_die(chk, sid) + cmp_or_die(chksum, sid) return t def addrgen( @@ -249,53 +251,61 @@ class CmdTestShared: check_ref = False, ftype = 'addr', id_str = None, - extra_args = [], + extra_opts = [], mmtype = None, stdout = False, dfl_wallet = False): - passgen = ftype[:4] == 'pass' + list_type = ftype[:4] + passgen = list_type == 'pass' if not mmtype and not passgen: mmtype = self.segwit_mmtype - cmd_pfx = (ftype,'pass')[passgen] t = self.spawn( - f'mmgen-{cmd_pfx}gen', - ['-d',self.tmpdir] + extra_args + + f'mmgen-{list_type}gen', + ['-d',self.tmpdir] + extra_opts + ([],['--type='+str(mmtype)])[bool(mmtype)] + ([],['--stdout'])[stdout] + ([],[wf])[bool(wf)] + ([],[id_str])[bool(id_str)] + - [getattr(self,f'{cmd_pfx}_idx_list')], + [getattr(self,f'{list_type}_idx_list')], extra_desc=f'({mmtype})' if mmtype in ('segwit','bech32') else '') t.license() wcls = get_wallet_cls( ext = 'mmdat' if dfl_wallet else get_extension(wf) ) t.passphrase(wcls.desc,self.wpasswd) t.expect('Passphrase is OK') desc = ('address','password')[passgen] - chk = t.expect_getend(rf'Checksum for {desc} data .*?: ',regex=True) - if passgen: - t.expect('Encrypt password list? (y/N): ','N') - t.read() if stdout else t.written_to_file(('Addresses','Password list')[passgen]) + chksum = strip_ansi_escapes(t.expect_getend(rf'Checksum for {desc} data .*?: ', regex=True)) if check_ref: - chk_ref = ( + chksum_chk = ( self.chk_data[self.test_name] if passgen else self.chk_data[self.test_name][self.fork][self.proto.testnet]) - cmp_or_die(chk,chk_ref,desc=f'{ftype}list data checksum') + cmp_or_die(chksum, chksum_chk, desc=f'{ftype}list data checksum') + if passgen: + t.expect('Encrypt password list? (y/N): ','N') + if stdout: + t.read() + else: + fn = t.written_to_file('Password list' if passgen else 'Addresses') + cls = PasswordList if passgen else AddrList + silence() + al = cls(cfg, self.proto, fn, skip_chksum_msg=True) # read back the file we’ve written + end_silence() + cmp_or_die(al.chksum, chksum, desc=f'{ftype}list data checksum from file') return t - def keyaddrgen(self,wf,check_ref=False,mmtype=None): + def keyaddrgen(self, wf, check_ref=False, extra_opts=[], mmtype=None): if not mmtype: mmtype = self.segwit_mmtype args = ['-d', self.tmpdir, self.usr_rand_arg, wf, self.addr_idx_list] t = self.spawn('mmgen-keygen', - ([],['--type='+str(mmtype)])[bool(mmtype)] + args, - extra_desc=f'({mmtype})' if mmtype in ('segwit','bech32') else '') + ([f'--type={mmtype}'] if mmtype else []) + extra_opts + args, + extra_desc = f'({mmtype})' if mmtype in ('segwit', 'bech32') else '') t.license() wcls = get_wallet_cls(ext=get_extension(wf)) t.passphrase(wcls.desc,self.wpasswd) - chk = t.expect_getend(r'Checksum for key-address data .*?: ',regex=True) + chksum = t.expect_getend(r'Checksum for key-address data .*?: ',regex=True) if check_ref: - chk_ref = self.chk_data[self.test_name][self.fork][self.proto.testnet] - cmp_or_die(chk,chk_ref,desc='key-address list data checksum') + chksum_chk = self.chk_data[self.test_name][self.fork][self.proto.testnet] + cmp_or_die(chksum, chksum_chk, desc='key-address list data checksum') t.expect('Encrypt key list? (y/N): ','y') t.usr_rand(self.usr_rand_chars) t.hash_preset('new key-address list','1') diff --git a/test/tooltest2.py b/test/tooltest2.py index 843b0f3f..3de66d1a 100755 --- a/test/tooltest2.py +++ b/test/tooltest2.py @@ -184,8 +184,8 @@ def run_test(cls, gid, cmd_name): # behavior is like cmdtest.py: run coin-dependent tests only if proto.testnet or proto.coin != BTC if gid in coin_dependent_groups: k = '{}_{}'.format( - ( cfg.token.lower() if proto.tokensym else proto.coin.lower() ), - ('mainnet','testnet')[proto.testnet] ) + (cfg.token.lower() if proto.tokensym else proto.coin.lower()), + proto.network) if k in data: data = data[k] m2 = f' ({k})' diff --git a/test/tooltest2_d/data.py b/test/tooltest2_d/data.py index c2f39baa..8f3b4f5a 100755 --- a/test/tooltest2_d/data.py +++ b/test/tooltest2_d/data.py @@ -25,7 +25,7 @@ from mmgen.xmrseed import is_xmrseed from ..unit_tests_d.ut_baseconv import unit_test as ut_baseconv from ..unit_tests_d.ut_bip39 import unit_tests as ut_bip39 -from ..unit_tests_d.ut_xmrseed import unit_test as ut_xmrseed +from ..unit_tests_d.ut_xmrseed import unit_tests as ut_xmrseed from ..include.common import cfg,sample_text proto = cfg._proto