Browse Source

minor fixes and cleanups throughout

The MMGen Project 7 months ago
parent
commit
a0eb2871f9

+ 1 - 0
mmgen/daemon.py

@@ -215,6 +215,7 @@ class Daemon(Lockable):
 				))
 			if self.wait:
 				self.wait_for_state('stopped')
+				time.sleep(0.3) # race condition
 			return ret
 		else:
 			if not (quiet or silent):

+ 1 - 1
mmgen/wallet/base.py

@@ -65,7 +65,7 @@ class wallet(MMGenObject,metaclass=WalletMeta):
 			self._deformat_retry()
 			self._decrypt_retry()
 
-		msg('Valid {a} for Seed ID {b}{c}{d}'.format(
+		self.cfg._util.qmsg('Valid {a} for Seed ID {b}{c}{d}'.format(
 			a = self.desc,
 			b = self.seed.sid.hl(),
 			c = f' (seed length {self.seed.bitlen})' if self.seed.bitlen != 256 else '',

+ 15 - 8
test/clean.py

@@ -14,6 +14,10 @@ test/clean.py: Clean the test directory
 
 import sys, os
 
+repo_root = os.path.normpath(os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), os.pardir)))
+os.chdir(repo_root)
+sys.path[0] = repo_root
+
 from mmgen.cfg import Config
 
 opts_data = {
@@ -29,10 +33,6 @@ opts_data = {
 
 cfg = Config(opts_data=opts_data)
 
-repo_root = os.path.normpath(os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), os.pardir)))
-os.chdir(repo_root)
-sys.path[0] = repo_root
-
 from test.overlay import get_overlay_tree_dir
 overlay_tree_dir = get_overlay_tree_dir(repo_root)
 if os.path.exists(overlay_tree_dir):
@@ -46,8 +46,15 @@ set_globals(cfg)
 
 from test.include.cfg import clean_cfgs
 
-data_dir = Config.test_datadir
-trash_dir = os.path.join('test', 'trash')
-trash_dir2 = os.path.join('test', 'trash2')
+extra_dirs = [
+	Config.test_datadir,
+	os.path.join('test', 'trash'),
+	os.path.join('test', 'trash2')
+]
+
+clean(clean_cfgs, extra_dirs=extra_dirs)
 
-clean(clean_cfgs, extra_dirs=[data_dir, trash_dir, trash_dir2])
+for d in extra_dirs:
+	if os.path.exists(d) and not os.path.isdir(d):
+		print(f'Removing non-directory ‘{d}’')
+		os.unlink(d)

+ 4 - 2
test/cmdtest.py

@@ -83,7 +83,7 @@ except ImportError:
 
 from mmgen.cfg import Config,gc
 from mmgen.color import red,yellow,green,blue,cyan,gray,nocolor,init_color
-from mmgen.util import msg, Msg, bmsg, die, suf, make_timestr
+from mmgen.util import msg, Msg, rmsg, bmsg, die, suf, make_timestr
 
 from test.include.common import (
 	set_globals,
@@ -1008,7 +1008,9 @@ if __name__ == '__main__':
 			Msg(red(str(e)))
 			Msg(blue('cmdtest.py: spawned script exited with error'))
 		raise
-	except Exception:
+	except Exception as e:
+		if type(e).__name__ == 'TestSuiteException':
+			rmsg('TEST ERROR: ' + str(e))
 		# if cmdtest.py itself is running under exec_wrapper, re-raise so exec_wrapper can handle exception:
 		if os.getenv('MMGEN_EXEC_WRAPPER') or not os.getenv('MMGEN_IGNORE_TEST_PY_EXCEPTION'):
 			raise

+ 2 - 2
test/cmdtest_py_d/common.py

@@ -22,7 +22,7 @@ test.cmdtest_py_d.common: Shared routines and data for the cmdtest.py test suite
 
 import sys,os
 
-from mmgen.color import green,blue
+from mmgen.color import green, blue, gray
 from mmgen.util import msg
 
 from ..include.common import cfg,getrand,text_jp,text_zh,ascii_cyr_gr,lat_cyr_gr
@@ -76,7 +76,7 @@ def ok_msg():
 	sys.stderr.write(green('\nOK\n') if cfg.exact_output or cfg.verbose else ' OK\n')
 
 def skip(name,reason=None):
-	msg('Skipping {}{}'.format( name, f' ({reason})' if reason else '' ))
+	msg(gray('Skipping {}{}'.format( name, f' ({reason})' if reason else '' )))
 	return 'skip'
 
 def confirm_continue():

+ 12 - 2
test/cmdtest_py_d/ct_input.py

@@ -63,7 +63,8 @@ class CmdTestInput(CmdTestBase):
 		('line_input_insert',             'line_input() [inserted text]'),
 		('line_input_insert_term1',       'line_input() [inserted text, term]'),
 		('line_input_insert_term2',       'line_input() [inserted text, term, no hold protect]'),
-		('line_input_edit_term',          'line_input() [inserted + edited text, term, utf8]'),
+		('line_input_edit_term',          'line_input() [edited text, term, utf8]'),
+		('line_input_edit_term_insert',   'line_input() [inserted + edited text, term, utf8]'),
 		('line_input_erase_term',         'line_input() [inserted + erased text, term]'),
 	),
 	'password': (
@@ -351,6 +352,15 @@ class CmdTestInput(CmdTestBase):
 			True)
 
 	def line_input_edit_term(self):
+		return self._line_input(
+			['prompt> ', True, '', True],
+			'\b\bφυφυ\b\bβαρ',
+			'φυβαρ',
+			True)
+
+	def line_input_edit_term_insert(self):
+		if self.skip_for_mac('readline text buffer issues'):
+			return 'skip'
 		return self._line_input(
 			['prompt> ', True, 'φυφυ', True],
 			'\b\bβαρ',
@@ -408,7 +418,7 @@ class CmdTestInput(CmdTestBase):
 			'Type a number.*: ',
 			('\n' if enter_for_dfl else str(mne.entry_modes.index(entry_mode)+1)),
 			regex = True )
-		t.expect('Using entry mode (\S+)',regex=True)
+		t.expect(r'Using entry mode (\S+)', regex=True)
 		mode = strip_ansi_escapes(t.p.match.group(1)).lower()
 		assert mode == mne.em.name.lower(), f'{mode} != {mne.em.name.lower()}'
 		stealth_mnemonic_entry(t,mne,mn,entry_mode=entry_mode,pad_entry=pad_entry)

+ 2 - 2
test/cmdtest_py_d/ct_main.py

@@ -23,7 +23,7 @@ test.cmdtest_py_d.ct_main: Basic operations tests for the cmdtest.py test suite
 import sys,os
 
 from mmgen.util import msg,msg_r,async_run,capfirst,get_extension,die
-from mmgen.color import green,cyan
+from mmgen.color import green, cyan, gray
 from mmgen.fileutil import get_data_from_file,write_data_to_file
 from mmgen.wallet import get_wallet_cls
 from mmgen.wallet.mmgen import wallet as MMGenWallet
@@ -671,7 +671,7 @@ class CmdTestMain(CmdTestBase,CmdTestShared):
 
 	def txbump(self,txfile,prepend_args=[],seed_args=[]):
 		if not self.proto.cap('rbf'):
-			msg('Skipping RBF')
+			msg(gray('Skipping RBF'))
 			return 'skip'
 		args = prepend_args + ['--quiet','--outdir='+self.tmpdir,txfile] + seed_args
 		t = self.spawn('mmgen-txbump',args)

+ 3 - 1
test/cmdtest_py_d/ct_misc.py

@@ -22,7 +22,7 @@ test.cmdtest_py_d.ct_misc: Miscellaneous test groups for the cmdtest.py test sui
 
 import sys,os,re,time
 
-from mmgen.util import ymsg
+from mmgen.util import ymsg, die
 
 from ..include.common import cfg,start_test_daemons,stop_test_daemons,imsg
 from .common import get_file_with_ext,dfl_words_file
@@ -131,6 +131,8 @@ class CmdTestMisc(CmdTestBase):
 				t.expect('foo')
 			except pexpect.TIMEOUT:
 				imsg('[input not echoed - OK]')
+			else:
+				die('TestSuiteException', 'Terminal echoed in noecho mode!')
 			t.send('x')
 
 		if self.skip_for_win('no termios support'):

+ 1 - 0
test/include/common.py

@@ -290,6 +290,7 @@ def test_daemons_ops(*network_ids,op,remove_datadir=False):
 		for network_id in network_ids:
 			d = CoinDaemon(cfg,network_id,test_suite=True)
 			if remove_datadir:
+				d.wait = True
 				d.stop(silent=True)
 				d.remove_datadir()
 			ret = d.cmd(op,silent=silent)

+ 13 - 8
test/misc/term_ni.py

@@ -7,6 +7,7 @@ sys.path[0] = os.curdir
 from mmgen.cfg import Config
 cfg = Config()
 
+from mmgen.util import msg
 from mmgen.term import init_term,get_term
 init_term(cfg)
 term = get_term()
@@ -16,16 +17,20 @@ if sys.argv[1] == 'echo':
 	from mmgen.ui import line_input
 	from mmgen.term import get_char_raw
 
-	term.init(noecho=True)
-	line_input( cfg, 'noecho> ' )
-	get_char_raw()
+	def test_noecho():
+		term.init(noecho=True)
+		ret = line_input(cfg, 'noecho> ')
+		msg(f'==> [{ret.upper()}]')
+		get_char_raw()
 
-	term.set('echo')
-	line_input( cfg, 'echo> ' )
+	def test_echo():
+		term.set('echo')
+		ret = line_input(cfg, 'echo> ')
+		msg(f'==> [{ret.upper()}]')
 
-	term.set('noecho')
-	line_input( cfg, 'noecho> ' )
-	get_char_raw()
+	test_noecho()
+	test_echo()
+	test_noecho()
 
 elif sys.argv[1] == 'cleanup':
 

+ 2 - 1
test/scrambletest.py

@@ -32,6 +32,7 @@ except ImportError:
 
 from mmgen.cfg import Config
 from mmgen.util import msg,msg_r,bmsg,die
