From 3cfc7d14370564e2f72fb4499b322bb431d0abdd Mon Sep 17 00:00:00 2001 From: tecnovert Date: Tue, 12 Jan 2021 00:15:06 +0200 Subject: [PATCH] Split tests. --- tests/basicswap/common.py | 62 +++- tests/basicswap/common_xmr.py | 186 ++++++++++ tests/basicswap/test_reload.py | 69 +--- tests/basicswap/test_reload_xmr.py | 421 ----------------------- tests/basicswap/test_xmr_bids_offline.py | 144 ++++++++ tests/basicswap/test_xmr_reload.py | 128 +++++++ 6 files changed, 531 insertions(+), 479 deletions(-) create mode 100644 tests/basicswap/common_xmr.py delete mode 100644 tests/basicswap/test_reload_xmr.py create mode 100644 tests/basicswap/test_xmr_bids_offline.py create mode 100644 tests/basicswap/test_xmr_reload.py diff --git a/tests/basicswap/common.py b/tests/basicswap/common.py index d5ff95f..6e5d2b1 100644 --- a/tests/basicswap/common.py +++ b/tests/basicswap/common.py @@ -157,6 +157,19 @@ def wait_for_no_offer(delay_event, swap_client, offer_id, wait_for=20): raise ValueError('wait_for_offer timed out.') +def wait_for_in_progress(delay_event, swap_client, bid_id, sent=False): + logging.info('wait_for_in_progress %s', bid_id.hex()) + for i in range(20): + if delay_event.is_set(): + raise ValueError('Test stopped.') + delay_event.wait(1) + swaps = swap_client.listSwapsInProgress() + for b in swaps: + if b[0] == bid_id: + return + raise ValueError('wait_for_in_progress timed out.') + + def wait_for_none_active(delay_event, port, wait_for=30): for i in range(wait_for): if delay_event.is_set(): @@ -168,17 +181,50 @@ def wait_for_none_active(delay_event, port, wait_for=30): raise ValueError('wait_for_none_active timed out.') -def wait_for_in_progress(delay_event, swap_client, bid_id, sent=False): - logging.info('wait_for_in_progress %s', bid_id.hex()) - for i in range(20): +def waitForServer(delay_event, port, wait_for=20): + for i in range(wait_for): if delay_event.is_set(): raise ValueError('Test stopped.') + try: + delay_event.wait(1) + summary = json.loads(urlopen('http://127.0.0.1:{}/json'.format(port)).read()) + return + except Exception as e: + print('waitForServer, error:', str(e)) + raise ValueError('waitForServer failed') + + +def waitForNumOffers(delay_event, port, offers, wait_for=20): + for i in range(wait_for): + if delay_event.is_set(): + raise ValueError('Test stopped.') + summary = json.loads(urlopen('http://127.0.0.1:{}/json'.format(port)).read()) + if summary['num_network_offers'] >= offers: + return delay_event.wait(1) - swaps = swap_client.listSwapsInProgress() - for b in swaps: - if b[0] == bid_id: - return - raise ValueError('wait_for_in_progress timed out.') + raise ValueError('waitForNumOffers failed') + + +def waitForNumBids(delay_event, port, bids, wait_for=20): + for i in range(wait_for): + if delay_event.is_set(): + raise ValueError('Test stopped.') + summary = json.loads(urlopen('http://127.0.0.1:{}/json'.format(port)).read()) + if summary['num_recv_bids'] >= bids: + return + delay_event.wait(1) + raise ValueError('waitForNumBids failed') + + +def waitForNumSwapping(delay_event, port, bids, wait_for=60): + for i in range(wait_for): + if delay_event.is_set(): + raise ValueError('Test stopped.') + summary = json.loads(urlopen('http://127.0.0.1:{}/json'.format(port)).read()) + if summary['num_swapping'] >= bids: + return + delay_event.wait(1) + raise ValueError('waitForNumSwapping failed') def delay_for(delay_event, delay_for=60): diff --git a/tests/basicswap/common_xmr.py b/tests/basicswap/common_xmr.py new file mode 100644 index 0000000..38d6136 --- /dev/null +++ b/tests/basicswap/common_xmr.py @@ -0,0 +1,186 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# Copyright (c) 2020-2021 tecnovert +# Distributed under the MIT software license, see the accompanying +# file LICENSE or http://www.opensource.org/licenses/mit-license.php. + +import os +import sys +import json +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 tests.basicswap.mnemonics import mnemonics +from tests.basicswap.common import ( + waitForServer, +) + +import basicswap.config as cfg +import bin.basicswap_prepare as prepareSystem +import bin.basicswap_run as runSystem + +test_path = os.path.expanduser(os.getenv('TEST_RELOAD_PATH', '~/test_basicswap1')) +PARTICL_PORT_BASE = int(os.getenv('PARTICL_PORT_BASE', '11938')) + +XMR_BASE_P2P_PORT = 17792 +XMR_BASE_RPC_PORT = 29798 +XMR_BASE_WALLET_RPC_PORT = 29998 + + +def waitForBidState(delay_event, port, bid_id, state_str, wait_for=60): + for i in range(wait_for): + if delay_event.is_set(): + raise ValueError('Test stopped.') + bid = json.loads(urlopen('http://127.0.0.1:12700/json/bids/{}'.format(bid_id)).read()) + if bid['bid_state'] == state_str: + return + delay_event.wait(1) + raise ValueError('waitForBidState failed') + + +def updateThread(xmr_addr, delay_event): + while not delay_event.is_set(): + try: + callrpc_xmr_na(XMR_BASE_RPC_PORT + 1, 'generateblocks', {'wallet_address': xmr_addr, 'amount_of_blocks': 1}) + except Exception as e: + print('updateThread error', str(e)) + delay_event.wait(2) + + +class XmrTestBase(unittest.TestCase): + @classmethod + def setUpClass(cls): + super(XmrTestBase, cls).setUpClass() + + cls.delay_event = threading.Event() + cls.update_thread = None + cls.processes = [] + + 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) + try: + shutil.rmtree(client_path) + except Exception as ex: + logging.warning('setUpClass %s', str(ex)) + testargs = [ + 'basicswap-prepare', + '-datadir="{}"'.format(client_path), + '-bindir="{}"'.format(os.path.join(test_path, 'bin')), + '-portoffset={}'.format(i), + '-particl_mnemonic="{}"'.format(mnemonics[i]), + '-regtest', + '-withcoin=monero', + '-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)) + fp.write('bind=127.0.0.1\n') + fp.write('dnsseed=0\n') + fp.write('minstakeinterval=5\n') + for ip in range(3): + if ip != i: + fp.write('connect=127.0.0.1:{}\n'.format(PARTICL_PORT_BASE + ip)) + + 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)) + for ip in range(3): + if ip != i: + fp.write('add-exclusive-node=127.0.0.1:{}\n'.format(XMR_BASE_P2P_PORT + ip)) + + 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 + + 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, 12701) + + wallets = json.loads(urlopen('http://127.0.0.1:12701/json/wallets').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.update_thread = threading.Thread(target=updateThread, args=(xmr_addr1, self.delay_event)) + 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.') + wallets = json.loads(urlopen('http://127.0.0.1:12701/json/wallets').read()) + particl_blocks = wallets['1']['blocks'] + print('particl_blocks', particl_blocks) + if particl_blocks >= num_blocks: + break + self.delay_event.wait(1) + 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 = [] diff --git a/tests/basicswap/test_reload.py b/tests/basicswap/test_reload.py index 342ded7..11c5139 100644 --- a/tests/basicswap/test_reload.py +++ b/tests/basicswap/test_reload.py @@ -18,7 +18,6 @@ python tests/basicswap/test_reload.py import os import sys import json -import time import shutil import logging import unittest @@ -33,6 +32,12 @@ from basicswap.rpc import ( callrpc_cli, ) from tests.basicswap.mnemonics import mnemonics +from tests.basicswap.common import ( + waitForServer, + waitForNumOffers, + waitForNumBids, + waitForNumSwapping, +) import basicswap.config as cfg import bin.basicswap_prepare as prepareSystem @@ -41,7 +46,7 @@ import bin.basicswap_run as runSystem test_path = os.path.expanduser(os.getenv('TEST_RELOAD_PATH', '~/test_basicswap1')) PARTICL_PORT_BASE = int(os.getenv('PARTICL_PORT_BASE', '11938')) BITCOIN_PORT_BASE = int(os.getenv('BITCOIN_PORT_BASE', '10938')) -stop_test = False +delay_event = threading.Event() logger = logging.getLogger() logger.level = logging.DEBUG @@ -55,50 +60,12 @@ def btcRpc(client_no, cmd): return callrpc_cli(bin_path, data_path, 'regtest', cmd, 'bitcoin-cli') -def waitForServer(port): - for i in range(20): - try: - time.sleep(1) - summary = json.loads(urlopen('http://127.0.0.1:{}/json'.format(port)).read()) - return - except Exception as e: - print('waitForServer, error:', str(e)) - raise ValueError('waitForServer failed') - - -def waitForNumOffers(port, offers): - for i in range(20): - summary = json.loads(urlopen('http://127.0.0.1:{}/json'.format(port)).read()) - if summary['num_network_offers'] >= offers: - return - time.sleep(1) - raise ValueError('waitForNumOffers failed') - - -def waitForNumBids(port, bids): - for i in range(20): - summary = json.loads(urlopen('http://127.0.0.1:{}/json'.format(port)).read()) - if summary['num_recv_bids'] >= bids: - return - time.sleep(1) - raise ValueError('waitForNumBids failed') - - -def waitForNumSwapping(port, bids): - for i in range(20): - summary = json.loads(urlopen('http://127.0.0.1:{}/json'.format(port)).read()) - if summary['num_swapping'] >= bids: - return - time.sleep(1) - raise ValueError('waitForNumSwapping failed') - - def updateThread(): btc_addr = btcRpc(0, 'getnewaddress mining_addr bech32') - while not stop_test: + while not delay_event.is_set(): btcRpc(0, 'generatetoaddress {} {}'.format(1, btc_addr)) - time.sleep(5) + delay_event.wait(5) class Test(unittest.TestCase): @@ -171,7 +138,7 @@ class Test(unittest.TestCase): processes[-1].start() try: - waitForServer(12700) + waitForServer(delay_event, 12700) num_blocks = 500 btc_addr = btcRpc(1, 'getnewaddress mining_addr bech32') @@ -179,10 +146,12 @@ class Test(unittest.TestCase): btcRpc(1, 'generatetoaddress {} {}'.format(num_blocks, btc_addr)) for i in range(20): + if delay_event.is_set(): + raise ValueError('Test stopped.') blocks = btcRpc(0, 'getblockchaininfo')['blocks'] if blocks >= num_blocks: break - time.sleep(2) + delay_event.wait(2) assert(blocks >= num_blocks) data = parse.urlencode({ @@ -200,7 +169,7 @@ class Test(unittest.TestCase): traceback.print_exc() logger.info('Waiting for offer:') - waitForNumOffers(12701, 1) + waitForNumOffers(delay_event, 12701, 1) offers = json.loads(urlopen('http://127.0.0.1:12701/json/offers').read()) offer = offers[0] @@ -211,7 +180,7 @@ class Test(unittest.TestCase): bid_id = json.loads(urlopen('http://127.0.0.1:12701/json/bids/new', data=data).read()) - waitForNumBids(12700, 1) + waitForNumBids(delay_event, 12700, 1) bids = json.loads(urlopen('http://127.0.0.1:12700/json/bids').read()) bid = bids[0] @@ -222,7 +191,7 @@ class Test(unittest.TestCase): rv = json.loads(urlopen('http://127.0.0.1:12700/json/bids/{}'.format(bid['bid_id']), data=data).read()) assert(rv['bid_state'] == 'Accepted') - waitForNumSwapping(12701, 1) + waitForNumSwapping(delay_event, 12701, 1) logger.info('Restarting client:') c1 = processes[1] @@ -231,7 +200,7 @@ class Test(unittest.TestCase): processes[1] = multiprocessing.Process(target=self.run_thread, args=(1,)) processes[1].start() - waitForServer(12701) + waitForServer(delay_event, 12701) rv = json.loads(urlopen('http://127.0.0.1:12701/json').read()) assert(rv['num_swapping'] == 1) @@ -240,7 +209,7 @@ class Test(unittest.TestCase): logger.info('Completing swap:') for i in range(240): - time.sleep(5) + delay_event.wait(5) rv = json.loads(urlopen('http://127.0.0.1:12700/json/bids/{}'.format(bid['bid_id'])).read()) print(rv) @@ -248,7 +217,7 @@ class Test(unittest.TestCase): break assert(rv['bid_state'] == 'Completed') - stop_test = True + delay_event.set() update_thread.join() for p in processes: p.terminate() diff --git a/tests/basicswap/test_reload_xmr.py b/tests/basicswap/test_reload_xmr.py deleted file mode 100644 index 3eefe0f..0000000 --- a/tests/basicswap/test_reload_xmr.py +++ /dev/null @@ -1,421 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- - -# Copyright (c) 2020-2021 tecnovert -# Distributed under the MIT software license, see the accompanying -# file LICENSE or http://www.opensource.org/licenses/mit-license.php. - -""" -export TEST_RELOAD_PATH=/tmp/test_basicswap -mkdir -p ${TEST_RELOAD_PATH}/bin/{particl,monero} -cp ~/tmp/particl-0.19.1.2-x86_64-linux-gnu.tar.gz ${TEST_RELOAD_PATH}/bin/particl -cp ~/tmp/monero-linux-x64-v0.17.1.9.tar.bz2 ${TEST_RELOAD_PATH}/bin/monero/monero-0.17.1.9-x86_64-linux-gnu.tar.bz2 -export PYTHONPATH=$(pwd) -python tests/basicswap/test_reload_xmr.py - - -""" - -import os -import sys -import json -import shutil -import signal -import logging -import unittest -import traceback -import threading -import multiprocessing -from urllib import parse -from urllib.request import urlopen -from unittest.mock import patch - -from basicswap.rpc_xmr import ( - callrpc_xmr_na, -) -from tests.basicswap.mnemonics import mnemonics - -import basicswap.config as cfg -import bin.basicswap_prepare as prepareSystem -import bin.basicswap_run as runSystem - -test_path = os.path.expanduser(os.getenv('TEST_RELOAD_PATH', '~/test_basicswap1')) -PARTICL_PORT_BASE = int(os.getenv('PARTICL_PORT_BASE', '11938')) - -XMR_BASE_P2P_PORT = 17792 -XMR_BASE_RPC_PORT = 29798 -XMR_BASE_WALLET_RPC_PORT = 29998 - -delay_event = threading.Event() - -logger = logging.getLogger() -logger.level = logging.DEBUG -if not len(logger.handlers): - logger.addHandler(logging.StreamHandler(sys.stdout)) - - -def waitForServer(port, wait_for=20): - for i in range(wait_for): - if delay_event.is_set(): - raise ValueError('Test stopped.') - try: - delay_event.wait(1) - summary = json.loads(urlopen('http://127.0.0.1:{}/json'.format(port)).read()) - return - except Exception as e: - print('waitForServer, error:', str(e)) - raise ValueError('waitForServer failed') - - -def waitForNumOffers(port, offers, wait_for=20): - for i in range(wait_for): - if delay_event.is_set(): - raise ValueError('Test stopped.') - summary = json.loads(urlopen('http://127.0.0.1:{}/json'.format(port)).read()) - if summary['num_network_offers'] >= offers: - return - delay_event.wait(1) - raise ValueError('waitForNumOffers failed') - - -def waitForNumBids(port, bids, wait_for=20): - for i in range(wait_for): - if delay_event.is_set(): - raise ValueError('Test stopped.') - summary = json.loads(urlopen('http://127.0.0.1:{}/json'.format(port)).read()) - if summary['num_recv_bids'] >= bids: - return - delay_event.wait(1) - raise ValueError('waitForNumBids failed') - - -def waitForNumSwapping(port, bids, wait_for=60): - for i in range(wait_for): - if delay_event.is_set(): - raise ValueError('Test stopped.') - summary = json.loads(urlopen('http://127.0.0.1:{}/json'.format(port)).read()) - if summary['num_swapping'] >= bids: - return - delay_event.wait(1) - raise ValueError('waitForNumSwapping failed') - - -def waitForBidState(port, bid_id, state_str, wait_for=60): - for i in range(wait_for): - if delay_event.is_set(): - raise ValueError('Test stopped.') - bid = json.loads(urlopen('http://127.0.0.1:12700/json/bids/{}'.format(bid_id)).read()) - print('[rm] bid', bid) - if bid['bid_state'] == state_str: - return - delay_event.wait(1) - raise ValueError('waitForBidState failed') - - -def updateThread(xmr_addr): - while not delay_event.is_set(): - try: - callrpc_xmr_na(XMR_BASE_RPC_PORT + 1, 'generateblocks', {'wallet_address': xmr_addr, 'amount_of_blocks': 1}) - except Exception as e: - print('updateThread error', str(e)) - delay_event.wait(2) - - -def signal_handler(sig, frame): - logging.info('signal {} detected.'.format(sig)) - delay_event.set() - - -class Test(unittest.TestCase): - @classmethod - def setUpClass(cls): - super(Test, cls).setUpClass() - - cls.update_thread = None - cls.processes = [] - - 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) - try: - shutil.rmtree(client_path) - except Exception as ex: - logger.warning('setUpClass %s', str(ex)) - testargs = [ - 'basicswap-prepare', - '-datadir="{}"'.format(client_path), - '-bindir="{}"'.format(os.path.join(test_path, 'bin')), - '-portoffset={}'.format(i), - '-particl_mnemonic="{}"'.format(mnemonics[i]), - '-regtest', - '-withcoin=monero', - '-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)) - fp.write('bind=127.0.0.1\n') - fp.write('dnsseed=0\n') - fp.write('minstakeinterval=5\n') - for ip in range(3): - if ip != i: - fp.write('connect=127.0.0.1:{}\n'.format(PARTICL_PORT_BASE + ip)) - - 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)) - for ip in range(3): - if ip != i: - fp.write('add-exclusive-node=127.0.0.1:{}\n'.format(XMR_BASE_P2P_PORT + ip)) - - with open(config_path) as fs: - settings = json.load(fs) - - settings['min_delay_event'] = 1 - settings['max_delay_event'] = 4 - - 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 - - with open(config_path, 'w') as fp: - json.dump(settings, fp, indent=4) - - signal.signal(signal.SIGINT, signal_handler) - - 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): - delay_event.clear() - - for i in range(3): - self.processes.append(multiprocessing.Process(target=self.run_thread, args=(i,))) - self.processes[-1].start() - - try: - waitForServer(12701) - - wallets = json.loads(urlopen('http://127.0.0.1:12701/json/wallets').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.update_thread = threading.Thread(target=updateThread, args=(xmr_addr1,)) - self.update_thread.start() - except Exception: - traceback.print_exc() - - def stop_processes(self): - logger.info('Stopping test') - delay_event.set() - if self.update_thread: - self.update_thread.join() - for p in self.processes: - p.terminate() - for p in self.processes: - p.join() - self.update_thread = None - self.processes = [] - - def test_01_reload(self): - self.start_processes() - - try: - waitForServer(12700) - waitForServer(12701) - wallets1 = json.loads(urlopen('http://127.0.0.1:12701/json/wallets').read()) - assert(float(wallets1['6']['balance']) > 0.0) - - data = parse.urlencode({ - 'addr_from': '-1', - 'coin_from': '1', - 'coin_to': '6', - 'amt_from': '1', - 'amt_to': '1', - 'lockhrs': '24'}).encode() - - offer_id = json.loads(urlopen('http://127.0.0.1:12700/json/offers/new', data=data).read())['offer_id'] - summary = json.loads(urlopen('http://127.0.0.1:12700/json').read()) - assert(summary['num_sent_offers'] == 1) - - logger.info('Waiting for offer') - waitForNumOffers(12701, 1) - - offers = json.loads(urlopen('http://127.0.0.1:12701/json/offers').read()) - offer = offers[0] - - data = parse.urlencode({ - 'offer_id': offer['offer_id'], - 'amount_from': offer['amount_from']}).encode() - - bid_id = json.loads(urlopen('http://127.0.0.1:12701/json/bids/new', data=data).read()) - - waitForNumBids(12700, 1) - - for i in range(10): - bids = json.loads(urlopen('http://127.0.0.1:12700/json/bids').read()) - bid = bids[0] - if bid['bid_state'] == 'Received': - break - delay_event.wait(1) - - data = parse.urlencode({ - 'accept': True - }).encode() - rv = json.loads(urlopen('http://127.0.0.1:12700/json/bids/{}'.format(bid['bid_id']), data=data).read()) - assert(rv['bid_state'] == 'Accepted') - - waitForNumSwapping(12701, 1) - - logger.info('Restarting client') - c1 = self.processes[1] - c1.terminate() - c1.join() - self.processes[1] = multiprocessing.Process(target=self.run_thread, args=(1,)) - self.processes[1].start() - - waitForServer(12701) - rv = json.loads(urlopen('http://127.0.0.1:12701/json').read()) - assert(rv['num_swapping'] == 1) - - rv = json.loads(urlopen('http://127.0.0.1:12700/json/revokeoffer/{}'.format(offer_id)).read()) - assert(rv['revoked_offer'] == offer_id) - - logger.info('Completing swap') - for i in range(240): - if delay_event.is_set(): - raise ValueError('Test stopped.') - delay_event.wait(4) - - rv = json.loads(urlopen('http://127.0.0.1:12700/json/bids/{}'.format(bid['bid_id'])).read()) - if rv['bid_state'] == 'Completed': - break - assert(rv['bid_state'] == 'Completed') - - # Ensure offer was revoked - summary = json.loads(urlopen('http://127.0.0.1:12700/json').read()) - assert(summary['num_network_offers'] == 0) - - except Exception as e: - traceback.print_exc() - raise(e) - finally: - self.stop_processes() - - def test_02_bids_offline(self): - # Start multiple bids while offering node is offline - self.start_processes() - - try: - waitForServer(12700) - waitForServer(12701) - wallets1 = json.loads(urlopen('http://127.0.0.1:12701/json/wallets').read()) - assert(float(wallets1['6']['balance']) > 0.0) - - offer_data = { - 'addr_from': '-1', - 'coin_from': '1', - 'coin_to': '6', - 'amt_from': '1', - 'amt_to': '1', - 'lockhrs': '24', - 'autoaccept': True} - rv = json.loads(urlopen('http://127.0.0.1:12700/json/offers/new', data=parse.urlencode(offer_data).encode()).read()) - offer0_id = rv['offer_id'] - - offer_data['amt_from'] = '2' - rv = json.loads(urlopen('http://127.0.0.1:12700/json/offers/new', data=parse.urlencode(offer_data).encode()).read()) - offer1_id = rv['offer_id'] - - summary = json.loads(urlopen('http://127.0.0.1:12700/json').read()) - assert(summary['num_sent_offers'] > 1) - - logger.info('Waiting for offer') - waitForNumOffers(12701, 2) - - logger.info('Stopping node 0') - c0 = self.processes[0] - c0.terminate() - c0.join() - - offers = json.loads(urlopen('http://127.0.0.1:12701/json/offers/{}'.format(offer0_id)).read()) - assert(len(offers) == 1) - offer0 = offers[0] - - bid_data = { - 'offer_id': offer0_id, - 'amount_from': offer0['amount_from']} - - bid0_id = json.loads(urlopen('http://127.0.0.1:12701/json/bids/new', data=parse.urlencode(bid_data).encode()).read())['bid_id'] - - offers = json.loads(urlopen('http://127.0.0.1:12701/json/offers/{}'.format(offer1_id)).read()) - assert(len(offers) == 1) - offer1 = offers[0] - - bid_data = { - 'offer_id': offer1_id, - 'amount_from': offer1['amount_from']} - - bid1_id = json.loads(urlopen('http://127.0.0.1:12701/json/bids/new', data=parse.urlencode(bid_data).encode()).read())['bid_id'] - - delay_event.wait(5) - - logger.info('Starting node 0') - self.processes[0] = multiprocessing.Process(target=self.run_thread, args=(0,)) - self.processes[0].start() - - waitForServer(12700) - waitForNumBids(12700, 2) - - waitForBidState(12700, bid0_id, 'Received') - waitForBidState(12700, bid1_id, 'Received') - - # Manually accept on top of auto-accept for extra chaos - data = parse.urlencode({ - 'accept': True - }).encode() - rv = json.loads(urlopen('http://127.0.0.1:12700/json/bids/{}'.format(bid0_id), data=data).read()) - assert(rv['bid_state'] == 'Accepted') - rv = json.loads(urlopen('http://127.0.0.1:12700/json/bids/{}'.format(bid1_id), data=data).read()) - assert(rv['bid_state'] == 'Accepted') - - logger.info('Completing swap') - for i in range(240): - if delay_event.is_set(): - raise ValueError('Test stopped.') - delay_event.wait(4) - - rv0 = json.loads(urlopen('http://127.0.0.1:12700/json/bids/{}'.format(bid0_id)).read()) - rv1 = json.loads(urlopen('http://127.0.0.1:12700/json/bids/{}'.format(bid1_id)).read()) - if rv0['bid_state'] == 'Completed' and rv1['bid_state'] == 'Completed': - break - assert(rv0['bid_state'] == 'Completed') - assert(rv1['bid_state'] == 'Completed') - - except Exception as e: - traceback.print_exc() - raise(e) - finally: - self.stop_processes() - - -if __name__ == '__main__': - unittest.main() diff --git a/tests/basicswap/test_xmr_bids_offline.py b/tests/basicswap/test_xmr_bids_offline.py new file mode 100644 index 0000000..742f851 --- /dev/null +++ b/tests/basicswap/test_xmr_bids_offline.py @@ -0,0 +1,144 @@ +#!/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 TEST_RELOAD_PATH=/tmp/test_basicswap +mkdir -p ${TEST_RELOAD_PATH}/bin/{particl,monero} +cp ~/tmp/particl-0.19.1.2-x86_64-linux-gnu.tar.gz ${TEST_RELOAD_PATH}/bin/particl +cp ~/tmp/monero-linux-x64-v0.17.1.9.tar.bz2 ${TEST_RELOAD_PATH}/bin/monero/monero-0.17.1.9-x86_64-linux-gnu.tar.bz2 +export PYTHONPATH=$(pwd) +python tests/basicswap/test_xmr_bids_offline.py + + +""" + +import sys +import json +import logging +import unittest +import multiprocessing +from urllib import parse +from urllib.request import urlopen + +from tests.basicswap.common import ( + waitForServer, + waitForNumOffers, + waitForNumBids, +) +from tests.basicswap.common_xmr import ( + XmrTestBase, + waitForBidState, +) + +logger = logging.getLogger() +logger.level = logging.DEBUG +if not len(logger.handlers): + logger.addHandler(logging.StreamHandler(sys.stdout)) + + +class Test(XmrTestBase): + + def test_bids_offline(self): + # Start multiple bids while offering node is offline + + self.start_processes() + + waitForServer(self.delay_event, 12700) + waitForServer(self.delay_event, 12701) + wallets1 = json.loads(urlopen('http://127.0.0.1:12701/json/wallets').read()) + assert(float(wallets1['6']['balance']) > 0.0) + + offer_data = { + 'addr_from': '-1', + 'coin_from': '1', + 'coin_to': '6', + 'amt_from': '1', + 'amt_to': '1', + 'lockhrs': '24', + 'autoaccept': True} + rv = json.loads(urlopen('http://127.0.0.1:12700/json/offers/new', data=parse.urlencode(offer_data).encode()).read()) + offer0_id = rv['offer_id'] + + offer_data['amt_from'] = '2' + rv = json.loads(urlopen('http://127.0.0.1:12700/json/offers/new', data=parse.urlencode(offer_data).encode()).read()) + offer1_id = rv['offer_id'] + + summary = json.loads(urlopen('http://127.0.0.1:12700/json').read()) + assert(summary['num_sent_offers'] > 1) + + logger.info('Waiting for offer') + waitForNumOffers(self.delay_event, 12701, 2) + + logger.info('Stopping node 0') + c0 = self.processes[0] + c0.terminate() + c0.join() + + offers = json.loads(urlopen('http://127.0.0.1:12701/json/offers/{}'.format(offer0_id)).read()) + assert(len(offers) == 1) + offer0 = offers[0] + + bid_data = { + 'offer_id': offer0_id, + 'amount_from': offer0['amount_from']} + + bid0_id = json.loads(urlopen('http://127.0.0.1:12701/json/bids/new', data=parse.urlencode(bid_data).encode()).read())['bid_id'] + + offers = json.loads(urlopen('http://127.0.0.1:12701/json/offers/{}'.format(offer1_id)).read()) + assert(len(offers) == 1) + offer1 = offers[0] + + bid_data = { + 'offer_id': offer1_id, + 'amount_from': offer1['amount_from']} + + bid1_id = json.loads(urlopen('http://127.0.0.1:12701/json/bids/new', data=parse.urlencode(bid_data).encode()).read())['bid_id'] + + logger.info('Delaying for 5 seconds.') + self.delay_event.wait(5) + + logger.info('Starting node 0') + self.processes[0] = multiprocessing.Process(target=self.run_thread, args=(0,)) + self.processes[0].start() + + waitForServer(self.delay_event, 12700) + waitForNumBids(self.delay_event, 12700, 2) + + waitForBidState(self.delay_event, 12700, bid0_id, 'Received') + waitForBidState(self.delay_event, 12700, bid1_id, 'Received') + + # Manually accept on top of auto-accept for extra chaos + data = parse.urlencode({ + 'accept': True + }).encode() + try: + rv = json.loads(urlopen('http://127.0.0.1:12700/json/bids/{}'.format(bid0_id), data=data).read()) + assert(rv['bid_state'] == 'Accepted') + except Exception as e: + print('Accept bid failed', str(e), rv) + try: + rv = json.loads(urlopen('http://127.0.0.1:12700/json/bids/{}'.format(bid1_id), data=data).read()) + assert(rv['bid_state'] == 'Accepted') + except Exception as e: + print('Accept bid failed', str(e), rv) + + logger.info('Completing swap') + for i in range(240): + if self.delay_event.is_set(): + raise ValueError('Test stopped.') + self.delay_event.wait(4) + + rv0 = json.loads(urlopen('http://127.0.0.1:12700/json/bids/{}'.format(bid0_id)).read()) + rv1 = json.loads(urlopen('http://127.0.0.1:12700/json/bids/{}'.format(bid1_id)).read()) + if rv0['bid_state'] == 'Completed' and rv1['bid_state'] == 'Completed': + break + assert(rv0['bid_state'] == 'Completed') + assert(rv1['bid_state'] == 'Completed') + + +if __name__ == '__main__': + unittest.main() diff --git a/tests/basicswap/test_xmr_reload.py b/tests/basicswap/test_xmr_reload.py new file mode 100644 index 0000000..721f776 --- /dev/null +++ b/tests/basicswap/test_xmr_reload.py @@ -0,0 +1,128 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# Copyright (c) 2020-2021 tecnovert +# Distributed under the MIT software license, see the accompanying +# file LICENSE or http://www.opensource.org/licenses/mit-license.php. + +""" +export TEST_RELOAD_PATH=/tmp/test_basicswap +mkdir -p ${TEST_RELOAD_PATH}/bin/{particl,monero} +cp ~/tmp/particl-0.19.1.2-x86_64-linux-gnu.tar.gz ${TEST_RELOAD_PATH}/bin/particl +cp ~/tmp/monero-linux-x64-v0.17.1.9.tar.bz2 ${TEST_RELOAD_PATH}/bin/monero/monero-0.17.1.9-x86_64-linux-gnu.tar.bz2 +export PYTHONPATH=$(pwd) +python tests/basicswap/test_xmr_reload.py + + +""" + +import sys +import json +import logging +import unittest +import multiprocessing +from urllib import parse +from urllib.request import urlopen + +from tests.basicswap.common import ( + waitForServer, + waitForNumOffers, + waitForNumBids, + waitForNumSwapping, +) +from tests.basicswap.common_xmr import ( + XmrTestBase, +) + +logger = logging.getLogger() +logger.level = logging.DEBUG +if not len(logger.handlers): + logger.addHandler(logging.StreamHandler(sys.stdout)) + + +class Test(XmrTestBase): + + def test_reload(self): + self.start_processes() + + waitForServer(self.delay_event, 12700) + waitForServer(self.delay_event, 12701) + wallets1 = json.loads(urlopen('http://127.0.0.1:12701/json/wallets').read()) + assert(float(wallets1['6']['balance']) > 0.0) + + data = parse.urlencode({ + 'addr_from': '-1', + 'coin_from': '1', + 'coin_to': '6', + 'amt_from': '1', + 'amt_to': '1', + 'lockhrs': '24'}).encode() + + offer_id = json.loads(urlopen('http://127.0.0.1:12700/json/offers/new', data=data).read())['offer_id'] + summary = json.loads(urlopen('http://127.0.0.1:12700/json').read()) + assert(summary['num_sent_offers'] == 1) + + logger.info('Waiting for offer') + waitForNumOffers(self.delay_event, 12701, 1) + + offers = json.loads(urlopen('http://127.0.0.1:12701/json/offers').read()) + offer = offers[0] + + data = parse.urlencode({ + 'offer_id': offer['offer_id'], + 'amount_from': offer['amount_from']}).encode() + + bid_id = json.loads(urlopen('http://127.0.0.1:12701/json/bids/new', data=data).read()) + + waitForNumBids(self.delay_event, 12700, 1) + + for i in range(10): + bids = json.loads(urlopen('http://127.0.0.1:12700/json/bids').read()) + bid = bids[0] + if bid['bid_state'] == 'Received': + break + self.delay_event.wait(1) + + data = parse.urlencode({ + 'accept': True + }).encode() + rv = json.loads(urlopen('http://127.0.0.1:12700/json/bids/{}'.format(bid['bid_id']), data=data).read()) + assert(rv['bid_state'] == 'Accepted') + + waitForNumSwapping(self.delay_event, 12701, 1) + + logger.info('Restarting client') + c1 = self.processes[1] + c1.terminate() + c1.join() + self.processes[1] = multiprocessing.Process(target=self.run_thread, args=(1,)) + self.processes[1].start() + + waitForServer(self.delay_event, 12701) + rv = json.loads(urlopen('http://127.0.0.1:12701/json').read()) + assert(rv['num_swapping'] == 1) + + rv = json.loads(urlopen('http://127.0.0.1:12700/json/revokeoffer/{}'.format(offer_id)).read()) + assert(rv['revoked_offer'] == offer_id) + + logger.info('Completing swap') + for i in range(240): + if self.delay_event.is_set(): + raise ValueError('Test stopped.') + self.delay_event.wait(4) + + rv = json.loads(urlopen('http://127.0.0.1:12700/json/bids/{}'.format(bid['bid_id'])).read()) + if rv['bid_state'] == 'Completed': + break + assert(rv['bid_state'] == 'Completed') + + # Ensure offer was revoked + summary = json.loads(urlopen('http://127.0.0.1:12700/json').read()) + assert(summary['num_network_offers'] == 0) + + # Wait for bid to be removed from in-progress + waitForNumBids(self.delay_event, 12700, 0) + + +if __name__ == '__main__': + unittest.main()