Browse Source

test suite: improve handling of environment vars

The MMGen Project 1 year ago
parent
commit
e92f241f7a

+ 1 - 1
mmgen/data/version

@@ -1 +1 @@
-13.3.dev58
+13.3.dev59

+ 4 - 2
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) α'):

+ 6 - 5
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()

+ 38 - 33
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:

+ 5 - 10
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):
 

+ 1 - 1
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)]
 

+ 5 - 0
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):

+ 1 - 4
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(

+ 1 - 4
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):

+ 3 - 3
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}'

+ 1 - 1
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')

+ 4 - 4
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):

+ 4 - 5
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)

+ 6 - 9
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))
 

+ 4 - 2
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

+ 1 - 5
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)