Persistent test.

This commit is contained in:
tecnovert 2021-01-16 10:21:59 +02:00
parent ed22fe7d12
commit 64caceebfe
No known key found for this signature in database
GPG key ID: 8ED6D8750C4E3F93
8 changed files with 324 additions and 17 deletions

View file

@ -12,7 +12,6 @@ lint_task:
test_task:
environment:
- TEST_PREPARE_PATH: $HOME/test_basicswap-prepare
- TEST_RELOAD_PATH: $HOME/test_basicswap1
- TEST_DIR: $HOME/test_basicswap2
- BIN_DIR: /tmp/cached_bin
@ -43,6 +42,4 @@ test_task:
- cp -r ${BIN_DIR} "${DATADIRS}/bin"
- mkdir -p "${TEST_RELOAD_PATH}/bin"
- cp -r ${BIN_DIR} "${TEST_RELOAD_PATH}/bin"
- mkdir -p "${TEST_PREPARE_PATH}/bin"
- cp -r ${BIN_DIR} "${TEST_PREPARE_PATH}/bin"
- tox

View file

@ -7,7 +7,6 @@ stages:
- test
env:
global:
- TEST_PREPARE_PATH=~/test_basicswap-prepare
- TEST_DIR=${HOME}/test_basicswap2
- TEST_RELOAD_PATH=~/test_basicswap1
- BIN_DIR=~/cached_bin
@ -36,8 +35,6 @@ script:
- cp -r ${BIN_DIR} "${DATADIRS}/bin"
- mkdir -p "${TEST_RELOAD_PATH}/bin"
- cp -r ${BIN_DIR} "${TEST_RELOAD_PATH}/bin"
- mkdir -p "${TEST_PREPARE_PATH}/bin"
- cp -r ${BIN_DIR} "${TEST_PREPARE_PATH}/bin"
- tox
after_success:
- echo "End test"

View file

