diff --git a/bin/basicswap-prepare.py b/bin/basicswap-prepare.py deleted file mode 100644 index ed0fb6e..0000000 --- a/bin/basicswap-prepare.py +++ /dev/null @@ -1,117 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- - -# Copyright (c) 2019 tecnovert -# Distributed under the MIT software license, see the accompanying -# file LICENSE.txt or http://www.opensource.org/licenses/mit-license.php. - -""" -Particl Atomic Swap - Proof of Concept - -sudo pip install python-gnupg - -""" - -import sys -import os -import subprocess -import time -import json -import hashlib -import mmap -import tarfile -import urllib.request -import urllib.parse -import logging - -import gnupg - - -logger = logging.getLogger() -logger.level = logging.DEBUG - - -def printVersion(): - from basicswap import __version__ - logger.info('Basicswap version:', __version__) - - -def printHelp(): - logger.info('Usage: basicswap-prepare ') - logger.info('\n--help, -h Print help.') - logger.info('\n--version, -v Print version.') - logger.info('\n--datadir=PATH Path to basicswap data directory, default:~/.basicswap.') - logger.info('\n--mainnet Run in mainnet mode.') - logger.info('\n--testnet Run in testnet mode.') - logger.info('\n--regtest Run in regtest mode.') - logger.info('\n--particl_mnemonic= Recovery phrase to use for the Particl wallet, default is randomly generated.') - - -def main(): - print('main') - data_dir = None - chain = 'mainnet' - particl_wallet_mnemonic = None - - for v in sys.argv[1:]: - if len(v) < 2 or v[0] != '-': - logger.warning('Unknown argument', v) - continue - - s = v.split('=') - name = s[0].strip() - - for i in range(2): - if name[0] == '-': - name = name[1:] - - if name == 'v' or name == 'version': - printVersion() - return 0 - if name == 'h' or name == 'help': - printHelp() - return 0 - if name == 'mainnet': - continue - if name == 'testnet': - chain = 'testnet' - continue - if name == 'regtest': - chain = 'regtest' - continue - - if len(s) == 2: - if name == 'datadir': - data_dir = os.path.expanduser(s[1]) - continue - if name == 'particl_mnemonic': - particl_wallet_mnemonic = s[1] - continue - - logger.warning('Unknown argument', v) - - if data_dir is None: - default_datadir = '~/.basicswap' - data_dir = os.path.join(os.path.expanduser(default_datadir)) - logger.info('Using datadir: %s', data_dir) - logger.info('Chain: %s', chain) - - if not os.path.exists(data_dir): - os.makedirs(data_dir) - - config_path = os.path.join(data_dir, 'basicswap.json') - if os.path.exists(config_path): - sys.stderr.write('Error: {} exists, exiting.'.format(config_path)) - exit(1) - - settings = { - 'debug': True, - } - - with open(config_path, 'w') as fp: - json.dump(settings, fp, indent=4) - - logger.info('Done.') - -if __name__ == '__main__': - main() diff --git a/bin/basicswap-prepare.py b/bin/basicswap-prepare.py new file mode 120000 index 0000000..3e1214f --- /dev/null +++ b/bin/basicswap-prepare.py @@ -0,0 +1 @@ +basicswap_prepare.py \ No newline at end of file diff --git a/bin/basicswap-run.py b/bin/basicswap-run.py deleted file mode 100644 index cccf364..0000000 --- a/bin/basicswap-run.py +++ /dev/null @@ -1,181 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- - -# Copyright (c) 2019 tecnovert -# Distributed under the MIT software license, see the accompanying -# file LICENSE.txt or http://www.opensource.org/licenses/mit-license.php. - -""" -Particl Atomic Swap - Proof of Concept - -Dependencies: - $ pacman -S python-pyzmq python-plyvel protobuf - -""" - -import sys -import os -import time -import json -import traceback -import signal -import subprocess -import logging - -import basicswap.config as cfg -from basicswap import __version__ -from basicswap.basicswap import BasicSwap -from basicswap.http_server import HttpThread - - -logger = logging.getLogger() -logger.level = logging.DEBUG -logger.addHandler(logging.StreamHandler(sys.stdout)) - -ALLOW_CORS = False -swap_client = None - - -def signal_handler(sig, frame): - logger.info('Signal %d detected, ending program.' % (sig)) - if swap_client is not None: - swap_client.stopRunning() - - -def startDaemon(node_dir, bin_dir, daemon_bin): - daemon_bin = os.path.join(bin_dir, daemon_bin) - - args = [daemon_bin, '-datadir=' + node_dir] - logger.info('Starting node ' + daemon_bin + ' ' + '-datadir=' + node_dir) - return subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - - -def runClient(fp, dataDir, chain): - global swap_client - settings_path = os.path.join(dataDir, 'basicswap.json') - - if not os.path.exists(settings_path): - raise ValueError('Settings file not found: ' + str(settings_path)) - - with open(settings_path) as fs: - settings = json.load(fs) - - daemons = [] - - for c, v in settings['chainclients'].items(): - if v['manage_daemon'] is True: - logger.info('Starting {} daemon'.format(c.capitalize())) - if c == 'particl': - daemons.append(startDaemon(v['datadir'], cfg.PARTICL_BINDIR, cfg.PARTICLD)) - logger.info('Started {} {}'.format(cfg.PARTICLD, daemons[-1].pid)) - elif c == 'bitcoin': - daemons.append(startDaemon(v['datadir'], cfg.BITCOIN_BINDIR, cfg.BITCOIND)) - logger.info('Started {} {}'.format(cfg.BITCOIND, daemons[-1].pid)) - elif c == 'litecoin': - daemons.append(startDaemon(v['datadir'], cfg.LITECOIN_BINDIR, cfg.LITECOIND)) - logger.info('Started {} {}'.format(cfg.LITECOIND, daemons[-1].pid)) - else: - logger.warning('Unknown chain', c) - - swap_client = BasicSwap(fp, dataDir, settings, chain) - - signal.signal(signal.SIGINT, signal_handler) - signal.signal(signal.SIGTERM, signal_handler) - swap_client.start() - - threads = [] - if 'htmlhost' in settings: - swap_client.log.info('Starting server at %s:%d.' % (settings['htmlhost'], settings['htmlport'])) - allow_cors = settings['allowcors'] if 'allowcors' in settings else ALLOW_CORS - tS1 = HttpThread(fp, settings['htmlhost'], settings['htmlport'], allow_cors, swap_client) - threads.append(tS1) - tS1.start() - - try: - logger.info('Exit with Ctrl + c.') - while swap_client.is_running: - time.sleep(0.5) - swap_client.update() - except Exception: - traceback.print_exc() - - swap_client.log.info('Stopping threads.') - for t in threads: - t.stop() - t.join() - - for d in daemons: - logger.info('Terminating {}'.format(d.pid)) - d.terminate() - d.wait(timeout=120) - if d.stdout: - d.stdout.close() - if d.stderr: - d.stderr.close() - if d.stdin: - d.stdin.close() - - -def printVersion(): - logger.info('Basicswap version:', __version__) - - -def printHelp(): - logger.info('basicswap-run.py --datadir=path -testnet') - - -def main(): - data_dir = None - chain = 'mainnet' - - for v in sys.argv[1:]: - if len(v) < 2 or v[0] != '-': - logger.warning('Unknown argument', v) - continue - - s = v.split('=') - name = s[0].strip() - - for i in range(2): - if name[0] == '-': - name = name[1:] - - if name == 'v' or name == 'version': - printVersion() - return 0 - if name == 'h' or name == 'help': - printHelp() - return 0 - if name == 'testnet': - chain = 'testnet' - continue - if name == 'regtest': - chain = 'regtest' - continue - - if len(s) == 2: - if name == 'datadir': - data_dir = os.path.expanduser(s[1]) - continue - - logger.warning('Unknown argument', v) - - if data_dir is None: - default_datadir = '~/.basicswap' - data_dir = os.path.join(os.path.expanduser(default_datadir)) - logger.info('Using datadir:', data_dir) - logger.info('Chain:', chain) - - if not os.path.exists(data_dir): - os.makedirs(data_dir) - - with open(os.path.join(data_dir, 'basicswap.log'), 'a') as fp: - logger.info(os.path.basename(sys.argv[0]) + ', version: ' + __version__ + '\n\n') - runClient(fp, data_dir, chain) - - logger.info('Done.') - return swap_client.fail_code if swap_client is not None else 0 - - -if __name__ == '__main__': - main() diff --git a/bin/basicswap-run.py b/bin/basicswap-run.py new file mode 120000 index 0000000..0bf5b17 --- /dev/null +++ b/bin/basicswap-run.py @@ -0,0 +1 @@ +basicswap_run.py \ No newline at end of file diff --git a/bin/basicswap_prepare.py b/bin/basicswap_prepare.py new file mode 100644 index 0000000..1bb0aea --- /dev/null +++ b/bin/basicswap_prepare.py @@ -0,0 +1,306 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# Copyright (c) 2019 tecnovert +# Distributed under the MIT software license, see the accompanying +# file LICENSE.txt or http://www.opensource.org/licenses/mit-license.php. + +""" +Atomic Swap Client - Proof of Concept + +sudo pip install python-gnupg + +""" + +import sys +import os +import json +import hashlib +import mmap +import tarfile +import stat +from urllib.request import urlretrieve +import urllib.parse +import logging + +import gnupg + +BIN_ARCH = 'x86_64-linux-gnu.tar.gz' + +logger = logging.getLogger() +logger.level = logging.DEBUG +if not len(logger.handlers): + logger.addHandler(logging.StreamHandler(sys.stdout)) + + +def make_reporthook(): + read = 0 # number of bytes read so far + last_percent_str = '' + + def reporthook(blocknum, blocksize, totalsize): + nonlocal read + nonlocal last_percent_str + read += blocksize + if totalsize > 0: + percent_str = '%5.1f%%' % (read * 1e2 / totalsize) + if percent_str != last_percent_str: + logger.info(percent_str) + last_percent_str = percent_str + else: + logger.info('read %d' % (read,)) + return reporthook + + +def downloadFile(url, path): + logger.info('Downloading file %s', url) + opener = urllib.request.build_opener() + opener.addheaders = [('User-agent', 'Mozilla/5.0')] + urllib.request.install_opener(opener) + urlretrieve(url, path, make_reporthook()) + + +def prepareCore(coin, version, settings, data_dir): + logger.info('prepareCore %s v%s', coin, version) + + bin_dir = settings['chainclients'][coin]['bindir'] + if not os.path.exists(bin_dir): + os.makedirs(bin_dir) + + if 'osx' in BIN_ARCH: + os_dir_name = 'osx-unsigned' + os_name = 'osx' + elif 'win32' in BIN_ARCH or 'win64' in BIN_ARCH: + os_dir_name = 'win-unsigned' + os_name = 'win' + else: + os_dir_name = 'linux' + os_name = 'linux' + + release_filename = '{}-{}-{}'.format(coin, version, BIN_ARCH) + if coin == 'particl': + signing_key_name = 'tecnovert' + release_url = 'https://github.com/particl/particl-core/releases/download/v{}/{}'.format(version, release_filename) + assert_filename = '{}-{}-{}-build.assert'.format(coin, os_name, version) + assert_url = 'https://raw.githubusercontent.com/particl/gitian.sigs/master/%s-%s/%s/%s' % (version, os_name, signing_key_name, assert_filename) + assert_sig_filename = assert_filename + '.sig' + assert_sig_url = assert_url + '.sig' + elif coin == 'litecoin': + signing_key_name = 'thrasher' + release_url = 'https://download.litecoin.org/litecoin-{}/{}/{}'.format(version, os_name, release_filename) + assert_filename = '{}-{}-0.17-build.assert'.format(coin, os_name) + assert_url = 'https://raw.githubusercontent.com/litecoin-project/gitian.sigs.ltc/master/%s-%s/%s/%s' % (version, os_name, signing_key_name, assert_filename) + assert_sig_filename = assert_filename + '.sig' + assert_sig_url = assert_url + '.sig' + else: + raise ValueError('Unknown coin') + + release_path = os.path.join(bin_dir, release_filename) + if not os.path.exists(release_path): + downloadFile(release_url, release_path) + + assert_path = os.path.join(bin_dir, assert_filename) + if not os.path.exists(assert_path): + downloadFile(assert_url, assert_path) + + assert_sig_path = os.path.join(bin_dir, assert_sig_filename) + if not os.path.exists(assert_sig_path): + downloadFile(assert_sig_url, assert_sig_path) + + hasher = hashlib.sha256() + with open(release_path, 'rb') as fp: + hasher.update(fp.read()) + release_hash = hasher.digest() + + logger.info('%s hash: %s', release_filename, release_hash.hex()) + with open(assert_path, 'rb', 0) as fp, mmap.mmap(fp.fileno(), 0, access=mmap.ACCESS_READ) as s: + if s.find(bytes(release_hash.hex(), 'utf-8')) == -1: + raise ValueError('Error: release hash %s not found in assert file.' % (release_hash.hex())) + else: + logger.info('Found release hash in assert file.') + + """ + gnupghome = os.path.join(data_dir, 'gpg') + if not os.path.exists(gnupghome): + os.makedirs(gnupghome) + """ + gpg = gnupg.GPG() + + with open(assert_sig_path, 'rb') as fp: + verified = gpg.verify_file(fp, assert_path) + + if verified.username is None: + logger.warning('Signature not verified.') + # TODO raise ValueError('Signature verification failed.') + + bins = [coin + 'd', coin + '-cli', coin + '-tx'] + with tarfile.open(release_path) as ft: + for b in bins: + out_path = os.path.join(bin_dir, b) + fi = ft.extractfile('{}-{}/bin/{}'.format(coin, version, b)) + with open(out_path, 'wb') as fout: + fout.write(fi.read()) + fi.close() + os.chmod(out_path, stat.S_IRWXU) + + +def extractCore(coin, version, settings): + logger.info('extractCore %s v%s', coin, version) + + +def printVersion(): + from basicswap import __version__ + logger.info('Basicswap version:', __version__) + + +def printHelp(): + logger.info('Usage: basicswap-prepare ') + logger.info('\n--help, -h Print help.') + logger.info('\n--version, -v Print version.') + logger.info('\n--datadir=PATH Path to basicswap data directory, default:~/.basicswap.') + logger.info('\n--mainnet Run in mainnet mode.') + logger.info('\n--testnet Run in testnet mode.') + logger.info('\n--regtest Run in regtest mode.') + logger.info('\n--particl_mnemonic= Recovery phrase to use for the Particl wallet, default is randomly generated.') + + +def main(): + data_dir = None + chain = 'mainnet' + particl_wallet_mnemonic = None + + for v in sys.argv[1:]: + if len(v) < 2 or v[0] != '-': + logger.warning('Unknown argument', v) + continue + + s = v.split('=') + name = s[0].strip() + + for i in range(2): + if name[0] == '-': + name = name[1:] + + if name == 'v' or name == 'version': + printVersion() + return 0 + if name == 'h' or name == 'help': + printHelp() + return 0 + if name == 'mainnet': + continue + if name == 'testnet': + chain = 'testnet' + continue + if name == 'regtest': + chain = 'regtest' + continue + + if len(s) == 2: + if name == 'datadir': + data_dir = os.path.expanduser(s[1]) + continue + if name == 'particl_mnemonic': + particl_wallet_mnemonic = s[1] + continue + + logger.warning('Unknown argument', v) + + if data_dir is None: + default_datadir = '~/.basicswap' + data_dir = os.path.join(os.path.expanduser(default_datadir)) + logger.info('Using datadir: %s', data_dir) + logger.info('Chain: %s', chain) + + if not os.path.exists(data_dir): + os.makedirs(data_dir) + + config_path = os.path.join(data_dir, 'basicswap.json') + if os.path.exists(config_path): + sys.stderr.write('Error: {} exists, exiting.\n'.format(config_path)) + exit(1) + + settings = { + 'debug': True, + 'zmqhost': 'tcp://127.0.0.1', + 'zmqport': 20792, + 'htmlhost': 'localhost', + 'htmlport': 12700, + 'network_key': '7sW2UEcHXvuqEjkpE5mD584zRaQYs6WXYohue4jLFZPTvMSxwvgs', + 'network_pubkey': '035758c4a22d7dd59165db02a56156e790224361eb3191f02197addcb3bde903d2', + 'chainclients': { + 'particl': { + 'connection_type': 'rpc', + 'manage_daemon': True, + 'rpcport': 19792, + 'datadir': os.path.join(data_dir, 'particl'), + 'bindir': os.path.join(data_dir, 'bins', 'particl'), + 'blocks_confirmed': 2 + }, + 'litecoin': { + 'connection_type': 'rpc', + 'manage_daemon': True, + 'rpcport': 19795, + 'datadir': os.path.join(data_dir, 'litecoin'), + 'bindir': os.path.join(data_dir, 'bins', 'litecoin'), + 'use_segwit': True, + 'blocks_confirmed': 2 + }, + 'bitcoin': { + 'connection_type': 'none', + 'manage_daemon': False, + 'rpcport': 19796, + 'datadir': os.path.join(data_dir, 'bitcoin'), + 'bindir': os.path.join(data_dir, 'bins', 'bitcoin'), + 'use_segwit': True + } + }, + 'check_progress_seconds': 60, + 'check_watched_seconds': 60, + 'check_expired_seconds': 60 + } + + with open(config_path, 'w') as fp: + json.dump(settings, fp, indent=4) + + cores = [ + ('particl', '0.18.0.12'), + ('litecoin', '0.17.1') + ] + for c in cores: + prepareCore(c[0], c[1], settings, data_dir) + coin = c[0] + + core_settings = settings['chainclients'][coin] + data_dir = core_settings['datadir'] + + if not os.path.exists(data_dir): + os.makedirs(data_dir) + + core_conf_path = os.path.join(data_dir, coin + '.conf') + if os.path.exists(core_conf_path): + sys.stderr.write('Error: %s exists, exiting.\n' % (core_conf_path)) + exit(1) + + with open(core_conf_path, 'w') as fp: + if chain != 'mainnet': + fp.write(chain + '=1\n\n') + + fp.write('rpcport={}\n'.format(core_settings['rpcport'])) + fp.write('printtoconsole=0\n') + fp.write('daemon=0\n') + + if coin == 'particl': + fp.write('debugexclude=libevent\n') + fp.write('zmqpubsmsg=tcp://127.0.0.1:{}\n'.format(settings['zmqport'])) + fp.write('spentindex=1') + fp.write('txindex=1') + elif coin == 'litecoin': + fp.write('prune=1000\n') + else: + logger.warning('Unknown coin %s', coin) + + logger.info('Done.') + + +if __name__ == '__main__': + main() diff --git a/bin/basicswap_run.py b/bin/basicswap_run.py new file mode 100644 index 0000000..2af5735 --- /dev/null +++ b/bin/basicswap_run.py @@ -0,0 +1,182 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# Copyright (c) 2019 tecnovert +# Distributed under the MIT software license, see the accompanying +# file LICENSE.txt or http://www.opensource.org/licenses/mit-license.php. + +""" +Atomic Swap Client - Proof of Concept + +Dependencies: + $ pacman -S python-pyzmq python-plyvel protobuf + +""" + +import sys +import os +import time +import json +import traceback +import signal +import subprocess +import logging + +import basicswap.config as cfg +from basicswap import __version__ +from basicswap.basicswap import BasicSwap +from basicswap.http_server import HttpThread + + +logger = logging.getLogger() +logger.level = logging.DEBUG +if not len(logger.handlers): + logger.addHandler(logging.StreamHandler(sys.stdout)) + +ALLOW_CORS = False +swap_client = None + + +def signal_handler(sig, frame): + logger.info('Signal %d detected, ending program.' % (sig)) + if swap_client is not None: + swap_client.stopRunning() + + +def startDaemon(node_dir, bin_dir, daemon_bin): + daemon_bin = os.path.join(bin_dir, daemon_bin) + + args = [daemon_bin, '-datadir=' + node_dir] + logger.info('Starting node ' + daemon_bin + ' ' + '-datadir=' + node_dir) + return subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + + +def runClient(fp, dataDir, chain): + global swap_client + settings_path = os.path.join(dataDir, 'basicswap.json') + + if not os.path.exists(settings_path): + raise ValueError('Settings file not found: ' + str(settings_path)) + + with open(settings_path) as fs: + settings = json.load(fs) + + daemons = [] + + for c, v in settings['chainclients'].items(): + if v['manage_daemon'] is True: + logger.info('Starting {} daemon'.format(c.capitalize())) + if c == 'particl': + daemons.append(startDaemon(v['datadir'], v['bindir'], cfg.PARTICLD)) + logger.info('Started {} {}'.format(cfg.PARTICLD, daemons[-1].pid)) + elif c == 'bitcoin': + daemons.append(startDaemon(v['datadir'], v['bindir'], cfg.BITCOIND)) + logger.info('Started {} {}'.format(cfg.BITCOIND, daemons[-1].pid)) + elif c == 'litecoin': + daemons.append(startDaemon(v['datadir'], v['bindir'], cfg.LITECOIND)) + logger.info('Started {} {}'.format(cfg.LITECOIND, daemons[-1].pid)) + else: + logger.warning('Unknown chain', c) + + swap_client = BasicSwap(fp, dataDir, settings, chain) + + signal.signal(signal.SIGINT, signal_handler) + signal.signal(signal.SIGTERM, signal_handler) + swap_client.start() + + threads = [] + if 'htmlhost' in settings: + swap_client.log.info('Starting server at %s:%d.' % (settings['htmlhost'], settings['htmlport'])) + allow_cors = settings['allowcors'] if 'allowcors' in settings else ALLOW_CORS + tS1 = HttpThread(fp, settings['htmlhost'], settings['htmlport'], allow_cors, swap_client) + threads.append(tS1) + tS1.start() + + try: + logger.info('Exit with Ctrl + c.') + while swap_client.is_running: + time.sleep(0.5) + swap_client.update() + except Exception: + traceback.print_exc() + + swap_client.log.info('Stopping threads.') + for t in threads: + t.stop() + t.join() + + for d in daemons: + logger.info('Terminating {}'.format(d.pid)) + d.terminate() + d.wait(timeout=120) + if d.stdout: + d.stdout.close() + if d.stderr: + d.stderr.close() + if d.stdin: + d.stdin.close() + + +def printVersion(): + logger.info('Basicswap version:', __version__) + + +def printHelp(): + logger.info('basicswap-run --datadir=path -testnet') + + +def main(): + data_dir = None + chain = 'mainnet' + + for v in sys.argv[1:]: + if len(v) < 2 or v[0] != '-': + logger.warning('Unknown argument', v) + continue + + s = v.split('=') + name = s[0].strip() + + for i in range(2): + if name[0] == '-': + name = name[1:] + + if name == 'v' or name == 'version': + printVersion() + return 0 + if name == 'h' or name == 'help': + printHelp() + return 0 + if name == 'testnet': + chain = 'testnet' + continue + if name == 'regtest': + chain = 'regtest' + continue + + if len(s) == 2: + if name == 'datadir': + data_dir = os.path.expanduser(s[1]) + continue + + logger.warning('Unknown argument', v) + + if data_dir is None: + default_datadir = '~/.basicswap' + data_dir = os.path.join(os.path.expanduser(default_datadir)) + logger.info('Using datadir:', data_dir) + logger.info('Chain:', chain) + + if not os.path.exists(data_dir): + os.makedirs(data_dir) + + with open(os.path.join(data_dir, 'basicswap.log'), 'a') as fp: + logger.info(os.path.basename(sys.argv[0]) + ', version: ' + __version__ + '\n\n') + runClient(fp, data_dir, chain) + + logger.info('Done.') + return swap_client.fail_code if swap_client is not None else 0 + + +if __name__ == '__main__': + main() diff --git a/setup.py b/setup.py index 28ce73f..f547cf9 100644 --- a/setup.py +++ b/setup.py @@ -11,8 +11,8 @@ setuptools.setup( name="basicswap", version=__version__, author="tecnovert", - author_email="hello@particl.io", - description="Particl atomic swap demo", + author_email="tecnovert@tecnovert.net", + description="Simple atomic swap demo", long_description=open("README.md").read(), long_description_content_type="text/markdown", url="https://github.com/tecnovert/basicswap", @@ -31,6 +31,7 @@ setuptools.setup( entry_points={ "console_scripts": [ "basicswap-run=bin.basicswap_run:main", + "basicswap-prepare=bin.basicswap_prepare:main", ] }, test_suite="tests.test_suite" diff --git a/tests/__init__.py b/tests/__init__.py index 48ce776..84bcea1 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -7,8 +7,8 @@ import tests.test_run def test_suite(): loader = unittest.TestLoader() - suite.addTests(loader.loadTestsFromModule(tests.test_other)) + suite = loader.loadTestsFromModule(tests.test_other) suite.addTests(loader.loadTestsFromModule(tests.test_prepare)) - suite = loader.loadTestsFromModule(tests.test_run) + suite.addTests(loader.loadTestsFromModule(tests.test_run)) return suite diff --git a/tests/test_prepare.py b/tests/test_prepare.py index 9c59f31..238803b 100644 --- a/tests/test_prepare.py +++ b/tests/test_prepare.py @@ -12,13 +12,14 @@ from unittest.mock import patch from io import StringIO import logging import shutil -import importlib -prepareSystem = importlib.import_module('bin.basicswap-prepare') +import bin.basicswap_prepare as prepareSystem test_path = os.path.expanduser('~/test_basicswap') logger = logging.getLogger() logger.level = logging.DEBUG +if not len(logger.handlers): + logger.addHandler(logging.StreamHandler(sys.stdout)) class Test(unittest.TestCase): diff --git a/tests/test_run.py b/tests/test_run.py index ca5ba6a..1d82551 100644 --- a/tests/test_run.py +++ b/tests/test_run.py @@ -50,7 +50,8 @@ import basicswap.config as cfg logger = logging.getLogger() logger.level = logging.DEBUG -logger.addHandler(logging.StreamHandler(sys.stdout)) +if not len(logger.handlers): + logger.addHandler(logging.StreamHandler(sys.stdout)) NUM_NODES = 3 BASE_PORT = 14792