2024-06-24 23:27:54 +00:00
|
|
|
import os
|
|
|
|
|
2022-09-26 08:25:49 +00:00
|
|
|
import allure
|
|
|
|
import pytest
|
2023-11-29 13:34:59 +00:00
|
|
|
from frostfs_testlib import reporter
|
2023-10-31 14:51:09 +00:00
|
|
|
from frostfs_testlib.s3 import S3ClientWrapper, VersioningStatus
|
2023-05-15 09:59:33 +00:00
|
|
|
from frostfs_testlib.steps.s3 import s3_helper
|
2023-08-02 11:54:03 +00:00
|
|
|
from frostfs_testlib.storage.dataclasses.object_size import ObjectSize
|
2024-06-24 23:27:54 +00:00
|
|
|
from frostfs_testlib.utils.file_utils import generate_file, generate_file_with_content, get_file_content
|
2022-10-11 08:18:08 +00:00
|
|
|
|
2022-09-26 08:25:49 +00:00
|
|
|
|
|
|
|
@pytest.mark.s3_gate
|
2022-11-10 05:27:52 +00:00
|
|
|
@pytest.mark.s3_gate_versioning
|
2023-05-15 09:59:33 +00:00
|
|
|
class TestS3GateVersioning:
|
2023-09-08 10:35:34 +00:00
|
|
|
@allure.title("Impossible to disable versioning with object_lock (s3_client={s3_client})")
|
2023-05-15 09:59:33 +00:00
|
|
|
def test_s3_version_off(self, s3_client: S3ClientWrapper):
|
|
|
|
bucket = s3_client.create_bucket(object_lock_enabled_for_bucket=True)
|
2022-09-26 08:25:49 +00:00
|
|
|
with pytest.raises(Exception):
|
2023-05-15 09:59:33 +00:00
|
|
|
s3_helper.set_bucket_versioning(s3_client, bucket, VersioningStatus.SUSPENDED)
|
2022-09-26 08:25:49 +00:00
|
|
|
|
2024-06-24 23:27:54 +00:00
|
|
|
@allure.title("Object versioning (s3_client={s3_client})")
|
|
|
|
def test_s3_api_versioning(self, s3_client: S3ClientWrapper, bucket: str, simple_object_size: ObjectSize):
|
|
|
|
"""
|
|
|
|
Test checks basic versioning functionality for S3 bucket.
|
|
|
|
"""
|
|
|
|
version_1_content = "Version 1"
|
|
|
|
version_2_content = "Version 2"
|
|
|
|
file_name_simple = generate_file_with_content(simple_object_size.value, content=version_1_content)
|
|
|
|
obj_key = os.path.basename(file_name_simple)
|
|
|
|
s3_helper.set_bucket_versioning(s3_client, bucket, VersioningStatus.ENABLED)
|
|
|
|
|
|
|
|
with reporter.step("Put several versions of object into bucket"):
|
|
|
|
version_id_1 = s3_client.put_object(bucket, file_name_simple)
|
|
|
|
generate_file_with_content(simple_object_size.value, file_path=file_name_simple, content=version_2_content)
|
|
|
|
version_id_2 = s3_client.put_object(bucket, file_name_simple)
|
|
|
|
|
|
|
|
with reporter.step("Check bucket shows all versions"):
|
|
|
|
versions = s3_client.list_objects_versions(bucket)
|
|
|
|
obj_versions = {version.get("VersionId") for version in versions if version.get("Key") == obj_key}
|
|
|
|
assert obj_versions == {
|
|
|
|
version_id_1,
|
|
|
|
version_id_2,
|
|
|
|
}, f"Expected object has versions: {version_id_1, version_id_2}"
|
|
|
|
|
|
|
|
with reporter.step("Show information about particular version"):
|
|
|
|
for version_id in (version_id_1, version_id_2):
|
|
|
|
response = s3_client.head_object(bucket, obj_key, version_id=version_id)
|
|
|
|
assert "LastModified" in response, "Expected LastModified field"
|
|
|
|
assert "ETag" in response, "Expected ETag field"
|
|
|
|
assert response.get("VersionId") == version_id, f"Expected VersionId is {version_id}"
|
|
|
|
assert response.get("ContentLength") != 0, "Expected ContentLength is not zero"
|
|
|
|
|
|
|
|
with reporter.step("Check object's attributes"):
|
|
|
|
for version_id in (version_id_1, version_id_2):
|
|
|
|
got_attrs = s3_client.get_object_attributes(bucket, obj_key, ["ETag"], version_id=version_id)
|
|
|
|
if got_attrs:
|
|
|
|
assert got_attrs.get("VersionId") == version_id, f"Expected VersionId is {version_id}"
|
|
|
|
|
|
|
|
with reporter.step("Delete object and check it was deleted"):
|
|
|
|
response = s3_client.delete_object(bucket, obj_key)
|
|
|
|
version_id_delete = response.get("VersionId")
|
|
|
|
|
|
|
|
with pytest.raises(Exception, match=r".*Not Found.*"):
|
|
|
|
s3_client.head_object(bucket, obj_key)
|
|
|
|
|
|
|
|
with reporter.step("Get content for all versions and check it is correct"):
|
|
|
|
for version, content in (
|
|
|
|
(version_id_2, version_2_content),
|
|
|
|
(version_id_1, version_1_content),
|
|
|
|
):
|
|
|
|
file_name = s3_client.get_object(bucket, obj_key, version_id=version)
|
|
|
|
got_content = get_file_content(file_name)
|
|
|
|
assert got_content == content, f"Expected object content is\n{content}\nGot\n{got_content}"
|
|
|
|
|
|
|
|
with reporter.step("Restore previous object version"):
|
|
|
|
s3_client.delete_object(bucket, obj_key, version_id=version_id_delete)
|
|
|
|
|
|
|
|
file_name = s3_client.get_object(bucket, obj_key)
|
|
|
|
got_content = get_file_content(file_name)
|
|
|
|
assert (
|
|
|
|
got_content == version_2_content
|
|
|
|
), f"Expected object content is\n{version_2_content}\nGot\n{got_content}"
|
|
|
|
|
2023-09-08 10:35:34 +00:00
|
|
|
@allure.title("Enable and disable versioning without object_lock (s3_client={s3_client})")
|
2023-08-02 11:54:03 +00:00
|
|
|
def test_s3_version(self, s3_client: S3ClientWrapper, simple_object_size: ObjectSize):
|
|
|
|
file_path = generate_file(simple_object_size.value)
|
2023-05-15 09:59:33 +00:00
|
|
|
file_name = s3_helper.object_key_from_file_path(file_path)
|
2022-09-26 08:25:49 +00:00
|
|
|
bucket_objects = [file_name]
|
2023-05-15 09:59:33 +00:00
|
|
|
bucket = s3_client.create_bucket(object_lock_enabled_for_bucket=False)
|
|
|
|
s3_helper.set_bucket_versioning(s3_client, bucket, VersioningStatus.SUSPENDED)
|
2022-09-26 08:25:49 +00:00
|
|
|
|
2023-11-29 13:34:59 +00:00
|
|
|
with reporter.step("Put object into bucket"):
|
2023-05-15 09:59:33 +00:00
|
|
|
s3_client.put_object(bucket, file_path)
|
|
|
|
objects_list = s3_client.list_objects(bucket)
|
2023-10-31 14:51:09 +00:00
|
|
|
assert objects_list == bucket_objects, f"Expected list with single objects in bucket, got {objects_list}"
|
2023-05-15 09:59:33 +00:00
|
|
|
object_version = s3_client.list_objects_versions(bucket)
|
2023-10-31 14:51:09 +00:00
|
|
|
actual_version = [version.get("VersionId") for version in object_version if version.get("Key") == file_name]
|
|
|
|
assert actual_version == ["null"], f"Expected version is null in list-object-versions, got {object_version}"
|
2023-05-15 09:59:33 +00:00
|
|
|
object_0 = s3_client.head_object(bucket, file_name)
|
2022-10-16 16:29:09 +00:00
|
|
|
assert (
|
|
|
|
object_0.get("VersionId") == "null"
|
|
|
|
), f"Expected version is null in head-object, got {object_0.get('VersionId')}"
|
2022-09-26 08:25:49 +00:00
|
|
|
|
2023-05-15 09:59:33 +00:00
|
|
|
s3_helper.set_bucket_versioning(s3_client, bucket, VersioningStatus.ENABLED)
|
2022-09-26 08:25:49 +00:00
|
|
|
|
2023-11-29 13:34:59 +00:00
|
|
|
with reporter.step("Put several versions of object into bucket"):
|
2023-05-15 09:59:33 +00:00
|
|
|
version_id_1 = s3_client.put_object(bucket, file_path)
|
2023-08-02 11:54:03 +00:00
|
|
|
file_name_1 = generate_file_with_content(simple_object_size.value, file_path=file_path)
|
2023-05-15 09:59:33 +00:00
|
|
|
version_id_2 = s3_client.put_object(bucket, file_name_1)
|
2022-09-26 08:25:49 +00:00
|
|
|
|
2023-11-29 13:34:59 +00:00
|
|
|
with reporter.step("Check bucket shows all versions"):
|
2023-05-15 09:59:33 +00:00
|
|
|
versions = s3_client.list_objects_versions(bucket)
|
2023-10-31 14:51:09 +00:00
|
|
|
obj_versions = [version.get("VersionId") for version in versions if version.get("Key") == file_name]
|
2022-09-26 08:25:49 +00:00
|
|
|
assert (
|
|
|
|
obj_versions.sort() == [version_id_1, version_id_2, "null"].sort()
|
|
|
|
), f"Expected object has versions: {version_id_1, version_id_2, 'null'}"
|
|
|
|
|
2023-11-29 13:34:59 +00:00
|
|
|
with reporter.step("Get object"):
|
2023-05-15 09:59:33 +00:00
|
|
|
object_1 = s3_client.get_object(bucket, file_name, full_output=True)
|
2023-10-31 14:51:09 +00:00
|
|
|
assert object_1.get("VersionId") == version_id_2, f"Get object with version {version_id_2}"
|
2022-09-26 08:25:49 +00:00
|
|
|
|
2023-11-29 13:34:59 +00:00
|
|
|
with reporter.step("Get first version of object"):
|
2023-05-15 09:59:33 +00:00
|
|
|
object_2 = s3_client.get_object(bucket, file_name, version_id_1, full_output=True)
|
2023-10-31 14:51:09 +00:00
|
|
|
assert object_2.get("VersionId") == version_id_1, f"Get object with version {version_id_1}"
|
2022-09-26 08:25:49 +00:00
|
|
|
|
2023-11-29 13:34:59 +00:00
|
|
|
with reporter.step("Get second version of object"):
|
2023-05-15 09:59:33 +00:00
|
|
|
object_3 = s3_client.get_object(bucket, file_name, version_id_2, full_output=True)
|
2023-10-31 14:51:09 +00:00
|
|
|
assert object_3.get("VersionId") == version_id_2, f"Get object with version {version_id_2}"
|