@ -64,12 +64,20 @@ XMR_SITE_COMMIT = 'd27c1eee9fe0e8daa011d07baae8b67dd2b62a04' # Lock hashes.txt
DEFAULT_XMR_RESTORE_HEIGHT = 2245107
UI_HTML_PORT = int(os.getenv('BASE_XMR_RPC_PORT', 12700))
PART_ZMQ_PORT = int(os.getenv('PART_ZMQ_PORT', 20792))
PART_RPC_HOST = os.getenv('PART_RPC_HOST', '127.0.0.1')
LTC_RPC_HOST = os.getenv('LTC_RPC_HOST', '127.0.0.1')
BTC_RPC_HOST = os.getenv('BTC_RPC_HOST', '127.0.0.1')
NMC_RPC_HOST = os.getenv('NMC_RPC_HOST', '127.0.0.1')
PART_RPC_PORT = int(os.getenv('PART_RPC_PORT', 19792))
LTC_RPC_PORT = int(os.getenv('LTC_RPC_PORT', 19795))
BTC_RPC_PORT = int(os.getenv('BTC_RPC_PORT', 19796))
NMC_RPC_PORT = int(os.getenv('NMC_RPC_PORT', 19798))
extract_core_overwrite = True
@ -537,7 +545,7 @@ def main():
'connection_type': 'rpc',
'manage_daemon': True if ('particl' in with_coins and PART_RPC_HOST == '127.0.0.1') else False,
'rpchost': PART_RPC_HOST,
'rpcport': 19792 + port_offset,
'rpcport': PART_RPC_PORT + port_offset,
'datadir': os.getenv('PART_DATA_DIR', os.path.join(data_dir, 'particl')),
'bindir': os.path.join(bin_dir, 'particl'),
'blocks_confirmed': 2,
@ -550,7 +558,7 @@ def main():
'connection_type': 'rpc' if 'litecoin' in with_coins else 'none',
'manage_daemon': True if ('litecoin' in with_coins and LTC_RPC_HOST == '127.0.0.1') else False,
'rpchost': LTC_RPC_HOST,
'rpcport': 19795 + port_offset,
'rpcport': LTC_RPC_PORT + port_offset,
'datadir': os.getenv('LTC_DATA_DIR', os.path.join(data_dir, 'litecoin')),
'bindir': os.path.join(bin_dir, 'litecoin'),
'use_segwit': True,
@ -563,7 +571,7 @@ def main():
'connection_type': 'rpc' if 'bitcoin' in with_coins else 'none',
'manage_daemon': True if ('bitcoin' in with_coins and BTC_RPC_HOST == '127.0.0.1') else False,
'rpchost': BTC_RPC_HOST,
'rpcport': 19796 + port_offset,
'rpcport': BTC_RPC_PORT + port_offset,
'datadir': os.getenv('BTC_DATA_DIR', os.path.join(data_dir, 'bitcoin')),
'bindir': os.path.join(bin_dir, 'bitcoin'),
'use_segwit': True,
@ -576,7 +584,7 @@ def main():
'connection_type': 'rpc' if 'namecoin' in with_coins else 'none',
'manage_daemon': True if ('namecoin' in with_coins and NMC_RPC_HOST == '127.0.0.1') else False,
'rpchost': NMC_RPC_HOST,
'rpcport': 19798 + port_offset,
'rpcport': NMC_RPC_PORT + port_offset,
'datadir': os.getenv('NMC_DATA_DIR', os.path.join(data_dir, 'namecoin')),
'bindir': os.path.join(bin_dir, 'namecoin'),
'use_segwit': False,
@ -669,9 +677,9 @@ def main():
settings = {
'debug': True,
'zmqhost': 'tcp://127.0.0.1',
'zmqport': 20792 + port_offset,
'zmqport': PART_ZMQ_PORT + port_offset,
'htmlhost': htmlhost,
'htmlport': 12700 + port_offset,
'htmlport': UI_HTML_PORT + port_offset,
'network_key': '7sW2UEcHXvuqEjkpE5mD584zRaQYs6WXYohue4jLFZPTvMSxwvgs',
'network_pubkey': '035758c4a22d7dd59165db02a56156e790224361eb3191f02197addcb3bde903d2',
'chainclients': withchainclients,

View file

@ -1,7 +1,7 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright (c) 2020 tecnovert
# Copyright (c) 2020-2021 tecnovert
# Distributed under the MIT software license, see the accompanying
# file LICENSE.txt or http://www.opensource.org/licenses/mit-license.php.

View file

@ -95,6 +95,9 @@ class XmrTestBase(unittest.TestCase):
fp.write('port={}\n'.format(PARTICL_PORT_BASE + i))
fp.write('bind=127.0.0.1\n')
fp.write('dnsseed=0\n')
fp.write('discover=0\n')
fp.write('listenonion=0\n')
fp.write('upnp=0\n')
fp.write('minstakeinterval=5\n')
for ip in range(3):
if ip != i:

View file

@ -95,6 +95,9 @@ class Test(unittest.TestCase):
fp.write('port={}\n'.format(PARTICL_PORT_BASE + i))
fp.write('bind=127.0.0.1\n')
fp.write('dnsseed=0\n')
fp.write('discover=0\n')
fp.write('listenonion=0\n')
fp.write('upnp=0\n')
fp.write('minstakeinterval=5\n')
for ip in range(3):
if ip != i:
@ -108,11 +111,11 @@ class Test(unittest.TestCase):
if not line.startswith('prune'):
fp.write(line)
fp.write('port={}\n'.format(BITCOIN_PORT_BASE + i))
fp.write('discover=0\n')
fp.write('bind=127.0.0.1\n')
fp.write('dnsseed=0\n')
fp.write('discover=0\n')
fp.write('listenonion=0\n')
fp.write('upnp=0\n')
fp.write('bind=127.0.0.1\n')
for ip in range(3):
if ip != i:
fp.write('connect=127.0.0.1:{}\n'.format(BITCOIN_PORT_BASE + ip))

View file

@ -0,0 +1,296 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright (c) 2021 tecnovert
# Distributed under the MIT software license, see the accompanying
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
"""
export RESET_TEST=true
export TEST_PATH=/tmp/test_persistent
mkdir -p ${TEST_PATH}/bin/{particl,monero,bitcoin}
cp ~/tmp/particl-0.19.1.2-x86_64-linux-gnu.tar.gz ${TEST_PATH}/bin/particl
cp ~/tmp/bitcoin-0.20.1-x86_64-linux-gnu.tar.gz ${TEST_PATH}/bin/bitcoin
cp ~/tmp/monero-linux-x64-v0.17.1.9.tar.bz2 ${TEST_PATH}/bin/monero/monero-0.17.1.9-x86_64-linux-gnu.tar.bz2
export PYTHONPATH=$(pwd)
python tests/basicswap/extended/test_xmr_persistent.py
"""
import os
import sys
import json
import time
import random
import shutil
import signal
import logging
import unittest
import threading
import multiprocessing
from urllib.request import urlopen
from unittest.mock import patch
from basicswap.rpc_xmr import (
callrpc_xmr_na,
)
from basicswap.rpc import (
callrpc,
)
from tests.basicswap.mnemonics import mnemonics
from tests.basicswap.common import (
waitForServer,
)
from basicswap.contrib.rpcauth import generate_salt, password_to_hmac
import basicswap.config as cfg
import bin.basicswap_prepare as prepareSystem
import bin.basicswap_run as runSystem
def make_boolean(s):
return s.lower() in ['1', 'true']
test_path = os.path.expanduser(os.getenv('TEST_PATH', '/tmp/test_persistent'))
PARTICL_PORT_BASE = int(os.getenv('PARTICL_PORT_BASE', '11938'))
BITCOIN_PORT_BASE = int(os.getenv('BITCOIN_PORT_BASE', '10938'))
RESET_TEST = make_boolean(os.getenv('RESET_TEST', 'false'))
XMR_BASE_P2P_PORT = 17792
XMR_BASE_RPC_PORT = 29798
XMR_BASE_WALLET_RPC_PORT = 29998
PORT_OFS = 1
UI_PORT = 12700 + PORT_OFS
BASE_PART_RPC_PORT = 19792
BASE_BTC_RPC_PORT = 19796
logger = logging.getLogger()
logger.level = logging.DEBUG
if not len(logger.handlers):
logger.addHandler(logging.StreamHandler(sys.stdout))
def callpartrpc(node_id, method, params=[], wallet=None, base_rpc_port=BASE_PART_RPC_PORT+PORT_OFS):
auth = 'test_part_{0}:test_part_pwd_{0}'.format(node_id)
return callrpc(base_rpc_port + node_id, auth, method, params, wallet)
def callbtcrpc(node_id, method, params=[], wallet=None, base_rpc_port=BASE_BTC_RPC_PORT+PORT_OFS):
auth = 'test_btc_{0}:test_btc_pwd_{0}'.format(node_id)
return callrpc(base_rpc_port + node_id, auth, method, params, wallet)
def updateThread(cls):
while not cls.delay_event.is_set():
try:
if cls.btc_addr is not None:
callbtcrpc(0, 'generatetoaddress', [1, cls.btc_addr])
if cls.xmr_addr is not None:
callrpc_xmr_na(XMR_BASE_RPC_PORT + 1, 'generateblocks', {'wallet_address': cls.xmr_addr, 'amount_of_blocks': 1})
except Exception as e:
print('updateThread error', str(e))
cls.delay_event.wait(random.randrange(1, 4))
class Test(unittest.TestCase):
@classmethod
def setUpClass(cls):
super(Test, cls).setUpClass()
cls.delay_event = threading.Event()
cls.update_thread = None
cls.processes = []
cls.btc_addr = None
cls.xmr_addr = None
random.seed(time.time())
for i in range(3):
client_path = os.path.join(test_path, 'client{}'.format(i))
config_path = os.path.join(client_path, cfg.CONFIG_FILENAME)
if RESET_TEST:
try:
logging.info('Removing dir %s', client_path)
shutil.rmtree(client_path)
except Exception as ex:
logging.warning('setUpClass %s', str(ex))
if not os.path.exists(config_path):
os.environ['PART_RPC_PORT'] = str(BASE_PART_RPC_PORT)
os.environ['BTC_RPC_PORT'] = str(BASE_BTC_RPC_PORT)
testargs = [
'basicswap-prepare',
'-datadir="{}"'.format(client_path),
'-bindir="{}"'.format(os.path.join(test_path, 'bin')),
'-portoffset={}'.format(i + PORT_OFS),
'-particl_mnemonic="{}"'.format(mnemonics[i]),
'-regtest',
'-withcoins=monero,bitcoin',
'-noextractover',
'-xmrrestoreheight=0']
with patch.object(sys, 'argv', testargs):
prepareSystem.main()
with open(os.path.join(client_path, 'particl', 'particl.conf'), 'r') as fp:
lines = fp.readlines()
with open(os.path.join(client_path, 'particl', 'particl.conf'), 'w') as fp:
for line in lines:
if not line.startswith('staking'):
fp.write(line)
fp.write('port={}\n'.format(PARTICL_PORT_BASE + i + PORT_OFS))
fp.write('bind=127.0.0.1\n')
fp.write('dnsseed=0\n')
fp.write('discover=0\n')
fp.write('listenonion=0\n')
fp.write('upnp=0\n')
fp.write('minstakeinterval=5\n')
salt = generate_salt(16)
fp.write('rpcauth={}:{}${}\n'.format('test_part_' + str(i), salt, password_to_hmac(salt, 'test_part_pwd_' + str(i))))
for ip in range(3):
if ip != i:
fp.write('connect=127.0.0.1:{}\n'.format(PARTICL_PORT_BASE + ip + PORT_OFS))
# Pruned nodes don't provide blocks
with open(os.path.join(client_path, 'bitcoin', 'bitcoin.conf'), 'r') as fp:
lines = fp.readlines()
with open(os.path.join(client_path, 'bitcoin', 'bitcoin.conf'), 'w') as fp:
for line in lines:
if not line.startswith('prune'):
fp.write(line)
fp.write('port={}\n'.format(BITCOIN_PORT_BASE + i + PORT_OFS))
fp.write('bind=127.0.0.1\n')
fp.write('dnsseed=0\n')
fp.write('discover=0\n')
fp.write('listenonion=0\n')
fp.write('upnp=0\n')
salt = generate_salt(16)
fp.write('rpcauth={}:{}${}\n'.format('test_btc_' + str(i), salt, password_to_hmac(salt, 'test_btc_pwd_' + str(i))))
for ip in range(3):
if ip != i:
fp.write('connect=127.0.0.1:{}\n'.format(BITCOIN_PORT_BASE + ip + PORT_OFS))
with open(os.path.join(client_path, 'monero', 'monerod.conf'), 'a') as fp:
fp.write('p2p-bind-ip=127.0.0.1\n')
fp.write('p2p-bind-port={}\n'.format(XMR_BASE_P2P_PORT + i + PORT_OFS))
for ip in range(3):
if ip != i:
fp.write('add-exclusive-node=127.0.0.1:{}\n'.format(XMR_BASE_P2P_PORT + ip + PORT_OFS))
with open(config_path) as fs:
settings = json.load(fs)
settings['min_delay_event'] = 1
settings['max_delay_event'] = 4
settings['min_delay_retry'] = 10
settings['max_delay_retry'] = 20
settings['check_progress_seconds'] = 5
settings['check_watched_seconds'] = 5
settings['check_expired_seconds'] = 60
settings['check_events_seconds'] = 5
settings['check_xmr_swaps_seconds'] = 5
settings['chainclients']['particl']['rpcuser'] = 'test_part_' + str(i)
settings['chainclients']['particl']['rpcpassword'] = 'test_part_pwd_' + str(i)
settings['chainclients']['bitcoin']['rpcuser'] = 'test_btc_' + str(i)
settings['chainclients']['bitcoin']['rpcpassword'] = 'test_btc_pwd_' + str(i)
with open(config_path, 'w') as fp:
json.dump(settings, fp, indent=4)
signal.signal(signal.SIGINT, lambda signal, frame: cls.signal_handler(cls, signal, frame))
def signal_handler(self, sig, frame):
logging.info('signal {} detected.'.format(sig))
self.delay_event.set()
def run_thread(self, client_id):
client_path = os.path.join(test_path, 'client{}'.format(client_id))
testargs = ['basicswap-run', '-datadir=' + client_path, '-regtest']
with patch.object(sys, 'argv', testargs):
runSystem.main()
def start_processes(self):
self.delay_event.clear()
for i in range(3):
self.processes.append(multiprocessing.Process(target=self.run_thread, args=(i,)))
self.processes[-1].start()
waitForServer(self.delay_event, UI_PORT + 0)
waitForServer(self.delay_event, UI_PORT + 1)
wallets = json.loads(urlopen('http://127.0.0.1:{}/json/wallets'.format(UI_PORT + 1)).read())
xmr_addr1 = wallets['6']['deposit_address']
num_blocks = 100
if callrpc_xmr_na(XMR_BASE_RPC_PORT + 1, 'get_block_count')['count'] < num_blocks:
logging.info('Mining {} Monero blocks to {}.'.format(num_blocks, xmr_addr1))
callrpc_xmr_na(XMR_BASE_RPC_PORT + 1, 'generateblocks', {'wallet_address': xmr_addr1, 'amount_of_blocks': num_blocks})
logging.info('XMR blocks: %d', callrpc_xmr_na(XMR_BASE_RPC_PORT + 1, 'get_block_count')['count'])
self.btc_addr = callbtcrpc(0, 'getnewaddress', ['mining_addr', 'bech32'])
rv = callbtcrpc(0, 'getblockchaininfo')
print('rv', rv)
num_blocks = 500 # Mine enough to activate segwit
if callbtcrpc(0, 'getblockchaininfo')['blocks'] < num_blocks:
logging.info('Mining %d Bitcoin blocks to %s', num_blocks, self.btc_addr)
callbtcrpc(0, 'generatetoaddress', [num_blocks, self.btc_addr])
logging.info('BTC blocks: %d', callbtcrpc(0, 'getblockchaininfo')['blocks'])
self.update_thread = threading.Thread(target=updateThread, args=(self,))
self.update_thread.start()
# Wait for height, or sequencelock is thrown off by genesis blocktime
num_blocks = 3
logging.info('Waiting for Particl chain height %d', num_blocks)
for i in range(60):
if self.delay_event.is_set():
raise ValueError('Test stopped.')
particl_blocks = callpartrpc(0, 'getblockchaininfo')['blocks']
print('particl_blocks', particl_blocks)
if particl_blocks >= num_blocks:
break
self.delay_event.wait(1)
logging.info('PART blocks: %d', callpartrpc(0, 'getblockchaininfo')['blocks'])
assert(particl_blocks >= num_blocks)
@classmethod
def tearDownClass(cls):
logging.info('Stopping test')
cls.delay_event.set()
if cls.update_thread:
cls.update_thread.join()
for p in cls.processes:
p.terminate()
for p in cls.processes:
p.join()
cls.update_thread = None
cls.processes = []
def test_persistent(self):
self.start_processes()
waitForServer(self.delay_event, UI_PORT + 0)
waitForServer(self.delay_event, UI_PORT + 1)
while not self.delay_event.is_set():
logging.info('Looping indefinitly, ctrl+c to exit.')
self.delay_event.wait(10)
if __name__ == '__main__':
unittest.main()

View file

@ -99,6 +99,9 @@ class Test(unittest.TestCase):
fp.write('port={}\n'.format(PARTICL_PORT_BASE + i))
fp.write('bind=127.0.0.1\n')
fp.write('dnsseed=0\n')
fp.write('discover=0\n')
fp.write('listenonion=0\n')
fp.write('upnp=0\n')
fp.write('minstakeinterval=5\n')
for ip in range(3):
if ip != i:
@ -112,11 +115,11 @@ class Test(unittest.TestCase):
if not line.startswith('prune'):
fp.write(line)
fp.write('port={}\n'.format(BITCOIN_PORT_BASE + i))
fp.write('discover=0\n')
fp.write('bind=127.0.0.1\n')
fp.write('dnsseed=0\n')
fp.write('discover=0\n')
fp.write('listenonion=0\n')
fp.write('upnp=0\n')
fp.write('bind=127.0.0.1\n')
for ip in range(3):
if ip != i:
fp.write('connect=127.0.0.1:{}\n'.format(BITCOIN_PORT_BASE + ip))