forked from TrueCloudLab/frostfs-testcases
Refactor for cluster usage
Signed-off-by: Andrey Berezin <a.berezin@yadro.com>
This commit is contained in:
parent
d9e881001e
commit
bd05aae585
46 changed files with 3859 additions and 2703 deletions
|
@ -4,6 +4,7 @@ import sys
|
|||
|
||||
import allure
|
||||
import pytest
|
||||
from cluster import Cluster
|
||||
from common import COMPLEX_OBJ_SIZE, SIMPLE_OBJ_SIZE
|
||||
from container import create_container
|
||||
from file_helper import generate_file, get_file_content, get_file_hash
|
||||
|
@ -12,16 +13,17 @@ from neofs_testlib.shell import Shell
|
|||
from pytest import FixtureRequest
|
||||
from python_keywords.neofs_verbs import (
|
||||
get_netmap_netinfo,
|
||||
get_object,
|
||||
get_object_from_random_node,
|
||||
get_range,
|
||||
get_range_hash,
|
||||
head_object,
|
||||
put_object,
|
||||
put_object_to_random_node,
|
||||
search_object,
|
||||
)
|
||||
from python_keywords.storage_policy import get_complex_object_copies, get_simple_object_copies
|
||||
|
||||
from helpers.storage_object_info import StorageObjectInfo
|
||||
from steps.cluster_test_base import ClusterTestBase
|
||||
from steps.storage_object import delete_objects
|
||||
|
||||
logger = logging.getLogger("NeoLogger")
|
||||
|
@ -87,11 +89,11 @@ def generate_ranges(file_size: int, max_object_size: int) -> list[(int, int)]:
|
|||
scope="module",
|
||||
)
|
||||
def storage_objects(
|
||||
prepare_wallet_and_deposit: str, client_shell: Shell, request: FixtureRequest
|
||||
default_wallet: str, client_shell: Shell, cluster: Cluster, request: FixtureRequest
|
||||
) -> list[StorageObjectInfo]:
|
||||
wallet = prepare_wallet_and_deposit
|
||||
wallet = default_wallet
|
||||
# Separate containers for complex/simple objects to avoid side-effects
|
||||
cid = create_container(wallet, shell=client_shell)
|
||||
cid = create_container(wallet, shell=client_shell, endpoint=cluster.default_rpc_endpoint)
|
||||
|
||||
file_path = generate_file(request.param)
|
||||
file_hash = get_file_hash(file_path)
|
||||
|
@ -101,11 +103,12 @@ def storage_objects(
|
|||
with allure.step("Put objects"):
|
||||
# We need to upload objects multiple times with different attributes
|
||||
for attributes in OBJECT_ATTRIBUTES:
|
||||
storage_object_id = put_object(
|
||||
storage_object_id = put_object_to_random_node(
|
||||
wallet=wallet,
|
||||
path=file_path,
|
||||
cid=cid,
|
||||
shell=client_shell,
|
||||
cluster=cluster,
|
||||
attributes=attributes,
|
||||
)
|
||||
|
||||
|
@ -121,357 +124,390 @@ def storage_objects(
|
|||
yield storage_objects
|
||||
|
||||
# Teardown after all tests done with current param
|
||||
delete_objects(storage_objects, client_shell)
|
||||
delete_objects(storage_objects, client_shell, cluster)
|
||||
|
||||
|
||||
@allure.title("Validate object storage policy by native API")
|
||||
@pytest.mark.sanity
|
||||
@pytest.mark.grpc_api
|
||||
def test_object_storage_policies(
|
||||
client_shell: Shell, request: FixtureRequest, storage_objects: list[StorageObjectInfo]
|
||||
):
|
||||
"""
|
||||
Validate object storage policy
|
||||
"""
|
||||
allure.dynamic.title(
|
||||
f"Validate object storage policy by native API for {request.node.callspec.id}"
|
||||
)
|
||||
class TestObjectApi(ClusterTestBase):
|
||||
@allure.title("Validate object storage policy by native API")
|
||||
def test_object_storage_policies(
|
||||
self, request: FixtureRequest, storage_objects: list[StorageObjectInfo]
|
||||
):
|
||||
"""
|
||||
Validate object storage policy
|
||||
"""
|
||||
allure.dynamic.title(
|
||||
f"Validate object storage policy by native API for {request.node.callspec.id}"
|
||||
)
|
||||
|
||||
with allure.step("Validate storage policy for objects"):
|
||||
for storage_object in storage_objects:
|
||||
if storage_object.size == SIMPLE_OBJ_SIZE:
|
||||
copies = get_simple_object_copies(
|
||||
with allure.step("Validate storage policy for objects"):
|
||||
for storage_object in storage_objects:
|
||||
if storage_object.size == SIMPLE_OBJ_SIZE:
|
||||
copies = get_simple_object_copies(
|
||||
storage_object.wallet_file_path,
|
||||
storage_object.cid,
|
||||
storage_object.oid,
|
||||
shell=self.shell,
|
||||
nodes=self.cluster.storage_nodes,
|
||||
)
|
||||
else:
|
||||
copies = get_complex_object_copies(
|
||||
storage_object.wallet_file_path,
|
||||
storage_object.cid,
|
||||
storage_object.oid,
|
||||
shell=self.shell,
|
||||
nodes=self.cluster.storage_nodes,
|
||||
)
|
||||
assert copies == 2, "Expected 2 copies"
|
||||
|
||||
@allure.title("Validate get object native API")
|
||||
def test_get_object_api(
|
||||
self, request: FixtureRequest, storage_objects: list[StorageObjectInfo]
|
||||
):
|
||||
"""
|
||||
Validate get object native API
|
||||
"""
|
||||
allure.dynamic.title(f"Validate get object native API for {request.node.callspec.id}")
|
||||
|
||||
with allure.step("Get objects and compare hashes"):
|
||||
for storage_object in storage_objects:
|
||||
file_path = get_object_from_random_node(
|
||||
storage_object.wallet_file_path,
|
||||
storage_object.cid,
|
||||
storage_object.oid,
|
||||
shell=client_shell,
|
||||
self.shell,
|
||||
cluster=self.cluster,
|
||||
)
|
||||
else:
|
||||
copies = get_complex_object_copies(
|
||||
storage_object.wallet_file_path,
|
||||
storage_object.cid,
|
||||
storage_object.oid,
|
||||
shell=client_shell,
|
||||
)
|
||||
assert copies == 2, "Expected 2 copies"
|
||||
file_hash = get_file_hash(file_path)
|
||||
assert storage_object.file_hash == file_hash
|
||||
|
||||
@allure.title("Validate head object native API")
|
||||
def test_head_object_api(
|
||||
self, request: FixtureRequest, storage_objects: list[StorageObjectInfo]
|
||||
):
|
||||
"""
|
||||
Validate head object native API
|
||||
"""
|
||||
allure.dynamic.title(f"Validate head object by native API for {request.node.callspec.id}")
|
||||
|
||||
@allure.title("Validate get object native API")
|
||||
@pytest.mark.sanity
|
||||
@pytest.mark.grpc_api
|
||||
def test_get_object_api(
|
||||
client_shell: Shell, request: FixtureRequest, storage_objects: list[StorageObjectInfo]
|
||||
):
|
||||
"""
|
||||
Validate get object native API
|
||||
"""
|
||||
allure.dynamic.title(f"Validate get object native API for {request.node.callspec.id}")
|
||||
storage_object_1 = storage_objects[0]
|
||||
storage_object_2 = storage_objects[1]
|
||||
|
||||
with allure.step("Get objects and compare hashes"):
|
||||
for storage_object in storage_objects:
|
||||
file_path = get_object(
|
||||
storage_object.wallet_file_path,
|
||||
storage_object.cid,
|
||||
storage_object.oid,
|
||||
client_shell,
|
||||
with allure.step("Head object and validate"):
|
||||
head_object(
|
||||
storage_object_1.wallet_file_path,
|
||||
storage_object_1.cid,
|
||||
storage_object_1.oid,
|
||||
shell=self.shell,
|
||||
endpoint=self.cluster.default_rpc_endpoint,
|
||||
)
|
||||
file_hash = get_file_hash(file_path)
|
||||
assert storage_object.file_hash == file_hash
|
||||
head_info = head_object(
|
||||
storage_object_2.wallet_file_path,
|
||||
storage_object_2.cid,
|
||||
storage_object_2.oid,
|
||||
shell=self.shell,
|
||||
endpoint=self.cluster.default_rpc_endpoint,
|
||||
)
|
||||
self.check_header_is_presented(head_info, storage_object_2.attributes)
|
||||
|
||||
@allure.title("Validate object search by native API")
|
||||
def test_search_object_api(
|
||||
self, request: FixtureRequest, storage_objects: list[StorageObjectInfo]
|
||||
):
|
||||
"""
|
||||
Validate object search by native API
|
||||
"""
|
||||
allure.dynamic.title(f"Validate object search by native API for {request.node.callspec.id}")
|
||||
|
||||
@allure.title("Validate head object native API")
|
||||
@pytest.mark.sanity
|
||||
@pytest.mark.grpc_api
|
||||
def test_head_object_api(
|
||||
client_shell: Shell, request: FixtureRequest, storage_objects: list[StorageObjectInfo]
|
||||
):
|
||||
"""
|
||||
Validate head object native API
|
||||
"""
|
||||
allure.dynamic.title(f"Validate head object by native API for {request.node.callspec.id}")
|
||||
oids = [storage_object.oid for storage_object in storage_objects]
|
||||
wallet = storage_objects[0].wallet_file_path
|
||||
cid = storage_objects[0].cid
|
||||
|
||||
storage_object_1 = storage_objects[0]
|
||||
storage_object_2 = storage_objects[1]
|
||||
test_table = [
|
||||
(OBJECT_ATTRIBUTES[1], oids[1:2]),
|
||||
(OBJECT_ATTRIBUTES[2], oids[2:3]),
|
||||
(COMMON_ATTRIBUTE, oids[1:3]),
|
||||
]
|
||||
|
||||
with allure.step("Head object and validate"):
|
||||
head_object(
|
||||
storage_object_1.wallet_file_path,
|
||||
storage_object_1.cid,
|
||||
storage_object_1.oid,
|
||||
shell=client_shell,
|
||||
)
|
||||
head_info = head_object(
|
||||
storage_object_2.wallet_file_path,
|
||||
storage_object_2.cid,
|
||||
storage_object_2.oid,
|
||||
shell=client_shell,
|
||||
)
|
||||
check_header_is_presented(head_info, storage_object_2.attributes)
|
||||
|
||||
|
||||
@allure.title("Validate object search by native API")
|
||||
@pytest.mark.sanity
|
||||
@pytest.mark.grpc_api
|
||||
def test_search_object_api(
|
||||
client_shell: Shell, request: FixtureRequest, storage_objects: list[StorageObjectInfo]
|
||||
):
|
||||
"""
|
||||
Validate object search by native API
|
||||
"""
|
||||
allure.dynamic.title(f"Validate object search by native API for {request.node.callspec.id}")
|
||||
|
||||
oids = [storage_object.oid for storage_object in storage_objects]
|
||||
wallet = storage_objects[0].wallet_file_path
|
||||
cid = storage_objects[0].cid
|
||||
|
||||
test_table = [
|
||||
(OBJECT_ATTRIBUTES[1], oids[1:2]),
|
||||
(OBJECT_ATTRIBUTES[2], oids[2:3]),
|
||||
(COMMON_ATTRIBUTE, oids[1:3]),
|
||||
]
|
||||
|
||||
with allure.step("Search objects"):
|
||||
# Search with no attributes
|
||||
result = search_object(
|
||||
wallet, cid, shell=client_shell, expected_objects_list=oids, root=True
|
||||
)
|
||||
assert sorted(oids) == sorted(result)
|
||||
|
||||
# search by test table
|
||||
for filter, expected_oids in test_table:
|
||||
with allure.step("Search objects"):
|
||||
# Search with no attributes
|
||||
result = search_object(
|
||||
wallet,
|
||||
cid,
|
||||
shell=client_shell,
|
||||
filters=filter,
|
||||
expected_objects_list=expected_oids,
|
||||
shell=self.shell,
|
||||
endpoint=self.cluster.default_rpc_endpoint,
|
||||
expected_objects_list=oids,
|
||||
root=True,
|
||||
)
|
||||
assert sorted(expected_oids) == sorted(result)
|
||||
assert sorted(oids) == sorted(result)
|
||||
|
||||
# search by test table
|
||||
for filter, expected_oids in test_table:
|
||||
result = search_object(
|
||||
wallet,
|
||||
cid,
|
||||
shell=self.shell,
|
||||
endpoint=self.cluster.default_rpc_endpoint,
|
||||
filters=filter,
|
||||
expected_objects_list=expected_oids,
|
||||
root=True,
|
||||
)
|
||||
assert sorted(expected_oids) == sorted(result)
|
||||
|
||||
@allure.title("Validate object search with removed items")
|
||||
@pytest.mark.sanity
|
||||
@pytest.mark.grpc_api
|
||||
@pytest.mark.parametrize(
|
||||
"object_size", [SIMPLE_OBJ_SIZE, COMPLEX_OBJ_SIZE], ids=["simple object", "complex object"]
|
||||
)
|
||||
def test_object_search_should_return_tombstone_items(
|
||||
prepare_wallet_and_deposit: str, client_shell: Shell, request: FixtureRequest, object_size: int
|
||||
):
|
||||
"""
|
||||
Validate object search with removed items
|
||||
"""
|
||||
allure.dynamic.title(
|
||||
f"Validate object search with removed items for {request.node.callspec.id}"
|
||||
@allure.title("Validate object search with removed items")
|
||||
@pytest.mark.parametrize(
|
||||
"object_size", [SIMPLE_OBJ_SIZE, COMPLEX_OBJ_SIZE], ids=["simple object", "complex object"]
|
||||
)
|
||||
|
||||
wallet = prepare_wallet_and_deposit
|
||||
cid = create_container(wallet, shell=client_shell)
|
||||
|
||||
with allure.step("Upload file"):
|
||||
file_path = generate_file(object_size)
|
||||
file_hash = get_file_hash(file_path)
|
||||
|
||||
storage_object = StorageObjectInfo(
|
||||
cid=cid,
|
||||
oid=put_object(wallet, file_path, cid, shell=client_shell),
|
||||
size=object_size,
|
||||
wallet_file_path=wallet,
|
||||
file_path=file_path,
|
||||
file_hash=file_hash,
|
||||
def test_object_search_should_return_tombstone_items(
|
||||
self, default_wallet: str, request: FixtureRequest, object_size: int
|
||||
):
|
||||
"""
|
||||
Validate object search with removed items
|
||||
"""
|
||||
allure.dynamic.title(
|
||||
f"Validate object search with removed items for {request.node.callspec.id}"
|
||||
)
|
||||
|
||||
with allure.step("Search object"):
|
||||
# Root Search object should return root object oid
|
||||
result = search_object(wallet, cid, shell=client_shell, root=True)
|
||||
assert result == [storage_object.oid]
|
||||
wallet = default_wallet
|
||||
cid = create_container(wallet, self.shell, self.cluster.default_rpc_endpoint)
|
||||
|
||||
with allure.step("Delete file"):
|
||||
delete_objects([storage_object], client_shell)
|
||||
with allure.step("Upload file"):
|
||||
file_path = generate_file(object_size)
|
||||
file_hash = get_file_hash(file_path)
|
||||
|
||||
with allure.step("Search deleted object with --root"):
|
||||
# Root Search object should return nothing
|
||||
result = search_object(wallet, cid, shell=client_shell, root=True)
|
||||
assert len(result) == 0
|
||||
storage_object = StorageObjectInfo(
|
||||
cid=cid,
|
||||
oid=put_object_to_random_node(wallet, file_path, cid, self.shell, self.cluster),
|
||||
size=object_size,
|
||||
wallet_file_path=wallet,
|
||||
file_path=file_path,
|
||||
file_hash=file_hash,
|
||||
)
|
||||
|
||||
with allure.step("Search deleted object with --phy should return only tombstones"):
|
||||
# Physical Search object should return only tombstones
|
||||
result = search_object(wallet, cid, shell=client_shell, phy=True)
|
||||
assert (
|
||||
storage_object.tombstone in result
|
||||
), f"Search result should contain tombstone of removed object"
|
||||
assert (
|
||||
storage_object.oid not in result
|
||||
), f"Search result should not contain ObjectId of removed object"
|
||||
for tombstone_oid in result:
|
||||
header = head_object(wallet, cid, tombstone_oid, shell=client_shell)["header"]
|
||||
object_type = header["objectType"]
|
||||
with allure.step("Search object"):
|
||||
# Root Search object should return root object oid
|
||||
result = search_object(
|
||||
wallet, cid, shell=self.shell, endpoint=self.cluster.default_rpc_endpoint, root=True
|
||||
)
|
||||
assert result == [storage_object.oid]
|
||||
|
||||
with allure.step("Delete file"):
|
||||
delete_objects([storage_object], self.shell, self.cluster)
|
||||
|
||||
with allure.step("Search deleted object with --root"):
|
||||
# Root Search object should return nothing
|
||||
result = search_object(
|
||||
wallet, cid, shell=self.shell, endpoint=self.cluster.default_rpc_endpoint, root=True
|
||||
)
|
||||
assert len(result) == 0
|
||||
|
||||
with allure.step("Search deleted object with --phy should return only tombstones"):
|
||||
# Physical Search object should return only tombstones
|
||||
result = search_object(
|
||||
wallet, cid, shell=self.shell, endpoint=self.cluster.default_rpc_endpoint, phy=True
|
||||
)
|
||||
assert (
|
||||
object_type == "TOMBSTONE"
|
||||
), f"Object wasn't deleted properly. Found object {tombstone_oid} with type {object_type}"
|
||||
|
||||
|
||||
@allure.title("Validate native object API get_range_hash")
|
||||
@pytest.mark.sanity
|
||||
@pytest.mark.grpc_api
|
||||
def test_object_get_range_hash(
|
||||
client_shell: Shell, request: FixtureRequest, storage_objects: list[StorageObjectInfo]
|
||||
):
|
||||
"""
|
||||
Validate get_range_hash for object by common gRPC API
|
||||
"""
|
||||
allure.dynamic.title(
|
||||
f"Validate native get_range_hash object API for {request.node.callspec.id}"
|
||||
)
|
||||
|
||||
wallet = storage_objects[0].wallet_file_path
|
||||
cid = storage_objects[0].cid
|
||||
oids = [storage_object.oid for storage_object in storage_objects[:2]]
|
||||
file_path = storage_objects[0].file_path
|
||||
net_info = get_netmap_netinfo(wallet, client_shell)
|
||||
max_object_size = net_info["maximum_object_size"]
|
||||
|
||||
file_ranges_to_test = generate_ranges(storage_objects[0].size, max_object_size)
|
||||
logging.info(f"Ranges used in test {file_ranges_to_test}")
|
||||
|
||||
for range_start, range_end in file_ranges_to_test:
|
||||
range_len = range_end - range_start
|
||||
range_cut = f"{range_start}:{range_len}"
|
||||
with allure.step(f"Get range hash ({range_cut})"):
|
||||
for oid in oids:
|
||||
range_hash = get_range_hash(
|
||||
wallet, cid, oid, shell=client_shell, range_cut=range_cut
|
||||
)
|
||||
storage_object.tombstone in result
|
||||
), "Search result should contain tombstone of removed object"
|
||||
assert (
|
||||
storage_object.oid not in result
|
||||
), "Search result should not contain ObjectId of removed object"
|
||||
for tombstone_oid in result:
|
||||
header = head_object(
|
||||
wallet,
|
||||
cid,
|
||||
tombstone_oid,
|
||||
shell=self.shell,
|
||||
endpoint=self.cluster.default_rpc_endpoint,
|
||||
)["header"]
|
||||
object_type = header["objectType"]
|
||||
assert (
|
||||
get_file_hash(file_path, range_len, range_start) == range_hash
|
||||
), f"Expected range hash to match {range_cut} slice of file payload"
|
||||
object_type == "TOMBSTONE"
|
||||
), f"Object wasn't deleted properly. Found object {tombstone_oid} with type {object_type}"
|
||||
|
||||
@allure.title("Validate native object API get_range_hash")
|
||||
@pytest.mark.sanity
|
||||
@pytest.mark.grpc_api
|
||||
def test_object_get_range_hash(
|
||||
self, request: FixtureRequest, storage_objects: list[StorageObjectInfo]
|
||||
):
|
||||
"""
|
||||
Validate get_range_hash for object by common gRPC API
|
||||
"""
|
||||
allure.dynamic.title(
|
||||
f"Validate native get_range_hash object API for {request.node.callspec.id}"
|
||||
)
|
||||
|
||||
@allure.title("Validate native object API get_range")
|
||||
@pytest.mark.sanity
|
||||
@pytest.mark.grpc_api
|
||||
def test_object_get_range(
|
||||
client_shell: Shell, request: FixtureRequest, storage_objects: list[StorageObjectInfo]
|
||||
):
|
||||
"""
|
||||
Validate get_range for object by common gRPC API
|
||||
"""
|
||||
allure.dynamic.title(f"Validate native get_range object API for {request.node.callspec.id}")
|
||||
wallet = storage_objects[0].wallet_file_path
|
||||
cid = storage_objects[0].cid
|
||||
oids = [storage_object.oid for storage_object in storage_objects[:2]]
|
||||
file_path = storage_objects[0].file_path
|
||||
net_info = get_netmap_netinfo(
|
||||
wallet, self.shell, endpoint=self.cluster.default_rpc_endpoint
|
||||
)
|
||||
max_object_size = net_info["maximum_object_size"]
|
||||
|
||||
wallet = storage_objects[0].wallet_file_path
|
||||
cid = storage_objects[0].cid
|
||||
oids = [storage_object.oid for storage_object in storage_objects[:2]]
|
||||
file_path = storage_objects[0].file_path
|
||||
net_info = get_netmap_netinfo(wallet, client_shell)
|
||||
max_object_size = net_info["maximum_object_size"]
|
||||
file_ranges_to_test = generate_ranges(storage_objects[0].size, max_object_size)
|
||||
logging.info(f"Ranges used in test {file_ranges_to_test}")
|
||||
|
||||
file_ranges_to_test = generate_ranges(storage_objects[0].size, max_object_size)
|
||||
logging.info(f"Ranges used in test {file_ranges_to_test}")
|
||||
|
||||
for range_start, range_end in file_ranges_to_test:
|
||||
range_len = range_end - range_start
|
||||
range_cut = f"{range_start}:{range_len}"
|
||||
with allure.step(f"Get range ({range_cut})"):
|
||||
for oid in oids:
|
||||
_, range_content = get_range(
|
||||
wallet, cid, oid, shell=client_shell, range_cut=range_cut
|
||||
)
|
||||
assert (
|
||||
get_file_content(
|
||||
file_path, content_len=range_len, mode="rb", offset=range_start
|
||||
for range_start, range_end in file_ranges_to_test:
|
||||
range_len = range_end - range_start
|
||||
range_cut = f"{range_start}:{range_len}"
|
||||
with allure.step(f"Get range hash ({range_cut})"):
|
||||
for oid in oids:
|
||||
range_hash = get_range_hash(
|
||||
wallet,
|
||||
cid,
|
||||
oid,
|
||||
shell=self.shell,
|
||||
endpoint=self.cluster.default_rpc_endpoint,
|
||||
range_cut=range_cut,
|
||||
)
|
||||
== range_content
|
||||
), f"Expected range content to match {range_cut} slice of file payload"
|
||||
assert (
|
||||
get_file_hash(file_path, range_len, range_start) == range_hash
|
||||
), f"Expected range hash to match {range_cut} slice of file payload"
|
||||
|
||||
@allure.title("Validate native object API get_range")
|
||||
@pytest.mark.sanity
|
||||
@pytest.mark.grpc_api
|
||||
def test_object_get_range(
|
||||
self, request: FixtureRequest, storage_objects: list[StorageObjectInfo]
|
||||
):
|
||||
"""
|
||||
Validate get_range for object by common gRPC API
|
||||
"""
|
||||
allure.dynamic.title(f"Validate native get_range object API for {request.node.callspec.id}")
|
||||
|
||||
@allure.title("Validate native object API get_range negative cases")
|
||||
@pytest.mark.sanity
|
||||
@pytest.mark.grpc_api
|
||||
def test_object_get_range_negatives(
|
||||
client_shell: Shell,
|
||||
request: FixtureRequest,
|
||||
storage_objects: list[StorageObjectInfo],
|
||||
):
|
||||
"""
|
||||
Validate get_range negative for object by common gRPC API
|
||||
"""
|
||||
allure.dynamic.title(
|
||||
f"Validate native get_range negative object API for {request.node.callspec.id}"
|
||||
)
|
||||
wallet = storage_objects[0].wallet_file_path
|
||||
cid = storage_objects[0].cid
|
||||
oids = [storage_object.oid for storage_object in storage_objects[:2]]
|
||||
file_path = storage_objects[0].file_path
|
||||
net_info = get_netmap_netinfo(
|
||||
wallet, self.shell, endpoint=self.cluster.default_rpc_endpoint
|
||||
)
|
||||
max_object_size = net_info["maximum_object_size"]
|
||||
|
||||
wallet = storage_objects[0].wallet_file_path
|
||||
cid = storage_objects[0].cid
|
||||
oids = [storage_object.oid for storage_object in storage_objects[:2]]
|
||||
file_size = storage_objects[0].size
|
||||
file_ranges_to_test = generate_ranges(storage_objects[0].size, max_object_size)
|
||||
logging.info(f"Ranges used in test {file_ranges_to_test}")
|
||||
|
||||
assert (
|
||||
RANGE_MIN_LEN < file_size
|
||||
), f"Incorrect test setup. File size ({file_size}) is less than RANGE_MIN_LEN ({RANGE_MIN_LEN})"
|
||||
for range_start, range_end in file_ranges_to_test:
|
||||
range_len = range_end - range_start
|
||||
range_cut = f"{range_start}:{range_len}"
|
||||
with allure.step(f"Get range ({range_cut})"):
|
||||
for oid in oids:
|
||||
_, range_content = get_range(
|
||||
wallet,
|
||||
cid,
|
||||
oid,
|
||||
shell=self.shell,
|
||||
endpoint=self.cluster.default_rpc_endpoint,
|
||||
range_cut=range_cut,
|
||||
)
|
||||
assert (
|
||||
get_file_content(
|
||||
file_path, content_len=range_len, mode="rb", offset=range_start
|
||||
)
|
||||
== range_content
|
||||
), f"Expected range content to match {range_cut} slice of file payload"
|
||||
|
||||
file_ranges_to_test = [
|
||||
# Offset is bigger than the file size, the length is small.
|
||||
(file_size + 1, RANGE_MIN_LEN),
|
||||
# Offset is ok, but offset+length is too big.
|
||||
(file_size - RANGE_MIN_LEN, RANGE_MIN_LEN * 2),
|
||||
# Offset is ok, and length is very-very big (e.g. MaxUint64) so that offset+length is wrapped and still "valid".
|
||||
(RANGE_MIN_LEN, sys.maxsize * 2 + 1),
|
||||
]
|
||||
@allure.title("Validate native object API get_range negative cases")
|
||||
@pytest.mark.sanity
|
||||
@pytest.mark.grpc_api
|
||||
def test_object_get_range_negatives(
|
||||
self,
|
||||
request: FixtureRequest,
|
||||
storage_objects: list[StorageObjectInfo],
|
||||
):
|
||||
"""
|
||||
Validate get_range negative for object by common gRPC API
|
||||
"""
|
||||
allure.dynamic.title(
|
||||
f"Validate native get_range negative object API for {request.node.callspec.id}"
|
||||
)
|
||||
|
||||
for range_start, range_len in file_ranges_to_test:
|
||||
range_cut = f"{range_start}:{range_len}"
|
||||
with allure.step(f"Get range ({range_cut})"):
|
||||
for oid in oids:
|
||||
with pytest.raises(Exception, match=OUT_OF_RANGE):
|
||||
get_range(wallet, cid, oid, shell=client_shell, range_cut=range_cut)
|
||||
wallet = storage_objects[0].wallet_file_path
|
||||
cid = storage_objects[0].cid
|
||||
oids = [storage_object.oid for storage_object in storage_objects[:2]]
|
||||
file_size = storage_objects[0].size
|
||||
|
||||
|
||||
@allure.title("Validate native object API get_range_hash negative cases")
|
||||
@pytest.mark.sanity
|
||||
@pytest.mark.grpc_api
|
||||
def test_object_get_range_hash_negatives(
|
||||
client_shell: Shell,
|
||||
request: FixtureRequest,
|
||||
storage_objects: list[StorageObjectInfo],
|
||||
):
|
||||
"""
|
||||
Validate get_range_hash negative for object by common gRPC API
|
||||
"""
|
||||
allure.dynamic.title(
|
||||
f"Validate native get_range_hash negative object API for {request.node.callspec.id}"
|
||||
)
|
||||
|
||||
wallet = storage_objects[0].wallet_file_path
|
||||
cid = storage_objects[0].cid
|
||||
oids = [storage_object.oid for storage_object in storage_objects[:2]]
|
||||
file_size = storage_objects[0].size
|
||||
|
||||
assert (
|
||||
RANGE_MIN_LEN < file_size
|
||||
), f"Incorrect test setup. File size ({file_size}) is less than RANGE_MIN_LEN ({RANGE_MIN_LEN})"
|
||||
|
||||
file_ranges_to_test = [
|
||||
# Offset is bigger than the file size, the length is small.
|
||||
(file_size + 1, RANGE_MIN_LEN),
|
||||
# Offset is ok, but offset+length is too big.
|
||||
(file_size - RANGE_MIN_LEN, RANGE_MIN_LEN * 2),
|
||||
# Offset is ok, and length is very-very big (e.g. MaxUint64) so that offset+length is wrapped and still "valid".
|
||||
(RANGE_MIN_LEN, sys.maxsize * 2 + 1),
|
||||
]
|
||||
|
||||
for range_start, range_len in file_ranges_to_test:
|
||||
range_cut = f"{range_start}:{range_len}"
|
||||
with allure.step(f"Get range ({range_cut})"):
|
||||
for oid in oids:
|
||||
with pytest.raises(Exception, match=OUT_OF_RANGE):
|
||||
get_range_hash(wallet, cid, oid, shell=client_shell, range_cut=range_cut)
|
||||
|
||||
|
||||
def check_header_is_presented(head_info: dict, object_header: dict) -> None:
|
||||
for key_to_check, val_to_check in object_header.items():
|
||||
assert (
|
||||
key_to_check in head_info["header"]["attributes"]
|
||||
), f"Key {key_to_check} is found in {head_object}"
|
||||
assert head_info["header"]["attributes"].get(key_to_check) == str(
|
||||
val_to_check
|
||||
), f"Value {val_to_check} is equal"
|
||||
RANGE_MIN_LEN < file_size
|
||||
), f"Incorrect test setup. File size ({file_size}) is less than RANGE_MIN_LEN ({RANGE_MIN_LEN})"
|
||||
|
||||
file_ranges_to_test = [
|
||||
# Offset is bigger than the file size, the length is small.
|
||||
(file_size + 1, RANGE_MIN_LEN),
|
||||
# Offset is ok, but offset+length is too big.
|
||||
(file_size - RANGE_MIN_LEN, RANGE_MIN_LEN * 2),
|
||||
# Offset is ok, and length is very-very big (e.g. MaxUint64) so that offset+length is wrapped and still "valid".
|
||||
(RANGE_MIN_LEN, sys.maxsize * 2 + 1),
|
||||
]
|
||||
|
||||
for range_start, range_len in file_ranges_to_test:
|
||||
range_cut = f"{range_start}:{range_len}"
|
||||
with allure.step(f"Get range ({range_cut})"):
|
||||
for oid in oids:
|
||||
with pytest.raises(Exception, match=OUT_OF_RANGE):
|
||||
get_range(
|
||||
wallet,
|
||||
cid,
|
||||
oid,
|
||||
shell=self.shell,
|
||||
endpoint=self.cluster.default_rpc_endpoint,
|
||||
range_cut=range_cut,
|
||||
)
|
||||
|
||||
@allure.title("Validate native object API get_range_hash negative cases")
|
||||
def test_object_get_range_hash_negatives(
|
||||
self,
|
||||
request: FixtureRequest,
|
||||
storage_objects: list[StorageObjectInfo],
|
||||
):
|
||||
"""
|
||||
Validate get_range_hash negative for object by common gRPC API
|
||||
"""
|
||||
allure.dynamic.title(
|
||||
f"Validate native get_range_hash negative object API for {request.node.callspec.id}"
|
||||
)
|
||||
|
||||
wallet = storage_objects[0].wallet_file_path
|
||||
cid = storage_objects[0].cid
|
||||
oids = [storage_object.oid for storage_object in storage_objects[:2]]
|
||||
file_size = storage_objects[0].size
|
||||
|
||||
assert (
|
||||
RANGE_MIN_LEN < file_size
|
||||
), f"Incorrect test setup. File size ({file_size}) is less than RANGE_MIN_LEN ({RANGE_MIN_LEN})"
|
||||
|
||||
file_ranges_to_test = [
|
||||
# Offset is bigger than the file size, the length is small.
|
||||
(file_size + 1, RANGE_MIN_LEN),
|
||||
# Offset is ok, but offset+length is too big.
|
||||
(file_size - RANGE_MIN_LEN, RANGE_MIN_LEN * 2),
|
||||
# Offset is ok, and length is very-very big (e.g. MaxUint64) so that offset+length is wrapped and still "valid".
|
||||
(RANGE_MIN_LEN, sys.maxsize * 2 + 1),
|
||||
]
|
||||
|
||||
for range_start, range_len in file_ranges_to_test:
|
||||
range_cut = f"{range_start}:{range_len}"
|
||||
with allure.step(f"Get range ({range_cut})"):
|
||||
for oid in oids:
|
||||
with pytest.raises(Exception, match=OUT_OF_RANGE):
|
||||
get_range_hash(
|
||||
wallet,
|
||||
cid,
|
||||
oid,
|
||||
shell=self.shell,
|
||||
endpoint=self.cluster.default_rpc_endpoint,
|
||||
range_cut=range_cut,
|
||||
)
|
||||
|
||||
def check_header_is_presented(self, head_info: dict, object_header: dict) -> None:
|
||||
for key_to_check, val_to_check in object_header.items():
|
||||
assert (
|
||||
key_to_check in head_info["header"]["attributes"]
|
||||
), f"Key {key_to_check} is found in {head_object}"
|
||||
assert head_info["header"]["attributes"].get(key_to_check) == str(
|
||||
val_to_check
|
||||
), f"Value {val_to_check} is equal"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue