From e92f241f7a6523e271e5dcd17874289455c5c5ee Mon Sep 17 00:00:00 2001 From: The MMGen Project Date: Tue, 23 May 2023 12:12:33 +0000 Subject: [PATCH] test suite: improve handling of environment vars --- mmgen/data/version | 2 +- test/include/pexpect.py | 6 ++- test/scrambletest.py | 11 ++--- test/test.py | 71 +++++++++++++++++-------------- test/test_py_d/common.py | 15 +++---- test/test_py_d/ts_autosign.py | 2 +- test/test_py_d/ts_base.py | 5 +++ test/test_py_d/ts_cfgfile.py | 5 +-- test/test_py_d/ts_ethdev.py | 5 +-- test/test_py_d/ts_input.py | 6 +-- test/test_py_d/ts_main.py | 2 +- test/test_py_d/ts_misc.py | 8 ++-- test/test_py_d/ts_ref.py | 9 ++-- test/test_py_d/ts_regtest.py | 15 +++---- test/test_py_d/ts_tool.py | 6 ++- test/test_py_d/ts_xmr_autosign.py | 6 +-- 16 files changed, 85 insertions(+), 89 deletions(-) diff --git a/mmgen/data/version b/mmgen/data/version index c3781b36..c4ac49d8 100644 --- a/mmgen/data/version +++ b/mmgen/data/version @@ -1 +1 @@ -13.3.dev58 +13.3.dev59 diff --git a/test/include/pexpect.py b/test/include/pexpect.py index f95efff8..bcafd313 100755 --- a/test/include/pexpect.py +++ b/test/include/pexpect.py @@ -53,11 +53,12 @@ class MMGenPexpect: self.req_exit_val = 0 self.skip_ok = False self.sent_value = None + self.spawn_env = spawn_env if direct_exec or cfg.direct_exec: from subprocess import Popen,DEVNULL redir = DEVNULL if (no_output or not cfg.exact_output) else None - self.ep = Popen([args[0]] + args[1:], stderr=redir ) + self.ep = Popen([args[0]] + args[1:], stderr=redir, env=spawn_env ) else: timeout = int(timeout or cfg.pexpect_timeout or 0) or (60,5)[bool(cfg.debug_pexpect)] if pexpect_spawn: @@ -100,7 +101,8 @@ class MMGenPexpect: return self def license(self): - if 'MMGEN_NO_LICENSE' in os.environ: return + if self.spawn_env.get('MMGEN_NO_LICENSE'): + return self.expect("'w' for conditions and warranty info, or 'c' to continue: ",'c') def label(self,label='Test Label (UTF-8) α'): diff --git a/test/scrambletest.py b/test/scrambletest.py index a0b1a7c0..cb7ca760 100755 --- a/test/scrambletest.py +++ b/test/scrambletest.py @@ -56,10 +56,6 @@ from test.include.common import set_globals,end_msg,green set_globals(cfg) -os.environ['MMGEN_DEBUG_ADDRLIST'] = '1' -if not cfg.system: - os.environ['PYTHONPATH'] = repo_root - from collections import namedtuple td = namedtuple('scrambletest_entry',['seed','str','id_str','lbl','addr']) @@ -103,8 +99,13 @@ passwd_data = { cvr_opts = ' -m trace --count --coverdir={} --file={}'.format( *init_coverage() ) if cfg.coverage else '' cmd_base = f'python3{cvr_opts} cmds/mmgen-{{}}gen -qS' +run_env = dict(os.environ) +run_env['MMGEN_DEBUG_ADDRLIST'] = '1' +if not cfg.system: + run_env['PYTHONPATH'] = repo_root + def get_cmd_output(cmd): - cp = run(cmd.split(),stdout=PIPE,stderr=PIPE) + cp = run( cmd.split(), stdout=PIPE, stderr=PIPE, env=run_env ) if cp.returncode != 0: die(2,f'\nSpawned program exited with error code {cp.returncode}:\n{cp.stderr.decode()}') return cp.stdout.decode().splitlines() diff --git a/test/test.py b/test/test.py index d3a34b1f..11f0e108 100755 --- a/test/test.py +++ b/test/test.py @@ -225,7 +225,7 @@ testing_segwit = cfg.segwit or cfg.segwit_random or cfg.bech32 if cfg.test_suite_deterministic: cfg.no_timings = True init_color(num_colors=0) - os.environ['MMGEN_DISABLE_COLOR'] = '1' + os.environ['MMGEN_DISABLE_COLOR'] = '1' # for this script and spawned scripts if cfg.profile: cfg.names = True @@ -340,23 +340,6 @@ def create_tmp_dirs(shm_dir): finally: os.symlink(src,cfgs[cfg]['tmpdir']) -def set_environ_for_spawned_scripts(): - - from mmgen.term import get_terminal_size - os.environ['MMGEN_COLUMNS'] = str(get_terminal_size().width) - - if os.getenv('MMGEN_DEBUG_ALL'): - for name in cfg._env_opts: - if name[:11] == 'MMGEN_DEBUG': - os.environ[name] = '1' - - if not cfg.system: - os.environ['PYTHONPATH'] = repo_root - - os.environ['MMGEN_NO_LICENSE'] = '1' - os.environ['MMGEN_BOGUS_SEND'] = '1' - os.environ['MMGEN_TEST_SUITE_PEXPECT'] = '1' - def set_restore_term_at_exit(): import termios,atexit fd = sys.stdin.fileno() @@ -572,6 +555,34 @@ class TestSuiteRunner(object): if cfg.pexpect_spawn: omsg(f'INFO → Using pexpect.spawn() for real terminal emulation') + self.set_spawn_env() + + def set_spawn_env(self): + + self.spawn_env = dict(os.environ) + self.spawn_env.update({ + 'MMGEN_NO_LICENSE': '1', + 'MMGEN_BOGUS_SEND': '1', + 'MMGEN_TEST_SUITE_PEXPECT': '1', + 'EXEC_WRAPPER_SPAWN':'1', + # if test.py itself is running under exec_wrapper, disable writing of traceback file for spawned script + 'EXEC_WRAPPER_TRACEBACK': '' if os.getenv('MMGEN_EXEC_WRAPPER') else '1', + }) + + if cfg.exact_output: + from mmgen.term import get_terminal_size + self.spawn_env['MMGEN_COLUMNS'] = str(get_terminal_size().width) + else: + self.spawn_env['MMGEN_COLUMNS'] = '120' + + if os.getenv('MMGEN_DEBUG_ALL'): + for name in cfg._env_opts: + if name[:11] == 'MMGEN_DEBUG': + self.spawn_env[name] = '1' + + if not cfg.system: + self.spawn_env['PYTHONPATH'] = repo_root + def spawn_wrapper(self,cmd, args = [], extra_desc = '', @@ -582,7 +593,8 @@ class TestSuiteRunner(object): no_exec_wrapper = False, timeout = None, pexpect_spawn = None, - direct_exec = False ): + direct_exec = False, + env = {} ): desc = self.ts.test_name if cfg.names else self.gm.dpy_data[self.ts.test_name][1] if extra_desc: @@ -641,21 +653,18 @@ class TestSuiteRunner(object): send_delay = 0.4 if pexpect_spawn is True or cfg.buf_keypress else None pexpect_spawn = pexpect_spawn if pexpect_spawn is not None else bool(cfg.pexpect_spawn) - os.environ['MMGEN_HOLD_PROTECT_DISABLE'] = '' if send_delay else '1' - os.environ['MMGEN_TEST_SUITE_POPEN_SPAWN'] = '' if pexpect_spawn else '1' - os.environ['MMGEN_TEST_SUITE_ENABLE_COLOR'] = '1' if self.ts.color else '' - - env = { 'EXEC_WRAPPER_SPAWN':'1' } - env.update(os.environ) - if os.getenv('MMGEN_EXEC_WRAPPER'): - # test.py itself is running under exec_wrapper, so disable traceback file writing for spawned script - env.update({ 'EXEC_WRAPPER_TRACEBACK':'' }) # Python 3.9: OR the dicts + spawn_env = dict(self.ts.spawn_env) + spawn_env.update({ + 'MMGEN_HOLD_PROTECT_DISABLE': '' if send_delay else '1', + 'MMGEN_TEST_SUITE_POPEN_SPAWN': '' if pexpect_spawn else '1', + }) + spawn_env.update(env) from test.include.pexpect import MMGenPexpect return MMGenPexpect( args = args, no_output = no_output, - spawn_env = env, + spawn_env = spawn_env, pexpect_spawn = pexpect_spawn, timeout = timeout, send_delay = send_delay, @@ -718,8 +727,6 @@ class TestSuiteRunner(object): start_test_daemons(network_id,remove_datadir=True) self.daemon_started = True - 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,sg_name,self.spawn_wrapper) self.ts_clsname = type(self.ts).__name__ @@ -1001,8 +1008,6 @@ elif cmd_args and cmd_args[0] in utils: if cfg.pause: set_restore_term_at_exit() -set_environ_for_spawned_scripts() - from mmgen.exception import TestSuiteException,TestSuiteFatalException try: diff --git a/test/test_py_d/common.py b/test/test_py_d/common.py index 258e553c..e1fd9772 100755 --- a/test/test_py_d/common.py +++ b/test/test_py_d/common.py @@ -94,17 +94,12 @@ def confirm_continue(): def randbool(): return getrand(1).hex()[0] in '02468ace' -def disable_debug(): - global save_debug - save_debug = {} +def get_env_without_debug_vars(): + ret = dict(os.environ) for k in cfg._env_opts: - if k[:11] == 'MMGEN_DEBUG': - save_debug[k] = os.getenv(k) - os.environ[k] = '' - -def restore_debug(): - for k in save_debug: - os.environ[k] = save_debug[k] or '' + if k[:11] == 'MMGEN_DEBUG' and k in ret: + del ret[k] + return ret def get_file_with_ext(tdir,ext,delete=True,no_dot=False,return_list=False,delete_all=False,substr=False): diff --git a/test/test_py_d/ts_autosign.py b/test/test_py_d/ts_autosign.py index 4ca1dc67..7002cea6 100755 --- a/test/test_py_d/ts_autosign.py +++ b/test/test_py_d/ts_autosign.py @@ -113,8 +113,8 @@ class TestSuiteAutosignBase(TestSuiteBase): die(1,red('This command must be run with --exact-output enabled!')) if self.simulate or not self.live: - os.environ['MMGEN_TEST_SUITE_AUTOSIGN_LED_SIMULATE'] = '1' LEDControl.create_dummy_control_files() + self.spawn_env['MMGEN_TEST_SUITE_AUTOSIGN_LED_SIMULATE'] = '1' self.opts = ['--coins='+','.join(self.coins)] diff --git a/test/test_py_d/ts_base.py b/test/test_py_d/ts_base.py index 6f6b9fee..a5588145 100755 --- a/test/test_py_d/ts_base.py +++ b/test/test_py_d/ts_base.py @@ -53,6 +53,11 @@ class TestSuiteBase: self.fork = d[self.proto.coin.lower()] if self.proto.coin.lower() in d else None if len(self.tmpdir_nums) == 1: self.tmpdir_num = self.tmpdir_nums[0] + if self.tr: + self.spawn_env = dict(self.tr.spawn_env) + self.spawn_env['MMGEN_TEST_SUITE_ENABLE_COLOR'] = '1' if self.color else '' + else: + self.spawn_env = {} # placeholder @property def tmpdir(self): diff --git a/test/test_py_d/ts_cfgfile.py b/test/test_py_d/ts_cfgfile.py index 1ea63bd3..8000c0bc 100755 --- a/test/test_py_d/ts_cfgfile.py +++ b/test/test_py_d/ts_cfgfile.py @@ -39,11 +39,8 @@ class TestSuiteCfgFile(TestSuiteBase): ) def __init__(self,trunner,cfgs,spawn): - os.environ['MMGEN_TEST_SUITE_CFGTEST'] = '1' TestSuiteBase.__init__(self,trunner,cfgs,spawn) - - def __del__(self): - os.environ['MMGEN_TEST_SUITE_CFGTEST'] = '' + self.spawn_env['MMGEN_TEST_SUITE_CFGTEST'] = '1' def spawn_test(self,args=[],extra_desc='',pexpect_spawn=None): return self.spawn( diff --git a/test/test_py_d/ts_ethdev.py b/test/test_py_d/ts_ethdev.py index 6d63255b..c7399fec 100755 --- a/test/test_py_d/ts_ethdev.py +++ b/test/test_py_d/ts_ethdev.py @@ -382,11 +382,8 @@ class TestSuiteEthdev(TestSuiteBase,TestSuiteShared): joinpath(self.tmpdir,parity_devkey_fn), dfl_devkey+'\n' ) - os.environ['MMGEN_BOGUS_SEND'] = '' self.message = 'attack at dawn' - - def __del__(self): - os.environ['MMGEN_BOGUS_SEND'] = '1' + self.spawn_env['MMGEN_BOGUS_SEND'] = '' @property def eth_args(self): diff --git a/test/test_py_d/ts_input.py b/test/test_py_d/ts_input.py index 43ad1643..5b413c4c 100755 --- a/test/test_py_d/ts_input.py +++ b/test/test_py_d/ts_input.py @@ -97,17 +97,17 @@ class TestSuiteInput(TestSuiteBase): from subprocess import run,PIPE cmd = ['python3','cmds/mmgen-walletconv','--in-fmt=words','--out-fmt=words','--outdir=test/trash'] mn = sample_mn['mmgen']['mn'] - os.environ['MMGEN_TEST_SUITE'] = '' + run_env = dict(os.environ) + run_env['MMGEN_TEST_SUITE'] = '' # the test can fail the first time if cfg file has changed, so run it twice if necessary: for i in range(2): - cp = run( cmd, input=mn.encode(), stdout=PIPE, stderr=PIPE ) + cp = run( cmd, input=mn.encode(), stdout=PIPE, stderr=PIPE, env=run_env ) if b'written to file' in cp.stderr: break from mmgen.color import set_vt100 set_vt100() - os.environ['MMGEN_TEST_SUITE'] = '1' imsg(cp.stderr.decode().strip()) res = get_data_from_file(cfg,'test/trash/A773B05C[128].mmwords',silent=True).strip() assert res == mn, f'{res} != {mn}' diff --git a/test/test_py_d/ts_main.py b/test/test_py_d/ts_main.py index 4cf81da8..4e247436 100755 --- a/test/test_py_d/ts_main.py +++ b/test/test_py_d/ts_main.py @@ -199,7 +199,7 @@ class TestSuiteMain(TestSuiteBase,TestSuiteShared): self.txbump_fee = {'btc':'123s','bch':'567s','ltc':'12345s'}[self.proto.coin.lower()] self.unspent_data_file = joinpath('test','trash','unspent.json') - os.environ['MMGEN_BOGUS_UNSPENT_DATA'] = self.unspent_data_file + self.spawn_env['MMGEN_BOGUS_UNSPENT_DATA'] = self.unspent_data_file def _get_addrfile_checksum(self,display=False): addrfile = self.get_file_with_ext('addrs') diff --git a/test/test_py_d/ts_misc.py b/test/test_py_d/ts_misc.py index 3b96dd22..2eee1ede 100755 --- a/test/test_py_d/ts_misc.py +++ b/test/test_py_d/ts_misc.py @@ -144,9 +144,10 @@ class TestSuiteHelp(TestSuiteBase): return t def license(self): - lsave = os.getenv('MMGEN_NO_LICENSE') - os.environ['MMGEN_NO_LICENSE'] = '' - t = self.spawn(f'mmgen-walletconv',['--stdout','--in-fmt=hex','--out-fmt=hex']) + t = self.spawn( + f'mmgen-walletconv', + ['--stdout','--in-fmt=hex','--out-fmt=hex'], + env = {'MMGEN_NO_LICENSE':''} ) t.expect('to continue: ', 'w') t.expect('TERMS AND CONDITIONS') # start of GPL text if cfg.pexpect_spawn: @@ -157,7 +158,6 @@ class TestSuiteHelp(TestSuiteBase): t.expect('to continue: ', 'c') t.expect('data: ','beadcafe'*4 + '\n') t.expect('to confirm: ', 'YES\n') - os.environ['MMGEN_NO_LICENSE'] = lsave return t def spawn_chk_expect(self,*args,**kwargs): diff --git a/test/test_py_d/ts_ref.py b/test/test_py_d/ts_ref.py index 0da150d5..0f95f7ef 100755 --- a/test/test_py_d/ts_ref.py +++ b/test/test_py_d/ts_ref.py @@ -281,12 +281,11 @@ class TestSuiteRef(TestSuiteBase,TestSuiteShared): def ref_tool_decrypt(self): f = joinpath(ref_dir,ref_enc_fn) - if not cfg.debug_utf8: - disable_debug() dec_file = joinpath(self.tmpdir,'famous.txt') - t = self.spawn('mmgen-tool', ['-q','decrypt',f,'outfile='+dec_file,'hash_preset=1']) - if not cfg.debug_utf8: - restore_debug() + t = self.spawn( + 'mmgen-tool', + ['-q','decrypt',f,'outfile='+dec_file,'hash_preset=1'], + env = os.environ if cfg.debug_utf8 else get_env_without_debug_vars() ) t.passphrase('data',tool_enc_passwd) t.written_to_file('Decrypted data') dec_txt = read_from_file(dec_file) diff --git a/test/test_py_d/ts_regtest.py b/test/test_py_d/ts_regtest.py index 87096c10..2d03a6fc 100755 --- a/test/test_py_d/ts_regtest.py +++ b/test/test_py_d/ts_regtest.py @@ -430,16 +430,13 @@ class TestSuiteRegtest(TestSuiteBase,TestSuiteShared): self.miner_addr = 'bcrt1qaq8t3pakcftpk095tnqfv5cmmczysls024atnd' # regtest.create_hdseed() self.miner_wif = 'cTyMdQ2BgfAsjopRVZrj7AoEGp97pKfrC2NkqLuwHr4KHfPNAKwp' - os.environ['MMGEN_BOGUS_SEND'] = '' + 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.burn_addr = make_burn_addr(self.proto) self.user_sids = {} - def __del__(self): - os.environ['MMGEN_BOGUS_SEND'] = '1' - def _add_comments_to_addr_file(self,addrfile,outfile,use_comments=False): silence() gmsg(f'Adding comments to address file {addrfile!r}') @@ -973,11 +970,11 @@ class TestSuiteRegtest(TestSuiteBase,TestSuiteShared): return t def _get_mempool(self): - if not cfg.debug_utf8: - disable_debug() - ret = self.spawn('mmgen-regtest',['mempool']).read() - if not cfg.debug_utf8: - restore_debug() + ret = self.spawn( + 'mmgen-regtest', + ['mempool'], + env = os.environ if cfg.debug_utf8 else get_env_without_debug_vars(), + ).read() m = re.search(r'(\[\s*"[a-f0-9]{64}"\s*])',ret) # allow for extra output by handler at end return json.loads(m.group(1)) diff --git a/test/test_py_d/ts_tool.py b/test/test_py_d/ts_tool.py index bad2c55d..c80a89f0 100755 --- a/test/test_py_d/ts_tool.py +++ b/test/test_py_d/ts_tool.py @@ -80,8 +80,10 @@ class TestSuiteTool(TestSuiteMain,TestSuiteBase): return t def tool_twview_bad_comment(self): # test correct operation of get_tw_label() - os.environ['MMGEN_BOGUS_UNSPENT_DATA'] = joinpath(ref_dir,'bad-comment-unspent.json') - t = self.spawn('mmgen-tool',['twview']) + t = self.spawn( + 'mmgen-tool', + ['twview'], + env = { 'MMGEN_BOGUS_UNSPENT_DATA': joinpath(ref_dir,'bad-comment-unspent.json') }) t.expect('cannot be converted to TwComment') t.req_exit_val = 2 return t diff --git a/test/test_py_d/ts_xmr_autosign.py b/test/test_py_d/ts_xmr_autosign.py index 5d5f5d7d..2de9d61c 100755 --- a/test/test_py_d/ts_xmr_autosign.py +++ b/test/test_py_d/ts_xmr_autosign.py @@ -91,8 +91,6 @@ class TestSuiteXMRAutosign(TestSuiteXMRWallet,TestSuiteAutosignBase): def __init__(self,trunner,cfgs,spawn): - os.environ['MMGEN_TEST_SUITE_XMR_AUTOSIGN'] = '1' - TestSuiteXMRWallet.__init__(self,trunner,cfgs,spawn) TestSuiteAutosignBase.__init__(self,trunner,cfgs,spawn) @@ -113,9 +111,7 @@ class TestSuiteXMRAutosign(TestSuiteXMRWallet,TestSuiteAutosignBase): self.opts.append('--xmrwallets={}'.format( self.users['alice'].kal_range )) # mmgen-autosign opts self.autosign_opts = [f'--autosign-mountpoint={self.mountpoint}'] # mmgen-xmrwallet opts self.tx_count = 1 - - def __del__(self): - os.environ['MMGEN_TEST_SUITE_XMR_AUTOSIGN'] = '' + self.spawn_env['MMGEN_TEST_SUITE_XMR_AUTOSIGN'] = '1' def create_tmp_wallets(self): self.spawn('',msg_only=True)