Browse Source

TestDaemon: support ETH; test.py: start/stop parity automatically

The MMGen Project 5 years ago
parent
commit
ebe21cf8d8
2 changed files with 60 additions and 47 deletions
  1. 56 2
      mmgen/test_daemon.py
  2. 4 45
      test/test_py_d/ts_ethdev.py

+ 56 - 2
mmgen/test_daemon.py

@@ -20,6 +20,7 @@
 test_daemon.py:  Daemon control classes for MMGen test suite and regtest mode
 """
 
+import shutil
 from subprocess import run,PIPE
 from collections import namedtuple
 from mmgen.exception import *
@@ -30,7 +31,7 @@ class TestDaemon(MMGenObject):
 
 	subclasses_must_implement = ('state','stop_cmd')
 
-	network_ids = ('btc','btc_tn','bch','bch_tn','ltc','ltc_tn','xmr')
+	network_ids = ('btc','btc_tn','bch','bch_tn','ltc','ltc_tn','xmr','eth','etc')
 
 	cd = namedtuple('coin_data',['coin','coind_exec','cli_exec','conf_file','dfl_rpc','dfl_rpc_tn'])
 	coins = {
@@ -52,6 +53,7 @@ class TestDaemon(MMGenObject):
 	coind_args = []
 	cli_args = []
 	shared_args = []
+	coind_cmd = []
 
 	coin_specific_coind_args = []
 	coin_specific_cli_args = []
@@ -81,6 +83,7 @@ class TestDaemon(MMGenObject):
 
 		me = MMGenObject.__new__(
 			MoneroTestDaemon        if coinsym == 'xmr'
+			else EthereumTestDaemon if coinsym in ('eth','etc')
 			else BitcoinTestDaemon )
 
 		me.network_id = network_id
@@ -158,7 +161,8 @@ class TestDaemon(MMGenObject):
 				+ self.coin_specific_coind_args
 				+ self.coin_specific_shared_args
 				+ self.usr_coind_args
-				+ self.usr_shared_args)
+				+ self.usr_shared_args
+				+ self.coind_cmd )
 
 	def cli_cmd(self,*cmds):
 		return ([self.cli_exec]
@@ -193,6 +197,10 @@ class TestDaemon(MMGenObject):
 			os.makedirs(self.datadir,exist_ok=True)
 			if self.conf_file:
 				open('{}/{}'.format(self.datadir,self.conf_file),'w').write(self.cfg_file_hdr)
+			if self.use_pidfile and os.path.exists(self.pidfile):
+				# Parity just overwrites the data in an existing pidfile, leading to
+				# interesting consequences.
+				os.unlink(self.pidfile)
 			ret = self.do_start(silent=silent)
 			if self.wait:
 				self.wait_for_state('ready')
@@ -305,4 +313,50 @@ class MoneroTestDaemon(TestDaemon):
 	def stop_cmd(self):
 		return [self.coind_exec] + self.shared_args + ['exit']
 
+class EthereumTestDaemon(TestDaemon):
+
+	def subclass_init(self):
+		# defaults:
+		# linux: $HOME/.local/share/io.parity.ethereum/chains/DevelopmentChain
+		# win:   $LOCALAPPDATA/Parity/Ethereum/chains/DevelopmentChain
+		self.chaindir = os.path.join(self.datadir,'devchain')
+		shutil.rmtree(self.chaindir,ignore_errors=True)
+
+	@property
+	def coind_cmd(self):
+		return ['daemon',self.pidfile] if self.platform == 'linux' else []
+
+	@property
+	def coind_args(self):
+		return ['--ports-shift={}'.format(self.port_shift),
+				'--base-path={}'.format(self.chaindir),
+				'--config=dev',
+				'--log-file={}'.format(os.path.join(self.datadir,'parity.log')) ]
+
+	@property
+	def state(self):
+		from mmgen.rpc import EthereumRPCConnection
+		try:
+			conn = EthereumRPCConnection('localhost',self.rpc_port,socket_timeout=0.2)
+		except:
+			return 'stopped'
+
+		ret = conn.eth_chainId(on_fail='return')
+
+		return ('stopped','ready')[ret == '0x11']
+
+	@property
+	def stop_cmd(self):
+		return ['kill','-Wf',self.pid] if g.platform == 'win' else ['kill',self.pid]
+
+	@property
+	def pid(self): # TODO: distinguish between ETH and ETC
+		if g.platform == 'win':
+			cp = self.run_cmd(['ps','-Wl'],silent=True,check=False)
+			for line in cp.stdout.decode().splitlines():
+				if 'parity.exe' in line:
+					return line.split()[3] # use Windows, not Cygwin, PID
+		else:
+			return super().pid
+
 TestDaemon.check_implement()

+ 4 - 45
test/test_py_d/ts_ethdev.py

@@ -302,43 +302,11 @@ class TestSuiteEthdev(TestSuiteBase,TestSuiteShared):
 
 	def setup(self):
 		self.spawn('',msg_only=True)
-		os.environ['MMGEN_BOGUS_WALLET_DATA'] = ''
-		opts = ['--ports-shift=4','--config=dev']
-		lf_arg = '--log-file=' + joinpath(self.tr.data_dir,'parity.log')
 		if g.platform == 'win':
-			dc_dir = joinpath(os.environ['LOCALAPPDATA'],'Parity','Ethereum','chains','DevelopmentChain')
-			shutil.rmtree(dc_dir,ignore_errors=True)
 			m1 = 'Please copy precompiled contract data to {d}/mm1 and {d}/mm2\n'.format(d=self.tmpdir)
-			m2 = 'Then start parity on another terminal as follows:\n'
-			m3 = ['parity',lf_arg] + opts
-			m4 = '\nPress ENTER to continue: '
-			my_raw_input(m1 + m2 + ' '.join(m3) + m4)
-		elif run(['which','parity'],stdout=DEVNULL).returncode == 0:
-			ss = 'parity.*--log-file=test/data_dir.*/parity.log' # allow for UTF8_DEBUG
-			try:
-				pid = run(['pgrep','-af',ss],stdout=PIPE).stdout.split()[0]
-				os.kill(int(pid),9)
-			except: pass
-			# '--base-path' doesn't work together with daemon mode, so we have to clobber the main dev chain
-			dc_dir = joinpath(os.environ['HOME'],'.local/share/io.parity.ethereum/chains/DevelopmentChain')
-			shutil.rmtree(dc_dir,ignore_errors=True)
-			bdir = joinpath(self.tr.data_dir,'parity')
-			try: os.mkdir(bdir)
-			except: pass
-			redir = None if opt.exact_output else PIPE
-			pidfile = joinpath(self.tmpdir,parity_pid_fn)
-			run(['parity',lf_arg] + opts + ['daemon',pidfile],stderr=redir,stdout=redir,check=True)
-			time.sleep(3) # race condition
-			pid = self.read_from_tmpfile(parity_pid_fn)
-		elif run('netstat -tnl | grep -q 127.0.0.1:8549',shell=True).returncode == 0:
-			m1 = 'No parity executable found on system, but port 8549 is active!'
-			m2 = 'Before continuing, you should probably run the command'
-			m3 = 'test/test.py -X setup ethdev'
-			m4 = 'on the remote host.'
-			sys.stderr.write('{}\n{}\n{} {}\n'.format(m1,m2,cyan(m3),m4))
-			confirm_continue()
-		else:
-			die(1,'No parity executable found!')
+			m2 = '\nPress ENTER to continue: '
+			my_raw_input(m1+m2)
+		start_test_daemons(g.coin)
 		return 'ok'
 
 	def wallet_upgrade(self,src_file):
@@ -950,14 +918,5 @@ class TestSuiteEthdev(TestSuiteBase,TestSuiteShared):
 
 	def stop(self):
 		self.spawn('',msg_only=True)
-		if g.platform == 'win':
-			my_raw_input('Please stop parity and Press ENTER to continue: ')
-		elif run(['which','parity'],stdout=DEVNULL).returncode == 0:
-			pid = self.read_from_tmpfile(parity_pid_fn)
-			if opt.no_daemon_stop:
-				msg_r('(leaving daemon running by user request)')
-			else:
-				run(['kill',pid],check=True)
-		else:
-			imsg('No parity executable found on system. Ignoring')
+		stop_test_daemons(g.coin)
 		return 'ok'