+from mmgen.color import gray
 
 opts_data = {
 	'text': {
@@ -133,7 +134,7 @@ def do_coin_tests():
 			tuple(bitcoin_data.items()) +
 			tuple(altcoin_data.items() if not cfg.no_altcoin else []) ):
 		if tname == 'zec_zcash_z' and sys.platform == 'win32':
-			msg("Skipping 'zec_zcash_z' test for Windows platform")
+			msg(gray("Skipping 'zec_zcash_z' test for Windows platform"))
 			continue
 		coin,mmtype = tname.split('_',1) if '_' in tname else (tname,None)
 		type_arg = ' --type='+mmtype if mmtype else ''

+ 1 - 1
test/test-release.d/cfg.sh

@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
 #
 # mmgen = Multi-Mode GENerator, a command-line cryptocurrency wallet
 # Copyright (C)2013-2024 The MMGen Project <mmgen@tuta.io>

+ 10 - 7
test/test-release.sh

@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
 #
 # mmgen = Multi-Mode GENerator, a command-line cryptocurrency wallet
 # Copyright (C)2013-2024 The MMGen Project <mmgen@tuta.io>
@@ -116,6 +116,10 @@ print_ver_hash() {
 	python3 -m pip freeze | grep "^$repo\>" | sed 's/.*sha256=//' | cut -c 1-12
 }
 
+do_typescript() {
+	script -O "$1" -c "$2"
+}
+
 install_package() {
 	echo -e "${BLUE}Installing package$YELLOW $repo$RESET"
 	rm -rf build dist *.egg-info
@@ -165,7 +169,7 @@ do_reexec() {
 		target_dir="$orig_cwd/.clone-test"
 		clone_dir=$target_dir
 	else # TYPESCRIPT=1
-		script -O "$orig_cwd/$typescript_file" -c "$exec_prog"
+		do_typescript "$orig_cwd/$typescript_file" "$exec_prog"
 		return
 	fi
 
@@ -194,7 +198,7 @@ do_reexec() {
 		echo -n 'Building sdist...'
 		eval "python3 -m build --no-isolation --sdist --config-setting=quiet $STDOUT_DEVNULL"
 		echo -e "done\n${BLUE}Unpacking sdist archive to $YELLOW$target_dir$RESET"
-		tar -C $target_dir -axf dist/*.tar.gz
+		tar -C $target_dir -zxf dist/*.tar.gz
 		cd $target_dir/${repo//-/[-_]}-*
 		echo -e "${BLUE}cd -> $YELLOW$PWD$RESET"
 		if [ "$clone_dir" ]; then rm -rf $clone_dir; fi
@@ -207,7 +211,7 @@ do_reexec() {
 	echo -e "\n${BLUE}Executing test runner: ${CYAN}test/test-release $ORIG_ARGS$RESET\n"
 
 	if [ "$TYPESCRIPT" ]; then
-		script -O "$orig_cwd/$typescript_file" -c "$exec_prog"
+		do_typescript "$orig_cwd/$typescript_file" "$exec_prog"
 	else
 		eval $exec_prog
 	fi
@@ -232,6 +236,7 @@ elif [ "$(uname -m)" == 'aarch64' ]; then
 	ARM64=1
 elif [ "$MSYSTEM" ] && uname -a | grep -qi 'msys'; then
 	MSYS2=1
+	DISTRO='MSYS2'
 fi
 
 [ "$ARM32" -o "$ARM64" ] && {
@@ -239,9 +244,7 @@ fi
 	HTTP_LONG_TIMEOUT='MMGEN_HTTP_TIMEOUT=300 '
 }
 
-if [ "$MSYS2" ]; then
-	DISTRO='MSYS2'
-else
+if [ -e '/etc/os-release' ]; then
 	DISTRO=$(grep '^ID=' '/etc/os-release' | cut -c 4-)
 	[ "$DISTRO" ] || {
 		echo 'Unable to determine distro from /etc/os-release. Aborting'

+ 3 - 2
test/tooltest2.py

@@ -210,7 +210,8 @@ def run_test(cls, gid, cmd_name):
 		if 'fmt=xmrseed' in args and cfg.no_altcoin:
 			if not skipping:
 				qmsg('')
-			qmsg(('' if n else '\n') + gray(f'Skipping altcoin test {cmd_name} {args}'))
+			skip_msg = f'Skipping altcoin test {cmd_name} {args}'
+			qmsg(('' if n else '\n') + gray(skip_msg if len(skip_msg) <= 100 else skip_msg[:97] + '...'))
 			skipping = True
 			continue
 		else:
@@ -228,7 +229,7 @@ def run_test(cls, gid, cmd_name):
 			cmd_out = fork_cmd(cmd_name,args,opts,stdin_input)
 		else:
 			if stdin_input and sys.platform == 'win32':
-				msg('Skipping for MSWin - no os.fork()')
+				msg(gray('Skipping for MSWin - no os.fork()'))
 				continue
 			method = getattr(cls(cfg,cmdname=cmd_name,proto=proto,mmtype=mmtype),cmd_name)
 			cmd_out = call_method(cls, method, cmd_name, args, mmtype, stdin_input)

+ 2 - 2
test/unit_tests.py

@@ -34,13 +34,13 @@ if not os.getenv('MMGEN_DEVTOOLS'):
 	init_dev()
 
 from mmgen.cfg import Config,gc
-from mmgen.color import green,gray,brown,orange
+from mmgen.color import green, gray, brown, orange, yellow, red
 from mmgen.util import msg,gmsg,ymsg,Msg
 
 from test.include.common import set_globals,end_msg
 
 def die(ev,s):
-	msg(s)
+	msg((red if ev > 1 else yellow)(s))
 	sys.exit(ev)
 
 opts_data = {

+ 9 - 4
test/unit_tests_d/ut_daemon.py

@@ -7,11 +7,11 @@ test.unit_tests_d.ut_daemon: unit test for the MMGen suite's Daemon class
 from subprocess import run,PIPE
 from collections import namedtuple
 
-from mmgen.color import orange
+from mmgen.color import orange, red
 from mmgen.util import fmt_list
 from mmgen.daemon import CoinDaemon
 
-from ..include.common import cfg,qmsg,qmsg_r,vmsg
+from ..include.common import cfg, qmsg, qmsg_r, vmsg, msg
 
 def test_flags():
 	d = CoinDaemon(cfg,'eth')
@@ -67,8 +67,13 @@ class unit_tests:
 		qmsg_r(message)
 		args = ['python3', f'test/{args_in[0]}-coin-daemons.py'] + list(args_in[1:]) + self.daemon_ctrl_args
 		vmsg('\n' + orange(f"Running '{' '.join(args)}':"))
-		pipe = None if cfg.verbose else PIPE
-		run( args, stdout=pipe, stderr=pipe, check=True )
+		cp = run(args, stdout=PIPE, stderr=PIPE, text=True)
+		if cp.returncode != 0:
+			if cp.stdout:
+				msg(cp.stdout)
+			if cp.stderr:
+				msg(red(cp.stderr))
+			return False
 		qmsg('OK')
 		return True
 

+ 8 - 2
test/unit_tests_d/ut_rpc.py

@@ -20,7 +20,7 @@ from ..include.common import cfg,qmsg,vmsg
 async def cfg_file_auth_test(cfg, d, bad_auth=False):
 	m = 'missing credentials' if bad_auth else f'credentials from {d.cfg_file}'
 	qmsg(cyan(f'\n  Testing authentication with {m}:'))
-	time.sleep(0.1) # race condition
+	d.stop()
 	d.remove_datadir() # removes cookie file to force authentication from cfg file
 	os.makedirs(d.network_datadir)
 
@@ -45,7 +45,9 @@ async def cfg_file_auth_test(cfg, d, bad_auth=False):
 		rpc = await rpc_init(cfg, d.proto)
 		assert rpc.auth.user == 'ut_rpc', f'{rpc.auth.user}: user is not ut_rpc!'
 
-	d.stop()
+	if not cfg.no_daemon_stop:
+		d.stop()
+		d.remove_datadir()
 
 async def print_daemon_info(rpc):
 
@@ -117,8 +119,11 @@ async def run_test(network_ids, test_cf_auth=False, daemon_ids=None, cfg_in=None
 
 	async def do_test(d, cfg):
 
+		d.wait = True
+
 		if not cfg.no_daemon_stop:
 			d.stop()
+			d.remove_datadir()
 
 		if not cfg.no_daemon_autostart:
 			d.remove_datadir()
@@ -132,6 +137,7 @@ async def run_test(network_ids, test_cf_auth=False, daemon_ids=None, cfg_in=None
 
 		if not cfg.no_daemon_stop:
 			d.stop()
+			d.remove_datadir()
 
 		if test_cf_auth and sys.platform != 'win32':
 			await cfg_file_auth_test(cfg, d)

+ 2 - 2
test/unit_tests_d/ut_tx_deserialize.py

@@ -98,7 +98,7 @@ async def do_mmgen_ref(daemons,fns,name,desc):
 			tx_hex   = tx.serialized,
 			desc     = fn,
 			n        = n+1 )
-	stop_test_daemons(*daemons)
+	stop_test_daemons(*daemons, remove_datadir=True)
 	Msg('OK')
 	return True
 
@@ -133,7 +133,7 @@ class unit_tests:
 				desc = e[0]
 
 		Msg('OK')
-		stop_test_daemons('btc')
+		stop_test_daemons('btc', remove_datadir=True)
 		return True
 
 	async def mmgen_ref(self,name,ut):