diff --git a/pytest.ini b/pytest.ini index 0b26a229..d8bb8f4e 100644 --- a/pytest.ini +++ b/pytest.ini @@ -19,6 +19,7 @@ markers = grpc_api: standard gRPC API tests grpc_control: tests related to using frostfs-cli control commands grpc_object_lock: gRPC lock tests + grpc_without_user: gRPC without user tests http_gate: HTTP gate contract http_put: HTTP gate test cases with PUT call s3_gate: All S3 gate tests diff --git a/pytest_tests/testsuites/object/test_object_without_user.py b/pytest_tests/testsuites/object/test_object_without_user.py new file mode 100644 index 00000000..4dfd74f6 --- /dev/null +++ b/pytest_tests/testsuites/object/test_object_without_user.py @@ -0,0 +1,414 @@ +import logging +import re + +import allure +import pytest +from frostfs_testlib import reporter +from frostfs_testlib.cli import FrostfsCli +from frostfs_testlib.resources.cli import CLI_DEFAULT_TIMEOUT, FROSTFS_CLI_EXEC +from frostfs_testlib.resources.error_patterns import OBJECT_IS_LOCKED +from frostfs_testlib.resources.wellknown_acl import PUBLIC_ACL_F +from frostfs_testlib.shell import Shell +from frostfs_testlib.steps.cli.container import create_container +from frostfs_testlib.storage.dataclasses.wallet import WalletInfo +from frostfs_testlib.testing.cluster_test_base import ClusterTestBase +from frostfs_testlib.testing.test_control import expect_not_raises +from frostfs_testlib.utils.file_utils import TestFile, get_file_hash + +logger = logging.getLogger("NeoLogger") + + +@pytest.mark.grpc_without_user +class TestObjectApiWithoutUser(ClusterTestBase): + def _parse_oid(self, stdout: str) -> str: + id_str = stdout.strip().split("\n")[-2] + oid = id_str.split(":")[1] + return oid.strip() + + def _parse_tombstone_oid(self, stdout: str) -> str: + id_str = stdout.split("\n")[1] + tombstone = id_str.split(":")[1] + return tombstone.strip() + + @pytest.fixture(scope="function") + def public_container(self, default_wallet: WalletInfo) -> str: + with reporter.step("Create public container"): + cid_public = create_container( + default_wallet, + self.shell, + self.cluster.default_rpc_endpoint, + basic_acl=PUBLIC_ACL_F, + ) + + return cid_public + + @pytest.fixture(scope="class") + def frostfs_cli(self, client_shell: Shell) -> FrostfsCli: + return FrostfsCli(client_shell, FROSTFS_CLI_EXEC) + + @allure.title("Get public container by native API with generate private key") + def test_get_container_with_generated_key(self, frostfs_cli: FrostfsCli, public_container: str): + """ + Validate `container get` native API with flag `--generate-key`. + """ + + cid = public_container + rpc_endpoint = self.cluster.default_rpc_endpoint + + with reporter.step("Get container with generate key"): + with expect_not_raises(): + frostfs_cli.container.get(rpc_endpoint, cid, generate_key=True, timeout=CLI_DEFAULT_TIMEOUT) + + @allure.title("Get list containers by native API with generate private key") + def test_list_containers_with_generated_key(self, frostfs_cli: FrostfsCli, default_wallet: WalletInfo, public_container: str): + """ + Validate `container list` native API with flag `--generate-key`. + """ + + rpc_endpoint = self.cluster.default_rpc_endpoint + owner = default_wallet.get_address_from_json(0) + + with reporter.step("List containers with generate key"): + with expect_not_raises(): + result = frostfs_cli.container.list(rpc_endpoint, owner=owner, generate_key=True, timeout=CLI_DEFAULT_TIMEOUT) + + with reporter.step("Expect container in received containers list"): + containers = result.stdout.split() + assert public_container in containers + + @allure.title("Get list of public container objects by native API with generate private key") + def test_list_objects_with_generate_key(self, frostfs_cli: FrostfsCli, public_container: str): + """ + Validate `container list_objects` native API with flag `--generate-key`. + """ + + cid = public_container + rpc_endpoint = self.cluster.default_rpc_endpoint + + with reporter.step("List objects with generate key"): + with expect_not_raises(): + result = frostfs_cli.container.list_objects(rpc_endpoint, cid, generate_key=True, timeout=CLI_DEFAULT_TIMEOUT) + + with reporter.step("Expect empty objects list"): + objects = result.stdout.split() + assert len(objects) == 0, objects + + @allure.title("Search public container nodes by native API with generate private key") + def test_search_nodes_with_generate_key(self, frostfs_cli: FrostfsCli, public_container: str): + """ + Validate `container search_node` native API with flag `--generate-key`. + """ + + cid = public_container + rpc_endpoint = self.cluster.default_rpc_endpoint + + with reporter.step("Search nodes with generate key"): + with expect_not_raises(): + frostfs_cli.container.search_node(rpc_endpoint, cid, generate_key=True, timeout=CLI_DEFAULT_TIMEOUT) + + @allure.title("Put object into public container by native API with generate private key (obj_size={object_size})") + def test_put_object_with_generate_key(self, frostfs_cli: FrostfsCli, public_container: str, file_path: TestFile): + """ + Validate `object put` into container with public ACL and flag `--generate-key`. + """ + + cid = public_container + rpc_endpoint = self.cluster.default_rpc_endpoint + + with reporter.step("Put object with generate key"): + with expect_not_raises(): + result = frostfs_cli.object.put( + rpc_endpoint, + cid, + file_path, + generate_key=True, + no_progress=True, + timeout=CLI_DEFAULT_TIMEOUT, + ) + + oid = self._parse_oid(result.stdout) + + with reporter.step("List objects with generate key"): + result = frostfs_cli.container.list_objects(rpc_endpoint, cid, generate_key=True, timeout=CLI_DEFAULT_TIMEOUT) + + with reporter.step("Expect object in received objects list"): + objects = result.stdout.split() + assert oid in objects, objects + + @allure.title("Get public container object by native API with generate private key (obj_size={object_size})") + def test_get_object_with_generate_key(self, frostfs_cli: FrostfsCli, public_container: str, file_path: TestFile): + """ + Validate `object get` for container with public ACL and flag `--generate-key`. + """ + + cid = public_container + rpc_endpoint = self.cluster.default_rpc_endpoint + expected_hash = get_file_hash(file_path) + + with reporter.step("Put object with generate key"): + result = frostfs_cli.object.put( + rpc_endpoint, + cid, + file_path, + generate_key=True, + no_progress=True, + timeout=CLI_DEFAULT_TIMEOUT, + ) + + oid = self._parse_oid(result.stdout) + + with reporter.step("Get object with generate key"): + with expect_not_raises(): + frostfs_cli.object.get( + rpc_endpoint, + cid, + oid, + file=file_path, + generate_key=True, + no_progress=True, + timeout=CLI_DEFAULT_TIMEOUT, + ) + + downloaded_hash = get_file_hash(file_path) + + with reporter.step("Validate downloaded file"): + assert expected_hash == downloaded_hash + + @allure.title("Head public container object by native API with generate private key (obj_size={object_size})") + def test_head_object_with_generate_key(self, frostfs_cli: FrostfsCli, public_container: str, file_path: TestFile): + """ + Validate `object head` for container with public ACL and flag `--generate-key`. + """ + + cid = public_container + rpc_endpoint = self.cluster.default_rpc_endpoint + + with reporter.step("Put object with generate key"): + result = frostfs_cli.object.put( + rpc_endpoint, + cid, + file_path, + generate_key=True, + no_progress=True, + timeout=CLI_DEFAULT_TIMEOUT, + ) + + oid = self._parse_oid(result.stdout) + + with reporter.step("Head object with generate key"): + with expect_not_raises(): + frostfs_cli.object.head(rpc_endpoint, cid, oid, generate_key=True, timeout=CLI_DEFAULT_TIMEOUT) + + @allure.title("Delete public container object by native API with generate private key (obj_size={object_size})") + def test_delete_object_with_generate_key(self, frostfs_cli: FrostfsCli, public_container: str, file_path: TestFile): + """ + Validate `object delete` for container with public ACL and flag `--generate key`. + """ + + cid = public_container + rpc_endpoint = self.cluster.default_rpc_endpoint + + with reporter.step("Put object with generate key"): + result = frostfs_cli.object.put( + rpc_endpoint, + cid, + file_path, + generate_key=True, + no_progress=True, + timeout=CLI_DEFAULT_TIMEOUT, + ) + + oid = self._parse_oid(result.stdout) + + with reporter.step("Delete object with generate key"): + with expect_not_raises(): + result = frostfs_cli.object.delete(rpc_endpoint, cid, oid, generate_key=True, timeout=CLI_DEFAULT_TIMEOUT) + + oid = self._parse_tombstone_oid(result.stdout) + + with reporter.step("Head object with generate key"): + result = frostfs_cli.object.head( + rpc_endpoint, + cid, + oid, + generate_key=True, + timeout=CLI_DEFAULT_TIMEOUT, + ) + + with reporter.step("Expect object type TOMBSTONE"): + object_type = re.search(r"(?<=type: )tombstone", result.stdout, re.IGNORECASE).group() + assert object_type == "TOMBSTONE", object_type + + @allure.title("Lock public container object by native API with generate private key (obj_size={object_size})") + def test_lock_object_with_generate_key(self, frostfs_cli: FrostfsCli, public_container: str, file_path: TestFile): + """ + Validate `object lock` for container with public ACL and flag `--generate-key`. + Attempt to delete the locked object. + """ + + cid = public_container + rpc_endpoint = self.cluster.default_rpc_endpoint + + with reporter.step("Put object with generate key"): + result = frostfs_cli.object.put( + rpc_endpoint, + cid, + file_path, + generate_key=True, + no_progress=True, + timeout=CLI_DEFAULT_TIMEOUT, + ) + + oid = self._parse_oid(result.stdout) + + with reporter.step("Lock object with generate key"): + with expect_not_raises(): + frostfs_cli.object.lock( + rpc_endpoint, + cid, + oid, + generate_key=True, + timeout=CLI_DEFAULT_TIMEOUT, + lifetime=5, + ) + + with reporter.step("Delete locked object with generate key and expect error"): + with pytest.raises(Exception, match=OBJECT_IS_LOCKED): + frostfs_cli.object.delete( + rpc_endpoint, + cid, + oid, + generate_key=True, + timeout=CLI_DEFAULT_TIMEOUT, + ) + + @allure.title("Search public container objects by native API with generate private key (obj_size={object_size})") + def test_search_object_with_generate_key(self, frostfs_cli: FrostfsCli, public_container: str, file_path: TestFile): + """ + Validate `object search` for container with public ACL and flag `--generate-key`. + """ + + cid = public_container + rpc_endpoint = self.cluster.default_rpc_endpoint + + with reporter.step("Put object with generate key"): + result = frostfs_cli.object.put( + rpc_endpoint, + cid, + file_path, + generate_key=True, + no_progress=True, + timeout=CLI_DEFAULT_TIMEOUT, + ) + + oid = self._parse_oid(result.stdout) + + with reporter.step("Object search with generate key"): + with expect_not_raises(): + result = frostfs_cli.object.search(rpc_endpoint, cid, generate_key=True, timeout=CLI_DEFAULT_TIMEOUT) + + with reporter.step("Expect object in received objects list of container"): + object_ids = re.findall(r"(\w{43,44})", result.stdout) + assert oid in object_ids + + @allure.title("Get range of public container object by native API with generate private key (obj_size={object_size})") + def test_range_with_generate_key(self, frostfs_cli: FrostfsCli, public_container: str, file_path: TestFile): + """ + Validate `object range` for container with public ACL and `--generate-key`. + """ + + cid = public_container + rpc_endpoint = self.cluster.default_rpc_endpoint + + with reporter.step("Put object with generate key"): + result = frostfs_cli.object.put( + rpc_endpoint, + cid, + file_path, + generate_key=True, + no_progress=True, + timeout=CLI_DEFAULT_TIMEOUT, + ) + + oid = self._parse_oid(result.stdout) + + with reporter.step("Get range of object with generate key"): + with expect_not_raises(): + frostfs_cli.object.range( + rpc_endpoint, + cid, + oid, + "0:10", + file=file_path, + generate_key=True, + timeout=CLI_DEFAULT_TIMEOUT, + ) + + @allure.title("Get hash of public container object by native API with generate private key (obj_size={object_size})") + def test_hash_with_generate_key(self, frostfs_cli: FrostfsCli, public_container: str, file_path: TestFile): + """ + Validate `object hash` for container with public ACL and `--generate-key`. + """ + + cid = public_container + rpc_endpoint = self.cluster.default_rpc_endpoint + + with reporter.step("Put object with generate key"): + result = frostfs_cli.object.put( + rpc_endpoint, + cid, + file_path, + generate_key=True, + no_progress=True, + timeout=CLI_DEFAULT_TIMEOUT, + ) + + oid = self._parse_oid(result.stdout) + + with reporter.step("Get range hash of object with generate key"): + with expect_not_raises(): + frostfs_cli.object.hash( + rpc_endpoint, + cid, + oid, + range="0:10", + generate_key=True, + timeout=CLI_DEFAULT_TIMEOUT, + ) + + @allure.title("Get public container object nodes by native API with generate private key (obj_size={object_size})") + def test_nodes_with_generate_key(self, frostfs_cli: FrostfsCli, public_container: str, file_path: TestFile): + """ + Validate `object nodes` for container with public ACL and `--generate-key`. + """ + + cid = public_container + rpc_endpoint = self.cluster.default_rpc_endpoint + + with reporter.step("Put object with generate key"): + result = frostfs_cli.object.put( + rpc_endpoint, + cid, + file_path, + no_progress=True, + generate_key=True, + timeout=CLI_DEFAULT_TIMEOUT, + ) + + oid = self._parse_oid(result.stdout) + + with reporter.step("Configure frostfs-cli for alive remote node"): + alive_node = self.cluster.cluster_nodes[0] + node_shell = alive_node.host.get_shell() + rpc_endpoint = alive_node.storage_node.get_rpc_endpoint() + node_frostfs_cli = FrostfsCli(node_shell, FROSTFS_CLI_EXEC) + + with reporter.step("Get object nodes with generate key"): + with expect_not_raises(): + node_frostfs_cli.object.nodes( + rpc_endpoint, + cid, + oid=oid, + generate_key=True, + timeout=CLI_DEFAULT_TIMEOUT, + )