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.shell import Shell 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.nightly @pytest.mark.grpc_api @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="class") def cli_without_wallet(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, cli_without_wallet: FrostfsCli, container: str, rpc_endpoint: str): """ Validate `container get` native API with flag `--generate-key`. """ with reporter.step("Get container with generate key"): with expect_not_raises(): cli_without_wallet.container.get(rpc_endpoint, container, 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, cli_without_wallet: FrostfsCli, default_wallet: WalletInfo, container: str, rpc_endpoint: str ): """ Validate `container list` native API with flag `--generate-key`. """ owner = default_wallet.get_address_from_json(0) with reporter.step("List containers with generate key"): with expect_not_raises(): result = cli_without_wallet.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 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, cli_without_wallet: FrostfsCli, container: str, rpc_endpoint: str): """ Validate `container list_objects` native API with flag `--generate-key`. """ with reporter.step("List objects with generate key"): with expect_not_raises(): result = cli_without_wallet.container.list_objects(rpc_endpoint, container, 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, cli_without_wallet: FrostfsCli, container: str, rpc_endpoint: str): """ Validate `container search_node` native API with flag `--generate-key`. """ with reporter.step("Search nodes with generate key"): with expect_not_raises(): cli_without_wallet.container.search_node(rpc_endpoint, container, 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, cli_without_wallet: FrostfsCli, container: str, file_path: TestFile, rpc_endpoint: str): """ Validate `object put` into container with public ACL and flag `--generate-key`. """ with reporter.step("Put object with generate key"): with expect_not_raises(): result = cli_without_wallet.object.put( rpc_endpoint, container, 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 = cli_without_wallet.container.list_objects(rpc_endpoint, container, 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, cli_without_wallet: FrostfsCli, container: str, file_path: TestFile, rpc_endpoint: str): """ Validate `object get` for container with public ACL and flag `--generate-key`. """ expected_hash = get_file_hash(file_path) with reporter.step("Put object with generate key"): result = cli_without_wallet.object.put( rpc_endpoint, container, 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(): cli_without_wallet.object.get( rpc_endpoint, container, 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, cli_without_wallet: FrostfsCli, container: str, file_path: TestFile, rpc_endpoint: str): """ Validate `object head` for container with public ACL and flag `--generate-key`. """ with reporter.step("Put object with generate key"): result = cli_without_wallet.object.put( rpc_endpoint, container, 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(): cli_without_wallet.object.head(rpc_endpoint, container, 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, cli_without_wallet: FrostfsCli, container: str, file_path: TestFile, rpc_endpoint: str): """ Validate `object delete` for container with public ACL and flag `--generate key`. """ with reporter.step("Put object with generate key"): result = cli_without_wallet.object.put( rpc_endpoint, container, 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 = cli_without_wallet.object.delete(rpc_endpoint, container, oid, generate_key=True, timeout=CLI_DEFAULT_TIMEOUT) oid = self._parse_tombstone_oid(result.stdout) with reporter.step("Head object with generate key"): result = cli_without_wallet.object.head( rpc_endpoint, container, 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, cli_without_wallet: FrostfsCli, container: str, file_path: TestFile, rpc_endpoint: str): """ Validate `object lock` for container with public ACL and flag `--generate-key`. Attempt to delete the locked object. """ with reporter.step("Put object with generate key"): result = cli_without_wallet.object.put( rpc_endpoint, container, 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(): cli_without_wallet.object.lock( rpc_endpoint, container, 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): cli_without_wallet.object.delete( rpc_endpoint, container, 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, cli_without_wallet: FrostfsCli, container: str, file_path: TestFile, rpc_endpoint: str): """ Validate `object search` for container with public ACL and flag `--generate-key`. """ with reporter.step("Put object with generate key"): result = cli_without_wallet.object.put( rpc_endpoint, container, 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 = cli_without_wallet.object.search(rpc_endpoint, container, 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, cli_without_wallet: FrostfsCli, container: str, file_path: TestFile, rpc_endpoint: str): """ Validate `object range` for container with public ACL and `--generate-key`. """ with reporter.step("Put object with generate key"): result = cli_without_wallet.object.put( rpc_endpoint, container, 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(): cli_without_wallet.object.range( rpc_endpoint, container, 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, cli_without_wallet: FrostfsCli, container: str, file_path: TestFile, rpc_endpoint: str): """ Validate `object hash` for container with public ACL and `--generate-key`. """ with reporter.step("Put object with generate key"): result = cli_without_wallet.object.put( rpc_endpoint, container, 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(): cli_without_wallet.object.hash( rpc_endpoint, container, 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, cli_without_wallet: FrostfsCli, container: str, file_path: TestFile, rpc_endpoint: str): """ Validate `object nodes` for container with public ACL and `--generate-key`. """ with reporter.step("Put object with generate key"): result = cli_without_wallet.object.put( rpc_endpoint, container, 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() alive_endpoint = alive_node.storage_node.get_rpc_endpoint() node_frostfs_cli_wo_wallet = FrostfsCli(node_shell, FROSTFS_CLI_EXEC) with reporter.step("Get object nodes with generate key"): with expect_not_raises(): node_frostfs_cli_wo_wallet.object.nodes( alive_endpoint, container, oid=oid, generate_key=True, timeout=CLI_DEFAULT_TIMEOUT, )