diff --git a/pyproject.toml b/pyproject.toml index 285ae2c..aba57d8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,3 +49,6 @@ include = ["src/leap"] [build-system] requires = ["hatchling"] build-backend = "hatchling.build" + +[project.entry-points."pytest11"] +leap = "leap.fixtures" diff --git a/src/leap/cleos.py b/src/leap/cleos.py index e0a34f9..6b62caf 100644 --- a/src/leap/cleos.py +++ b/src/leap/cleos.py @@ -44,6 +44,7 @@ class CLEOS: def __init__( self, endpoint: str = 'http://127.0.0.1:8888', + node_dir: Path | None = None, logger = None ): if logger is None: @@ -52,6 +53,7 @@ def __init__( self.logger = logger self.endpoint = endpoint + self.node_dir = node_dir self.keys: dict[str, str] = {} self.private_keys: dict[str, str] = {} diff --git a/src/leap/fixtures.py b/src/leap/fixtures.py index e498d68..f31f620 100644 --- a/src/leap/fixtures.py +++ b/src/leap/fixtures.py @@ -22,7 +22,7 @@ DEFAULT_NODEOS_REPO = 'guilledk/py-leap' -DEFAULT_NODEOS_IMAGE = 'leap-4.0.4' +DEFAULT_NODEOS_IMAGE = 'leap-5.0.3' def default_nodeos_image(): @@ -37,6 +37,91 @@ def maybe_get_marker(request, mark_name: str, field: str, default): return getattr(mark, field) +@contextmanager +def open_test_nodeos(request, tmp_path_factory): + tmp_path = tmp_path_factory.getbasetemp() / request.node.name + leap_path = tmp_path / 'leap' + leap_path.mkdir(parents=True, exist_ok=True) + leap_path = leap_path.resolve() + + logging.info(f'created tmp path at {leap_path}') + + dclient = docker.from_env() + + container_img = default_nodeos_image() + '-bs' + logging.info(f'launching {container_img} container...') + + http_port = get_free_port() + cmd = ['nodeos', '-e', '-p', 'eosio', '--config-dir', '/', '--data-dir', '/data'] + cmd += [ + '>>', '/root/nodeos.log', '2>&1' + ] + + container_cmd = ['/bin/bash', '-c', ' '.join(cmd)] + + vtestnet = get_container( + dclient, + container_img, + force_unique=True, + name=f'{tmp_path.name}-leap', + detach=True, + remove=True, + ports={'8888/tcp': http_port}, + mounts=[Mount('/root', str(leap_path), 'bind')], + command=container_cmd + ) + cleos = CLEOS(f'http://127.0.0.1:{http_port}', node_dir=leap_path) + + # preload apis + rcleos = CLEOS('https://testnet.telos.net') + for account_name in ['eosio', 'eosio.token']: + abi = rcleos.get_abi(account_name) + cleos.load_abi(account_name, abi) + + # load keys + ec, out = vtestnet.exec_run('cat /keys.json') + keys = json.loads(out.decode('utf-8')) + + for account, keys in keys.items(): + priv, _pub = keys + cleos.import_key(account, priv) + + did_nodeos_launch = False + + try: + cleos.import_key('eosio', '5Jr65kdYmn33C3UabzhmWDm2PuqbRfPuDStts3ZFNSBLM7TqaiL') + cleos.wait_blocks(1) + + did_nodeos_launch = True + + yield cleos + + finally: + if did_nodeos_launch: + logging.info(f'to see nodeos logs: \"less {leap_path}/nodeos.log\"') + + else: + process = subprocess.run( + ['cat', str(leap_path / 'nodeos.log')], + text=True, capture_output=True + ) + logging.error('seems nodeos didn\'t launch? showing logs...') + logging.error(process.stdout) + + if vtestnet is not None: + try: + vtestnet.exec_run('pkill -f nodeos') + vtestnet.wait(timeout=120) + vtestnet.kill(signal='SIGTERM') + vtestnet.wait(timeout=20) + + except docker.errors.NotFound: + ... + + except docker.errors.APIError: + ... + + @contextmanager def bootstrap_test_nodeos(request, tmp_path_factory): tmp_path = tmp_path_factory.getbasetemp() / request.node.name @@ -60,7 +145,7 @@ def bootstrap_test_nodeos(request, tmp_path_factory): container_img = default_nodeos_image() logging.info(f'launching {container_img} container...') - cmd = ['nodeos', '-e', '-p', 'eosio', '--config-dir', '/root'] + cmd = ['nodeos', '-e', '-p', 'eosio', '--config-dir', '/root', '--data-dir', '/root/data'] for plugin in [ 'net_plugin', @@ -79,7 +164,7 @@ def bootstrap_test_nodeos(request, tmp_path_factory): if randomize: priv, pub = gen_key_pair() else: - priv, pub = ('5KU4gWTqUWHHh2EhjcK73eYF4T8cWytNkv38qtg4tXtF8iphTZy', 'EOS6FQkekshKwynMNxQLJjXFFLLekiDNYXXK2bAukVVrkhqdkusoj') + priv, pub = ('5Jr65kdYmn33C3UabzhmWDm2PuqbRfPuDStts3ZFNSBLM7TqaiL', 'EOS5GnobZ231eekYUJHGTcmy2qve1K23r5jSFQbMfwWTtPB7mFZ1L') cmd += ['--signature-provider', f'{pub}=KEY:{priv}'] @@ -141,7 +226,7 @@ def bootstrap_test_nodeos(request, tmp_path_factory): download_location.mkdir(exist_ok=True, parents=True) - cleos = CLEOS(f'http://127.0.0.1:{http_port}') + cleos = CLEOS(f'http://127.0.0.1:{http_port}', node_dir=leap_path) rcleos = CLEOS('https://testnet.telos.net') def maybe_download_contract( @@ -197,25 +282,39 @@ def maybe_download_contract( yield cleos finally: - try: - if did_nodeos_launch: - logging.info(f'to see nodeos logs: \"less {leap_path}/nodeos.log\"') + if did_nodeos_launch: + logging.info(f'to see nodeos logs: \"less {leap_path}/nodeos.log\"') + + else: + process = subprocess.run( + ['cat', str(leap_path / 'nodeos.log')], + text=True, capture_output=True + ) + logging.error('seems nodeos didn\'t launch? showing logs...') + logging.error(process.stdout) - else: - process = subprocess.run( - ['cat', str(leap_path / 'nodeos.log')], - text=True, capture_output=True - ) - logging.error('seems nodeos didn\'t launch? showing logs...') - logging.error(process.stdout) + vtestnet.exec_run('chmod 777 /root') - vtestnet.kill() + if vtestnet is not None: + try: + vtestnet.exec_run('pkill -f nodeos') + vtestnet.wait(timeout=120) + vtestnet.kill(signal='SIGTERM') + vtestnet.wait(timeout=20) - except docker.errors.NotFound: - ... + except docker.errors.NotFound: + ... + except docker.errors.APIError: + ... -@pytest.fixture() + +@pytest.fixture(scope='module') def cleos(request, tmp_path_factory): with bootstrap_test_nodeos(request, tmp_path_factory) as cleos: yield cleos + +@pytest.fixture(scope='module') +def cleos_bs(request, tmp_path_factory): + with open_test_nodeos(request, tmp_path_factory) as cleos: + yield cleos diff --git a/tests/conftest.py b/tests/conftest.py index 4db6da3..2cfe887 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -11,15 +11,10 @@ def nodeless_cleos(): yield CLEOS() -@pytest.fixture(scope='module') -def cleos(request, tmp_path_factory): - with bootstrap_test_nodeos(request, tmp_path_factory) as cleos: - yield cleos - - @pytest.fixture(scope='module') def cleos_w_bootstrap(request, tmp_path_factory): request.applymarker(pytest.mark.bootstrap(True)) + request.applymarker(pytest.mark.randomize(False)) with bootstrap_test_nodeos(request, tmp_path_factory) as cleos: yield cleos diff --git a/tests/test_generate_preload.py b/tests/test_generate_preload.py new file mode 100644 index 0000000..44d7eca --- /dev/null +++ b/tests/test_generate_preload.py @@ -0,0 +1,13 @@ +import json + +def test_generate(cleos_w_bootstrap): + cleos = cleos_w_bootstrap + + with open(cleos.node_dir / 'keys.json', 'w+') as key_file: + accounts = list(cleos.private_keys.keys()) + key_file.write(json.dumps({ + account: (cleos.private_keys[account], cleos.keys[account]) + for account in accounts + }, indent=4)) + + cleos.wait_blocks(1) diff --git a/tests/test_rscdk.py b/tests/test_rscdk.py index e7fa11a..7620c33 100644 --- a/tests/test_rscdk.py +++ b/tests/test_rscdk.py @@ -10,7 +10,7 @@ def test_wait_start(cleos_w_indextest): print("eosio: ", cleos.private_keys['eosio']) print("cindextest: ", cleos.private_keys['cindextest']) print("rindextest: ", cleos.private_keys['rindextest']) - breakpoint() + # breakpoint() def test_load_storage_only(cleos_w_indextest): diff --git a/tests/test_token.py b/tests/test_token.py index 4252b57..aafbb45 100644 --- a/tests/test_token.py +++ b/tests/test_token.py @@ -6,8 +6,8 @@ from leap.errors import TransactionPushError -def test_create(cleos_w_bootstrap): - cleos = cleos_w_bootstrap +def test_create(cleos_bs): + cleos = cleos_bs creator = cleos.new_account() sym = random_token_symbol() max_supply = f'1000.000 {sym}' @@ -21,8 +21,8 @@ def test_create(cleos_w_bootstrap): assert tkn_stats['issuer'] == creator -def test_create_negative_supply(cleos_w_bootstrap): - cleos = cleos_w_bootstrap +def test_create_negative_supply(cleos_bs): + cleos = cleos_bs creator = cleos.new_account() with pytest.raises(TransactionPushError) as err: @@ -32,8 +32,8 @@ def test_create_negative_supply(cleos_w_bootstrap): assert 'max-supply must be positive' in str(err) -def test_symbol_exists(cleos_w_bootstrap): - cleos = cleos_w_bootstrap +def test_symbol_exists(cleos_bs): + cleos = cleos_bs creator = cleos.new_account() sym = random_token_symbol() max_supply = f'1000.000 {sym}' @@ -48,8 +48,8 @@ def test_symbol_exists(cleos_w_bootstrap): assert 'token with symbol already exists' in str(err) -def test_create_max_possible(cleos_w_bootstrap): - cleos = cleos_w_bootstrap +def test_create_max_possible(cleos_bs): + cleos = cleos_bs creator = cleos.new_account() amount = (1 << 62) - 1 sym = random_token_symbol() @@ -64,8 +64,8 @@ def test_create_max_possible(cleos_w_bootstrap): assert tkn_stats['issuer'] == creator -def test_create_max_possible_plus_one(cleos_w_bootstrap): - cleos = cleos_w_bootstrap +def test_create_max_possible_plus_one(cleos_bs): + cleos = cleos_bs creator = cleos.new_account() amount = (1 << 62) sym = random_token_symbol() @@ -76,8 +76,8 @@ def test_create_max_possible_plus_one(cleos_w_bootstrap): assert 'invalid supply' in str(err) -def test_create_max_decimals(cleos_w_bootstrap): - cleos = cleos_w_bootstrap +def test_create_max_decimals(cleos_bs): + cleos = cleos_bs creator = cleos.new_account() amount = 1 decimals = 18 @@ -94,8 +94,8 @@ def test_create_max_decimals(cleos_w_bootstrap): assert tkn_stats['issuer'] == creator -def test_issue(cleos_w_bootstrap): - cleos = cleos_w_bootstrap +def test_issue(cleos_bs): + cleos = cleos_bs creator = cleos.new_account() sym = random_token_symbol() max_supply = f'1000.000 {sym}' @@ -132,8 +132,8 @@ def test_issue(cleos_w_bootstrap): cleos.issue_token(creator, issued, 'hola') -def test_retire(cleos_w_bootstrap): - cleos = cleos_w_bootstrap +def test_retire(cleos_bs): + cleos = cleos_bs creator = cleos.new_account() sym = random_token_symbol() max_supply = f'1000.000 {sym}' @@ -207,8 +207,8 @@ def test_retire(cleos_w_bootstrap): assert 'overdrawn balance' in str(err) -def test_transfer(cleos_w_bootstrap): - cleos = cleos_w_bootstrap +def test_transfer(cleos_bs): + cleos = cleos_bs creator = cleos.new_account() sym = random_token_symbol() max_supply = f'1000 {sym}' @@ -249,8 +249,8 @@ def test_transfer(cleos_w_bootstrap): assert 'must transfer positive quantity' in str(err) -def test_open(cleos_w_bootstrap): - cleos = cleos_w_bootstrap +def test_open(cleos_bs): + cleos = cleos_bs creator = cleos.new_account() sym = random_token_symbol() max_supply = f'1000 {sym}' @@ -306,8 +306,8 @@ def test_open(cleos_w_bootstrap): assert 'symbol precision mismatch' in str(err) -def test_close(cleos_w_bootstrap): - cleos = cleos_w_bootstrap +def test_close(cleos_bs): + cleos = cleos_bs creator = cleos.new_account() sym = random_token_symbol() max_supply = f'1000 {sym}'