From f8785fa2993870cc25dae1fc5a96af9aa8fbb212 Mon Sep 17 00:00:00 2001 From: Kirill Sosnovskikh Date: Fri, 20 Dec 2024 17:15:04 +0300 Subject: [PATCH] [#368] Extend `test_object_api_lifetime` test with `EC 3.1` policy Signed-off-by: Kirill Sosnovskikh --- .../testsuites/object/test_object_lifetime.py | 73 ++++++++++--------- 1 file changed, 38 insertions(+), 35 deletions(-) diff --git a/pytest_tests/testsuites/object/test_object_lifetime.py b/pytest_tests/testsuites/object/test_object_lifetime.py index b0926f10..9d073404 100644 --- a/pytest_tests/testsuites/object/test_object_lifetime.py +++ b/pytest_tests/testsuites/object/test_object_lifetime.py @@ -1,58 +1,61 @@ -import logging - import allure import pytest from frostfs_testlib import reporter -from frostfs_testlib.resources.error_patterns import OBJECT_NOT_FOUND -from frostfs_testlib.steps.cli.object import get_object_from_random_node, head_object, put_object_to_random_node -from frostfs_testlib.steps.epoch import get_epoch -from frostfs_testlib.storage.dataclasses.wallet import WalletInfo +from frostfs_testlib.resources.common import STORAGE_GC_TIME +from frostfs_testlib.resources.error_patterns import OBJECT_ALREADY_REMOVED, OBJECT_NOT_FOUND +from frostfs_testlib.steps.cli.container import DEFAULT_EC_PLACEMENT_RULE, DEFAULT_PLACEMENT_RULE +from frostfs_testlib.storage.grpc_operations.interfaces_wrapper import GrpcClientWrapper from frostfs_testlib.testing.cluster_test_base import ClusterTestBase -from frostfs_testlib.testing.test_control import expect_not_raises +from frostfs_testlib.testing.test_control import wait_for_success +from frostfs_testlib.utils import datetime_utils from frostfs_testlib.utils.file_utils import TestFile -from ...helpers.utility import wait_for_gc_pass_on_storage_nodes +from ...helpers.container_request import APE_EVERYONE_ALLOW_ALL, ContainerRequest -logger = logging.getLogger("NeoLogger") + +@wait_for_success(datetime_utils.parse_time(STORAGE_GC_TIME) * 5, datetime_utils.parse_time(STORAGE_GC_TIME)) +def wait_for_object_status_change_to(status: str, grpc_client: GrpcClientWrapper, cid: str, oid: str, endpoint: str) -> None: + with pytest.raises(Exception, match=status): + grpc_client.object.head(cid, oid, endpoint) @pytest.mark.nightly @pytest.mark.sanity @pytest.mark.grpc_api class TestObjectApiLifetime(ClusterTestBase): - @allure.title("Object is removed when lifetime expired (obj_size={object_size})") - def test_object_api_lifetime(self, container: str, test_file: TestFile, default_wallet: WalletInfo): + @allure.title("Object is removed when lifetime expired (obj_size={object_size}, policy={container_request.short_name})") + @pytest.mark.parametrize( + "container_request", + [ + ContainerRequest(DEFAULT_PLACEMENT_RULE, APE_EVERYONE_ALLOW_ALL, "REP 2"), + ContainerRequest(DEFAULT_EC_PLACEMENT_RULE, APE_EVERYONE_ALLOW_ALL, "EC 3.1"), + ], + ) + def test_object_api_lifetime(self, grpc_client: GrpcClientWrapper, container: str, test_file: TestFile): """ Test object deleted after expiration epoch. """ - wallet = default_wallet + with reporter.step("Get current epoch"): + current_epoch = self.get_epoch() + last_active_epoch = current_epoch + 1 - epoch = get_epoch(self.shell, self.cluster) + with reporter.step("Put object to random node"): + oid = grpc_client.object.put_to_random_node(test_file, container, self.cluster, expire_at=last_active_epoch) - oid = put_object_to_random_node(wallet, test_file.path, container, self.shell, self.cluster, expire_at=epoch + 1) - with expect_not_raises(): - head_object(wallet, container, oid, self.shell, self.cluster.default_rpc_endpoint) + with reporter.step("Ensure that expiration of object has expected value"): + object_info: dict = grpc_client.object.head(container, oid, self.cluster.default_rpc_endpoint) + expiration_epoch = int(object_info["header"]["attributes"]["__SYSTEM__EXPIRATION_EPOCH"]) + assert expiration_epoch == last_active_epoch, f"Expiration time set for object is not expected: {expiration_epoch}" - with reporter.step("Tick two epochs"): + with reporter.step("Tick two epoch for object expiration"): self.tick_epochs(2) - # Wait for GC, because object with expiration is counted as alive until GC removes it - wait_for_gc_pass_on_storage_nodes() + with reporter.step("Wait until GC marks object as 'already removed' or 'not found'"): + wait_for_object_status_change_to( + f"{OBJECT_ALREADY_REMOVED}|{OBJECT_NOT_FOUND}", grpc_client, container, oid, self.cluster.default_rpc_endpoint + ) - with reporter.step("Check object deleted because it expires on epoch"): - with pytest.raises(Exception, match=OBJECT_NOT_FOUND): - head_object(wallet, container, oid, self.shell, self.cluster.default_rpc_endpoint) - with pytest.raises(Exception, match=OBJECT_NOT_FOUND): - get_object_from_random_node(wallet, container, oid, self.shell, self.cluster) - - with reporter.step("Tick additional epoch"): - self.tick_epoch() - - wait_for_gc_pass_on_storage_nodes() - - with reporter.step("Check object deleted because it expires on previous epoch"): - with pytest.raises(Exception, match=OBJECT_NOT_FOUND): - head_object(wallet, container, oid, self.shell, self.cluster.default_rpc_endpoint) - with pytest.raises(Exception, match=OBJECT_NOT_FOUND): - get_object_from_random_node(wallet, container, oid, self.shell, self.cluster) + with reporter.step("Try to get object from random node and make sure it is really deleted"): + with pytest.raises(Exception, match=f"{OBJECT_ALREADY_REMOVED}|{OBJECT_NOT_FOUND}"): + grpc_client.object.get_from_random_node(container, oid, self.cluster)