diff --git a/pytest_tests/requirements.txt b/pytest_tests/requirements.txt index 1aa9655..d729ec3 100644 --- a/pytest_tests/requirements.txt +++ b/pytest_tests/requirements.txt @@ -35,6 +35,7 @@ neo-mamba==0.10.0 neo3crypto==0.2.1 neo3vm==0.9.0 neo3vm-stubs==0.9.0 +neofs-testlib==0.1.0 netaddr==0.8.0 orjson==3.6.8 packaging==21.3 diff --git a/pytest_tests/testsuites/acl/conftest.py b/pytest_tests/testsuites/acl/conftest.py index 89a4cfc..2acd5d1 100644 --- a/pytest_tests/testsuites/acl/conftest.py +++ b/pytest_tests/testsuites/acl/conftest.py @@ -63,10 +63,10 @@ def file_path(): @pytest.fixture(scope="function") -def eacl_container_with_objects(wallets, file_path): +def eacl_container_with_objects(wallets, client_shell, file_path): user_wallet = wallets.get_wallet() with allure.step("Create eACL public container"): - cid = create_container(user_wallet.wallet_path, basic_acl=PUBLIC_ACL) + cid = create_container(user_wallet.wallet_path, basic_acl=PUBLIC_ACL, shell=client_shell) with allure.step("Add test objects to container"): objects_oids = [ @@ -75,6 +75,7 @@ def eacl_container_with_objects(wallets, file_path): file_path, cid, attributes={"key1": "val1", "key": val, "key2": "abc"}, + shell=client_shell, ) for val in range(OBJECT_COUNT) ] diff --git a/pytest_tests/testsuites/acl/storage_group/test_storagegroup.py b/pytest_tests/testsuites/acl/storage_group/test_storagegroup.py index fa1d981..41fd99c 100644 --- a/pytest_tests/testsuites/acl/storage_group/test_storagegroup.py +++ b/pytest_tests/testsuites/acl/storage_group/test_storagegroup.py @@ -57,10 +57,10 @@ class TestStorageGroup: neofs_deposit(self.other_wallet, 30) @allure.title("Test Storage Group in Private Container") - def test_storagegroup_basic_private_container(self, object_size): - cid = create_container(self.main_wallet) + def test_storagegroup_basic_private_container(self, client_shell, object_size): + cid = create_container(self.main_wallet, shell=client_shell) file_path = generate_file(object_size) - oid = put_object(self.main_wallet, file_path, cid) + oid = put_object(self.main_wallet, file_path, cid, shell=client_shell) objects = [oid] storage_group = put_storagegroup(self.main_wallet, cid, objects) @@ -73,10 +73,10 @@ class TestStorageGroup: ) @allure.title("Test Storage Group in Public Container") - def test_storagegroup_basic_public_container(self, object_size): - cid = create_container(self.main_wallet, basic_acl="public-read-write") + def test_storagegroup_basic_public_container(self, client_shell, object_size): + cid = create_container(self.main_wallet, basic_acl="public-read-write", shell=client_shell) file_path = generate_file(object_size) - oid = put_object(self.main_wallet, file_path, cid) + oid = put_object(self.main_wallet, file_path, cid, shell=client_shell) objects = [oid] self.expect_success_for_storagegroup_operations(self.main_wallet, cid, objects, object_size) self.expect_success_for_storagegroup_operations( @@ -87,10 +87,10 @@ class TestStorageGroup: ) @allure.title("Test Storage Group in Read-Only Container") - def test_storagegroup_basic_ro_container(self, object_size): - cid = create_container(self.main_wallet, basic_acl="public-read") + def test_storagegroup_basic_ro_container(self, client_shell, object_size): + cid = create_container(self.main_wallet, basic_acl="public-read", shell=client_shell) file_path = generate_file(object_size) - oid = put_object(self.main_wallet, file_path, cid) + oid = put_object(self.main_wallet, file_path, cid, shell=client_shell) objects = [oid] self.expect_success_for_storagegroup_operations(self.main_wallet, cid, objects, object_size) self.storagegroup_operations_by_other_ro_container( @@ -101,10 +101,12 @@ class TestStorageGroup: ) @allure.title("Test Storage Group with Bearer Allow") - def test_storagegroup_bearer_allow(self, object_size): - cid = create_container(self.main_wallet, basic_acl="eacl-public-read-write") + def test_storagegroup_bearer_allow(self, client_shell, object_size): + cid = create_container( + self.main_wallet, basic_acl="eacl-public-read-write", shell=client_shell + ) file_path = generate_file(object_size) - oid = put_object(self.main_wallet, file_path, cid) + oid = put_object(self.main_wallet, file_path, cid, shell=client_shell) objects = [oid] self.expect_success_for_storagegroup_operations(self.main_wallet, cid, objects, object_size) storage_group = put_storagegroup(self.main_wallet, cid, objects) @@ -130,10 +132,10 @@ class TestStorageGroup: ) @allure.title("Test to check Storage Group lifetime") - def test_storagegroup_lifetime(self, object_size): - cid = create_container(self.main_wallet) + def test_storagegroup_lifetime(self, client_shell, object_size): + cid = create_container(self.main_wallet, shell=client_shell) file_path = generate_file(object_size) - oid = put_object(self.main_wallet, file_path, cid) + oid = put_object(self.main_wallet, file_path, cid, shell=client_shell) objects = [oid] storage_group = put_storagegroup(self.main_wallet, cid, objects, lifetime="1") tick_epoch() diff --git a/pytest_tests/testsuites/acl/test_acl.py b/pytest_tests/testsuites/acl/test_acl.py index 06a7ab1..b0853b0 100644 --- a/pytest_tests/testsuites/acl/test_acl.py +++ b/pytest_tests/testsuites/acl/test_acl.py @@ -1,5 +1,6 @@ import allure import pytest + from python_keywords.acl import EACLRole from python_keywords.container import create_container from python_keywords.container_access import ( @@ -16,10 +17,12 @@ from wellknown_acl import PRIVATE_ACL_F, PUBLIC_ACL_F, READONLY_ACL_F @pytest.mark.acl_basic class TestACLBasic: @pytest.fixture(scope="function") - def public_container(self, wallets): + def public_container(self, client_shell, wallets): user_wallet = wallets.get_wallet() with allure.step("Create public container"): - cid_public = create_container(user_wallet.wallet_path, basic_acl=PUBLIC_ACL_F) + cid_public = create_container( + user_wallet.wallet_path, basic_acl=PUBLIC_ACL_F, shell=client_shell + ) yield cid_public @@ -27,10 +30,12 @@ class TestACLBasic: # delete_container(user_wallet.wallet_path, cid_public) @pytest.fixture(scope="function") - def private_container(self, wallets): + def private_container(self, client_shell, wallets): user_wallet = wallets.get_wallet() with allure.step("Create private container"): - cid_private = create_container(user_wallet.wallet_path, basic_acl=PRIVATE_ACL_F) + cid_private = create_container( + user_wallet.wallet_path, basic_acl=PRIVATE_ACL_F, shell=client_shell + ) yield cid_private @@ -38,10 +43,12 @@ class TestACLBasic: # delete_container(user_wallet.wallet_path, cid_private) @pytest.fixture(scope="function") - def read_only_container(self, wallets): + def read_only_container(self, client_shell, wallets): user_wallet = wallets.get_wallet() with allure.step("Create public readonly container"): - cid_read_only = create_container(user_wallet.wallet_path, basic_acl=READONLY_ACL_F) + cid_read_only = create_container( + user_wallet.wallet_path, basic_acl=READONLY_ACL_F, shell=client_shell + ) yield cid_read_only @@ -49,7 +56,7 @@ class TestACLBasic: # delete_container(user_wallet.wallet_path, cid_read_only) @allure.title("Test basic ACL on public container") - def test_basic_acl_public(self, wallets, public_container, file_path): + def test_basic_acl_public(self, wallets, client_shell, public_container, file_path): """ Test basic ACL set during public container creation. """ @@ -64,20 +71,26 @@ class TestACLBasic: user_wallet.wallet_path, file_path, cid, + shell=client_shell, attributes={"created": "owner"}, ) other_object_oid = put_object( other_wallet.wallet_path, file_path, cid, + shell=client_shell, attributes={"created": "other"}, ) with allure.step(f"Check {desc} has full access to public container"): - check_full_access_to_container(wallet.wallet_path, cid, owner_object_oid, file_path) - check_full_access_to_container(wallet.wallet_path, cid, other_object_oid, file_path) + check_full_access_to_container( + wallet.wallet_path, cid, owner_object_oid, file_path, shell=client_shell + ) + check_full_access_to_container( + wallet.wallet_path, cid, other_object_oid, file_path, shell=client_shell + ) @allure.title("Test basic ACL on private container") - def test_basic_acl_private(self, wallets, private_container, file_path): + def test_basic_acl_private(self, wallets, client_shell, private_container, file_path): """ Test basic ACL set during private container creation. """ @@ -85,21 +98,23 @@ class TestACLBasic: other_wallet = wallets.get_wallet(role=EACLRole.OTHERS) cid = private_container with allure.step("Add test objects to container"): - owner_object_oid = put_object(user_wallet.wallet_path, file_path, cid) + owner_object_oid = put_object( + user_wallet.wallet_path, file_path, cid, shell=client_shell + ) with allure.step("Check only owner has full access to private container"): with allure.step("Check no one except owner has access to operations with container"): check_no_access_to_container( - other_wallet.wallet_path, cid, owner_object_oid, file_path + other_wallet.wallet_path, cid, owner_object_oid, file_path, shell=client_shell ) with allure.step("Check owner has full access to private container"): check_full_access_to_container( - user_wallet.wallet_path, cid, owner_object_oid, file_path + user_wallet.wallet_path, cid, owner_object_oid, file_path, shell=client_shell ) @allure.title("Test basic ACL on readonly container") - def test_basic_acl_readonly(self, wallets, read_only_container, file_path): + def test_basic_acl_readonly(self, wallets, client_shell, read_only_container, file_path): """ Test basic ACL Operations for Read-Only Container. """ @@ -108,10 +123,14 @@ class TestACLBasic: cid = read_only_container with allure.step("Add test objects to container"): - object_oid = put_object(user_wallet.wallet_path, file_path, cid) + object_oid = put_object(user_wallet.wallet_path, file_path, cid, shell=client_shell) with allure.step("Check other has read-only access to operations with container"): - check_read_only_container(other_wallet.wallet_path, cid, object_oid, file_path) + check_read_only_container( + other_wallet.wallet_path, cid, object_oid, file_path, shell=client_shell + ) with allure.step("Check owner has full access to public container"): - check_full_access_to_container(user_wallet.wallet_path, cid, object_oid, file_path) + check_full_access_to_container( + user_wallet.wallet_path, cid, object_oid, file_path, shell=client_shell + ) diff --git a/pytest_tests/testsuites/acl/test_bearer.py b/pytest_tests/testsuites/acl/test_bearer.py index 787b004..87ff6a6 100644 --- a/pytest_tests/testsuites/acl/test_bearer.py +++ b/pytest_tests/testsuites/acl/test_bearer.py @@ -22,7 +22,9 @@ from python_keywords.container_access import ( @pytest.mark.acl_bearer class TestACLBearer: @pytest.mark.parametrize("role", [EACLRole.USER, EACLRole.OTHERS]) - def test_bearer_token_operations(self, wallets, eacl_container_with_objects, role): + def test_bearer_token_operations( + self, wallets, client_shell, eacl_container_with_objects, role + ): allure.dynamic.title(f"Testcase to validate NeoFS operations with {role.value} BearerToken") cid, objects_oids, file_path = eacl_container_with_objects user_wallet = wallets.get_wallet() @@ -35,14 +37,15 @@ class TestACLBearer: objects_oids.pop(), file_path, wallet_config=deny_wallet.config_path, + shell=client_shell, ) with allure.step(f"Set deny all operations for {role.value} via eACL"): eacl = [ EACLRule(access=EACLAccess.DENY, role=role, operation=op) for op in EACLOperation ] - eacl_file = create_eacl(cid, eacl) - set_eacl(user_wallet.wallet_path, cid, eacl_file) + eacl_file = create_eacl(cid, eacl, shell=client_shell) + set_eacl(user_wallet.wallet_path, cid, eacl_file, shell=client_shell) wait_for_cache_expired() with allure.step(f"Create bearer token for {role.value} with all operations allowed"): @@ -53,6 +56,7 @@ class TestACLBearer: EACLRule(operation=op, access=EACLAccess.ALLOW, role=role) for op in EACLOperation ], + shell=client_shell, ) with allure.step( @@ -64,6 +68,7 @@ class TestACLBearer: objects_oids.pop(), file_path, wallet_config=deny_wallet.config_path, + shell=client_shell, ) with allure.step( @@ -76,14 +81,15 @@ class TestACLBearer: file_path, bearer=bearer_token, wallet_config=deny_wallet.config_path, + shell=client_shell, ) with allure.step(f"Set allow all operations for {role.value} via eACL"): eacl = [ EACLRule(access=EACLAccess.ALLOW, role=role, operation=op) for op in EACLOperation ] - eacl_file = create_eacl(cid, eacl) - set_eacl(user_wallet.wallet_path, cid, eacl_file) + eacl_file = create_eacl(cid, eacl, shell=client_shell) + set_eacl(user_wallet.wallet_path, cid, eacl_file, shell=client_shell) wait_for_cache_expired() with allure.step( @@ -95,10 +101,13 @@ class TestACLBearer: objects_oids.pop(), file_path, wallet_config=deny_wallet.config_path, + shell=client_shell, ) @allure.title("BearerToken Operations for compound Operations") - def test_bearer_token_compound_operations(self, wallets, eacl_container_with_objects): + def test_bearer_token_compound_operations( + self, wallets, client_shell, eacl_container_with_objects + ): cid, objects_oids, file_path = eacl_container_with_objects user_wallet = wallets.get_wallet() other_wallet = wallets.get_wallet(role=EACLRole.OTHERS) @@ -141,7 +150,12 @@ class TestACLBearer: eacl_deny += [ EACLRule(access=EACLAccess.DENY, role=role, operation=op) for op in operations ] - set_eacl(user_wallet.wallet_path, cid, eacl_table_path=create_eacl(cid, eacl_deny)) + set_eacl( + user_wallet.wallet_path, + cid, + eacl_table_path=create_eacl(cid, eacl_deny, shell=client_shell), + shell=client_shell, + ) wait_for_cache_expired() with allure.step("Check rule consistency without bearer"): @@ -152,6 +166,7 @@ class TestACLBearer: file_path, deny_operations=deny_map[EACLRole.USER], wallet_config=user_wallet.config_path, + shell=client_shell, ) check_custom_access_to_container( other_wallet.wallet_path, @@ -160,6 +175,7 @@ class TestACLBearer: file_path, deny_operations=deny_map[EACLRole.OTHERS], wallet_config=other_wallet.config_path, + shell=client_shell, ) with allure.step("Check rule consistency using bearer token"): @@ -170,6 +186,7 @@ class TestACLBearer: EACLRule(operation=op, access=EACLAccess.ALLOW, role=EACLRole.USER) for op in bearer_map[EACLRole.USER] ], + shell=client_shell, ) bearer_token_other = form_bearertoken_file( @@ -179,6 +196,7 @@ class TestACLBearer: EACLRule(operation=op, access=EACLAccess.ALLOW, role=EACLRole.OTHERS) for op in bearer_map[EACLRole.OTHERS] ], + shell=client_shell, ) check_custom_access_to_container( @@ -189,6 +207,7 @@ class TestACLBearer: deny_operations=deny_map_with_bearer[EACLRole.USER], bearer=bearer_token_user, wallet_config=user_wallet.config_path, + shell=client_shell, ) check_custom_access_to_container( other_wallet.wallet_path, @@ -198,4 +217,5 @@ class TestACLBearer: deny_operations=deny_map_with_bearer[EACLRole.OTHERS], bearer=bearer_token_other, wallet_config=other_wallet.config_path, + shell=client_shell, ) diff --git a/pytest_tests/testsuites/acl/test_eacl.py b/pytest_tests/testsuites/acl/test_eacl.py index 3523074..d5f32d9 100644 --- a/pytest_tests/testsuites/acl/test_eacl.py +++ b/pytest_tests/testsuites/acl/test_eacl.py @@ -27,6 +27,7 @@ from python_keywords.object_access import ( can_put_object, can_search_object, ) +from neofs_testlib.shell import Shell from wellknown_acl import PUBLIC_ACL @@ -37,14 +38,17 @@ class TestEACLContainer: NODE_COUNT = len(NEOFS_NETMAP_DICT.keys()) @pytest.fixture(scope="function") - def eacl_full_placement_container_with_object(self, wallets, file_path): + def eacl_full_placement_container_with_object(self, wallets, file_path, shell: Shell): user_wallet = wallets.get_wallet() with allure.step("Create eACL public container with full placement rule"): full_placement_rule = ( f"REP {self.NODE_COUNT} IN X CBF 1 SELECT {self.NODE_COUNT} FROM * AS X" ) cid = create_container( - user_wallet.wallet_path, full_placement_rule, basic_acl=PUBLIC_ACL + user_wallet.wallet_path, + full_placement_rule, + basic_acl=PUBLIC_ACL, + shell=shell, ) with allure.step("Add test object to container"): @@ -55,7 +59,7 @@ class TestEACLContainer: @pytest.mark.parametrize("deny_role", [EACLRole.USER, EACLRole.OTHERS]) def test_extended_acl_deny_all_operations( - self, wallets, eacl_container_with_objects, deny_role + self, wallets, client_shell, eacl_container_with_objects, deny_role ): user_wallet = wallets.get_wallet() other_wallet = wallets.get_wallet(EACLRole.OTHERS) @@ -71,7 +75,12 @@ class TestEACLContainer: EACLRule(access=EACLAccess.DENY, role=deny_role, operation=op) for op in EACLOperation ] - set_eacl(user_wallet.wallet_path, cid, create_eacl(cid, eacl_deny)) + set_eacl( + user_wallet.wallet_path, + cid, + create_eacl(cid, eacl_deny, shell=client_shell), + shell=client_shell, + ) wait_for_cache_expired() with allure.step(f"Check only {not_deny_role_str} has full access to container"): @@ -79,14 +88,22 @@ class TestEACLContainer: f"Check {deny_role_str} has not access to any operations with container" ): check_no_access_to_container( - deny_role_wallet.wallet_path, cid, object_oids[0], file_path + deny_role_wallet.wallet_path, + cid, + object_oids[0], + file_path, + shell=client_shell, ) with allure.step( f"Check {not_deny_role_wallet} has full access to eACL public container" ): check_full_access_to_container( - not_deny_role_wallet.wallet_path, cid, object_oids.pop(), file_path + not_deny_role_wallet.wallet_path, + cid, + object_oids.pop(), + file_path, + shell=client_shell, ) with allure.step(f"Allow all operations for {deny_role_str} via eACL"): @@ -94,20 +111,33 @@ class TestEACLContainer: EACLRule(access=EACLAccess.ALLOW, role=deny_role, operation=op) for op in EACLOperation ] - set_eacl(user_wallet.wallet_path, cid, create_eacl(cid, eacl_deny)) + set_eacl( + user_wallet.wallet_path, + cid, + create_eacl(cid, eacl_deny, shell=client_shell), + shell=client_shell, + ) wait_for_cache_expired() with allure.step(f"Check all have full access to eACL public container"): check_full_access_to_container( - user_wallet.wallet_path, cid, object_oids.pop(), file_path + user_wallet.wallet_path, + cid, + object_oids.pop(), + file_path, + shell=client_shell, ) check_full_access_to_container( - other_wallet.wallet_path, cid, object_oids.pop(), file_path + other_wallet.wallet_path, + cid, + object_oids.pop(), + file_path, + shell=client_shell, ) @allure.title("Testcase to allow NeoFS operations for only one other pubkey.") def test_extended_acl_deny_all_operations_exclude_pubkey( - self, wallets, eacl_container_with_objects + self, wallets, client_shell, eacl_container_with_objects ): user_wallet = wallets.get_wallet() other_wallet, other_wallet_allow = wallets.get_wallets_list(EACLRole.OTHERS)[0:2] @@ -126,28 +156,45 @@ class TestEACLContainer: EACLRule(access=EACLAccess.DENY, role=EACLRole.OTHERS, operation=op) for op in EACLOperation ] - set_eacl(user_wallet.wallet_path, cid, create_eacl(cid, eacl)) + set_eacl( + user_wallet.wallet_path, + cid, + create_eacl(cid, eacl, shell=client_shell), + shell=client_shell, + ) wait_for_cache_expired() with allure.step("Check only owner and allowed other have full access to public container"): with allure.step("Check other has not access to operations with container"): check_no_access_to_container( - other_wallet.wallet_path, cid, object_oids[0], file_path + other_wallet.wallet_path, + cid, + object_oids[0], + file_path, + shell=client_shell, ) with allure.step("Check owner has full access to public container"): check_full_access_to_container( - user_wallet.wallet_path, cid, object_oids.pop(), file_path + user_wallet.wallet_path, + cid, + object_oids.pop(), + file_path, + shell=client_shell, ) with allure.step("Check allowed other has full access to public container"): check_full_access_to_container( - other_wallet_allow.wallet_path, cid, object_oids.pop(), file_path + other_wallet_allow.wallet_path, + cid, + object_oids.pop(), + file_path, + shell=client_shell, ) @allure.title("Testcase to validate NeoFS replication with eACL deny rules.") def test_extended_acl_deny_replication( - self, wallets, eacl_full_placement_container_with_object, file_path + self, wallets, client_shell, eacl_full_placement_container_with_object, file_path ): user_wallet = wallets.get_wallet() cid, oid, file_path = eacl_full_placement_container_with_object @@ -161,7 +208,12 @@ class TestEACLContainer: EACLRule(access=EACLAccess.DENY, role=EACLRole.OTHERS, operation=op) for op in EACLOperation ] - set_eacl(user_wallet.wallet_path, cid, create_eacl(cid, eacl_deny)) + set_eacl( + user_wallet.wallet_path, + cid, + create_eacl(cid, eacl_deny, shell=client_shell), + shell=client_shell, + ) wait_for_cache_expired() with allure.step("Drop object to check replication"): @@ -172,7 +224,7 @@ class TestEACLContainer: wait_object_replication_on_nodes(storage_wallet_path, cid, oid, self.NODE_COUNT) @allure.title("Testcase to validate NeoFS system operations with extended ACL") - def test_extended_actions_system(self, wallets, eacl_container_with_objects): + def test_extended_actions_system(self, wallets, client_shell, eacl_container_with_objects): user_wallet = wallets.get_wallet() ir_wallet, storage_wallet = wallets.get_wallets_list(role=EACLRole.SYSTEM)[:2] @@ -180,10 +232,18 @@ class TestEACLContainer: with allure.step("Check IR and STORAGE rules compliance"): assert not can_put_object( - ir_wallet.wallet_path, cid, file_path, wallet_config=ir_wallet.config_path + ir_wallet.wallet_path, + cid, + file_path, + shell=client_shell, + wallet_config=ir_wallet.config_path, ) assert can_put_object( - storage_wallet.wallet_path, cid, file_path, wallet_config=storage_wallet.config_path + storage_wallet.wallet_path, + cid, + file_path, + shell=client_shell, + wallet_config=storage_wallet.config_path, ) assert can_get_object( @@ -191,6 +251,7 @@ class TestEACLContainer: cid, object_oids[0], file_path, + shell=client_shell, wallet_config=ir_wallet.config_path, ) assert can_get_object( @@ -198,62 +259,88 @@ class TestEACLContainer: cid, object_oids[0], file_path, + shell=client_shell, wallet_config=storage_wallet.config_path, ) assert can_get_head_object( - ir_wallet.wallet_path, cid, object_oids[0], wallet_config=ir_wallet.config_path + ir_wallet.wallet_path, + cid, + object_oids[0], + shell=client_shell, + wallet_config=ir_wallet.config_path, ) assert can_get_head_object( storage_wallet.wallet_path, cid, object_oids[0], + shell=client_shell, wallet_config=storage_wallet.config_path, ) assert can_search_object( - ir_wallet.wallet_path, cid, object_oids[0], wallet_config=ir_wallet.config_path + ir_wallet.wallet_path, + cid, + shell=client_shell, + oid=object_oids[0], + wallet_config=ir_wallet.config_path, ) assert can_search_object( storage_wallet.wallet_path, cid, - object_oids[0], + shell=client_shell, + oid=object_oids[0], wallet_config=storage_wallet.config_path, ) with pytest.raises(AssertionError): assert can_get_range_of_object( - ir_wallet.wallet_path, cid, object_oids[0], wallet_config=ir_wallet.config_path + wallet=ir_wallet.wallet_path, + cid=cid, + oid=object_oids[0], + shell=client_shell, + wallet_config=ir_wallet.config_path, ) with pytest.raises(AssertionError): assert can_get_range_of_object( - storage_wallet.wallet_path, - cid, - object_oids[0], + wallet=storage_wallet.wallet_path, + cid=cid, + oid=object_oids[0], + shell=client_shell, wallet_config=storage_wallet.config_path, ) with pytest.raises(AssertionError): assert can_get_range_hash_of_object( - ir_wallet.wallet_path, cid, object_oids[0], wallet_config=ir_wallet.config_path + wallet=ir_wallet.wallet_path, + cid=cid, + oid=object_oids[0], + shell=client_shell, + wallet_config=ir_wallet.config_path, ) with pytest.raises(AssertionError): assert can_get_range_hash_of_object( - storage_wallet.wallet_path, - cid, - object_oids[0], + wallet=storage_wallet.wallet_path, + cid=cid, + oid=object_oids[0], + shell=client_shell, wallet_config=storage_wallet.config_path, ) with pytest.raises(AssertionError): assert can_delete_object( - ir_wallet.wallet_path, cid, object_oids[0], wallet_config=ir_wallet.config_path + wallet=ir_wallet.wallet_path, + cid=cid, + oid=object_oids[0], + shell=client_shell, + wallet_config=ir_wallet.config_path, ) with pytest.raises(AssertionError): assert can_delete_object( - storage_wallet.wallet_path, - cid, - object_oids[0], + wallet=storage_wallet.wallet_path, + cid=cid, + oid=object_oids[0], + shell=client_shell, wallet_config=storage_wallet.config_path, ) @@ -262,97 +349,134 @@ class TestEACLContainer: user_wallet.wallet_path, cid, create_eacl( - cid, - [ + cid=cid, + rules_list=[ EACLRule(access=EACLAccess.DENY, role=EACLRole.SYSTEM, operation=op) for op in EACLOperation ], + shell=client_shell, ), + shell=client_shell, ) wait_for_cache_expired() with allure.step("Check IR and STORAGE rules compliance with deny eACL"): assert not can_put_object( - ir_wallet.wallet_path, cid, file_path, wallet_config=ir_wallet.config_path + wallet=ir_wallet.wallet_path, + cid=cid, + file_name=file_path, + shell=client_shell, + wallet_config=ir_wallet.config_path, ) assert not can_put_object( - storage_wallet.wallet_path, cid, file_path, wallet_config=storage_wallet.config_path + wallet=storage_wallet.wallet_path, + cid=cid, + file_name=file_path, + shell=client_shell, + wallet_config=storage_wallet.config_path, ) with pytest.raises(AssertionError): assert can_get_object( - ir_wallet.wallet_path, - cid, - object_oids[0], - file_path, + wallet=ir_wallet.wallet_path, + cid=cid, + oid=object_oids[0], + file_name=file_path, + shell=client_shell, wallet_config=ir_wallet.config_path, ) with pytest.raises(AssertionError): assert can_get_object( - storage_wallet.wallet_path, - cid, - object_oids[0], - file_path, + wallet=storage_wallet.wallet_path, + cid=cid, + oid=object_oids[0], + file_name=file_path, + shell=client_shell, wallet_config=storage_wallet.config_path, ) with pytest.raises(AssertionError): assert can_get_head_object( - ir_wallet.wallet_path, cid, object_oids[0], wallet_config=ir_wallet.config_path + wallet=ir_wallet.wallet_path, + cid=cid, + oid=object_oids[0], + shell=client_shell, + wallet_config=ir_wallet.config_path, ) with pytest.raises(AssertionError): assert can_get_head_object( - storage_wallet.wallet_path, - cid, - object_oids[0], + wallet=storage_wallet.wallet_path, + cid=cid, + oid=object_oids[0], + shell=client_shell, wallet_config=storage_wallet.config_path, ) with pytest.raises(AssertionError): assert can_search_object( - ir_wallet.wallet_path, cid, object_oids[0], wallet_config=ir_wallet.config_path + wallet=ir_wallet.wallet_path, + cid=cid, + shell=client_shell, + oid=object_oids[0], + wallet_config=ir_wallet.config_path, ) with pytest.raises(AssertionError): assert can_search_object( - storage_wallet.wallet_path, - cid, - object_oids[0], + wallet=storage_wallet.wallet_path, + cid=cid, + shell=client_shell, + oid=object_oids[0], wallet_config=storage_wallet.config_path, ) with pytest.raises(AssertionError): assert can_get_range_of_object( - ir_wallet.wallet_path, cid, object_oids[0], wallet_config=ir_wallet.config_path + wallet=ir_wallet.wallet_path, + cid=cid, + oid=object_oids[0], + shell=client_shell, + wallet_config=ir_wallet.config_path, ) with pytest.raises(AssertionError): assert can_get_range_of_object( - storage_wallet.wallet_path, - cid, - object_oids[0], + wallet=storage_wallet.wallet_path, + cid=cid, + oid=object_oids[0], + shell=client_shell, wallet_config=storage_wallet.config_path, ) with pytest.raises(AssertionError): assert can_get_range_hash_of_object( - ir_wallet.wallet_path, cid, object_oids[0], wallet_config=ir_wallet.config_path + wallet=ir_wallet.wallet_path, + cid=cid, + oid=object_oids[0], + shell=client_shell, + wallet_config=ir_wallet.config_path, ) with pytest.raises(AssertionError): assert can_get_range_hash_of_object( - storage_wallet.wallet_path, - cid, - object_oids[0], + wallet=storage_wallet.wallet_path, + cid=cid, + oid=object_oids[0], + shell=client_shell, wallet_config=storage_wallet.config_path, ) with pytest.raises(AssertionError): assert can_delete_object( - ir_wallet.wallet_path, cid, object_oids[0], wallet_config=ir_wallet.config_path + wallet=ir_wallet.wallet_path, + cid=cid, + oid=object_oids[0], + shell=client_shell, + wallet_config=ir_wallet.config_path, ) with pytest.raises(AssertionError): assert can_delete_object( - storage_wallet.wallet_path, - cid, - object_oids[0], + wallet=storage_wallet.wallet_path, + cid=cid, + oid=object_oids[0], + shell=client_shell, wallet_config=storage_wallet.config_path, ) @@ -361,90 +485,127 @@ class TestEACLContainer: user_wallet.wallet_path, cid, create_eacl( - cid, - [ + cid=cid, + rules_list=[ EACLRule(access=EACLAccess.ALLOW, role=EACLRole.SYSTEM, operation=op) for op in EACLOperation ], + shell=client_shell, ), + shell=client_shell, ) wait_for_cache_expired() with allure.step("Check IR and STORAGE rules compliance with allow eACL"): assert not can_put_object( - ir_wallet.wallet_path, cid, file_path, wallet_config=ir_wallet.config_path + wallet=ir_wallet.wallet_path, + cid=cid, + file_name=file_path, + shell=client_shell, + wallet_config=ir_wallet.config_path, ) assert can_put_object( - storage_wallet.wallet_path, cid, file_path, wallet_config=storage_wallet.config_path + wallet=storage_wallet.wallet_path, + cid=cid, + file_name=file_path, + shell=client_shell, + wallet_config=storage_wallet.config_path, ) assert can_get_object( - ir_wallet.wallet_path, - cid, - object_oids[0], - file_path, + wallet=ir_wallet.wallet_path, + cid=cid, + oid=object_oids[0], + file_name=file_path, + shell=client_shell, wallet_config=ir_wallet.config_path, ) assert can_get_object( - storage_wallet.wallet_path, - cid, - object_oids[0], - file_path, + wallet=storage_wallet.wallet_path, + cid=cid, + oid=object_oids[0], + file_name=file_path, + shell=client_shell, wallet_config=storage_wallet.config_path, ) assert can_get_head_object( - ir_wallet.wallet_path, cid, object_oids[0], wallet_config=ir_wallet.config_path + wallet=ir_wallet.wallet_path, + cid=cid, + oid=object_oids[0], + shell=client_shell, + wallet_config=ir_wallet.config_path, ) assert can_get_head_object( - storage_wallet.wallet_path, - cid, - object_oids[0], + wallet=storage_wallet.wallet_path, + cid=cid, + oid=object_oids[0], + shell=client_shell, wallet_config=storage_wallet.config_path, ) assert can_search_object( - ir_wallet.wallet_path, cid, object_oids[0], wallet_config=ir_wallet.config_path + wallet=ir_wallet.wallet_path, + cid=cid, + shell=client_shell, + oid=object_oids[0], + wallet_config=ir_wallet.config_path, ) assert can_search_object( - storage_wallet.wallet_path, - cid, - object_oids[0], + wallet=storage_wallet.wallet_path, + cid=cid, + shell=client_shell, + oid=object_oids[0], wallet_config=storage_wallet.config_path, ) with pytest.raises(AssertionError): assert can_get_range_of_object( - ir_wallet.wallet_path, cid, object_oids[0], wallet_config=ir_wallet.config_path + wallet=ir_wallet.wallet_path, + cid=cid, + oid=object_oids[0], + shell=client_shell, + wallet_config=ir_wallet.config_path, ) with pytest.raises(AssertionError): assert can_get_range_of_object( - storage_wallet.wallet_path, - cid, - object_oids[0], + wallet=storage_wallet.wallet_path, + cid=cid, + oid=object_oids[0], + shell=client_shell, wallet_config=storage_wallet.config_path, ) with pytest.raises(AssertionError): assert can_get_range_hash_of_object( - ir_wallet.wallet_path, cid, object_oids[0], wallet_config=ir_wallet.config_path + wallet=ir_wallet.wallet_path, + cid=cid, + oid=object_oids[0], + shell=client_shell, + wallet_config=ir_wallet.config_path, ) with pytest.raises(AssertionError): assert can_get_range_hash_of_object( - storage_wallet.wallet_path, - cid, - object_oids[0], + wallet=storage_wallet.wallet_path, + cid=cid, + oid=object_oids[0], + shell=client_shell, wallet_config=storage_wallet.config_path, ) with pytest.raises(AssertionError): assert can_delete_object( - ir_wallet.wallet_path, cid, object_oids[0], wallet_config=ir_wallet.config_path + wallet=ir_wallet.wallet_path, + cid=cid, + oid=object_oids[0], + shell=client_shell, + wallet_config=ir_wallet.config_path, ) with pytest.raises(AssertionError): assert can_delete_object( - storage_wallet.wallet_path, - cid, - object_oids[0], + wallet=storage_wallet.wallet_path, + cid=cid, + oid=object_oids[0], + shell=client_shell, wallet_config=storage_wallet.config_path, ) diff --git a/pytest_tests/testsuites/acl/test_eacl_filters.py b/pytest_tests/testsuites/acl/test_eacl_filters.py index c541bc3..e9a3e1a 100644 --- a/pytest_tests/testsuites/acl/test_eacl_filters.py +++ b/pytest_tests/testsuites/acl/test_eacl_filters.py @@ -68,10 +68,12 @@ class TestEACLFilters: ] @pytest.fixture(scope="function") - def eacl_container_with_objects(self, wallets, file_path): + def eacl_container_with_objects(self, wallets, client_shell, file_path): user_wallet = wallets.get_wallet() with allure.step("Create eACL public container"): - cid = create_container(user_wallet.wallet_path, basic_acl=PUBLIC_ACL) + cid = create_container( + user_wallet.wallet_path, basic_acl=PUBLIC_ACL, shell=client_shell + ) with allure.step("Add test objects to container"): objects_with_header = [ @@ -79,6 +81,7 @@ class TestEACLFilters: user_wallet.wallet_path, file_path, cid, + shell=client_shell, attributes={**self.SET_HEADERS, "key": val}, ) for val in range(self.OBJECT_COUNT) @@ -89,25 +92,28 @@ class TestEACLFilters: user_wallet.wallet_path, file_path, cid, + shell=client_shell, attributes={**self.OTHER_HEADERS, "key": val}, ) for val in range(self.OBJECT_COUNT) ] objects_without_header = [ - put_object(user_wallet.wallet_path, file_path, cid) + put_object(user_wallet.wallet_path, file_path, cid, shell=client_shell) for _ in range(self.OBJECT_COUNT) ] yield cid, objects_with_header, objects_with_other_header, objects_without_header, file_path with allure.step("Delete eACL public container"): - delete_container(user_wallet.wallet_path, cid) + delete_container(user_wallet.wallet_path, cid, shell=client_shell) @pytest.mark.parametrize( "match_type", [EACLMatchType.STRING_EQUAL, EACLMatchType.STRING_NOT_EQUAL] ) - def test_extended_acl_filters_request(self, wallets, eacl_container_with_objects, match_type): + def test_extended_acl_filters_request( + self, wallets, client_shell, eacl_container_with_objects, match_type + ): allure.dynamic.title(f"Validate NeoFS operations with request filter: {match_type.name}") user_wallet = wallets.get_wallet() other_wallet = wallets.get_wallet(EACLRole.OTHERS) @@ -131,7 +137,12 @@ class TestEACLFilters: ) for op in EACLOperation ] - set_eacl(user_wallet.wallet_path, cid, create_eacl(cid, eacl_deny)) + set_eacl( + user_wallet.wallet_path, + cid, + create_eacl(cid, eacl_deny, shell=client_shell), + shell=client_shell, + ) wait_for_cache_expired() # Filter denies requests where "check_key {match_type} ATTRIBUTE", so when match_type @@ -152,7 +163,9 @@ class TestEACLFilters: objects_without_header, ): with allure.step("Check other has full access when sending request without headers"): - check_full_access_to_container(other_wallet.wallet_path, cid, oid.pop(), file_path) + check_full_access_to_container( + other_wallet.wallet_path, cid, oid.pop(), file_path, shell=client_shell + ) with allure.step( "Check other has full access when sending request with allowed headers" @@ -162,6 +175,7 @@ class TestEACLFilters: cid, oid.pop(), file_path, + shell=client_shell, xhdr=allow_headers, ) @@ -171,6 +185,7 @@ class TestEACLFilters: cid, oid.pop(), file_path, + shell=client_shell, xhdr=deny_headers, ) @@ -185,12 +200,14 @@ class TestEACLFilters: EACLRule(operation=op, access=EACLAccess.ALLOW, role=EACLRole.OTHERS) for op in EACLOperation ], + shell=client_shell, ) check_full_access_to_container( other_wallet.wallet_path, cid, oid.pop(), file_path, + shell=client_shell, xhdr=deny_headers, bearer=bearer_token_other, ) @@ -199,7 +216,7 @@ class TestEACLFilters: "match_type", [EACLMatchType.STRING_EQUAL, EACLMatchType.STRING_NOT_EQUAL] ) def test_extended_acl_deny_filters_object( - self, wallets, eacl_container_with_objects, match_type + self, wallets, client_shell, eacl_container_with_objects, match_type ): allure.dynamic.title( f"Validate NeoFS operations with deny user headers filter: {match_type.name}" @@ -226,7 +243,12 @@ class TestEACLFilters: ) for op in self.OBJECT_ATTRIBUTES_FILTER_SUPPORTED_OPERATIONS ] - set_eacl(user_wallet.wallet_path, cid, create_eacl(cid, eacl_deny)) + set_eacl( + user_wallet.wallet_path, + cid, + create_eacl(cid, eacl_deny, shell=client_shell), + shell=client_shell, + ) wait_for_cache_expired() allow_objects = ( @@ -250,6 +272,7 @@ class TestEACLFilters: cid, objs_without_header.pop(), file_path, + shell=client_shell, xhdr=xhdr, ) @@ -259,13 +282,18 @@ class TestEACLFilters: cid, allow_objects.pop(), file_path, + shell=client_shell, xhdr=xhdr, ) with allure.step("Check other have no access to objects with deny attribute"): with pytest.raises(AssertionError): assert can_get_head_object( - other_wallet.wallet_path, cid, deny_objects[0], xhdr=xhdr + other_wallet.wallet_path, + cid, + deny_objects[0], + shell=client_shell, + xhdr=xhdr, ) with pytest.raises(AssertionError): assert can_get_object( @@ -273,6 +301,7 @@ class TestEACLFilters: cid, deny_objects[0], file_path, + shell=client_shell, xhdr=xhdr, ) @@ -290,12 +319,14 @@ class TestEACLFilters: ) for op in EACLOperation ], + shell=client_shell, ) check_full_access_to_container( other_wallet.wallet_path, cid, deny_objects.pop(), file_path, + shell=client_shell, xhdr=xhdr, bearer=bearer_token_other, ) @@ -305,9 +336,13 @@ class TestEACLFilters: ) with allure.step("Check other can PUT objects without denied attribute"): assert can_put_object( - other_wallet.wallet_path, cid, file_path, attributes=allow_attribute + other_wallet.wallet_path, + cid, + file_path, + shell=client_shell, + attributes=allow_attribute, ) - assert can_put_object(other_wallet.wallet_path, cid, file_path) + assert can_put_object(other_wallet.wallet_path, cid, file_path, shell=client_shell) deny_attribute = ( self.ATTRIBUTE if match_type == EACLMatchType.STRING_EQUAL else self.OTHER_ATTRIBUTE @@ -315,7 +350,11 @@ class TestEACLFilters: with allure.step("Check other can not PUT objects with denied attribute"): with pytest.raises(AssertionError): assert can_put_object( - other_wallet.wallet_path, cid, file_path, attributes=deny_attribute + other_wallet.wallet_path, + cid, + file_path, + shell=client_shell, + attributes=deny_attribute, ) with allure.step( @@ -331,11 +370,13 @@ class TestEACLFilters: role=EACLRole.OTHERS, ) ], + shell=client_shell, ) assert can_put_object( other_wallet.wallet_path, cid, file_path, + shell=client_shell, attributes=deny_attribute, bearer=bearer_token_other_for_put, ) @@ -344,7 +385,7 @@ class TestEACLFilters: "match_type", [EACLMatchType.STRING_EQUAL, EACLMatchType.STRING_NOT_EQUAL] ) def test_extended_acl_allow_filters_object( - self, wallets, eacl_container_with_objects, match_type + self, wallets, client_shell, eacl_container_with_objects, match_type ): allure.dynamic.title( "Testcase to validate NeoFS operation with allow eACL user headers filters:" @@ -377,7 +418,12 @@ class TestEACLFilters: EACLRule(access=EACLAccess.DENY, role=EACLRole.OTHERS, operation=op) for op in self.OBJECT_ATTRIBUTES_FILTER_SUPPORTED_OPERATIONS ] - set_eacl(user_wallet.wallet_path, cid, create_eacl(cid, eacl)) + set_eacl( + user_wallet.wallet_path, + cid, + create_eacl(cid, eacl, shell=client_shell), + shell=client_shell, + ) wait_for_cache_expired() if match_type == EACLMatchType.STRING_EQUAL: @@ -394,11 +440,13 @@ class TestEACLFilters: with allure.step(f"Check other cannot get and put objects without attributes"): oid = objects_without_header.pop() with pytest.raises(AssertionError): - assert can_get_head_object(other_wallet.wallet_path, cid, oid) + assert can_get_head_object(other_wallet.wallet_path, cid, oid, shell=client_shell) with pytest.raises(AssertionError): - assert can_get_object(other_wallet.wallet_path, cid, oid, file_path) + assert can_get_object( + other_wallet.wallet_path, cid, oid, file_path, shell=client_shell + ) with pytest.raises(AssertionError): - assert can_put_object(other_wallet.wallet_path, cid, file_path) + assert can_put_object(other_wallet.wallet_path, cid, file_path, shell=client_shell) with allure.step( "Check other can get and put objects without attributes and using bearer token" @@ -414,11 +462,13 @@ class TestEACLFilters: ) for op in EACLOperation ], + shell=client_shell, ) assert can_get_head_object( other_wallet.wallet_path, cid, objects_without_header[0], + shell=client_shell, bearer=bearer_token_other, ) assert can_get_object( @@ -426,28 +476,45 @@ class TestEACLFilters: cid, objects_without_header[0], file_path, + shell=client_shell, bearer=bearer_token_other, ) assert can_put_object( - other_wallet.wallet_path, cid, file_path, bearer=bearer_token_other + other_wallet.wallet_path, + cid, + file_path, + shell=client_shell, + bearer=bearer_token_other, ) with allure.step(f"Check other can get objects with attributes matching the filter"): oid = allow_objects.pop() - assert can_get_head_object(other_wallet.wallet_path, cid, oid) - assert can_get_object(other_wallet.wallet_path, cid, oid, file_path) + assert can_get_head_object(other_wallet.wallet_path, cid, oid, shell=client_shell) + assert can_get_object(other_wallet.wallet_path, cid, oid, file_path, shell=client_shell) assert can_put_object( - other_wallet.wallet_path, cid, file_path, attributes=allow_attribute + other_wallet.wallet_path, + cid, + file_path, + shell=client_shell, + attributes=allow_attribute, ) with allure.step("Check other cannot get objects without attributes matching the filter"): with pytest.raises(AssertionError): - assert can_get_head_object(other_wallet.wallet_path, cid, deny_objects[0]) + assert can_get_head_object( + other_wallet.wallet_path, cid, deny_objects[0], shell=client_shell + ) with pytest.raises(AssertionError): - assert can_get_object(other_wallet.wallet_path, cid, deny_objects[0], file_path) + assert can_get_object( + other_wallet.wallet_path, cid, deny_objects[0], file_path, shell=client_shell + ) with pytest.raises(AssertionError): assert can_put_object( - other_wallet.wallet_path, cid, file_path, attributes=deny_attribute + other_wallet.wallet_path, + cid, + file_path, + attributes=deny_attribute, + shell=client_shell, ) with allure.step( @@ -456,15 +523,21 @@ class TestEACLFilters: ): oid = deny_objects.pop() assert can_get_head_object( - other_wallet.wallet_path, cid, oid, bearer=bearer_token_other + other_wallet.wallet_path, cid, oid, shell=client_shell, bearer=bearer_token_other ) assert can_get_object( - other_wallet.wallet_path, cid, oid, file_path, bearer=bearer_token_other + other_wallet.wallet_path, + cid, + oid, + file_path, + shell=client_shell, + bearer=bearer_token_other, ) assert can_put_object( other_wallet.wallet_path, cid, file_path, + shell=client_shell, attributes=deny_attribute, bearer=bearer_token_other, ) diff --git a/pytest_tests/testsuites/conftest.py b/pytest_tests/testsuites/conftest.py index 4ef80ed..82935db 100644 --- a/pytest_tests/testsuites/conftest.py +++ b/pytest_tests/testsuites/conftest.py @@ -8,15 +8,20 @@ import allure import pytest import wallet from cli_helpers import _cmd_run -from cli_utils import NeofsAdm, NeofsCli from common import ( ASSETS_DIR, FREE_STORAGE, INFRASTRUCTURE_TYPE, MAINNET_WALLET_PATH, + NEOFS_ADM_EXEC, + NEOFS_CLI_EXEC, NEOFS_NETMAP_DICT, + WALLET_CONFIG, ) +from neofs_testlib.cli import NeofsAdm, NeofsCli + from env_properties import save_env_properties +from neofs_testlib.shell import LocalShell, Shell from payment_neogo import neofs_deposit, transfer_mainnet_gas from python_keywords.node_management import node_healthcheck from service_helper import get_storage_service_helper @@ -24,6 +29,11 @@ from service_helper import get_storage_service_helper logger = logging.getLogger("NeoLogger") +@pytest.fixture(scope="session") +def client_shell() -> Shell: + yield LocalShell() + + @pytest.fixture(scope="session") def cloud_infrastructure_check(): if INFRASTRUCTURE_TYPE != "CLOUD_VM": @@ -33,18 +43,20 @@ def cloud_infrastructure_check(): @pytest.fixture(scope="session", autouse=True) @allure.title("Check binary versions") -def check_binary_versions(request): +def check_binary_versions(request, client_shell): # Collect versions of local binaries binaries = ["neo-go", "neofs-authmate"] local_binaries = _get_binaries_version_local(binaries) try: - local_binaries["neofs-adm"] = NeofsAdm().version.get() + local_binaries["neofs-adm"] = NeofsAdm(client_shell, NEOFS_ADM_EXEC).version.get() except RuntimeError: logger.info(f"neofs-adm not installed") - local_binaries["neofs-cli"] = NeofsCli().version.get() - + local_binaries["neofs-cli"] = NeofsCli( + client_shell, NEOFS_CLI_EXEC, WALLET_CONFIG + ).version.get() # Collect versions of remote binaries + helper = get_storage_service_helper() remote_binaries = helper.get_binaries_version() all_binaries = {**local_binaries, **remote_binaries} diff --git a/pytest_tests/testsuites/container/test_container.py b/pytest_tests/testsuites/container/test_container.py index 31afbd1..fc74f38 100644 --- a/pytest_tests/testsuites/container/test_container.py +++ b/pytest_tests/testsuites/container/test_container.py @@ -18,7 +18,7 @@ from wellknown_acl import PRIVATE_ACL_F @pytest.mark.parametrize("name", ["", "test-container"], ids=["No name", "Set particular name"]) @pytest.mark.sanity @pytest.mark.container -def test_container_creation(prepare_wallet_and_deposit, name): +def test_container_creation(client_shell, prepare_wallet_and_deposit, name): scenario_title = f"with name {name}" if name else "without name" allure.dynamic.title(f"User can create container {scenario_title}") @@ -27,12 +27,12 @@ def test_container_creation(prepare_wallet_and_deposit, name): json_wallet = json.load(file) placement_rule = "REP 2 IN X CBF 1 SELECT 2 FROM * AS X" - cid = create_container(wallet, rule=placement_rule, name=name) + cid = create_container(wallet, rule=placement_rule, name=name, shell=client_shell) - containers = list_containers(wallet) + containers = list_containers(wallet, shell=client_shell) assert cid in containers, f"Expected container {cid} in containers: {containers}" - container_info: str = get_container(wallet, cid, json_mode=False) + container_info: str = get_container(wallet, cid, json_mode=False, shell=client_shell) container_info = container_info.casefold() # To ignore case when comparing with expected values info_to_check = { @@ -57,15 +57,15 @@ def test_container_creation(prepare_wallet_and_deposit, name): ), f"Expected {expected_info} in container info:\n{container_info}" with allure.step("Delete container and check it was deleted"): - delete_container(wallet, cid) + delete_container(wallet, cid, shell=client_shell) tick_epoch() - wait_for_container_deletion(wallet, cid) + wait_for_container_deletion(wallet, cid, shell=client_shell) @allure.title("Parallel container creation and deletion") @pytest.mark.sanity @pytest.mark.container -def test_container_creation_deletion_parallel(prepare_wallet_and_deposit): +def test_container_creation_deletion_parallel(client_shell, prepare_wallet_and_deposit): containers_count = 3 wallet = prepare_wallet_and_deposit placement_rule = "REP 2 IN X CBF 1 SELECT 2 FROM * AS X" @@ -75,16 +75,22 @@ def test_container_creation_deletion_parallel(prepare_wallet_and_deposit): for _ in range(containers_count): cids.append( create_container( - wallet, rule=placement_rule, await_mode=False, wait_for_creation=False + wallet, + rule=placement_rule, + await_mode=False, + shell=client_shell, + wait_for_creation=False, ) ) with allure.step(f"Wait for containers occur in container list"): for cid in cids: - wait_for_container_creation(wallet, cid, sleep_interval=containers_count) + wait_for_container_creation( + wallet, cid, sleep_interval=containers_count, shell=client_shell + ) with allure.step("Delete containers and check they were deleted"): for cid in cids: - delete_container(wallet, cid) + delete_container(wallet, cid, shell=client_shell) tick_epoch() - wait_for_container_deletion(wallet, cid) + wait_for_container_deletion(wallet, cid, shell=client_shell) diff --git a/pytest_tests/testsuites/failovers/test_failover_network.py b/pytest_tests/testsuites/failovers/test_failover_network.py index e914dc0..96d92c2 100644 --- a/pytest_tests/testsuites/failovers/test_failover_network.py +++ b/pytest_tests/testsuites/failovers/test_failover_network.py @@ -48,7 +48,7 @@ def restore_network(): @allure.title("Block Storage node traffic") @pytest.mark.failover @pytest.mark.failover_net -def test_block_storage_node_traffic(prepare_wallet_and_deposit, cloud_infrastructure_check): +def test_block_storage_node_traffic(prepare_wallet_and_deposit, client_shell, cloud_infrastructure_check): """ Block storage nodes traffic using iptables and wait for replication for objects. """ @@ -59,9 +59,9 @@ def test_block_storage_node_traffic(prepare_wallet_and_deposit, cloud_infrastruc nodes_to_block_count = 2 source_file_path = generate_file() - cid = create_container(wallet, rule=placement_rule, basic_acl=PUBLIC_ACL) - oid = put_object(wallet, source_file_path, cid) - nodes = wait_object_replication_on_nodes(wallet, cid, oid, 2) + cid = create_container(wallet, shell=client_shell, rule=placement_rule, basic_acl=PUBLIC_ACL) + oid = put_object(wallet, source_file_path, cid, shell=client_shell) + nodes = wait_object_replication_on_nodes(wallet, cid, oid, 2, shell=client_shell) logger.info(f"Nodes are {nodes}") random_nodes = [(node, node.split(":")[0]) for node in nodes] @@ -89,7 +89,7 @@ def test_block_storage_node_traffic(prepare_wallet_and_deposit, cloud_infrastruc assert random_node not in new_nodes - got_file_path = get_object(wallet, cid, oid, endpoint=new_nodes[0]) + got_file_path = get_object(wallet, cid, oid, shell=client_shell, endpoint=new_nodes[0]) assert get_file_hash(source_file_path) == get_file_hash(got_file_path) for random_node, random_node_ip in random_nodes: @@ -108,7 +108,7 @@ def test_block_storage_node_traffic(prepare_wallet_and_deposit, cloud_infrastruc blocked_hosts.remove(random_node_ip) sleep(wakeup_node_timeout) - new_nodes = wait_object_replication_on_nodes(wallet, cid, oid, 2) + new_nodes = wait_object_replication_on_nodes(wallet, cid, oid, 2, shell=client_shell) - got_file_path = get_object(wallet, cid, oid, endpoint=new_nodes[0]) + got_file_path = get_object(wallet, cid, oid, shell=client_shell, endpoint=new_nodes[0]) assert get_file_hash(source_file_path) == get_file_hash(got_file_path) diff --git a/pytest_tests/testsuites/failovers/test_failover_storage.py b/pytest_tests/testsuites/failovers/test_failover_storage.py index 9dcbcb8..18aedf4 100644 --- a/pytest_tests/testsuites/failovers/test_failover_storage.py +++ b/pytest_tests/testsuites/failovers/test_failover_storage.py @@ -64,6 +64,7 @@ def return_all_storage_nodes(sbercloud_client: SberCloud) -> None: @pytest.mark.failover def test_lost_storage_node( prepare_wallet_and_deposit, + client_shell, sbercloud_client: SberCloud, cloud_infrastructure_check, hard_reboot: bool, @@ -71,27 +72,29 @@ def test_lost_storage_node( wallet = prepare_wallet_and_deposit placement_rule = "REP 2 IN X CBF 2 SELECT 2 FROM * AS X" source_file_path = generate_file() - cid = create_container(wallet, rule=placement_rule, basic_acl=PUBLIC_ACL) - oid = put_object(wallet, source_file_path, cid) - nodes = wait_object_replication_on_nodes(wallet, cid, oid, 2) + cid = create_container(wallet, shell=client_shell, rule=placement_rule, basic_acl=PUBLIC_ACL) + oid = put_object(wallet, source_file_path, cid, shell=client_shell) + nodes = wait_object_replication_on_nodes(wallet, cid, oid, 2, shell=client_shell) new_nodes = [] for node in nodes: stopped_hosts.append(node) with allure.step(f"Stop storage node {node}"): sbercloud_client.stop_node(node_ip=node.split(":")[-2], hard=hard_reboot) - new_nodes = wait_object_replication_on_nodes(wallet, cid, oid, 2, excluded_nodes=[node]) + new_nodes = wait_object_replication_on_nodes( + wallet, cid, oid, 2, shell=client_shell, excluded_nodes=[node] + ) assert not [node for node in nodes if node in new_nodes] - got_file_path = get_object(wallet, cid, oid, endpoint=new_nodes[0]) + got_file_path = get_object(wallet, cid, oid, shell=client_shell, endpoint=new_nodes[0]) assert get_file_hash(source_file_path) == get_file_hash(got_file_path) with allure.step(f"Return storage nodes"): return_all_storage_nodes(sbercloud_client) - new_nodes = wait_object_replication_on_nodes(wallet, cid, oid, 2) + new_nodes = wait_object_replication_on_nodes(wallet, cid, oid, 2, shell=client_shell) - got_file_path = get_object(wallet, cid, oid, endpoint=new_nodes[0]) + got_file_path = get_object(wallet, cid, oid, shell=client_shell, endpoint=new_nodes[0]) assert get_file_hash(source_file_path) == get_file_hash(got_file_path) @@ -99,14 +102,16 @@ def test_lost_storage_node( @pytest.mark.parametrize("sequence", [True, False]) @pytest.mark.failover_panic @pytest.mark.failover -def test_panic_storage_node(prepare_wallet_and_deposit, cloud_infrastructure_check, sequence: bool): +def test_panic_storage_node( + prepare_wallet_and_deposit, client_shell, cloud_infrastructure_check, sequence: bool +): wallet = prepare_wallet_and_deposit placement_rule = "REP 2 IN X CBF 2 SELECT 2 FROM * AS X" source_file_path = generate_file() - cid = create_container(wallet, rule=placement_rule, basic_acl=PUBLIC_ACL) - oid = put_object(wallet, source_file_path, cid) + cid = create_container(wallet, shell=client_shell, rule=placement_rule, basic_acl=PUBLIC_ACL) + oid = put_object(wallet, source_file_path, cid, shell=client_shell) - nodes = wait_object_replication_on_nodes(wallet, cid, oid, 2) + nodes = wait_object_replication_on_nodes(wallet, cid, oid, 2, shell=client_shell) new_nodes: list[str] = [] allure.attach("\n".join(nodes), "Current nodes with object", allure.attachment_type.TEXT) for node in nodes: @@ -115,10 +120,12 @@ def test_panic_storage_node(prepare_wallet_and_deposit, cloud_infrastructure_che if sequence: try: new_nodes = wait_object_replication_on_nodes( - wallet, cid, oid, 2, excluded_nodes=[node] + wallet, cid, oid, 2, shell=client_shell, excluded_nodes=[node] ) except AssertionError: - new_nodes = wait_object_replication_on_nodes(wallet, cid, oid, 2) + new_nodes = wait_object_replication_on_nodes( + wallet, cid, oid, 2, shell=client_shell + ) allure.attach( "\n".join(new_nodes), @@ -127,10 +134,10 @@ def test_panic_storage_node(prepare_wallet_and_deposit, cloud_infrastructure_che ) if not sequence: - new_nodes = wait_object_replication_on_nodes(wallet, cid, oid, 2) + new_nodes = wait_object_replication_on_nodes(wallet, cid, oid, 2, shell=client_shell) allure.attach( "\n".join(new_nodes), "Nodes with object after nodes fail", allure.attachment_type.TEXT ) - got_file_path = get_object(wallet, cid, oid, endpoint=new_nodes[0]) + got_file_path = get_object(wallet, cid, oid, shell=client_shell, endpoint=new_nodes[0]) assert get_file_hash(source_file_path) == get_file_hash(got_file_path) diff --git a/pytest_tests/testsuites/network/test_node_management.py b/pytest_tests/testsuites/network/test_node_management.py index 30adef7..20b8b11 100644 --- a/pytest_tests/testsuites/network/test_node_management.py +++ b/pytest_tests/testsuites/network/test_node_management.py @@ -4,9 +4,9 @@ from time import sleep import allure import pytest +from neofs_testlib.shell import Shell from common import ( COMPLEX_OBJ_SIZE, - MAINNET_BLOCK_TIME, MORPH_BLOCK_TIME, NEOFS_CONTRACT_CACHE_TIMEOUT, NEOFS_NETMAP_DICT, @@ -46,15 +46,15 @@ check_nodes = [] @pytest.fixture @allure.title("Create container and pick the node with data") -def create_container_and_pick_node(prepare_wallet_and_deposit): +def create_container_and_pick_node(prepare_wallet_and_deposit, client_shell): wallet = prepare_wallet_and_deposit file_path = generate_file() placement_rule = "REP 1 IN X CBF 1 SELECT 1 FROM * AS X" - cid = create_container(wallet, rule=placement_rule, basic_acl=PUBLIC_ACL) - oid = put_object(wallet, file_path, cid) + cid = create_container(wallet, shell=client_shell, rule=placement_rule, basic_acl=PUBLIC_ACL) + oid = put_object(wallet, file_path, cid, shell=client_shell) - nodes = get_nodes_with_object(wallet, cid, oid) + nodes = get_nodes_with_object(wallet, cid, oid, shell=client_shell) assert len(nodes) == 1 node = nodes[0] @@ -83,13 +83,13 @@ def after_run_start_all_nodes(): @pytest.fixture -def return_nodes_after_test_run(): +def return_nodes_after_test_run(client_shell): yield - return_nodes() + return_nodes(shell=client_shell) @allure.step("Return node to cluster") -def return_nodes(alive_node: str = None): +def return_nodes(shell: Shell, alive_node: str = None): helper = get_storage_service_helper() for node in list(check_nodes): with allure.step(f"Start node {node}"): @@ -113,13 +113,15 @@ def return_nodes(alive_node: str = None): except RuntimeError: sleep(3) - check_node_in_map(node, alive_node) + check_node_in_map(node, shell=shell, alive_node=alive_node) @allure.title("Add one node to cluster") @pytest.mark.add_nodes @pytest.mark.node_mgmt -def test_add_nodes(prepare_tmp_dir, prepare_wallet_and_deposit, return_nodes_after_test_run): +def test_add_nodes( + prepare_tmp_dir, client_shell, prepare_wallet_and_deposit, return_nodes_after_test_run +): wallet = prepare_wallet_and_deposit placement_rule_3 = "REP 3 IN X CBF 1 SELECT 3 FROM * AS X" placement_rule_4 = "REP 4 IN X CBF 1 SELECT 4 FROM * AS X" @@ -134,7 +136,7 @@ def test_add_nodes(prepare_tmp_dir, prepare_wallet_and_deposit, return_nodes_aft ) alive_node = choice([node for node in NEOFS_NETMAP_DICT if node != additional_node]) - check_node_in_map(additional_node, alive_node) + check_node_in_map(additional_node, shell=client_shell, alive_node=alive_node) # Add node to recovery list before messing with it check_nodes.append(additional_node) @@ -147,7 +149,7 @@ def test_add_nodes(prepare_tmp_dir, prepare_wallet_and_deposit, return_nodes_aft ) wait_object_replication_on_nodes(wallet, cid, oid, 3) - return_nodes(alive_node) + return_nodes(shell=client_shell, alive_node=alive_node) with allure.step("Check data could be replicated to new node"): random_node = choice( @@ -156,7 +158,7 @@ def test_add_nodes(prepare_tmp_dir, prepare_wallet_and_deposit, return_nodes_aft exclude_node_from_network_map(random_node, alive_node) wait_object_replication_on_nodes(wallet, cid, oid, 3, excluded_nodes=[random_node]) - include_node_to_network_map(random_node, alive_node) + include_node_to_network_map(random_node, alive_node, shell=client_shell) wait_object_replication_on_nodes(wallet, cid, oid, 3) with allure.step("Check container could be created with new node"): @@ -164,12 +166,12 @@ def test_add_nodes(prepare_tmp_dir, prepare_wallet_and_deposit, return_nodes_aft oid = put_object( wallet, source_file_path, cid, endpoint=NEOFS_NETMAP_DICT[alive_node].get("rpc") ) - wait_object_replication_on_nodes(wallet, cid, oid, 4) + wait_object_replication_on_nodes(wallet, cid, oid, 4, shell=client_shell) @allure.title("Control Operations with storage nodes") @pytest.mark.node_mgmt -def test_nodes_management(prepare_tmp_dir): +def test_nodes_management(prepare_tmp_dir, client_shell): """ This test checks base control operations with storage nodes (healthcheck, netmap-snapshot, set-status). """ @@ -181,7 +183,7 @@ def test_nodes_management(prepare_tmp_dir): random_node_netmap_key = get_wallet_public_key(random_node_wallet_path, STORAGE_WALLET_PASS) with allure.step("Check node {random_node} is in netmap"): - snapshot = get_netmap_snapshot(node_name=alive_node) + snapshot = get_netmap_snapshot(node_name=alive_node, shell=client_shell) assert random_node_netmap_key in snapshot, f"Expected node {random_node} in netmap" with allure.step("Run health check for all storage nodes"): @@ -198,7 +200,7 @@ def test_nodes_management(prepare_tmp_dir): with allure.step(f"Check node {random_node} went to offline"): health_check = node_healthcheck(random_node) assert health_check.health_status == "READY" and health_check.network_status == "OFFLINE" - snapshot = get_netmap_snapshot(node_name=alive_node) + snapshot = get_netmap_snapshot(node_name=alive_node, shell=client_shell) assert random_node_netmap_key not in snapshot, f"Expected node {random_node} not in netmap" with allure.step(f"Check node {random_node} went to online"): @@ -210,7 +212,7 @@ def test_nodes_management(prepare_tmp_dir): with allure.step(f"Check node {random_node} went to online"): health_check = node_healthcheck(random_node) assert health_check.health_status == "READY" and health_check.network_status == "ONLINE" - snapshot = get_netmap_snapshot(node_name=alive_node) + snapshot = get_netmap_snapshot(node_name=alive_node, shell=client_shell) assert random_node_netmap_key in snapshot, f"Expected node {random_node} in netmap" diff --git a/pytest_tests/testsuites/object/test_object_api.py b/pytest_tests/testsuites/object/test_object_api.py index ffdfb36..fe8be9e 100644 --- a/pytest_tests/testsuites/object/test_object_api.py +++ b/pytest_tests/testsuites/object/test_object_api.py @@ -18,6 +18,7 @@ from python_keywords.neofs_verbs import ( search_object, ) from python_keywords.storage_policy import get_complex_object_copies, get_simple_object_copies +from neofs_testlib.shell import Shell from tombstone import verify_head_tombstone from utility import wait_for_gc_pass_on_storage_nodes @@ -32,14 +33,14 @@ CLEANUP_TIMEOUT = 10 @pytest.mark.parametrize( "object_size", [SIMPLE_OBJ_SIZE, COMPLEX_OBJ_SIZE], ids=["simple object", "complex object"] ) -def test_object_api(prepare_wallet_and_deposit, request, object_size): +def test_object_api(prepare_wallet_and_deposit, client_shell, request, object_size): """ Test common gRPC API for object (put/get/head/get_range_hash/get_range/search/delete). """ allure.dynamic.title(f"Test native object API for {request.node.callspec.id}") wallet = prepare_wallet_and_deposit - cid = create_container(wallet) + cid = create_container(wallet, shell=client_shell) wallet_cid = {"wallet": wallet, "cid": cid} file_usr_header = {"key1": 1, "key2": "abc", "common_key": "common_value"} file_usr_header_oth = {"key1": 2, "common_key": "common_value"} @@ -50,70 +51,114 @@ def test_object_api(prepare_wallet_and_deposit, request, object_size): file_hash = get_file_hash(file_path) with allure.step("Check container is empty"): - search_object(**wallet_cid, expected_objects_list=[]) + search_object(**wallet_cid, expected_objects_list=[], shell=client_shell) oids = [] with allure.step("Put objects"): - oids.append(put_object(wallet=wallet, path=file_path, cid=cid)) - oids.append(put_object(wallet=wallet, path=file_path, cid=cid, attributes=file_usr_header)) + oids.append(put_object(wallet=wallet, path=file_path, cid=cid, shell=client_shell)) oids.append( - put_object(wallet=wallet, path=file_path, cid=cid, attributes=file_usr_header_oth) + put_object( + wallet=wallet, + path=file_path, + cid=cid, + shell=client_shell, + attributes=file_usr_header, + ) + ) + oids.append( + put_object( + wallet=wallet, + path=file_path, + cid=cid, + shell=client_shell, + attributes=file_usr_header_oth, + ) ) with allure.step("Validate storage policy for objects"): for oid_to_check in oids: if object_size == SIMPLE_OBJ_SIZE: - copies = get_simple_object_copies(wallet=wallet, cid=cid, oid=oid_to_check) + copies = get_simple_object_copies( + wallet=wallet, cid=cid, oid=oid_to_check, shell=client_shell + ) else: - copies = get_complex_object_copies(wallet=wallet, cid=cid, oid=oid_to_check) + copies = get_complex_object_copies( + wallet=wallet, cid=cid, oid=oid_to_check, shell=client_shell + ) assert copies == 2, "Expected 2 copies" with allure.step("Get objects and compare hashes"): for oid_to_check in oids: - got_file_path = get_object(wallet=wallet, cid=cid, oid=oid_to_check) + got_file_path = get_object(wallet=wallet, cid=cid, oid=oid_to_check, shell=client_shell) got_file_hash = get_file_hash(got_file_path) assert file_hash == got_file_hash with allure.step("Get range/range hash"): - range_hash = get_range_hash(**wallet_cid, oid=oids[0], bearer_token="", range_cut=range_cut) + range_hash = get_range_hash( + **wallet_cid, oid=oids[0], shell=client_shell, range_cut=range_cut + ) assert ( get_file_hash(file_path, range_len) == range_hash ), f"Expected range hash to match {range_cut} slice of file payload" - range_hash = get_range_hash(**wallet_cid, oid=oids[1], bearer_token="", range_cut=range_cut) + range_hash = get_range_hash( + **wallet_cid, oid=oids[1], shell=client_shell, range_cut=range_cut + ) assert ( get_file_hash(file_path, range_len) == range_hash ), f"Expected range hash to match {range_cut} slice of file payload" - _, range_content = get_range(**wallet_cid, oid=oids[1], bearer="", range_cut=range_cut) + _, range_content = get_range( + **wallet_cid, oid=oids[1], shell=client_shell, range_cut=range_cut + ) assert ( get_file_content(file_path, content_len=range_len, mode="rb") == range_content ), f"Expected range content to match {range_cut} slice of file payload" with allure.step("Search objects"): - search_object(**wallet_cid, expected_objects_list=oids) - search_object(**wallet_cid, filters=file_usr_header, expected_objects_list=oids[1:2]) - search_object(**wallet_cid, filters=file_usr_header_oth, expected_objects_list=oids[2:3]) - search_object(**wallet_cid, filters=common_header, expected_objects_list=oids[1:3]) + search_object(**wallet_cid, shell=client_shell, expected_objects_list=oids) + search_object( + **wallet_cid, + shell=client_shell, + filters=file_usr_header, + expected_objects_list=oids[1:2], + ) + search_object( + **wallet_cid, + shell=client_shell, + filters=file_usr_header_oth, + expected_objects_list=oids[2:3], + ) + search_object( + **wallet_cid, shell=client_shell, filters=common_header, expected_objects_list=oids[1:3] + ) with allure.step("Head object and validate"): - head_object(**wallet_cid, oid=oids[0]) - head_info = head_object(**wallet_cid, oid=oids[1]) + head_object(**wallet_cid, oid=oids[0], shell=client_shell) + head_info = head_object(**wallet_cid, oid=oids[1], shell=client_shell) check_header_is_presented(head_info, file_usr_header) with allure.step("Delete objects"): - tombstone_s = delete_object(**wallet_cid, oid=oids[0]) - tombstone_h = delete_object(**wallet_cid, oid=oids[1]) + tombstone_s = delete_object(**wallet_cid, oid=oids[0], shell=client_shell) + tombstone_h = delete_object(**wallet_cid, oid=oids[1], shell=client_shell) - verify_head_tombstone(wallet_path=wallet, cid=cid, oid_ts=tombstone_s, oid=oids[0]) - verify_head_tombstone(wallet_path=wallet, cid=cid, oid_ts=tombstone_h, oid=oids[1]) + verify_head_tombstone( + wallet_path=wallet, cid=cid, oid_ts=tombstone_s, oid=oids[0], shell=client_shell + ) + verify_head_tombstone( + wallet_path=wallet, cid=cid, oid_ts=tombstone_h, oid=oids[1], shell=client_shell + ) tick_epoch() sleep(CLEANUP_TIMEOUT) with allure.step("Get objects and check errors"): - get_object_and_check_error(**wallet_cid, oid=oids[0], error_pattern=OBJECT_ALREADY_REMOVED) - get_object_and_check_error(**wallet_cid, oid=oids[1], error_pattern=OBJECT_ALREADY_REMOVED) + get_object_and_check_error( + **wallet_cid, oid=oids[0], error_pattern=OBJECT_ALREADY_REMOVED, shell=client_shell + ) + get_object_and_check_error( + **wallet_cid, oid=oids[1], error_pattern=OBJECT_ALREADY_REMOVED, shell=client_shell + ) @allure.title("Test object life time") @@ -122,12 +167,12 @@ def test_object_api(prepare_wallet_and_deposit, request, object_size): @pytest.mark.parametrize( "object_size", [SIMPLE_OBJ_SIZE, COMPLEX_OBJ_SIZE], ids=["simple object", "complex object"] ) -def test_object_api_lifetime(prepare_wallet_and_deposit, request, object_size): +def test_object_api_lifetime(prepare_wallet_and_deposit, client_shell, request, object_size): """ Test object deleted after expiration epoch. """ wallet = prepare_wallet_and_deposit - cid = create_container(wallet) + cid = create_container(wallet, shell=client_shell) allure.dynamic.title(f"Test object life time for {request.node.callspec.id}") @@ -135,8 +180,8 @@ def test_object_api_lifetime(prepare_wallet_and_deposit, request, object_size): file_hash = get_file_hash(file_path) epoch = get_epoch() - oid = put_object(wallet, file_path, cid, expire_at=epoch + 1) - got_file = get_object(wallet, cid, oid) + oid = put_object(wallet, file_path, cid, shell=client_shell, expire_at=epoch + 1) + got_file = get_object(wallet, cid, oid, shell=client_shell) assert get_file_hash(got_file) == file_hash with allure.step("Tick two epochs"): @@ -148,12 +193,14 @@ def test_object_api_lifetime(prepare_wallet_and_deposit, request, object_size): with allure.step("Check object deleted because it expires-on epoch"): with pytest.raises(Exception, match=OBJECT_NOT_FOUND): - get_object(wallet, cid, oid) + get_object(wallet, cid, oid, shell=client_shell) -def get_object_and_check_error(wallet: str, cid: str, oid: str, error_pattern: str) -> None: +def get_object_and_check_error( + wallet: str, cid: str, oid: str, error_pattern: str, shell: Shell +) -> None: try: - get_object(wallet=wallet, cid=cid, oid=oid) + get_object(wallet=wallet, cid=cid, oid=oid, shell=shell) raise AssertionError(f"Expected object {oid} removed, but it is not") except Exception as err: logger.info(f"Error is {err}") diff --git a/pytest_tests/testsuites/payment/test_balance.py b/pytest_tests/testsuites/payment/test_balance.py index f1a1d09..de3298b 100644 --- a/pytest_tests/testsuites/payment/test_balance.py +++ b/pytest_tests/testsuites/payment/test_balance.py @@ -3,8 +3,8 @@ import logging import allure import pytest import yaml -from cli_utils import NeofsCli -from common import ASSETS_DIR, FREE_STORAGE, NEOFS_ENDPOINT, WALLET_CONFIG +from common import ASSETS_DIR, FREE_STORAGE, NEOFS_CLI_EXEC, NEOFS_ENDPOINT, WALLET_CONFIG +from neofs_testlib.cli import NeofsCli from python_keywords.payment_neogo import _address_from_wallet from wallet import init_wallet @@ -22,27 +22,27 @@ class TestBalanceAccounting: _, self.another_address, _ = init_wallet(ASSETS_DIR) @allure.title("Test balance request with wallet and address") - def test_balance_wallet_address(self): - cli = NeofsCli(config=WALLET_CONFIG) + def test_balance_wallet_address(self, client_shell): + cli = NeofsCli(client_shell, NEOFS_CLI_EXEC, WALLET_CONFIG) output = cli.accounting.balance( wallet=self.user_wallet, rpc_endpoint=NEOFS_ENDPOINT, address=self.address, ) logger.info(f"Out wallet+address: {output}") - assert int(output.rstrip()) == DEPOSIT_AMOUNT + assert int(output.stdout.rstrip()) == DEPOSIT_AMOUNT @allure.title("Test balance request with wallet only") - def test_balance_wallet(self): - cli = NeofsCli(config=WALLET_CONFIG) + def test_balance_wallet(self, client_shell): + cli = NeofsCli(client_shell, NEOFS_CLI_EXEC, WALLET_CONFIG) output = cli.accounting.balance(wallet=self.user_wallet, rpc_endpoint=NEOFS_ENDPOINT) logger.info(f"Out wallet: {output}") - assert int(output.rstrip()) == DEPOSIT_AMOUNT + assert int(output.stdout.rstrip()) == DEPOSIT_AMOUNT @allure.title("Test balance request with wallet and wrong address") - def test_balance_wrong_address(self): + def test_balance_wrong_address(self, client_shell): with pytest.raises(Exception, match="address option must be specified and valid"): - cli = NeofsCli(config=WALLET_CONFIG) + cli = NeofsCli(client_shell, NEOFS_CLI_EXEC, WALLET_CONFIG) cli.accounting.balance( wallet=self.user_wallet, rpc_endpoint=NEOFS_ENDPOINT, @@ -50,13 +50,13 @@ class TestBalanceAccounting: ) @allure.title("Test balance request with config file") - def test_balance_api(self): + def test_balance_api(self, client_shell): config_file = self.write_api_config(endpoint=NEOFS_ENDPOINT, wallet=self.user_wallet) logger.info(f"YAML: {config_file}") - cli = NeofsCli(config=config_file) + cli = NeofsCli(client_shell, NEOFS_CLI_EXEC, WALLET_CONFIG) output = cli.accounting.balance() - logger.info(f"Out api: {output}") - assert int(output.rstrip()) == DEPOSIT_AMOUNT + logger.info(f"Out api: {output.stdout}") + assert int(output.stdout.rstrip()) == DEPOSIT_AMOUNT @staticmethod @allure.step("Write YAML config") diff --git a/pytest_tests/testsuites/services/test_http_gate.py b/pytest_tests/testsuites/services/test_http_gate.py index 300e1c5..757c14c 100644 --- a/pytest_tests/testsuites/services/test_http_gate.py +++ b/pytest_tests/testsuites/services/test_http_gate.py @@ -17,6 +17,7 @@ from python_keywords.http_gate import ( upload_via_http_gate, upload_via_http_gate_curl, ) +from neofs_testlib.shell import Shell from python_keywords.neofs_verbs import get_object, put_object from python_keywords.storage_policy import get_nodes_without_object from utility import wait_for_gc_pass_on_storage_nodes @@ -46,7 +47,7 @@ class TestHttpGate: TestHttpGate.wallet = prepare_wallet_and_deposit @allure.title("Test Put over gRPC, Get over HTTP") - def test_put_grpc_get_http(self): + def test_put_grpc_get_http(self, client_shell): """ Test that object can be put using gRPC interface and get using HTTP. @@ -61,21 +62,27 @@ class TestHttpGate: Expected result: Hashes must be the same. """ - cid = create_container(self.wallet, rule=self.PLACEMENT_RULE, basic_acl=PUBLIC_ACL) + cid = create_container( + self.wallet, shell=client_shell, rule=self.PLACEMENT_RULE, basic_acl=PUBLIC_ACL + ) file_path_simple, file_path_large = generate_file(), generate_file(COMPLEX_OBJ_SIZE) with allure.step("Put objects using gRPC"): - oid_simple = put_object(wallet=self.wallet, path=file_path_simple, cid=cid) - oid_large = put_object(wallet=self.wallet, path=file_path_large, cid=cid) + oid_simple = put_object( + wallet=self.wallet, path=file_path_simple, cid=cid, shell=client_shell + ) + oid_large = put_object( + wallet=self.wallet, path=file_path_large, cid=cid, shell=client_shell + ) for oid, file_path in ((oid_simple, file_path_simple), (oid_large, file_path_large)): - self.get_object_and_verify_hashes(oid, file_path, self.wallet, cid) + self.get_object_and_verify_hashes(oid, file_path, self.wallet, cid, shell=client_shell) @allure.link("https://github.com/nspcc-dev/neofs-http-gw#uploading", name="uploading") @allure.link("https://github.com/nspcc-dev/neofs-http-gw#downloading", name="downloading") @pytest.mark.sanity @allure.title("Test Put over HTTP, Get over HTTP") - def test_put_http_get_http(self): + def test_put_http_get_http(self, client_shell): """ Test that object can be put and get using HTTP interface. @@ -88,7 +95,9 @@ class TestHttpGate: Expected result: Hashes must be the same. """ - cid = create_container(self.wallet, rule=self.PLACEMENT_RULE, basic_acl=PUBLIC_ACL) + cid = create_container( + self.wallet, shell=client_shell, rule=self.PLACEMENT_RULE, basic_acl=PUBLIC_ACL + ) file_path_simple, file_path_large = generate_file(), generate_file(COMPLEX_OBJ_SIZE) with allure.step("Put objects using HTTP"): @@ -96,7 +105,7 @@ class TestHttpGate: oid_large = upload_via_http_gate(cid=cid, path=file_path_large) for oid, file_path in ((oid_simple, file_path_simple), (oid_large, file_path_large)): - self.get_object_and_verify_hashes(oid, file_path, self.wallet, cid) + self.get_object_and_verify_hashes(oid, file_path, self.wallet, cid, shell=client_shell) @allure.link( "https://github.com/nspcc-dev/neofs-http-gw#by-attributes", name="download by attributes" @@ -111,7 +120,7 @@ class TestHttpGate: ], ids=["simple", "hyphen", "percent"], ) - def test_put_http_get_http_with_headers(self, attributes: dict): + def test_put_http_get_http_with_headers(self, client_shell, attributes: dict): """ Test that object can be downloaded using different attributes in HTTP header. @@ -124,7 +133,9 @@ class TestHttpGate: Expected result: Hashes must be the same. """ - cid = create_container(self.wallet, rule=self.PLACEMENT_RULE, basic_acl=PUBLIC_ACL) + cid = create_container( + self.wallet, shell=client_shell, rule=self.PLACEMENT_RULE, basic_acl=PUBLIC_ACL + ) file_path = generate_file() with allure.step("Put objects using HTTP with attribute"): @@ -136,8 +147,10 @@ class TestHttpGate: self.get_object_by_attr_and_verify_hashes(oid, file_path, cid, attributes) @allure.title("Test Expiration-Epoch in HTTP header") - def test_expiration_epoch_in_http(self): - cid = create_container(self.wallet, rule=self.PLACEMENT_RULE, basic_acl=PUBLIC_ACL) + def test_expiration_epoch_in_http(self, client_shell): + cid = create_container( + self.wallet, shell=client_shell, rule=self.PLACEMENT_RULE, basic_acl=PUBLIC_ACL + ) file_path = generate_file() oids = [] @@ -172,8 +185,10 @@ class TestHttpGate: get_via_http_gate(cid=cid, oid=oid) @allure.title("Test Zip in HTTP header") - def test_zip_in_http(self): - cid = create_container(self.wallet, rule=self.PLACEMENT_RULE, basic_acl=PUBLIC_ACL) + def test_zip_in_http(self, client_shell): + cid = create_container( + self.wallet, shell=client_shell, rule=self.PLACEMENT_RULE, basic_acl=PUBLIC_ACL + ) file_path_simple, file_path_large = generate_file(), generate_file(COMPLEX_OBJ_SIZE) common_prefix = "my_files" @@ -194,11 +209,13 @@ class TestHttpGate: @pytest.mark.curl @pytest.mark.long @allure.title("Test Put over HTTP/Curl, Get over HTTP/Curl for large object") - def test_put_http_get_http_large_file(self): + def test_put_http_get_http_large_file(self, client_shell): """ This test checks upload and download using curl with 'large' object. Large is object with size up to 20Mb. """ - cid = create_container(self.wallet, rule=self.PLACEMENT_RULE, basic_acl=PUBLIC_ACL) + cid = create_container( + self.wallet, shell=client_shell, rule=self.PLACEMENT_RULE, basic_acl=PUBLIC_ACL + ) obj_size = int(os.getenv("BIG_OBJ_SIZE", COMPLEX_OBJ_SIZE)) file_path = generate_file(obj_size) @@ -207,16 +224,18 @@ class TestHttpGate: oid_gate = upload_via_http_gate(cid=cid, path=file_path) oid_curl = upload_via_http_gate_curl(cid=cid, filepath=file_path, large_object=True) - self.get_object_and_verify_hashes(oid_gate, file_path, self.wallet, cid) - self.get_object_and_verify_hashes(oid_curl, file_path, self.wallet, cid, get_via_http_curl) + self.get_object_and_verify_hashes(oid_gate, file_path, self.wallet, cid, shell=client_shell) + self.get_object_and_verify_hashes(oid_curl, file_path, self.wallet, cid, shell=client_shell, object_getter=get_via_http_curl) @pytest.mark.curl @allure.title("Test Put/Get over HTTP using Curl utility") - def test_put_http_get_http_curl(self): + def test_put_http_get_http_curl(self, client_shell): """ Test checks upload and download over HTTP using curl utility. """ - cid = create_container(self.wallet, rule=self.PLACEMENT_RULE, basic_acl=PUBLIC_ACL) + cid = create_container( + self.wallet, shell=client_shell, rule=self.PLACEMENT_RULE, basic_acl=PUBLIC_ACL + ) file_path_simple, file_path_large = generate_file(), generate_file(COMPLEX_OBJ_SIZE) with allure.step("Put objects using curl utility"): @@ -224,7 +243,7 @@ class TestHttpGate: oid_large = upload_via_http_gate_curl(cid=cid, filepath=file_path_large) for oid, file_path in ((oid_simple, file_path_simple), (oid_large, file_path_large)): - self.get_object_and_verify_hashes(oid, file_path, self.wallet, cid, get_via_http_curl) + self.get_object_and_verify_hashes(oid, file_path, self.wallet, cid, shell=client_shell, object_getter=get_via_http_curl) @staticmethod @allure.step("Try to get object and expect error") @@ -251,13 +270,15 @@ class TestHttpGate: @staticmethod @allure.step("Verify object can be get using HTTP") def get_object_and_verify_hashes( - oid: str, file_name: str, wallet: str, cid: str, object_getter=None + oid: str, file_name: str, wallet: str, cid: str, shell: Shell, object_getter=None ) -> None: - nodes = get_nodes_without_object(wallet=wallet, cid=cid, oid=oid) + nodes = get_nodes_without_object(wallet=wallet, cid=cid, oid=oid, shell=shell) random_node = choice(nodes) object_getter = object_getter or get_via_http_gate - got_file_path = get_object(wallet=wallet, cid=cid, oid=oid, endpoint=random_node) + got_file_path = get_object( + wallet=wallet, cid=cid, oid=oid, shell=shell, endpoint=random_node + ) got_file_path_http = object_getter(cid=cid, oid=oid) TestHttpGate._assert_hashes_are_equal(file_name, got_file_path, got_file_path_http) diff --git a/pytest_tests/testsuites/session_token/test_object_session_token.py b/pytest_tests/testsuites/session_token/test_object_session_token.py index eaab0a7..eec422c 100644 --- a/pytest_tests/testsuites/session_token/test_object_session_token.py +++ b/pytest_tests/testsuites/session_token/test_object_session_token.py @@ -2,6 +2,7 @@ import random import allure import pytest +from neofs_testlib.shell import Shell from common import COMPLEX_OBJ_SIZE, NEOFS_NETMAP_DICT, SIMPLE_OBJ_SIZE from file_helper import generate_file from grpc_responses import SESSION_NOT_FOUND @@ -25,7 +26,7 @@ from python_keywords.session_token import create_session_token [SIMPLE_OBJ_SIZE, COMPLEX_OBJ_SIZE], ids=["simple object", "complex object"], ) -def test_object_session_token(prepare_wallet_and_deposit, object_size): +def test_object_session_token(prepare_wallet_and_deposit, client_shell: Shell, object_size): """ Test how operations over objects are executed with a session token @@ -61,18 +62,19 @@ def test_object_session_token(prepare_wallet_and_deposit, object_size): f'AS LOC_{locode}_PLACE FILTER "UN-LOCODE" ' f'EQ "{un_locode}" AS LOC_{locode}' ) - cid = create_container(wallet, rule=placement_policy) + cid = create_container(wallet, shell=client_shell, rule=placement_policy) with allure.step("Put Objects"): file_path = generate_file(object_size) - oid = put_object(wallet=wallet, path=file_path, cid=cid) - oid_delete = put_object(wallet=wallet, path=file_path, cid=cid) + oid = put_object(wallet=wallet, path=file_path, cid=cid, shell=client_shell) + oid_delete = put_object(wallet=wallet, path=file_path, cid=cid, shell=client_shell) with allure.step("Node not in container but granted a session token"): put_object( wallet=wallet, path=file_path, cid=cid, + shell=client_shell, endpoint=session_token_node, session=session_token, ) @@ -80,12 +82,14 @@ def test_object_session_token(prepare_wallet_and_deposit, object_size): wallet=wallet, cid=cid, oid=oid, + shell=client_shell, endpoint=session_token_node, session=session_token, ) search_object( wallet=wallet, cid=cid, + shell=client_shell, endpoint=session_token_node, expected_objects_list=[oid], session=session_token, @@ -94,6 +98,7 @@ def test_object_session_token(prepare_wallet_and_deposit, object_size): wallet=wallet, cid=cid, oid=oid, + shell=client_shell, endpoint=session_token_node, session=session_token, ) @@ -101,6 +106,7 @@ def test_object_session_token(prepare_wallet_and_deposit, object_size): wallet=wallet, cid=cid, oid=oid, + shell=client_shell, range_cut="0:256", endpoint=session_token_node, session=session_token, @@ -109,6 +115,7 @@ def test_object_session_token(prepare_wallet_and_deposit, object_size): wallet=wallet, cid=cid, oid=oid_delete, + shell=client_shell, endpoint=session_token_node, session=session_token, ) @@ -119,6 +126,7 @@ def test_object_session_token(prepare_wallet_and_deposit, object_size): wallet=wallet, path=file_path, cid=cid, + shell=client_shell, endpoint=container_node, session=session_token, ) @@ -126,12 +134,14 @@ def test_object_session_token(prepare_wallet_and_deposit, object_size): wallet=wallet, cid=cid, oid=oid, + shell=client_shell, endpoint=container_node, session=session_token, ) search_object( wallet=wallet, cid=cid, + shell=client_shell, endpoint=container_node, expected_objects_list=[oid], session=session_token, @@ -140,6 +150,7 @@ def test_object_session_token(prepare_wallet_and_deposit, object_size): wallet=wallet, cid=cid, oid=oid, + shell=client_shell, endpoint=container_node, session=session_token, ) @@ -148,6 +159,7 @@ def test_object_session_token(prepare_wallet_and_deposit, object_size): cid=cid, oid=oid, range_cut="0:256", + shell=client_shell, endpoint=container_node, session=session_token, ) @@ -156,6 +168,7 @@ def test_object_session_token(prepare_wallet_and_deposit, object_size): wallet=wallet, cid=cid, oid=oid, + shell=client_shell, endpoint=container_node, session=session_token, ) @@ -166,6 +179,7 @@ def test_object_session_token(prepare_wallet_and_deposit, object_size): wallet=wallet, path=file_path, cid=cid, + shell=client_shell, endpoint=noncontainer_node, session=session_token, ) @@ -173,12 +187,14 @@ def test_object_session_token(prepare_wallet_and_deposit, object_size): wallet=wallet, cid=cid, oid=oid, + shell=client_shell, endpoint=noncontainer_node, session=session_token, ) search_object( wallet=wallet, cid=cid, + shell=client_shell, endpoint=noncontainer_node, expected_objects_list=[oid], session=session_token, @@ -187,6 +203,7 @@ def test_object_session_token(prepare_wallet_and_deposit, object_size): wallet=wallet, cid=cid, oid=oid, + shell=client_shell, endpoint=noncontainer_node, session=session_token, ) @@ -195,6 +212,7 @@ def test_object_session_token(prepare_wallet_and_deposit, object_size): cid=cid, oid=oid, range_cut="0:256", + shell=client_shell, endpoint=noncontainer_node, session=session_token, ) @@ -203,6 +221,7 @@ def test_object_session_token(prepare_wallet_and_deposit, object_size): wallet=wallet, cid=cid, oid=oid, + shell=client_shell, endpoint=noncontainer_node, session=session_token, ) diff --git a/robot/resources/lib/python_keywords/acl.py b/robot/resources/lib/python_keywords/acl.py index 14e74ed..992f7d2 100644 --- a/robot/resources/lib/python_keywords/acl.py +++ b/robot/resources/lib/python_keywords/acl.py @@ -11,9 +11,10 @@ from typing import Any, Dict, List, Optional, Union import allure import base58 from cli_helpers import _cmd_run -from cli_utils import NeofsCli from common import ASSETS_DIR, NEOFS_CLI_EXEC, NEOFS_ENDPOINT, WALLET_CONFIG from data_formatters import get_wallet_public_key +from neofs_testlib.cli import NeofsCli +from neofs_testlib.shell import Shell logger = logging.getLogger("NeoLogger") EACL_LIFETIME = 100500 @@ -76,7 +77,8 @@ class EACLFilters: return ( ",".join( [ - f"{filter.header_type.value}:{filter.key}{filter.match_type.value}{filter.value}" + f"{filter.header_type.value}:" + f"{filter.key}{filter.match_type.value}{filter.value}" for filter in self.filters ] ) @@ -115,22 +117,22 @@ class EACLRule: @allure.title("Get extended ACL") -def get_eacl(wallet_path: str, cid: str) -> Optional[str]: - cli = NeofsCli(config=WALLET_CONFIG) +def get_eacl(wallet_path: str, cid: str, shell: Shell) -> Optional[str]: + cli = NeofsCli(shell, NEOFS_CLI_EXEC, WALLET_CONFIG) try: output = cli.container.get_eacl(wallet=wallet_path, rpc_endpoint=NEOFS_ENDPOINT, cid=cid) except RuntimeError as exc: logger.info("Extended ACL table is not set for this container") logger.info(f"Got exception while getting eacl: {exc}") return None - if "extended ACL table is not set for this container" in output: + if "extended ACL table is not set for this container" in output.stdout: return None - return output + return output.stdout @allure.title("Set extended ACL") -def set_eacl(wallet_path: str, cid: str, eacl_table_path: str) -> None: - cli = NeofsCli(config=WALLET_CONFIG, timeout=60) +def set_eacl(wallet_path: str, cid: str, eacl_table_path: str, shell: Shell) -> None: + cli = NeofsCli(shell, NEOFS_CLI_EXEC, WALLET_CONFIG) cli.container.set_eacl( wallet=wallet_path, rpc_endpoint=NEOFS_ENDPOINT, @@ -145,9 +147,10 @@ def _encode_cid_for_eacl(cid: str) -> str: return base64.b64encode(cid_base58).decode("utf-8") -def create_eacl(cid: str, rules_list: List[EACLRule]) -> str: +def create_eacl(cid: str, rules_list: List[EACLRule], shell: Shell) -> str: table_file_path = f"{os.getcwd()}/{ASSETS_DIR}/eacl_table_{str(uuid.uuid4())}.json" - NeofsCli().acl.extended_create(cid=cid, out=table_file_path, rule=rules_list) + cli = NeofsCli(shell, NEOFS_CLI_EXEC, WALLET_CONFIG) + cli.acl.extended_create(cid=cid, out=table_file_path, rule=rules_list) with open(table_file_path, "r") as file: table_data = file.read() @@ -157,7 +160,7 @@ def create_eacl(cid: str, rules_list: List[EACLRule]) -> str: def form_bearertoken_file( - wif: str, cid: str, eacl_rule_list: List[Union[EACLRule, EACLPubKey]] + wif: str, cid: str, eacl_rule_list: List[Union[EACLRule, EACLPubKey]], shell: Shell ) -> str: """ This function fetches eACL for given on behalf of , @@ -167,7 +170,7 @@ def form_bearertoken_file( enc_cid = _encode_cid_for_eacl(cid) file_path = f"{os.getcwd()}/{ASSETS_DIR}/{str(uuid.uuid4())}" - eacl = get_eacl(wif, cid) + eacl = get_eacl(wif, cid, shell=shell) json_eacl = dict() if eacl: eacl = eacl.replace("eACL: ", "").split("Signature")[0] diff --git a/robot/resources/lib/python_keywords/cli_utils/__init__.py b/robot/resources/lib/python_keywords/cli_utils/__init__.py deleted file mode 100644 index 3647f35..0000000 --- a/robot/resources/lib/python_keywords/cli_utils/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from .adm import CompletionType, NeofsAdm -from .cli import NeofsCli diff --git a/robot/resources/lib/python_keywords/cli_utils/adm/__init__.py b/robot/resources/lib/python_keywords/cli_utils/adm/__init__.py deleted file mode 100644 index 312516f..0000000 --- a/robot/resources/lib/python_keywords/cli_utils/adm/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from .adm import NeofsAdm -from .completion_type import CompletionType diff --git a/robot/resources/lib/python_keywords/cli_utils/adm/adm.py b/robot/resources/lib/python_keywords/cli_utils/adm/adm.py deleted file mode 100644 index a6a3a8f..0000000 --- a/robot/resources/lib/python_keywords/cli_utils/adm/adm.py +++ /dev/null @@ -1,49 +0,0 @@ -from typing import Optional - -from common import NEOFS_ADM_EXEC - -from .completion import NeofsAdmCompletion -from .config import NeofsAdmConfig -from .gendoc import NeofsAdmGenDoc -from .morph import NeofsAdmMorph -from .storage_config import NeofsAdmStorageConfig -from .subnet import NeofsAdmMorphSubnet -from .version import NeofsAdmVersion - - -class NeofsAdm: - neofs_adm_exec_path: Optional[str] = None - config_file: Optional[str] = None - - completion: Optional[NeofsAdmCompletion] = None - config: Optional[NeofsAdmConfig] = None - gendoc: Optional[NeofsAdmGenDoc] = None - morph: Optional[NeofsAdmMorph] = None - subnet: Optional[NeofsAdmMorphSubnet] = None - storage_config: Optional[NeofsAdmStorageConfig] = None - version: Optional[NeofsAdmVersion] = None - - def __init__( - self, - neofs_adm_exec_path: Optional[str] = None, - config_file: Optional[str] = None, - timeout: int = 30, - ): - self.config_file = config_file - self.neofs_adm_exec_path = neofs_adm_exec_path or NEOFS_ADM_EXEC - - self.completion = NeofsAdmCompletion( - self.neofs_adm_exec_path, timeout=timeout, config=config_file - ) - self.config = NeofsAdmConfig(self.neofs_adm_exec_path, timeout=timeout, config=config_file) - self.gendoc = NeofsAdmGenDoc(self.neofs_adm_exec_path, timeout=timeout, config=config_file) - self.morph = NeofsAdmMorph(self.neofs_adm_exec_path, timeout=timeout, config=config_file) - self.subnet = NeofsAdmMorphSubnet( - self.neofs_adm_exec_path, timeout=timeout, config=config_file - ) - self.storage_config = NeofsAdmStorageConfig( - self.neofs_adm_exec_path, timeout=timeout, config=config_file - ) - self.version = NeofsAdmVersion( - self.neofs_adm_exec_path, timeout=timeout, config=config_file - ) diff --git a/robot/resources/lib/python_keywords/cli_utils/adm/completion.py b/robot/resources/lib/python_keywords/cli_utils/adm/completion.py deleted file mode 100644 index 11f0bc0..0000000 --- a/robot/resources/lib/python_keywords/cli_utils/adm/completion.py +++ /dev/null @@ -1,30 +0,0 @@ -from cli_utils.cli_command import NeofsCliCommand - -from .completion_type import CompletionType - - -class NeofsAdmCompletion(NeofsCliCommand): - def get(self, completion_type: CompletionType = CompletionType.FISH) -> str: - """To load completions: - Bash: - $ source <(neofs-adm completion bash) - - Zsh: - If shell completion is not already enabled in your environment you will need - to enable it. You can execute the following once: - $ echo "autoload -U compinit; compinit" >> ~/.zshrc - - You will need to start a new shell for this setup to take effect. - - Fish: - $ neofs-adm completion fish | source - - Args: - completion_type (CompletionType): Select completion type (default: Fish) - - - Returns: - str: Command string - - """ - return self._execute("completion " + completion_type.value) diff --git a/robot/resources/lib/python_keywords/cli_utils/adm/completion_type.py b/robot/resources/lib/python_keywords/cli_utils/adm/completion_type.py deleted file mode 100644 index 7cd0702..0000000 --- a/robot/resources/lib/python_keywords/cli_utils/adm/completion_type.py +++ /dev/null @@ -1,8 +0,0 @@ -from enum import Enum - - -class CompletionType(Enum): - BASH = "bash" - ZHS = "zsh" - FISH = "fish" - POWERSHELL = "powershell" diff --git a/robot/resources/lib/python_keywords/cli_utils/adm/config.py b/robot/resources/lib/python_keywords/cli_utils/adm/config.py deleted file mode 100644 index cf5b06a..0000000 --- a/robot/resources/lib/python_keywords/cli_utils/adm/config.py +++ /dev/null @@ -1,19 +0,0 @@ -from cli_utils.cli_command import NeofsCliCommand - - -class NeofsAdmConfig(NeofsCliCommand): - def init(self, path: str = "~/.neofs/adm/config.yml") -> str: - """Initialize basic neofs-adm configuration file. - - Args: - path (str): path to config (default ~/.neofs/adm/config.yml) - - - Returns: - str: Command string - - """ - return self._execute( - "config init", - **{param: value for param, value in locals().items() if param not in ["self"]}, - ) diff --git a/robot/resources/lib/python_keywords/cli_utils/adm/gendoc.py b/robot/resources/lib/python_keywords/cli_utils/adm/gendoc.py deleted file mode 100644 index 9ed0040..0000000 --- a/robot/resources/lib/python_keywords/cli_utils/adm/gendoc.py +++ /dev/null @@ -1,40 +0,0 @@ -from typing import Optional - -from cli_utils.cli_command import NeofsCliCommand - - -class NeofsAdmGenDoc(NeofsCliCommand): - def get( - self, doc_file: str, depth: int = 1, doc_type: str = "md", extension: Optional[str] = None - ) -> str: - """Generate documentation for this command. If the template is not provided, - builtin cobra generator is used and each subcommand is placed in - a separate file in the same directory. - - The last optional argument specifies the template to use with text/template. - In this case there is a number of helper functions which can be used: - replace STR FROM TO -- same as strings.ReplaceAll - join ARRAY SEPARATOR -- same as strings.Join - split STR SEPARATOR -- same as strings.Split - fullUse CMD -- slice of all command names starting from the parent - listFlags CMD -- list of command flags - - Args: - depth (int): if template is specified, unify all commands starting from depth in a single file. - Default = 1. - doc_file (str): file where to save generated documentation - extension (str): if the template is specified, string to append to the output file names - doc_type (str): type for the documentation ('md' or 'man') (default "md") - - Returns: - str: Command string - - """ - return self._execute( - f"gendoc {doc_file}", - **{ - param: value - for param, value in locals().items() - if param not in ["self", "doc_file"] - }, - ) diff --git a/robot/resources/lib/python_keywords/cli_utils/adm/morph.py b/robot/resources/lib/python_keywords/cli_utils/adm/morph.py deleted file mode 100644 index 0deee52..0000000 --- a/robot/resources/lib/python_keywords/cli_utils/adm/morph.py +++ /dev/null @@ -1,308 +0,0 @@ -from typing import Optional - -from cli_utils.cli_command import NeofsCliCommand - - -class NeofsAdmMorph(NeofsCliCommand): - def deposit_notary( - self, - rpc_endpoint: str, - account: str, - gas: str, - storage_wallet: Optional[str] = None, - till: Optional[str] = None, - ) -> str: - """ - Deposit GAS for notary service. - - Args: - account (str): wallet account address - gas (str): amount of GAS to deposit - rpc_endpoint (str): N3 RPC node endpoint - storage_wallet (str): path to storage node wallet - till (str): notary deposit duration in blocks - - Returns: - str: Command string - """ - return self._execute( - "morph deposit-notary", - **{param: value for param, value in locals().items() if param not in ["self"]}, - ) - - def dump_balances( - self, - rpc_endpoint: str, - alphabet: Optional[str] = None, - proxy: Optional[str] = None, - script_hash: Optional[str] = None, - storage: Optional[str] = None, - ) -> str: - """ - Dump GAS balances. - - Args: - alphabet (str): dump balances of alphabet contracts - proxy (str): dump balances of the proxy contract - rpc_endpoint (str): N3 RPC node endpoint - script_hash (str): use script-hash format for addresses - storage (str): dump balances of storage nodes from the current netmap - - Returns: - str: Command string - """ - return self._execute( - "morph dump-balances", - **{param: value for param, value in locals().items() if param not in ["self"]}, - ) - - def dump_config(self, rpc_endpoint: str) -> str: - """ - Dump NeoFS network config. - - Args: - rpc_endpoint (str): N3 RPC node endpoint - - Returns: - str: Command string - """ - return self._execute( - "morph dump-config", - **{param: value for param, value in locals().items() if param not in ["self"]}, - ) - - def dump_containers( - self, - rpc_endpoint: str, - cid: Optional[str] = None, - container_contract: Optional[str] = None, - dump: Optional[str] = None, - ) -> str: - """ - Dump NeoFS containers to file. - - Args: - cid (str): containers to dump - container_contract (str): container contract hash (for networks without NNS) - dump (str): file where to save dumped containers - rpc_endpoint (str): N3 RPC node endpoint - - Returns: - str: Command string - """ - return self._execute( - "morph dump-containers", - **{param: value for param, value in locals().items() if param not in ["self"]}, - ) - - def dump_hashes(self, rpc_endpoint: str) -> str: - """ - Dump deployed contract hashes. - - Args: - rpc_endpoint (str): N3 RPC node endpoint - - Returns: - str: Command string - """ - return self._execute( - "morph dump-hashes", - **{param: value for param, value in locals().items() if param not in ["self"]}, - ) - - def force_new_epoch( - self, rpc_endpoint: Optional[str] = None, alphabet: Optional[str] = None - ) -> str: - """ - Create new NeoFS epoch event in the side chain - - Args: - alphabet (str): path to alphabet wallets dir - rpc_endpoint (str): N3 RPC node endpoint - - Returns: - str: Command string - """ - return self._execute( - "morph force-new-epoch", - **{param: value for param, value in locals().items() if param not in ["self"]}, - ) - - def generate_alphabet(self, rpc_endpoint: str, alphabet_wallets: str, size: int = 7) -> str: - """ - Generate alphabet wallets for consensus nodes of the morph network. - - Args: - alphabet_wallets (str): path to alphabet wallets dir - size (int): amount of alphabet wallets to generate (default 7) - rpc_endpoint (str): N3 RPC node endpoint - - Returns: - str: Command string - """ - return self._execute( - "morph generate-alphabet", - **{param: value for param, value in locals().items() if param not in ["self"]}, - ) - - def generate_storage_wallet( - self, - rpc_endpoint: str, - alphabet_wallets: str, - storage_wallet: str, - initial_gas: Optional[str] = None, - ) -> str: - """ - Generate storage node wallet for the morph network. - - Args: - alphabet_wallets (str): path to alphabet wallets dir - initial_gas (str): initial amount of GAS to transfer - rpc_endpoint (str): N3 RPC node endpoint - storage_wallet (str): path to new storage node wallet - - Returns: - str: Command string - """ - return self._execute( - "morph generate-storage-wallet", - **{param: value for param, value in locals().items() if param not in ["self"]}, - ) - - def init( - self, - rpc_endpoint: str, - alphabet_wallets: str, - contracts: str, - protocol: str, - container_alias_fee: int = 500, - container_fee: int = 1000, - epoch_duration: int = 240, - homomorphic_disabled: bool = False, - local_dump: Optional[str] = None, - max_object_size: int = 67108864, - ) -> str: - """ - Initialize side chain network with smart-contracts and network settings. - - Args: - alphabet_wallets (str): path to alphabet wallets dir - container_alias_fee (int): container alias fee (default 500) - container_fee (int): container registration fee (default 1000) - contracts (str): path to archive with compiled NeoFS contracts - (default fetched from latest github release) - epoch_duration (int): amount of side chain blocks in one NeoFS epoch (default 240) - homomorphic_disabled: (bool): disable object homomorphic hashing - local_dump (str): path to the blocks dump file - max_object_size (int): max single object size in bytes (default 67108864) - protocol (str): path to the consensus node configuration - rpc_endpoint (str): N3 RPC node endpoint - - Returns: - str: Command string - """ - return self._execute( - "morph init", - **{param: value for param, value in locals().items() if param not in ["self"]}, - ) - - def refill_gas( - self, - rpc_endpoint: str, - alphabet_wallets: str, - storage_wallet: str, - gas: Optional[str] = None, - ) -> str: - """ - Refill GAS of storage node's wallet in the morph network. - - Args: - alphabet_wallets (str): path to alphabet wallets dir - gas (str): additional amount of GAS to transfer - rpc_endpoint (str): N3 RPC node endpoint - storage_wallet (str): path to new storage node wallet - - Returns: - str: Command string - """ - return self._execute( - "morph refill-gas", - **{param: value for param, value in locals().items() if param not in ["self"]}, - ) - - def restore_containers( - self, rpc_endpoint: str, alphabet_wallets: str, cid: str, dump: str - ) -> str: - """ - Restore NeoFS containers from file. - - Args: - alphabet_wallets (str): path to alphabet wallets dir - cid (str): containers to restore - dump (str): file to restore containers from - rpc_endpoint (str): N3 RPC node endpoint - - Returns: - str: Command string - """ - return self._execute( - "morph restore-containers", - **{param: value for param, value in locals().items() if param not in ["self"]}, - ) - - def set_policy( - self, - rpc_endpoint: str, - alphabet_wallets: str, - exec_fee_factor: Optional[int] = None, - storage_price: Optional[int] = None, - fee_per_byte: Optional[int] = None, - ) -> str: - """ - Set global policy values. - - Args: - alphabet_wallets (str): path to alphabet wallets dir - exec_fee_factor (int): ExecFeeFactor= - storage_price (int): StoragePrice= - fee_per_byte (int): FeePerByte= - rpc_endpoint (str): N3 RPC node endpoint - - Returns: - str: Command string - """ - non_param_attribute = "" - if exec_fee_factor: - non_param_attribute += f"ExecFeeFactor={exec_fee_factor} " - if storage_price: - non_param_attribute += f"StoragePrice={storage_price} " - if fee_per_byte: - non_param_attribute += f"FeePerByte={fee_per_byte} " - return self._execute( - f"morph restore-containers {non_param_attribute}", - **{ - param: value - for param, value in locals().items() - if param not in ["self", "exec_fee_factor", "storage_price", "fee_per_byte"] - }, - ) - - def update_contracts( - self, rpc_endpoint: str, alphabet_wallets: str, contracts: Optional[str] = None - ) -> str: - """ - Update NeoFS contracts. - - Args: - alphabet_wallets (str): path to alphabet wallets dir - contracts (str): path to archive with compiled NeoFS contracts - (default fetched from latest github release) - rpc_endpoint (str): N3 RPC node endpoint - - Returns: - str: Command string - """ - return self._execute( - "morph update-contracts", - **{param: value for param, value in locals().items() if param not in ["self"]}, - ) diff --git a/robot/resources/lib/python_keywords/cli_utils/adm/storage_config.py b/robot/resources/lib/python_keywords/cli_utils/adm/storage_config.py deleted file mode 100644 index b241ecb..0000000 --- a/robot/resources/lib/python_keywords/cli_utils/adm/storage_config.py +++ /dev/null @@ -1,20 +0,0 @@ -from cli_utils.cli_command import NeofsCliCommand - - -class NeofsAdmStorageConfig(NeofsCliCommand): - def set(self, account: str, wallet: str) -> str: - """Initialize basic neofs-adm configuration file. - - Args: - account (str): wallet account - wallet (str): path to wallet - - - Returns: - str: Command string - - """ - return self._execute( - "storage-config", - **{param: value for param, value in locals().items() if param not in ["self"]}, - ) diff --git a/robot/resources/lib/python_keywords/cli_utils/adm/subnet.py b/robot/resources/lib/python_keywords/cli_utils/adm/subnet.py deleted file mode 100644 index 8ba1d84..0000000 --- a/robot/resources/lib/python_keywords/cli_utils/adm/subnet.py +++ /dev/null @@ -1,210 +0,0 @@ -from typing import Optional - -from cli_utils.cli_command import NeofsCliCommand - - -class NeofsAdmMorphSubnet(NeofsCliCommand): - def create(self, rpc_endpoint: str, address: str, wallet: str, notary: bool = False) -> str: - """Create NeoFS subnet. - - Args: - address (str): Address in the wallet, optional - notary (bool): Flag to create subnet in notary environment - rpc_endpoint (str): N3 RPC node endpoint - wallet (str): Path to file with wallet - - - Returns: - str: Command string - - """ - return self._execute( - "morph subnet create", - **{param: value for param, value in locals().items() if param not in ["self"]}, - ) - - def get(self, rpc_endpoint: str, subnet: str) -> str: - """ - Read information about the NeoFS subnet. - - Args: - rpc_endpoint (str): N3 RPC node endpoint - subnet (str): ID of the subnet to read - - Returns: - str: Command string - """ - return self._execute( - "morph subnet get", - **{param: value for param, value in locals().items() if param not in ["self"]}, - ) - - def remove( - self, rpc_endpoint: str, wallet: str, subnet: str, address: Optional[str] = None - ) -> str: - """ - Remove NeoFS subnet. - - Args: - address (str): Address in the wallet, optional - rpc_endpoint (str): N3 RPC node endpoint - subnet (str): ID of the subnet to read - wallet (str): Path to file with wallet - - Returns: - str: Command string - """ - return self._execute( - "morph subnet remove", - **{param: value for param, value in locals().items() if param not in ["self"]}, - ) - - def admin_add( - self, - rpc_endpoint: str, - wallet: str, - admin: str, - subnet: str, - client: Optional[str] = None, - group: Optional[str] = None, - address: Optional[str] = None, - ) -> str: - """ - Add admin to the NeoFS subnet. - - Args: - address (str): Address in the wallet, optional - admin (str): Hex-encoded public key of the admin - client (str): Add client admin instead of node one - group (str): Client group ID in text format (needed with --client only) - rpc_endpoint (str): N3 RPC node endpoint - subnet (str): ID of the subnet to read - wallet (str): Path to file with wallet - - Returns: - str: Command string - """ - return self._execute( - "morph subnet admin add", - **{param: value for param, value in locals().items() if param not in ["self"]}, - ) - - def admin_remove( - self, - rpc_endpoint: str, - wallet: str, - admin: str, - subnet: str, - client: Optional[str] = None, - address: Optional[str] = None, - ) -> str: - """ - Remove admin of the NeoFS subnet. - - Args: - address (str): Address in the wallet, optional - admin (str): Hex-encoded public key of the admin - client (str): Remove client admin instead of node one - rpc_endpoint (str): N3 RPC node endpoint - subnet (str): ID of the subnet to read - wallet (str): Path to file with wallet - - Returns: - str: Command string - """ - return self._execute( - "morph subnet admin remove", - **{param: value for param, value in locals().items() if param not in ["self"]}, - ) - - def client_add( - self, - rpc_endpoint: str, - wallet: str, - subnet: str, - client: Optional[str] = None, - group: Optional[str] = None, - address: Optional[str] = None, - ) -> str: - """ - Add client to the NeoFS subnet. - - Args: - address (str): Address in the wallet, optional - client (str): Add client admin instead of node one - group (str): Client group ID in text format (needed with --client only) - rpc_endpoint (str): N3 RPC node endpoint - subnet (str): ID of the subnet to read - wallet (str): Path to file with wallet - - Returns: - str: Command string - """ - return self._execute( - "morph subnet client add", - **{param: value for param, value in locals().items() if param not in ["self"]}, - ) - - def client_remove( - self, - rpc_endpoint: str, - wallet: str, - client: str, - group: str, - subnet: str, - address: Optional[str] = None, - ) -> str: - """ - Remove client of the NeoFS subnet. - - Args: - address (str): Address in the wallet, optional - client (str): Remove client admin instead of node one - group (str): ID of the client group to work with - rpc_endpoint (str): N3 RPC node endpoint - subnet (str): ID of the subnet to read - wallet (str): Path to file with wallet - - Returns: - str: Command string - """ - return self._execute( - "morph subnet client remove", - **{param: value for param, value in locals().items() if param not in ["self"]}, - ) - - def node_add(self, rpc_endpoint: str, wallet: str, node: str, subnet: str) -> str: - """ - Add node to the NeoFS subnet. - - Args: - node (str): Hex-encoded public key of the node - rpc_endpoint (str): N3 RPC node endpoint - subnet (str): ID of the subnet to read - wallet (str): Path to file with wallet - - Returns: - str: Command string - """ - return self._execute( - "morph subnet node add", - **{param: value for param, value in locals().items() if param not in ["self"]}, - ) - - def node_remove(self, rpc_endpoint: str, wallet: str, node: str, subnet: str) -> str: - """ - Remove node from the NeoFS subnet. - - Args: - node (str): Hex-encoded public key of the node - rpc_endpoint (str): N3 RPC node endpoint - subnet (str): ID of the subnet to read - wallet (str): Path to file with wallet - - Returns: - str: Command string - """ - return self._execute( - "morph subnet node remove", - **{param: value for param, value in locals().items() if param not in ["self"]}, - ) diff --git a/robot/resources/lib/python_keywords/cli_utils/adm/version.py b/robot/resources/lib/python_keywords/cli_utils/adm/version.py deleted file mode 100644 index d307e7a..0000000 --- a/robot/resources/lib/python_keywords/cli_utils/adm/version.py +++ /dev/null @@ -1,12 +0,0 @@ -from cli_utils.cli_command import NeofsCliCommand - - -class NeofsAdmVersion(NeofsCliCommand): - def get(self) -> str: - """Application version - - Returns: - str: Command string - - """ - return self._execute("", version=True) diff --git a/robot/resources/lib/python_keywords/cli_utils/cli/__init__.py b/robot/resources/lib/python_keywords/cli_utils/cli/__init__.py deleted file mode 100644 index 8627b23..0000000 --- a/robot/resources/lib/python_keywords/cli_utils/cli/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .cli import NeofsCli diff --git a/robot/resources/lib/python_keywords/cli_utils/cli/accounting.py b/robot/resources/lib/python_keywords/cli_utils/cli/accounting.py deleted file mode 100644 index de2bb90..0000000 --- a/robot/resources/lib/python_keywords/cli_utils/cli/accounting.py +++ /dev/null @@ -1,29 +0,0 @@ -from typing import Optional - -from cli_utils.cli_command import NeofsCliCommand - - -class NeofsCliAccounting(NeofsCliCommand): - def balance( - self, - wallet: Optional[str] = None, - rpc_endpoint: Optional[str] = None, - address: Optional[str] = None, - owner: Optional[str] = None, - ) -> str: - """Get internal balance of NeoFS account - - Args: - address: address of wallet account - owner: owner of balance account (omit to use owner from private key) - rpc_endpoint: remote node address (as 'multiaddr' or ':') - wallet: WIF (NEP-2) string or path to the wallet or binary key - - Returns: - str: Command string - - """ - return self._execute( - "accounting balance", - **{param: value for param, value in locals().items() if param not in ["self"]}, - ) diff --git a/robot/resources/lib/python_keywords/cli_utils/cli/acl.py b/robot/resources/lib/python_keywords/cli_utils/cli/acl.py deleted file mode 100644 index eaa5cee..0000000 --- a/robot/resources/lib/python_keywords/cli_utils/cli/acl.py +++ /dev/null @@ -1,49 +0,0 @@ -from typing import Optional - -from cli_utils.cli_command import NeofsCliCommand - - -class NeofsCliACL(NeofsCliCommand): - def extended_create( - self, cid: str, out: str, file: Optional[str] = None, rule: Optional[list] = None - ) -> str: - - """Create extended ACL from the text representation. - - Rule consist of these blocks: [ ...] [ ...] - Action is 'allow' or 'deny'. - Operation is an object service verb: 'get', 'head', 'put', 'search', 'delete', 'getrange', or 'getrangehash'. - - Filter consists of : - Typ is 'obj' for object applied filter or 'req' for request applied filter. - Key is a valid unicode string corresponding to object or request header key. - Well-known system object headers start with '$Object:' prefix. - User defined headers start without prefix. - Read more about filter keys at: - http://github.com/nspcc-dev/neofs-api/blob/master/proto-docs/acl.md#message-eaclrecordfilter - Match is '=' for matching and '!=' for non-matching filter. - Value is a valid unicode string corresponding to object or request header value. - - Target is - 'user' for container owner, - 'system' for Storage nodes in container and Inner Ring nodes, - 'others' for all other request senders, - 'pubkey:,,...' for exact request sender, where is a hex-encoded 33-byte public key. - - When both '--rule' and '--file' arguments are used, '--rule' records will be placed higher in resulting - extended ACL table. - - Args: - cid: Container ID - file: Read list of extended ACL table records from from text file - out: Save JSON formatted extended ACL table in file - rule: Extended ACL table record to apply - - Returns: - str: Command string - - """ - return self._execute( - "acl extended create", - **{param: value for param, value in locals().items() if param not in ["self"]}, - ) diff --git a/robot/resources/lib/python_keywords/cli_utils/cli/cli.py b/robot/resources/lib/python_keywords/cli_utils/cli/cli.py deleted file mode 100644 index 6b1fda5..0000000 --- a/robot/resources/lib/python_keywords/cli_utils/cli/cli.py +++ /dev/null @@ -1,33 +0,0 @@ -from typing import Optional - -from cli_utils.cli.netmap import NeofsCliNetmap -from common import NEOFS_CLI_EXEC - -from .accounting import NeofsCliAccounting -from .acl import NeofsCliACL -from .container import NeofsCliContainer -from .object import NeofsCliObject -from .version import NeofsCliVersion - - -class NeofsCli: - accounting: NeofsCliAccounting - acl: NeofsCliACL - container: NeofsCliContainer - netmap: NeofsCliNetmap - object: NeofsCliObject - version: NeofsCliVersion - - def __init__( - self, - neofs_cli_exec_path: Optional[str] = None, - config: Optional[str] = None, - timeout: int = 30, - ): - neofs_cli_exec_path = neofs_cli_exec_path or NEOFS_CLI_EXEC - self.accounting = NeofsCliAccounting(neofs_cli_exec_path, timeout=timeout, config=config) - self.acl = NeofsCliACL(neofs_cli_exec_path, timeout=timeout, config=config) - self.container = NeofsCliContainer(neofs_cli_exec_path, timeout=timeout, config=config) - self.netmap = NeofsCliNetmap(neofs_cli_exec_path, timeout=timeout, config=config) - self.object = NeofsCliObject(neofs_cli_exec_path, timeout=timeout, config=config) - self.version = NeofsCliVersion(neofs_cli_exec_path, timeout=timeout, config=config) diff --git a/robot/resources/lib/python_keywords/cli_utils/cli/container.py b/robot/resources/lib/python_keywords/cli_utils/cli/container.py deleted file mode 100644 index 239aa8c..0000000 --- a/robot/resources/lib/python_keywords/cli_utils/cli/container.py +++ /dev/null @@ -1,248 +0,0 @@ -from typing import Optional - -from cli_utils.cli_command import NeofsCliCommand - - -class NeofsCliContainer(NeofsCliCommand): - def create( - self, - rpc_endpoint: str, - wallet: str, - address: Optional[str] = None, - attributes: Optional[dict] = None, - basic_acl: Optional[str] = None, - await_mode: bool = False, - disable_timestamp: bool = False, - name: Optional[str] = None, - nonce: Optional[str] = None, - policy: Optional[str] = None, - session: Optional[str] = None, - subnet: Optional[str] = None, - ttl: Optional[int] = None, - xhdr: Optional[dict] = None, - ) -> str: - """ - Create a new container and register it in the NeoFS. - It will be stored in the sidechain when the Inner Ring accepts it. - - Args: - address: address of wallet account - attributes: comma separated pairs of container attributes in form of Key1=Value1,Key2=Value2 - await_mode: block execution until container is persisted - basic_acl: hex encoded basic ACL value or keywords like 'public-read-write', 'private', - 'eacl-public-read' (default "private") - disable_timestamp: disable timestamp container attribute - name: container name attribute - nonce: UUIDv4 nonce value for container - policy: QL-encoded or JSON-encoded placement policy or path to file with it - rpc_endpoint: remote node address (as 'multiaddr' or ':') - session: path to a JSON-encoded container session token - subnet: string representation of container subnetwork - ttl: TTL value in request meta header (default 2) - wallet: WIF (NEP-2) string or path to the wallet or binary key - xhdr: Request X-Headers in form of Key=Value - - Returns: - str: Command string - """ - return self._execute( - "container create", - **{param: value for param, value in locals().items() if param not in ["self"]}, - ) - - def delete( - self, - rpc_endpoint: str, - wallet: str, - cid: str, - address: Optional[str] = None, - await_mode: bool = False, - session: Optional[str] = None, - ttl: Optional[int] = None, - xhdr: Optional[dict] = None, - force: bool = False, - ) -> str: - """ - Delete an existing container. - Only the owner of the container has permission to remove the container. - - Args: - address: address of wallet account - await_mode: block execution until container is removed - cid: container ID - force: do not check whether container contains locks and remove immediately - rpc_endpoint: remote node address (as 'multiaddr' or ':') - session: path to a JSON-encoded container session token - ttl: TTL value in request meta header (default 2) - wallet: WIF (NEP-2) string or path to the wallet or binary key - xhdr: Request X-Headers in form of Key=Value - - Returns: - str: Command string - """ - - return self._execute( - "container delete", - **{param: value for param, value in locals().items() if param not in ["self"]}, - ) - - def get( - self, - rpc_endpoint: str, - wallet: str, - cid: str, - address: Optional[str] = None, - await_mode: bool = False, - to: Optional[str] = None, - json_mode: bool = False, - ttl: Optional[int] = None, - xhdr: Optional[dict] = None, - ) -> str: - """ - Get container field info. - - Args: - address: address of wallet account - await_mode: block execution until container is removed - cid: container ID - json_mode: print or dump container in JSON format - rpc_endpoint: remote node address (as 'multiaddr' or ':') - to: path to dump encoded container - ttl: TTL value in request meta header (default 2) - wallet: WIF (NEP-2) string or path to the wallet or binary key - xhdr: Request X-Headers in form of Key=Value - - Returns: - str: Command string - """ - return self._execute( - "container get", - **{param: value for param, value in locals().items() if param not in ["self"]}, - ) - - def get_eacl( - self, - rpc_endpoint: str, - wallet: str, - cid: str, - address: Optional[str] = None, - await_mode: bool = False, - to: Optional[str] = None, - session: Optional[str] = None, - ttl: Optional[int] = None, - xhdr: Optional[dict] = None, - ) -> str: - """ - Get extended ACL table of container. - - Args: - address: address of wallet account - await_mode: block execution until container is removed - cid: container ID - rpc_endpoint: remote node address (as 'multiaddr' or ':') - to: path to dump encoded container - session: path to a JSON-encoded container session token - ttl: TTL value in request meta header (default 2) - wallet: WIF (NEP-2) string or path to the wallet or binary key - xhdr: Request X-Headers in form of Key=Value - - Returns: - str: Command string - - """ - return self._execute( - "container get-eacl", - **{param: value for param, value in locals().items() if param not in ["self"]}, - ) - - def list( - self, - rpc_endpoint: str, - wallet: str, - address: Optional[str] = None, - owner: Optional[str] = None, - ttl: Optional[int] = None, - xhdr: Optional[dict] = None, - **params, - ) -> str: - """ - List all created containers. - - Args: - address: address of wallet account - owner: owner of containers (omit to use owner from private key) - rpc_endpoint: remote node address (as 'multiaddr' or ':') - ttl: TTL value in request meta header (default 2) - wallet: WIF (NEP-2) string or path to the wallet or binary key - xhdr: Request X-Headers in form of Key=Value - - Returns: - str: Command string - """ - return self._execute( - "container list", - **{param: value for param, value in locals().items() if param not in ["self"]}, - ) - - def list_objects( - self, - rpc_endpoint: str, - wallet: str, - cid: str, - address: Optional[str] = None, - ttl: Optional[int] = None, - xhdr: Optional[dict] = None, - ) -> str: - """ - List existing objects in container. - - Args: - address: address of wallet account - cid: container ID - rpc_endpoint: remote node address (as 'multiaddr' or ':') - ttl: TTL value in request meta header (default 2) - wallet: WIF (NEP-2) string or path to the wallet or binary key - xhdr: Request X-Headers in form of Key=Value - - Returns: - str: Command string - """ - return self._execute( - "container list-objects", - **{param: value for param, value in locals().items() if param not in ["self"]}, - ) - - def set_eacl( - self, - rpc_endpoint: str, - wallet: str, - cid: str, - address: Optional[str] = None, - await_mode: bool = False, - table: Optional[str] = None, - session: Optional[str] = None, - ttl: Optional[int] = None, - xhdr: Optional[dict] = None, - ) -> str: - """ - Set a new extended ACL table for the container. - Container ID in the EACL table will be substituted with the ID from the CLI. - - Args: - address: address of wallet account - await_mode: block execution until container is removed - cid: container ID - rpc_endpoint: remote node address (as 'multiaddr' or ':') - session: path to a JSON-encoded container session token - table: path to file with JSON or binary encoded EACL table - ttl: TTL value in request meta header (default 2) - wallet: WIF (NEP-2) string or path to the wallet or binary key - xhdr: Request X-Headers in form of Key=Value - - Returns: - str: Command string - """ - return self._execute( - "container set-eacl", - **{param: value for param, value in locals().items() if param not in ["self"]}, - ) diff --git a/robot/resources/lib/python_keywords/cli_utils/cli/netmap.py b/robot/resources/lib/python_keywords/cli_utils/cli/netmap.py deleted file mode 100644 index 98cb26c..0000000 --- a/robot/resources/lib/python_keywords/cli_utils/cli/netmap.py +++ /dev/null @@ -1,119 +0,0 @@ -from typing import Optional - -from cli_utils.cli_command import NeofsCliCommand - - -class NeofsCliNetmap(NeofsCliCommand): - def epoch( - self, - rpc_endpoint: str, - wallet: str, - address: Optional[str] = None, - generate_key: bool = False, - ttl: Optional[int] = None, - xhdr: Optional[dict] = None, - ) -> str: - """ - Get current epoch number. - - Args: - address: address of wallet account - generate_key: generate new private key - rpc_endpoint: remote node address (as 'multiaddr' or ':') - ttl: TTL value in request meta header (default 2) - wallet: path to the wallet or binary key - xhdr: request X-Headers in form of Key=Value - - Returns: - str: Raw command output - """ - return self._execute( - "netmap epoch", - **{param: value for param, value in locals().items() if param not in ["self"]}, - ) - - def netinfo( - self, - rpc_endpoint: str, - wallet: str, - address: Optional[str] = None, - generate_key: bool = False, - ttl: Optional[int] = None, - xhdr: Optional[dict] = None, - ) -> str: - """ - Get information about NeoFS network. - - Args: - address: address of wallet account - generate_key: generate new private key - rpc_endpoint: remote node address (as 'multiaddr' or ':') - ttl: TTL value in request meta header (default 2) - wallet: path to the wallet or binary key - xhdr: request X-Headers in form of Key=Value - - Returns: - str: Raw command output - """ - return self._execute( - "netmap netinfo", - **{param: value for param, value in locals().items() if param not in ["self"]}, - ) - - def nodeinfo( - self, - rpc_endpoint: str, - wallet: str, - address: Optional[str] = None, - generate_key: bool = False, - json: bool = False, - ttl: Optional[int] = None, - xhdr: Optional[dict] = None, - ) -> str: - """ - Get target node info. - - Args: - address: address of wallet account - generate_key: generate new private key - json: print node info in JSON format - rpc_endpoint: remote node address (as 'multiaddr' or ':') - ttl: TTL value in request meta header (default 2) - wallet: path to the wallet or binary key - xhdr: request X-Headers in form of Key=Value - - Returns: - str: Raw command output - """ - return self._execute( - "netmap nodeinfo", - **{param: value for param, value in locals().items() if param not in ["self"]}, - ) - - def snapshot( - self, - rpc_endpoint: str, - wallet: str, - address: Optional[str] = None, - generate_key: bool = False, - ttl: Optional[int] = None, - xhdr: Optional[dict] = None, - ) -> str: - """ - Request current local snapshot of the network map. - - Args: - address: address of wallet account - generate_key: generate new private key - rpc_endpoint: remote node address (as 'multiaddr' or ':') - ttl: TTL value in request meta header (default 2) - wallet: path to the wallet or binary key - xhdr: request X-Headers in form of Key=Value - - Returns: - str: Raw command output - """ - return self._execute( - "netmap snapshot", - **{param: value for param, value in locals().items() if param not in ["self"]}, - ) diff --git a/robot/resources/lib/python_keywords/cli_utils/cli/object.py b/robot/resources/lib/python_keywords/cli_utils/cli/object.py deleted file mode 100644 index 03e679f..0000000 --- a/robot/resources/lib/python_keywords/cli_utils/cli/object.py +++ /dev/null @@ -1,329 +0,0 @@ -from typing import Optional - -from cli_utils.cli_command import NeofsCliCommand - - -class NeofsCliObject(NeofsCliCommand): - def delete( - self, - rpc_endpoint: str, - wallet: str, - cid: str, - oid: str, - address: Optional[str] = None, - bearer: Optional[str] = None, - session: Optional[str] = None, - ttl: Optional[int] = None, - xhdr: Optional[dict] = None, - ) -> str: - """ - Delete object from NeoFS. - - Args: - address: address of wallet account - bearer: File with signed JSON or binary encoded bearer token - cid: Container ID - oid: Object ID - rpc_endpoint: remote node address (as 'multiaddr' or ':') - session: path to a JSON-encoded container session token - ttl: TTL value in request meta header (default 2) - wallet: WIF (NEP-2) string or path to the wallet or binary key - xhdr: Request X-Headers in form of Key=Value - - Returns: - str: Command string - """ - return self._execute( - "object delete", - **{param: value for param, value in locals().items() if param not in ["self"]}, - ) - - def get( - self, - rpc_endpoint: str, - wallet: str, - cid: str, - oid: str, - address: Optional[str] = None, - bearer: Optional[str] = None, - file: Optional[str] = None, - header: Optional[str] = None, - no_progress: bool = False, - raw: bool = False, - session: Optional[str] = None, - ttl: Optional[int] = None, - xhdr: Optional[dict] = None, - ) -> str: - """ - Get object from NeoFS. - - Args: - address: address of wallet account - bearer: File with signed JSON or binary encoded bearer token - cid: Container ID - file: File to write object payload to. Default: stdout. - header: File to write header to. Default: stdout. - no_progress: Do not show progress bar - oid: Object ID - raw: Set raw request option - rpc_endpoint: remote node address (as 'multiaddr' or ':') - session: path to a JSON-encoded container session token - ttl: TTL value in request meta header (default 2) - wallet: WIF (NEP-2) string or path to the wallet or binary key - xhdr: Request X-Headers in form of Key=Value - - Returns: - str: Command string - """ - return self._execute( - "object get", - **{param: value for param, value in locals().items() if param not in ["self"]}, - ) - - def hash( - self, - rpc_endpoint: str, - wallet: str, - cid: str, - oid: str, - address: Optional[str] = None, - bearer: Optional[str] = None, - range: Optional[str] = None, - salt: Optional[str] = None, - ttl: Optional[int] = None, - hash_type: Optional[str] = None, - xhdr: Optional[dict] = None, - ) -> str: - """ - Get object hash. - - Args: - address: address of wallet account - bearer: File with signed JSON or binary encoded bearer token - cid: Container ID - oid: Object ID - range: Range to take hash from in the form offset1:length1,... - rpc_endpoint: remote node address (as 'multiaddr' or ':') - salt: Salt in hex format - ttl: TTL value in request meta header (default 2) - hash_type: Hash type. Either 'sha256' or 'tz' (default "sha256") - wallet: WIF (NEP-2) string or path to the wallet or binary key - xhdr: Request X-Headers in form of Key=Value - - Returns: - str: Command string - """ - return self._execute( - "object hash", - **{ - param: value for param, value in locals().items() if param not in ["self", "params"] - }, - ) - - def head( - self, - rpc_endpoint: str, - wallet: str, - cid: str, - oid: str, - address: Optional[str] = None, - bearer: Optional[str] = None, - file: Optional[str] = None, - json_mode: bool = False, - main_only: bool = False, - proto: bool = False, - raw: bool = False, - session: Optional[str] = None, - ttl: Optional[int] = None, - xhdr: Optional[dict] = None, - ) -> str: - """ - Get object header. - - Args: - address: address of wallet account - bearer: File with signed JSON or binary encoded bearer token - cid: Container ID - file: File to write object payload to. Default: stdout. - json_mode: Marshal output in JSON - main_only: Return only main fields - oid: Object ID - proto: Marshal output in Protobuf - raw: Set raw request option - rpc_endpoint: remote node address (as 'multiaddr' or ':') - session: path to a JSON-encoded container session token - ttl: TTL value in request meta header (default 2) - wallet: WIF (NEP-2) string or path to the wallet or binary key - xhdr: Request X-Headers in form of Key=Value - - Returns: - str: Command string - """ - return self._execute( - "object head", - **{param: value for param, value in locals().items() if param not in ["self"]}, - ) - - def lock( - self, - rpc_endpoint: str, - wallet: str, - cid: str, - oid: str, - lifetime: int, - address: Optional[str] = None, - bearer: Optional[str] = None, - session: Optional[str] = None, - ttl: Optional[int] = None, - xhdr: Optional[dict] = None, - ) -> str: - """ - Lock object in container. - - Args: - address: address of wallet account - bearer: File with signed JSON or binary encoded bearer token - cid: Container ID - oid: Object ID - lifetime: Object lifetime - rpc_endpoint: remote node address (as 'multiaddr' or ':') - session: path to a JSON-encoded container session token - ttl: TTL value in request meta header (default 2) - wallet: WIF (NEP-2) string or path to the wallet or binary key - xhdr: Request X-Headers in form of Key=Value - - Returns: - str: Command string - """ - return self._execute( - "object lock", - **{param: value for param, value in locals().items() if param not in ["self"]}, - ) - - def put( - self, - rpc_endpoint: str, - wallet: str, - cid: str, - file: str, - address: Optional[str] = None, - attributes: Optional[dict] = None, - bearer: Optional[str] = None, - disable_filename: bool = False, - disable_timestamp: bool = False, - expire_at: Optional[int] = None, - no_progress: bool = False, - notify: Optional[str] = None, - session: Optional[str] = None, - ttl: Optional[int] = None, - xhdr: Optional[dict] = None, - ) -> str: - """ - Put object to NeoFS. - - Args: - address: address of wallet account - attributes: User attributes in form of Key1=Value1,Key2=Value2 - bearer: File with signed JSON or binary encoded bearer token - cid: Container ID - disable_filename: Do not set well-known filename attribute - disable_timestamp: Do not set well-known timestamp attribute - expire_at: Last epoch in the life of the object - file: File with object payload - no_progress: Do not show progress bar - notify: Object notification in the form of *epoch*:*topic*; '-' topic means using default - rpc_endpoint: remote node address (as 'multiaddr' or ':') - session: path to a JSON-encoded container session token - ttl: TTL value in request meta header (default 2) - wallet: WIF (NEP-2) string or path to the wallet or binary key - xhdr: Request X-Headers in form of Key=Value - - Returns: - str: Command string - """ - return self._execute( - "object put", - **{param: value for param, value in locals().items() if param not in ["self"]}, - ) - - def range( - self, - rpc_endpoint: str, - wallet: str, - cid: str, - oid: str, - range: str, - address: Optional[str] = None, - bearer: Optional[str] = None, - file: Optional[str] = None, - json_mode: bool = False, - raw: bool = False, - session: Optional[str] = None, - ttl: Optional[int] = None, - xhdr: Optional[dict] = None, - ) -> str: - """ - Get payload range data of an object. - - Args: - address: address of wallet account - bearer: File with signed JSON or binary encoded bearer token - cid: Container ID - file: File to write object payload to. Default: stdout. - json_mode: Marshal output in JSON - oid: Object ID - range: Range to take data from in the form offset:length - raw: Set raw request option - rpc_endpoint: remote node address (as 'multiaddr' or ':') - session: path to a JSON-encoded container session token - ttl: TTL value in request meta header (default 2) - wallet: WIF (NEP-2) string or path to the wallet or binary key - xhdr: Request X-Headers in form of Key=Value - - Returns: - str: Command string - """ - return self._execute( - "object range", - **{param: value for param, value in locals().items() if param not in ["self"]}, - ) - - def search( - self, - rpc_endpoint: str, - wallet: str, - cid: str, - address: Optional[str] = None, - bearer: Optional[str] = None, - filters: Optional[list] = None, - oid: Optional[str] = None, - phy: bool = False, - root: bool = False, - session: Optional[str] = None, - ttl: Optional[int] = None, - xhdr: Optional[dict] = None, - ) -> str: - """ - Search object. - - Args: - address: address of wallet account - bearer: File with signed JSON or binary encoded bearer token - cid: Container ID - filters: Repeated filter expressions or files with protobuf JSON - oid: Object ID - phy: Search physically stored objects - root: Search for user objects - rpc_endpoint: remote node address (as 'multiaddr' or ':') - session: path to a JSON-encoded container session token - ttl: TTL value in request meta header (default 2) - wallet: WIF (NEP-2) string or path to the wallet or binary key - xhdr: Request X-Headers in form of Key=Value - - Returns: - str: Command string - """ - return self._execute( - "object search", - **{param: value for param, value in locals().items() if param not in ["self"]}, - ) diff --git a/robot/resources/lib/python_keywords/cli_utils/cli/version.py b/robot/resources/lib/python_keywords/cli_utils/cli/version.py deleted file mode 100644 index f8af747..0000000 --- a/robot/resources/lib/python_keywords/cli_utils/cli/version.py +++ /dev/null @@ -1,12 +0,0 @@ -from cli_utils.cli_command import NeofsCliCommand - - -class NeofsCliVersion(NeofsCliCommand): - def get(self) -> str: - """ - Application version and NeoFS API compatibility. - - Returns: - str: Command string - """ - return self._execute("", version=True) diff --git a/robot/resources/lib/python_keywords/cli_utils/cli_command.py b/robot/resources/lib/python_keywords/cli_utils/cli_command.py deleted file mode 100644 index 5d72b6a..0000000 --- a/robot/resources/lib/python_keywords/cli_utils/cli_command.py +++ /dev/null @@ -1,56 +0,0 @@ -from typing import Optional - -from cli_helpers import _cmd_run - - -class NeofsCliCommand: - neofs_cli_exec: Optional[str] = None - timeout: Optional[int] = None - __base_params: Optional[str] = None - map_params = { - "json_mode": "json", - "await_mode": "await", - "hash_type": "hash", - "doc_type": "type", - } - - def __init__(self, neofs_cli_exec: str, timeout: int, **base_params): - self.neofs_cli_exec = neofs_cli_exec - self.timeout = timeout - self.__base_params = " ".join( - [f"--{param} {value}" for param, value in base_params.items() if value] - ) - - def _format_command(self, command: str, **params) -> str: - param_str = [] - for param, value in params.items(): - if param in self.map_params.keys(): - param = self.map_params[param] - param = param.replace("_", "-") - if not value: - continue - if isinstance(value, bool): - param_str.append(f"--{param}") - elif isinstance(value, int): - param_str.append(f"--{param} {value}") - elif isinstance(value, list): - for value_item in value: - val_str = str(value_item).replace("'", "\\'") - param_str.append(f"--{param} '{val_str}'") - elif isinstance(value, dict): - param_str.append( - f"--{param} '{','.join(f'{key}={val}' for key, val in value.items())}'" - ) - else: - if "'" in str(value): - value_str = str(value).replace('"', '\\"') - param_str.append(f'--{param} "{value_str}"') - else: - param_str.append(f"--{param} '{value}'") - - param_str = " ".join(param_str) - - return f'{self.neofs_cli_exec} {self.__base_params} {command or ""} {param_str}' - - def _execute(self, command: Optional[str], **params) -> str: - return _cmd_run(self._format_command(command, **params), timeout=self.timeout) diff --git a/robot/resources/lib/python_keywords/complex_object_actions.py b/robot/resources/lib/python_keywords/complex_object_actions.py index f88483c..1bc9b1a 100644 --- a/robot/resources/lib/python_keywords/complex_object_actions.py +++ b/robot/resources/lib/python_keywords/complex_object_actions.py @@ -11,17 +11,24 @@ """ import logging +from typing import Optional import allure import neofs_verbs from common import NEOFS_NETMAP, WALLET_CONFIG +from neofs_testlib.shell import Shell logger = logging.getLogger("NeoLogger") @allure.step("Get Link Object") def get_link_object( - wallet: str, cid: str, oid: str, bearer_token: str = "", wallet_config: str = WALLET_CONFIG + wallet: str, + cid: str, + oid: str, + shell: Shell, + bearer_token: str = "", + wallet_config: str = WALLET_CONFIG, ): """ Args: @@ -29,6 +36,7 @@ def get_link_object( are requested cid (str): Container ID which stores the Large Object oid (str): Large Object ID + shell: executor for cli command bearer_token (optional, str): path to Bearer token file wallet_config (optional, str): path to the neofs-cli config file Returns: @@ -42,6 +50,7 @@ def get_link_object( wallet, cid, oid, + shell=shell, endpoint=node, is_raw=True, is_direct=True, @@ -57,13 +66,14 @@ def get_link_object( @allure.step("Get Last Object") -def get_last_object(wallet: str, cid: str, oid: str): +def get_last_object(wallet: str, cid: str, oid: str, shell: Shell) -> Optional[str]: """ Args: wallet (str): path to the wallet on whose behalf the Storage Nodes are requested cid (str): Container ID which stores the Large Object oid (str): Large Object ID + shell: executor for cli command Returns: (str): Last Object ID When no Last Object ID is found after all Storage Nodes polling, @@ -72,7 +82,7 @@ def get_last_object(wallet: str, cid: str, oid: str): for node in NEOFS_NETMAP: try: resp = neofs_verbs.head_object( - wallet, cid, oid, endpoint=node, is_raw=True, is_direct=True + wallet, cid, oid, shell=shell, endpoint=node, is_raw=True, is_direct=True ) if resp["lastPart"]: return resp["lastPart"] diff --git a/robot/resources/lib/python_keywords/container.py b/robot/resources/lib/python_keywords/container.py index d4ac312..c79e5e0 100644 --- a/robot/resources/lib/python_keywords/container.py +++ b/robot/resources/lib/python_keywords/container.py @@ -11,8 +11,9 @@ from typing import Optional, Union import allure import json_transformers -from cli_utils import NeofsCli -from common import NEOFS_ENDPOINT, WALLET_CONFIG +from common import NEOFS_CLI_EXEC, NEOFS_ENDPOINT, WALLET_CONFIG +from neofs_testlib.cli import NeofsCli +from neofs_testlib.shell import Shell logger = logging.getLogger("NeoLogger") @@ -22,6 +23,7 @@ DEFAULT_PLACEMENT_RULE = "REP 2 IN X CBF 1 SELECT 4 FROM * AS X" @allure.step("Create Container") def create_container( wallet: str, + shell: Shell, rule: str = DEFAULT_PLACEMENT_RULE, basic_acl: str = "", attributes: Optional[dict] = None, @@ -46,6 +48,7 @@ def create_container( session_wallet(optional, str): a path to the wallet which signed the session token; this parameter makes sense when paired with `session_token` + shell: executor for cli command options (optional, dict): any other options to pass to the call name (optional, str): container name attribute await_mode (bool): block execution until container is persisted @@ -55,7 +58,7 @@ def create_container( (str): CID of the created container """ - cli = NeofsCli(config=WALLET_CONFIG, timeout=60) + cli = NeofsCli(shell, NEOFS_CLI_EXEC, WALLET_CONFIG) output = cli.container.create( rpc_endpoint=NEOFS_ENDPOINT, wallet=session_wallet if session_wallet else wallet, @@ -68,19 +71,21 @@ def create_container( **options or {}, ) - cid = _parse_cid(output) + cid = _parse_cid(output.stdout) logger.info("Container created; waiting until it is persisted in the sidechain") if wait_for_creation: - wait_for_container_creation(wallet, cid) + wait_for_container_creation(wallet, cid, shell=shell) return cid -def wait_for_container_creation(wallet: str, cid: str, attempts: int = 15, sleep_interval: int = 1): +def wait_for_container_creation( + wallet: str, cid: str, shell: Shell, attempts: int = 15, sleep_interval: int = 1 +): for _ in range(attempts): - containers = list_containers(wallet) + containers = list_containers(wallet, shell=shell) if cid in containers: return logger.info(f"There is no {cid} in {containers} yet; sleep {sleep_interval} and continue") @@ -90,10 +95,12 @@ def wait_for_container_creation(wallet: str, cid: str, attempts: int = 15, sleep ) -def wait_for_container_deletion(wallet: str, cid: str, attempts: int = 30, sleep_interval: int = 1): +def wait_for_container_deletion( + wallet: str, cid: str, shell: Shell, attempts: int = 30, sleep_interval: int = 1 +): for _ in range(attempts): try: - get_container(wallet, cid) + get_container(wallet, cid, shell=shell) sleep(sleep_interval) continue except Exception as err: @@ -104,42 +111,46 @@ def wait_for_container_deletion(wallet: str, cid: str, attempts: int = 30, sleep @allure.step("List Containers") -def list_containers(wallet: str) -> list[str]: +def list_containers(wallet: str, shell: Shell) -> list[str]: """ A wrapper for `neofs-cli container list` call. It returns all the available containers for the given wallet. Args: wallet (str): a wallet on whose behalf we list the containers + shell: executor for cli command Returns: (list): list of containers """ - cli = NeofsCli(config=WALLET_CONFIG) + cli = NeofsCli(shell, NEOFS_CLI_EXEC, WALLET_CONFIG) output = cli.container.list(rpc_endpoint=NEOFS_ENDPOINT, wallet=wallet) logger.info(f"Containers: \n{output}") - return output.split() + return output.stdout.split() @allure.step("Get Container") -def get_container(wallet: str, cid: str, json_mode: bool = True) -> Union[dict, str]: +def get_container( + wallet: str, cid: str, shell: Shell, json_mode: bool = True, +) -> Union[dict, str]: """ A wrapper for `neofs-cli container get` call. It extracts container's attributes and rearranges them into a more compact view. Args: wallet (str): path to a wallet on whose behalf we get the container cid (str): ID of the container to get + shell: executor for cli command json_mode (bool): return container in JSON format Returns: (dict, str): dict of container attributes """ - cli = NeofsCli(config=WALLET_CONFIG) + cli = NeofsCli(shell, NEOFS_CLI_EXEC, WALLET_CONFIG) output = cli.container.get( rpc_endpoint=NEOFS_ENDPOINT, wallet=wallet, cid=cid, json_mode=json_mode ) if not json_mode: - return output + return output.stdout - container_info = json.loads(output) + container_info = json.loads(output.stdout) attributes = dict() for attr in container_info["attributes"]: attributes[attr["key"]] = attr["value"] @@ -151,17 +162,20 @@ def get_container(wallet: str, cid: str, json_mode: bool = True) -> Union[dict, @allure.step("Delete Container") # TODO: make the error message about a non-found container more user-friendly # https://github.com/nspcc-dev/neofs-contract/issues/121 -def delete_container(wallet: str, cid: str, force: bool = False) -> None: +def delete_container( + wallet: str, cid: str, shell: Shell, force: bool = False +) -> None: """ A wrapper for `neofs-cli container delete` call. Args: wallet (str): path to a wallet on whose behalf we delete the container cid (str): ID of the container to delete + shell: executor for cli command force (bool): do not check whether container contains locks and remove immediately This function doesn't return anything. """ - cli = NeofsCli(config=WALLET_CONFIG) + cli = NeofsCli(shell, NEOFS_CLI_EXEC, WALLET_CONFIG) cli.container.delete(wallet=wallet, cid=cid, rpc_endpoint=NEOFS_ENDPOINT, force=force) @@ -183,6 +197,7 @@ def _parse_cid(output: str) -> str: # taking first line from command's output first_line = output.split("\n")[0] except Exception: + first_line = "" logger.error(f"Got empty output: {output}") splitted = first_line.split(": ") if len(splitted) != 2: diff --git a/robot/resources/lib/python_keywords/container_access.py b/robot/resources/lib/python_keywords/container_access.py index 9db7ebe..79f64e4 100644 --- a/robot/resources/lib/python_keywords/container_access.py +++ b/robot/resources/lib/python_keywords/container_access.py @@ -1,6 +1,7 @@ from typing import List, Optional from acl import EACLOperation +from neofs_testlib.shell import Shell from python_keywords.object_access import ( can_delete_object, can_get_head_object, @@ -17,17 +18,18 @@ def check_full_access_to_container( cid: str, oid: str, file_name: str, + shell: Shell, bearer: Optional[str] = None, wallet_config: Optional[str] = None, xhdr: Optional[dict] = None, ): - assert can_put_object(wallet, cid, file_name, bearer, wallet_config, xhdr) - assert can_get_head_object(wallet, cid, oid, bearer, wallet_config, xhdr) - assert can_get_range_of_object(wallet, cid, oid, bearer, wallet_config, xhdr) - assert can_get_range_hash_of_object(wallet, cid, oid, bearer, wallet_config, xhdr) - assert can_search_object(wallet, cid, oid, bearer, wallet_config, xhdr) - assert can_get_object(wallet, cid, oid, file_name, bearer, wallet_config, xhdr) - assert can_delete_object(wallet, cid, oid, bearer, wallet_config, xhdr) + assert can_put_object(wallet, cid, file_name, shell, bearer, wallet_config, xhdr) + assert can_get_head_object(wallet, cid, oid, shell, bearer, wallet_config, xhdr) + assert can_get_range_of_object(wallet, cid, oid, shell, bearer, wallet_config, xhdr) + assert can_get_range_hash_of_object(wallet, cid, oid, shell, bearer, wallet_config, xhdr) + assert can_search_object(wallet, cid, shell, oid, bearer, wallet_config, xhdr) + assert can_get_object(wallet, cid, oid, file_name, shell, bearer, wallet_config, xhdr) + assert can_delete_object(wallet, cid, oid, shell, bearer, wallet_config, xhdr) def check_no_access_to_container( @@ -35,17 +37,18 @@ def check_no_access_to_container( cid: str, oid: str, file_name: str, + shell: Shell, bearer: Optional[str] = None, wallet_config: Optional[str] = None, xhdr: Optional[dict] = None, ): - assert not can_put_object(wallet, cid, file_name, bearer, wallet_config, xhdr) - assert not can_get_head_object(wallet, cid, oid, bearer, wallet_config, xhdr) - assert not can_get_range_of_object(wallet, cid, oid, bearer, wallet_config, xhdr) - assert not can_get_range_hash_of_object(wallet, cid, oid, bearer, wallet_config, xhdr) - assert not can_search_object(wallet, cid, oid, bearer, wallet_config, xhdr) - assert not can_get_object(wallet, cid, oid, file_name, bearer, wallet_config, xhdr) - assert not can_delete_object(wallet, cid, oid, bearer, wallet_config, xhdr) + assert not can_put_object(wallet, cid, file_name, shell, bearer, wallet_config, xhdr) + assert not can_get_head_object(wallet, cid, oid, shell, bearer, wallet_config, xhdr) + assert not can_get_range_of_object(wallet, cid, oid, shell, bearer, wallet_config, xhdr) + assert not can_get_range_hash_of_object(wallet, cid, oid, shell, bearer, wallet_config, xhdr) + assert not can_search_object(wallet, cid, shell, oid, bearer, wallet_config, xhdr) + assert not can_get_object(wallet, cid, oid, file_name, shell, bearer, wallet_config, xhdr) + assert not can_delete_object(wallet, cid, oid, shell, bearer, wallet_config, xhdr) def check_custom_access_to_container( @@ -53,6 +56,7 @@ def check_custom_access_to_container( cid: str, oid: str, file_name: str, + shell: Shell, deny_operations: Optional[List[EACLOperation]] = None, ignore_operations: Optional[List[EACLOperation]] = None, bearer: Optional[str] = None, @@ -64,31 +68,31 @@ def check_custom_access_to_container( checks: dict = {} if EACLOperation.PUT.value not in ignore_operations: checks[EACLOperation.PUT.value] = can_put_object( - wallet, cid, file_name, bearer, wallet_config, xhdr + wallet, cid, file_name, shell, bearer, wallet_config, xhdr ) if EACLOperation.HEAD.value not in ignore_operations: checks[EACLOperation.HEAD.value] = can_get_head_object( - wallet, cid, oid, bearer, wallet_config, xhdr + wallet, cid, oid, shell, bearer, wallet_config, xhdr ) if EACLOperation.GET_RANGE.value not in ignore_operations: checks[EACLOperation.GET_RANGE.value] = can_get_range_of_object( - wallet, cid, oid, bearer, wallet_config, xhdr + wallet, cid, oid, shell, bearer, wallet_config, xhdr ) if EACLOperation.GET_RANGE_HASH.value not in ignore_operations: checks[EACLOperation.GET_RANGE_HASH.value] = can_get_range_hash_of_object( - wallet, cid, oid, bearer, wallet_config, xhdr + wallet, cid, oid, shell, bearer, wallet_config, xhdr ) if EACLOperation.SEARCH.value not in ignore_operations: checks[EACLOperation.SEARCH.value] = can_search_object( - wallet, cid, oid, bearer, wallet_config, xhdr + wallet, cid, shell, oid, bearer, wallet_config, xhdr ) if EACLOperation.GET.value not in ignore_operations: checks[EACLOperation.GET.value] = can_get_object( - wallet, cid, oid, file_name, bearer, wallet_config, xhdr + wallet, cid, oid, file_name, shell, bearer, wallet_config, xhdr ) if EACLOperation.DELETE.value not in ignore_operations: checks[EACLOperation.DELETE.value] = can_delete_object( - wallet, cid, oid, bearer, wallet_config, xhdr + wallet, cid, oid, shell, bearer, wallet_config, xhdr ) failed_checks = [ @@ -109,6 +113,7 @@ def check_read_only_container( cid: str, oid: str, file_name: str, + shell: Shell, bearer: Optional[str] = None, wallet_config: Optional[str] = None, xhdr: Optional[dict] = None, @@ -122,4 +127,5 @@ def check_read_only_container( bearer=bearer, wallet_config=wallet_config, xhdr=xhdr, + shell=shell, ) diff --git a/robot/resources/lib/python_keywords/failover_utils.py b/robot/resources/lib/python_keywords/failover_utils.py index 678523d..d9088fe 100644 --- a/robot/resources/lib/python_keywords/failover_utils.py +++ b/robot/resources/lib/python_keywords/failover_utils.py @@ -4,6 +4,7 @@ from typing import Optional import allure from common import NEOFS_NETMAP_DICT +from neofs_testlib.shell import Shell from python_keywords.node_management import node_healthcheck from storage_policy import get_nodes_with_object @@ -16,13 +17,14 @@ def wait_object_replication_on_nodes( cid: str, oid: str, expected_copies: int, + shell: Shell, excluded_nodes: Optional[list[str]] = None, ) -> list[str]: excluded_nodes = excluded_nodes or [] sleep_interval, attempts = 10, 18 nodes = [] for __attempt in range(attempts): - nodes = get_nodes_with_object(wallet, cid, oid, skip_nodes=excluded_nodes) + nodes = get_nodes_with_object(wallet, cid, oid, shell=shell, skip_nodes=excluded_nodes) if len(nodes) == expected_copies: return nodes sleep(sleep_interval) diff --git a/robot/resources/lib/python_keywords/neofs_verbs.py b/robot/resources/lib/python_keywords/neofs_verbs.py index f429022..3feb288 100644 --- a/robot/resources/lib/python_keywords/neofs_verbs.py +++ b/robot/resources/lib/python_keywords/neofs_verbs.py @@ -13,8 +13,9 @@ from typing import Optional import allure import json_transformers -from cli_utils import NeofsCli -from common import ASSETS_DIR, NEOFS_ENDPOINT, NEOFS_NETMAP, WALLET_CONFIG +from common import ASSETS_DIR, NEOFS_CLI_EXEC, NEOFS_ENDPOINT, NEOFS_NETMAP, WALLET_CONFIG +from neofs_testlib.cli import NeofsCli +from neofs_testlib.shell import Shell logger = logging.getLogger("NeoLogger") @@ -24,6 +25,7 @@ def get_object( wallet: str, cid: str, oid: str, + shell: Shell, bearer_token: Optional[str] = None, write_object: str = "", endpoint: str = "", @@ -39,6 +41,7 @@ def get_object( wallet (str): wallet on whose behalf GET is done cid (str): ID of Container where we get the Object from oid (str): Object ID + shell: executor for cli command bearer_token (optional, str): path to Bearer Token file, appends to `--bearer` key write_object (optional, str): path to downloaded file, appends to `--file` key endpoint (optional, str): NeoFS endpoint to send request to, appends to `--rpc-endpoint` key @@ -50,7 +53,6 @@ def get_object( (str): path to downloaded file """ - wallet_config = wallet_config or WALLET_CONFIG if not write_object: write_object = str(uuid.uuid4()) file_path = f"{ASSETS_DIR}/{write_object}" @@ -58,7 +60,7 @@ def get_object( if not endpoint: endpoint = random.sample(NEOFS_NETMAP, 1)[0] - cli = NeofsCli(config=wallet_config) + cli = NeofsCli(shell, NEOFS_CLI_EXEC, wallet_config or WALLET_CONFIG) cli.object.get( rpc_endpoint=endpoint or NEOFS_ENDPOINT, wallet=wallet, @@ -74,14 +76,14 @@ def get_object( return file_path -# TODO: make `bearer_token` optional @allure.step("Get Range Hash") def get_range_hash( wallet: str, cid: str, oid: str, - bearer_token: str, range_cut: str, + shell: Shell, + bearer_token: Optional[str] = None, endpoint: Optional[str] = None, wallet_config: Optional[str] = None, xhdr: Optional[dict] = None, @@ -93,6 +95,7 @@ def get_range_hash( wallet (str): wallet on whose behalf GETRANGEHASH is done cid (str): ID of Container where we get the Object from oid (str): Object ID + shell: executor for cli command bearer_token (optional, str): path to Bearer Token file, appends to `--bearer` key range_cut (str): Range to take hash from in the form offset1:length1,..., value to pass to the `--range` parameter @@ -103,8 +106,7 @@ def get_range_hash( None """ - wallet_config = wallet_config or WALLET_CONFIG - cli = NeofsCli(config=wallet_config) + cli = NeofsCli(shell, NEOFS_CLI_EXEC, wallet_config or WALLET_CONFIG) output = cli.object.hash( rpc_endpoint=endpoint or NEOFS_ENDPOINT, wallet=wallet, @@ -116,7 +118,7 @@ def get_range_hash( ) # cutting off output about range offset and length - return output.split(":")[1].strip() + return output.stdout.split(":")[1].strip() @allure.step("Put object") @@ -124,7 +126,8 @@ def put_object( wallet: str, path: str, cid: str, - bearer: str = "", + shell: Shell, + bearer: Optional[str] = None, attributes: Optional[dict] = None, xhdr: Optional[dict] = None, endpoint: Optional[str] = None, @@ -140,6 +143,7 @@ def put_object( wallet (str): wallet on whose behalf PUT is done path (str): path to file to be PUT cid (str): ID of Container where we get the Object from + shell: executor for cli command bearer (optional, str): path to Bearer Token file, appends to `--bearer` key attributes (optional, str): User attributes in form of Key1=Value1,Key2=Value2 endpoint(optional, str): NeoFS endpoint to send request to @@ -151,13 +155,12 @@ def put_object( Returns: (str): ID of uploaded Object """ - wallet_config = wallet_config or WALLET_CONFIG if not endpoint: endpoint = random.sample(NEOFS_NETMAP, 1)[0] if not endpoint: logger.info(f"---DEB:\n{NEOFS_NETMAP}") - cli = NeofsCli(config=wallet_config) + cli = NeofsCli(shell, NEOFS_CLI_EXEC, wallet_config or WALLET_CONFIG) output = cli.object.put( rpc_endpoint=endpoint, wallet=wallet, @@ -172,7 +175,7 @@ def put_object( ) # splitting CLI output to lines and taking the penultimate line - id_str = output.strip().split("\n")[-2] + id_str = output.stdout.strip().split("\n")[-2] oid = id_str.split(":")[1] return oid.strip() @@ -182,6 +185,7 @@ def delete_object( wallet: str, cid: str, oid: str, + shell: Shell, endpoint: Optional[str] = None, bearer: str = "", wallet_config: Optional[str] = None, @@ -195,6 +199,7 @@ def delete_object( wallet (str): wallet on whose behalf DELETE is done cid (str): ID of Container where we get the Object from oid (str): ID of Object we are going to delete + shell: executor for cli command bearer (optional, str): path to Bearer Token file, appends to `--bearer` key endpoint (optional, str): NeoFS endpoint to send request to, appends to `--rpc-endpoint` key wallet_config(optional, str): path to the wallet config @@ -203,8 +208,7 @@ def delete_object( Returns: (str): Tombstone ID """ - wallet_config = wallet_config or WALLET_CONFIG - cli = NeofsCli(config=wallet_config) + cli = NeofsCli(shell, NEOFS_CLI_EXEC, wallet_config or WALLET_CONFIG) output = cli.object.delete( rpc_endpoint=endpoint or NEOFS_ENDPOINT, wallet=wallet, @@ -215,7 +219,7 @@ def delete_object( session=session, ) - id_str = output.split("\n")[1] + id_str = output.stdout.split("\n")[1] tombstone = id_str.split(":")[1] return tombstone.strip() @@ -226,6 +230,7 @@ def get_range( cid: str, oid: str, range_cut: str, + shell: Shell, endpoint: Optional[str] = None, wallet_config: Optional[str] = None, bearer: str = "", @@ -240,6 +245,7 @@ def get_range( cid (str): ID of Container where we get the Object from oid (str): ID of Object we are going to request range_cut (str): range to take data from in the form offset:length + shell: executor for cli command endpoint (optional, str): NeoFS endpoint to send request to, appends to `--rpc-endpoint` key bearer (optional, str): path to Bearer Token file, appends to `--bearer` key wallet_config(optional, str): path to the wallet config @@ -248,10 +254,9 @@ def get_range( Returns: (str, bytes) - path to the file with range content and content of this file as bytes """ - wallet_config = wallet_config or WALLET_CONFIG range_file = f"{ASSETS_DIR}/{uuid.uuid4()}" - cli = NeofsCli(config=wallet_config) + cli = NeofsCli(shell, NEOFS_CLI_EXEC, wallet_config or WALLET_CONFIG) cli.object.range( rpc_endpoint=endpoint or NEOFS_ENDPOINT, wallet=wallet, @@ -273,6 +278,7 @@ def get_range( def search_object( wallet: str, cid: str, + shell: Shell, bearer: str = "", endpoint: Optional[str] = None, filters: Optional[dict] = None, @@ -287,6 +293,7 @@ def search_object( Args: wallet (str): wallet on whose behalf SEARCH is done cid (str): ID of Container where we get the Object from + shell: executor for cli command bearer (optional, str): path to Bearer Token file, appends to `--bearer` key endpoint (optional, str): NeoFS endpoint to send request to, appends to `--rpc-endpoint` key filters (optional, dict): key=value pairs to filter Objects @@ -298,8 +305,7 @@ def search_object( (list): list of found ObjectIDs """ - wallet_config = wallet_config or WALLET_CONFIG - cli = NeofsCli(config=wallet_config) + cli = NeofsCli(shell, NEOFS_CLI_EXEC, wallet_config or WALLET_CONFIG) output = cli.object.search( rpc_endpoint=endpoint or NEOFS_ENDPOINT, wallet=wallet, @@ -312,7 +318,7 @@ def search_object( session=session, ) - found_objects = re.findall(r"(\w{43,44})", output) + found_objects = re.findall(r"(\w{43,44})", output.stdout) if expected_objects_list: if sorted(found_objects) == sorted(expected_objects_list): @@ -334,7 +340,8 @@ def head_object( wallet: str, cid: str, oid: str, - bearer_token: str = "", + shell: Shell, + bearer: str = "", xhdr: Optional[dict] = None, endpoint: Optional[str] = None, json_output: bool = True, @@ -350,7 +357,8 @@ def head_object( wallet (str): wallet on whose behalf HEAD is done cid (str): ID of Container where we get the Object from oid (str): ObjectID to HEAD - bearer_token (optional, str): path to Bearer Token file, appends to `--bearer` key + shell: executor for cli command + bearer (optional, str): path to Bearer Token file, appends to `--bearer` key endpoint(optional, str): NeoFS endpoint to send request to json_output(optional, bool): return reponse in JSON format or not; this flag turns into `--json` key @@ -368,14 +376,13 @@ def head_object( (str): HEAD response as a plain text """ - wallet_config = wallet_config or WALLET_CONFIG - cli = NeofsCli(config=wallet_config) + cli = NeofsCli(shell, NEOFS_CLI_EXEC, wallet_config or WALLET_CONFIG) output = cli.object.head( rpc_endpoint=endpoint or NEOFS_ENDPOINT, wallet=wallet, cid=cid, oid=oid, - bearer=bearer_token, + bearer=bearer, json_mode=json_output, raw=is_raw, ttl=1 if is_direct else None, @@ -387,15 +394,15 @@ def head_object( return output try: - decoded = json.loads(output) + decoded = json.loads(output.stdout) except Exception as exc: # If we failed to parse output as JSON, the cause might be # the plain text string in the beginning of the output. # Here we cut off first string and try to parse again. logger.info(f"failed to parse output: {exc}") logger.info("parsing output in another way") - fst_line_idx = output.find("\n") - decoded = json.loads(output[fst_line_idx:]) + fst_line_idx = output.stdout.find("\n") + decoded = json.loads(output.stdout[fst_line_idx:]) # If response is Complex Object header, it has `splitId` key if "splitId" in decoded.keys(): diff --git a/robot/resources/lib/python_keywords/node_management.py b/robot/resources/lib/python_keywords/node_management.py index aa0ee39..84aa927 100644 --- a/robot/resources/lib/python_keywords/node_management.py +++ b/robot/resources/lib/python_keywords/node_management.py @@ -8,10 +8,17 @@ from dataclasses import dataclass from typing import Optional import allure -from cli_utils.cli.cli import NeofsCli -from common import MORPH_BLOCK_TIME, NEOFS_NETMAP_DICT, STORAGE_WALLET_CONFIG, STORAGE_WALLET_PASS +from common import ( + MORPH_BLOCK_TIME, + NEOFS_CLI_EXEC, + NEOFS_NETMAP_DICT, + STORAGE_WALLET_CONFIG, + STORAGE_WALLET_PASS, +) from data_formatters import get_wallet_public_key from epoch import tick_epoch +from neofs_testlib.cli import NeofsCli +from neofs_testlib.shell import Shell from service_helper import get_storage_service_helper from utility import parse_time @@ -90,8 +97,8 @@ def node_set_status(node_name: str, status: str, retries: int = 0) -> None: """ The function sets particular status for given node. Args: - node_name str: node name for which status should be set. - status str: online or offline. + node_name: node name for which status should be set. + status: online or offline. retries (optional, int): number of retry attempts if it didn't work from the first time """ command = f"control set-status --status {status}" @@ -99,7 +106,7 @@ def node_set_status(node_name: str, status: str, retries: int = 0) -> None: @allure.step("Get netmap snapshot") -def get_netmap_snapshot(node_name: str) -> str: +def get_netmap_snapshot(node_name: str, shell: Shell) -> str: """ The function returns string representation of netmap snapshot. Args: @@ -108,11 +115,11 @@ def get_netmap_snapshot(node_name: str) -> str: string representation of netmap """ node_info = NEOFS_NETMAP_DICT[node_name] - cli = NeofsCli(config=STORAGE_WALLET_CONFIG) + cli = NeofsCli(shell, NEOFS_CLI_EXEC, config_file=STORAGE_WALLET_CONFIG) return cli.netmap.snapshot( rpc_endpoint=node_info["rpc"], wallet=node_info["wallet_path"], - ) + ).stdout @allure.step("Get shard list for node {node_name}") @@ -160,7 +167,7 @@ def delete_node_data(node_name: str) -> None: @allure.step("Exclude node {node_to_exclude} from network map") -def exclude_node_from_network_map(node_to_exclude: str, alive_node: str) -> None: +def exclude_node_from_network_map(node_to_exclude: str, alive_node: str, shell: Shell) -> None: node_wallet_path = NEOFS_NETMAP_DICT[node_to_exclude]["wallet_path"] node_netmap_key = get_wallet_public_key(node_wallet_path, STORAGE_WALLET_PASS) @@ -169,31 +176,31 @@ def exclude_node_from_network_map(node_to_exclude: str, alive_node: str) -> None time.sleep(parse_time(MORPH_BLOCK_TIME)) tick_epoch() - snapshot = get_netmap_snapshot(node_name=alive_node) + snapshot = get_netmap_snapshot(node_name=alive_node, shell=shell) assert ( node_netmap_key not in snapshot ), f"Expected node with key {node_netmap_key} not in network map" @allure.step("Include node {node_to_include} into network map") -def include_node_to_network_map(node_to_include: str, alive_node: str) -> None: +def include_node_to_network_map(node_to_include: str, alive_node: str, shell: Shell) -> None: node_set_status(node_to_include, status="online") time.sleep(parse_time(MORPH_BLOCK_TIME)) tick_epoch() - check_node_in_map(node_to_include, alive_node) + check_node_in_map(node_to_include, alive_node, shell=shell) @allure.step("Check node {node_name} in network map") -def check_node_in_map(node_name: str, alive_node: Optional[str] = None) -> None: +def check_node_in_map(node_name: str, shell: Shell, alive_node: Optional[str] = None) -> None: alive_node = alive_node or node_name node_wallet_path = NEOFS_NETMAP_DICT[node_name]["wallet_path"] node_netmap_key = get_wallet_public_key(node_wallet_path, STORAGE_WALLET_PASS) logger.info(f"Node {node_name} netmap key: {node_netmap_key}") - snapshot = get_netmap_snapshot(node_name=alive_node) + snapshot = get_netmap_snapshot(node_name=alive_node, shell=shell) assert node_netmap_key in snapshot, f"Expected node with key {node_netmap_key} in network map" diff --git a/robot/resources/lib/python_keywords/object_access.py b/robot/resources/lib/python_keywords/object_access.py index d30392b..8c633ee 100644 --- a/robot/resources/lib/python_keywords/object_access.py +++ b/robot/resources/lib/python_keywords/object_access.py @@ -3,6 +3,7 @@ from typing import Optional import allure from file_helper import get_file_hash from grpc_responses import OBJECT_ACCESS_DENIED, error_matches_status +from neofs_testlib.shell import Shell from python_keywords.neofs_verbs import ( delete_object, get_object, @@ -21,6 +22,7 @@ def can_get_object( cid: str, oid: str, file_name: str, + shell: Shell, bearer: Optional[str] = None, wallet_config: Optional[str] = None, xhdr: Optional[dict] = None, @@ -28,7 +30,7 @@ def can_get_object( with allure.step("Try get object from container"): try: got_file_path = get_object( - wallet, cid, oid, bearer_token=bearer, wallet_config=wallet_config, xhdr=xhdr + wallet, cid, oid, bearer_token=bearer, wallet_config=wallet_config, xhdr=xhdr, shell=shell, ) except OPERATION_ERROR_TYPE as err: assert error_matches_status( @@ -43,6 +45,7 @@ def can_put_object( wallet: str, cid: str, file_name: str, + shell: Shell, bearer: Optional[str] = None, wallet_config: Optional[str] = None, xhdr: Optional[dict] = None, @@ -58,6 +61,7 @@ def can_put_object( wallet_config=wallet_config, xhdr=xhdr, attributes=attributes, + shell=shell, ) except OPERATION_ERROR_TYPE as err: assert error_matches_status( @@ -71,13 +75,16 @@ def can_delete_object( wallet: str, cid: str, oid: str, + shell: Shell, bearer: Optional[str] = None, wallet_config: Optional[str] = None, xhdr: Optional[dict] = None, ) -> bool: with allure.step("Try delete object from container"): try: - delete_object(wallet, cid, oid, bearer=bearer, wallet_config=wallet_config, xhdr=xhdr) + delete_object( + wallet, cid, oid, bearer=bearer, wallet_config=wallet_config, xhdr=xhdr, shell=shell + ) except OPERATION_ERROR_TYPE as err: assert error_matches_status( err, OBJECT_ACCESS_DENIED @@ -90,6 +97,7 @@ def can_get_head_object( wallet: str, cid: str, oid: str, + shell: Shell, bearer: Optional[str] = None, wallet_config: Optional[str] = None, xhdr: Optional[dict] = None, @@ -97,7 +105,13 @@ def can_get_head_object( with allure.step("Try get head of object"): try: head_object( - wallet, cid, oid, bearer_token=bearer, wallet_config=wallet_config, xhdr=xhdr + wallet, + cid, + oid, + bearer=bearer, + wallet_config=wallet_config, + xhdr=xhdr, + shell=shell, ) except OPERATION_ERROR_TYPE as err: assert error_matches_status( @@ -111,6 +125,7 @@ def can_get_range_of_object( wallet: str, cid: str, oid: str, + shell: Shell, bearer: Optional[str] = None, wallet_config: Optional[str] = None, xhdr: Optional[dict] = None, @@ -125,6 +140,7 @@ def can_get_range_of_object( range_cut="0:10", wallet_config=wallet_config, xhdr=xhdr, + shell=shell, ) except OPERATION_ERROR_TYPE as err: assert error_matches_status( @@ -138,6 +154,7 @@ def can_get_range_hash_of_object( wallet: str, cid: str, oid: str, + shell: Shell, bearer: Optional[str] = None, wallet_config: Optional[str] = None, xhdr: Optional[dict] = None, @@ -152,6 +169,7 @@ def can_get_range_hash_of_object( range_cut="0:10", wallet_config=wallet_config, xhdr=xhdr, + shell=shell, ) except OPERATION_ERROR_TYPE as err: assert error_matches_status( @@ -164,6 +182,7 @@ def can_get_range_hash_of_object( def can_search_object( wallet: str, cid: str, + shell: Shell, oid: Optional[str] = None, bearer: Optional[str] = None, wallet_config: Optional[str] = None, @@ -171,7 +190,9 @@ def can_search_object( ) -> bool: with allure.step("Try search object in container"): try: - oids = search_object(wallet, cid, bearer=bearer, wallet_config=wallet_config, xhdr=xhdr) + oids = search_object( + wallet, cid, bearer=bearer, wallet_config=wallet_config, xhdr=xhdr, shell=shell + ) except OPERATION_ERROR_TYPE as err: assert error_matches_status( err, OBJECT_ACCESS_DENIED diff --git a/robot/resources/lib/python_keywords/storage_policy.py b/robot/resources/lib/python_keywords/storage_policy.py index adac87f..b48e989 100644 --- a/robot/resources/lib/python_keywords/storage_policy.py +++ b/robot/resources/lib/python_keywords/storage_policy.py @@ -6,19 +6,20 @@ """ import logging -from typing import Optional +from typing import List, Optional import allure import complex_object_actions import neofs_verbs from common import NEOFS_NETMAP from grpc_responses import OBJECT_NOT_FOUND, error_matches_status +from neofs_testlib.shell import Shell logger = logging.getLogger("NeoLogger") @allure.step("Get Object Copies") -def get_object_copies(complexity: str, wallet: str, cid: str, oid: str): +def get_object_copies(complexity: str, wallet: str, cid: str, oid: str, shell: Shell) -> int: """ The function performs requests to all nodes of the container and finds out if they store a copy of the object. The procedure is @@ -31,18 +32,19 @@ def get_object_copies(complexity: str, wallet: str, cid: str, oid: str): copies are got cid (str): ID of the container oid (str): ID of the Object + shell: executor for cli command Returns: (int): the number of object copies in the container """ return ( - get_simple_object_copies(wallet, cid, oid) + get_simple_object_copies(wallet, cid, oid, shell) if complexity == "Simple" - else get_complex_object_copies(wallet, cid, oid) + else get_complex_object_copies(wallet, cid, oid, shell) ) @allure.step("Get Simple Object Copies") -def get_simple_object_copies(wallet: str, cid: str, oid: str): +def get_simple_object_copies(wallet: str, cid: str, oid: str, shell: Shell) -> int: """ To figure out the number of a simple object copies, only direct HEAD requests should be made to the every node of the container. @@ -52,13 +54,16 @@ def get_simple_object_copies(wallet: str, cid: str, oid: str): copies are got cid (str): ID of the container oid (str): ID of the Object + shell: executor for cli command Returns: (int): the number of object copies in the container """ copies = 0 for node in NEOFS_NETMAP: try: - response = neofs_verbs.head_object(wallet, cid, oid, endpoint=node, is_direct=True) + response = neofs_verbs.head_object( + wallet, cid, oid, shell=shell, endpoint=node, is_direct=True + ) if response: logger.info(f"Found object {oid} on node {node}") copies += 1 @@ -69,7 +74,7 @@ def get_simple_object_copies(wallet: str, cid: str, oid: str): @allure.step("Get Complex Object Copies") -def get_complex_object_copies(wallet: str, cid: str, oid: str): +def get_complex_object_copies(wallet: str, cid: str, oid: str, shell: Shell) -> int: """ To figure out the number of a complex object copies, we firstly need to retrieve its Last object. We consider that the number of @@ -81,16 +86,18 @@ def get_complex_object_copies(wallet: str, cid: str, oid: str): copies are got cid (str): ID of the container oid (str): ID of the Object + shell: executor for cli command Returns: (int): the number of object copies in the container """ - last_oid = complex_object_actions.get_last_object(wallet, cid, oid) - return get_simple_object_copies(wallet, cid, last_oid) + last_oid = complex_object_actions.get_last_object(wallet, cid, oid, shell) + assert last_oid, f"No Last Object for {cid}/{oid} found among all Storage Nodes" + return get_simple_object_copies(wallet, cid, last_oid, shell) @allure.step("Get Nodes With Object") def get_nodes_with_object( - wallet: str, cid: str, oid: str, skip_nodes: Optional[list[str]] = None + wallet: str, cid: str, oid: str, shell: Shell, skip_nodes: Optional[list[str]] = None ) -> list[str]: """ The function returns list of nodes which store @@ -100,6 +107,7 @@ def get_nodes_with_object( we request the nodes cid (str): ID of the container which store the object oid (str): object ID + shell: executor for cli command skip_nodes (list): list of nodes that should be excluded from check Returns: (list): nodes which store the object @@ -111,7 +119,9 @@ def get_nodes_with_object( nodes_list = [] for node in nodes_to_search: try: - res = neofs_verbs.head_object(wallet, cid, oid, endpoint=node, is_direct=True) + res = neofs_verbs.head_object( + wallet, cid, oid, shell=shell, endpoint=node, is_direct=True + ) if res is not None: logger.info(f"Found object {oid} on node {node}") nodes_list.append(node) @@ -122,7 +132,7 @@ def get_nodes_with_object( @allure.step("Get Nodes Without Object") -def get_nodes_without_object(wallet: str, cid: str, oid: str): +def get_nodes_without_object(wallet: str, cid: str, oid: str, shell: Shell) -> List[str]: """ The function returns list of nodes which do not store the given object. @@ -131,13 +141,16 @@ def get_nodes_without_object(wallet: str, cid: str, oid: str): we request the nodes cid (str): ID of the container which store the object oid (str): object ID + shell: executor for cli command Returns: (list): nodes which do not store the object """ nodes_list = [] for node in NEOFS_NETMAP: try: - res = neofs_verbs.head_object(wallet, cid, oid, endpoint=node, is_direct=True) + res = neofs_verbs.head_object( + wallet, cid, oid, shell=shell, endpoint=node, is_direct=True + ) if res is None: nodes_list.append(node) except Exception as err: diff --git a/robot/resources/lib/python_keywords/tombstone.py b/robot/resources/lib/python_keywords/tombstone.py index f0fd762..53273b2 100644 --- a/robot/resources/lib/python_keywords/tombstone.py +++ b/robot/resources/lib/python_keywords/tombstone.py @@ -1,18 +1,16 @@ -#!/usr/bin/python3 - import json import allure -import neofs_verbs from neo3 import wallet +from neofs_testlib.shell import Shell +from neofs_verbs import head_object + @allure.step("Verify Head Tombstone") -def verify_head_tombstone(wallet_path: str, cid: str, oid_ts: str, oid: str): - header = neofs_verbs.head_object(wallet_path, cid, oid_ts) - header = header["header"] +def verify_head_tombstone(wallet_path: str, cid: str, oid_ts: str, oid: str, shell: Shell): + header = head_object(wallet_path, cid, oid_ts, shell=shell)["header"] assert header["containerID"] == cid, "Tombstone Header CID is wrong" - wlt_data = dict() with open(wallet_path, "r") as fout: wlt_data = json.loads(fout.read()) wlt = wallet.Wallet.from_json(wlt_data, password="")