import allure import pytest from frostfs_testlib import reporter 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 wait_for_success from frostfs_testlib.utils import datetime_utils from frostfs_testlib.utils.file_utils import TestFile from ...helpers.container_request import APE_EVERYONE_ALLOW_ALL, ContainerRequest @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}, 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. """ with reporter.step("Get current epoch"): current_epoch = self.get_epoch() last_active_epoch = current_epoch + 1 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) 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 epoch for object expiration"): self.tick_epochs(2) 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("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)