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

This commit is contained in:
The MMGen Project 2019-12-08 18:36:40 +00:00
commit ebe21cf8d8
Signed by: mmgen
GPG key ID: 3F8B1861E32B7DA2
2 changed files with 60 additions and 47 deletions

View file

@ -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()

View file

@ -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'