From 76d83c7925797bd5d6bfd0bd183b13e2a5996e00 Mon Sep 17 00:00:00 2001 From: Kirill Sosnovskikh Date: Fri, 26 Jul 2024 20:24:46 +0300 Subject: [PATCH] [#278] Add object operation tests with `-g` flag The tests check the result of an 'anonymous' user interacting with a gRPC API object. Signed-off-by: Kirill Sosnovskikh --- pytest.ini | 1 + .../object/test_object_without_user.py | 449 ++++++++++++++++++ 2 files changed, 450 insertions(+) create mode 100644 pytest_tests/testsuites/object/test_object_without_user.py 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..7b79092a --- /dev/null +++ b/pytest_tests/testsuites/object/test_object_without_user.py @@ -0,0 +1,449 @@ +import logging +import os +import re +import uuid +from collections.abc import Generator + +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.common import ASSETS_DIR +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, delete_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 + +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) -> Generator[str, None, None]: + with reporter.step("Create public container"): + cid_public = create_container( + default_wallet, + self.shell, + self.cluster.default_rpc_endpoint, + basic_acl=PUBLIC_ACL_F, + ) + + yield cid_public + + with reporter.step("Delete public container"): + delete_container( + default_wallet, + cid_public, + self.shell, + self.cluster.default_rpc_endpoint, + force=True, + ) + + @pytest.fixture(scope="class") + def frostfs_cli(self, client_shell: Shell) -> FrostfsCli: + return FrostfsCli(client_shell, FROSTFS_CLI_EXEC) + + @pytest.fixture(scope="function") + def test_file(self) -> TestFile: + write_object = str(uuid.uuid4()) + return TestFile(os.path.join(ASSETS_DIR, write_object)) + + @allure.title("Get public container") + def test_get_container_with_generated_key(self, frostfs_cli: FrostfsCli, public_container: str): + """ + Get container with public ACL, with generated private key. + """ + + cid = public_container + rpc_endpoint = self.cluster.default_rpc_endpoint + + with reporter.step("Get container with generate key"): + with expect_not_raises(): + result = frostfs_cli.container.get(rpc_endpoint, cid, generate_key=True, timeout=CLI_DEFAULT_TIMEOUT) + + assert result.return_code == 0, result.stderr + + @allure.title("Get list containers") + def test_list_containers_with_generated_key(self, frostfs_cli: FrostfsCli, default_wallet: WalletInfo, public_container: str): + """ + Get list containers with generated private key. + """ + + rpc_endpoint = self.cluster.default_rpc_endpoint + owner = default_wallet.get_address_from_json(0) + + with reporter.step("Get 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) + + assert result.return_code == 0, result.stderr + + containers = result.stdout.split() + assert public_container in containers + + @allure.title("Get list of public container objects") + def test_list_objects_with_generate_key(self, frostfs_cli: FrostfsCli, public_container: str): + """ + Get list container objects with public ACL, with generated private key. + """ + + cid = public_container + rpc_endpoint = self.cluster.default_rpc_endpoint + + with reporter.step("Get 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) + + assert result.return_code == 0, result.stderr + + objects = result.stdout.split() + assert len(objects) == 0, objects + + @allure.title("Search public container nodes") + def test_search_nodes_with_generate_key(self, frostfs_cli: FrostfsCli, public_container: str): + """ + Get list container nodes with public ACL, with generated private key. + """ + + cid = public_container + rpc_endpoint = self.cluster.default_rpc_endpoint + + with reporter.step("Search nodes with generate key"): + with expect_not_raises(): + result = frostfs_cli.container.search_node(rpc_endpoint, cid, generate_key=True, timeout=CLI_DEFAULT_TIMEOUT) + + assert result.return_code == 0, result.stderr + + @allure.title("Put object into public container (obj_size={object_size})") + def test_put_object_with_generate_key(self, frostfs_cli: FrostfsCli, public_container: str, file_path: str): + """ + Put object into container with public ACL, with generated private key + and check object in container object list. + """ + + cid = public_container + rpc_endpoint = self.cluster.default_rpc_endpoint + + with reporter.step("Upload 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, + ) + + assert result.return_code == 0, result.stderr + + oid = self._parse_oid(result.stdout) + + with reporter.step("Get list objects and check occurrence of uploaded object"): + result = frostfs_cli.container.list_objects(rpc_endpoint, cid, generate_key=True, timeout=CLI_DEFAULT_TIMEOUT) + objects = result.stdout.split() + assert oid in objects, objects + + @allure.title("Get public container object (obj_size={object_size})") + def test_get_object_with_generate_key(self, frostfs_cli: FrostfsCli, public_container: str, file_path: str, test_file: TestFile): + """ + Get object uploaded to container with public ACL, with generated private key. + """ + + cid = public_container + rpc_endpoint = self.cluster.default_rpc_endpoint + + with reporter.step("Upload 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=test_file, + generate_key=True, + no_progress=True, + timeout=CLI_DEFAULT_TIMEOUT, + ) + + with reporter.step("Validate downloaded file"): + with open(file_path, "rb") as file: + expected = file.read() + + with open(test_file.path, "rb") as file: + data = file.read() + + assert data == expected + + @allure.title("Head public container object (obj_size={object_size})") + def test_head_object_with_generate_key(self, frostfs_cli: FrostfsCli, public_container: str, file_path: str): + """ + Head object uploaded to container with public ACL, with generated private key. + """ + + cid = public_container + rpc_endpoint = self.cluster.default_rpc_endpoint + + with reporter.step("Upload 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(): + result = frostfs_cli.object.head(rpc_endpoint, cid, oid, generate_key=True, timeout=CLI_DEFAULT_TIMEOUT) + + assert result.return_code == 0, result.stderr + + @allure.title("Delete public container object (obj_size={object_size})") + def test_delete_object_with_generate_key(self, frostfs_cli: FrostfsCli, public_container: str, file_path: str): + """ + Delete object uploaded to container with public ACL, with generated private key. + """ + + cid = public_container + rpc_endpoint = self.cluster.default_rpc_endpoint + + with reporter.step("Upload 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) + + assert result.return_code == 0, result.stderr + + oid = self._parse_tombstone_oid(result.stdout) + + with reporter.step("Head object and expected tombstone"): + result = frostfs_cli.object.head( + rpc_endpoint, + cid, + oid, + generate_key=True, + timeout=CLI_DEFAULT_TIMEOUT, + ) + + object_type = re.search(r"(?<=type: )tombstone", result.stdout, re.IGNORECASE).group() + assert object_type == "TOMBSTONE", object_type + + @allure.title("Lock public container object (obj_size={object_size})") + def test_lock_object_with_generate_key(self, frostfs_cli: FrostfsCli, public_container: str, file_path: str): + """ + Lock object uploaded to container with public ACL, with generated private key. + Attempt to delete the locked object. + """ + + cid = public_container + rpc_endpoint = self.cluster.default_rpc_endpoint + + with reporter.step("Upload 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 and expect error"): + with pytest.raises(Exception, match=OBJECT_IS_LOCKED): + result = frostfs_cli.object.delete( + rpc_endpoint, + cid, + oid, + generate_key=True, + timeout=CLI_DEFAULT_TIMEOUT, + ) + + @allure.title("Search public container objects (obj_size={object_size})") + def test_search_object_with_generate_key(self, frostfs_cli: FrostfsCli, public_container: str, file_path: str): + """ + Search container objects with public ACL, with generated private key. + """ + + cid = public_container + rpc_endpoint = self.cluster.default_rpc_endpoint + + with reporter.step("Upload 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("Search objects with generate key"): + with expect_not_raises(): + result = frostfs_cli.object.search(rpc_endpoint, cid, generate_key=True, timeout=CLI_DEFAULT_TIMEOUT) + + assert result.return_code == 0, result.stderr + + object_ids = re.findall(r"(\w{43,44})", result.stdout) + assert oid in object_ids + + @allure.title("Get range of public container object (obj_size={object_size})") + def test_range_with_generate_key(self, frostfs_cli: FrostfsCli, public_container: str, file_path: str, test_file: TestFile): + """ + Get range of container object with public ACL, with generated private key. + """ + + cid = public_container + rpc_endpoint = self.cluster.default_rpc_endpoint + + with reporter.step("Upload 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=test_file, + generate_key=True, + timeout=CLI_DEFAULT_TIMEOUT, + ) + + @allure.title("Get hash of public container object (obj_size={object_size})") + def test_hash_with_generate_key(self, frostfs_cli: FrostfsCli, public_container: str, file_path: str): + """ + Get range hash of container object with public ACL, with generated private key. + """ + + cid = public_container + rpc_endpoint = self.cluster.default_rpc_endpoint + + with reporter.step("Upload 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(): + result = frostfs_cli.object.hash( + rpc_endpoint, + cid, + oid, + range="0:10", + generate_key=True, + timeout=CLI_DEFAULT_TIMEOUT, + ) + + assert result.return_code == 0, result.stderr + + @allure.title("Get public container object nodes (obj_size={object_size})") + def test_nodes_with_generate_key(self, frostfs_cli: FrostfsCli, public_container: str, file_path: str): + """ + Get container object nodes with public ACL, with generated private key. + """ + + cid = public_container + rpc_endpoint = self.cluster.default_rpc_endpoint + + with reporter.step("Upload 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) + + 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(): + result = node_frostfs_cli.object.nodes( + rpc_endpoint, + cid, + oid=oid, + generate_key=True, + timeout=CLI_DEFAULT_TIMEOUT, + ) + + assert result.return_code == 0, result.stderr