From f0f8a6cb875ba79c8e77fcabebf1ac9913e28727 Mon Sep 17 00:00:00 2001 From: Evgeniy Zayats Date: Thu, 28 Sep 2023 14:02:13 -0400 Subject: [PATCH] tests: verify COMMON_PREFIX search filter, closes #244 Signed-off-by: Evgeniy Zayats --- .../testsuites/object/test_object_api.py | 93 +++++++++++++++++-- .../lib/python_keywords/neofs_verbs.py | 18 ++-- 2 files changed, 96 insertions(+), 15 deletions(-) diff --git a/pytest_tests/testsuites/object/test_object_api.py b/pytest_tests/testsuites/object/test_object_api.py index 36ff6c862..a7dd7ca0b 100755 --- a/pytest_tests/testsuites/object/test_object_api.py +++ b/pytest_tests/testsuites/object/test_object_api.py @@ -1,10 +1,12 @@ import logging +import os import random import sys import allure import pytest from cluster import Cluster +from common import ASSETS_DIR, TEST_FILES_DIR from complex_object_actions import get_complex_object_split_ranges from file_helper import generate_file, get_file_content, get_file_hash from grpc_responses import ( @@ -16,7 +18,7 @@ ) from neofs_testlib.shell import Shell from pytest import FixtureRequest -from python_keywords.container import create_container +from python_keywords.container import create_container, delete_container from python_keywords.neofs_verbs import ( get_object_from_random_node, get_range, @@ -135,6 +137,14 @@ def storage_objects( with expect_not_raises(): delete_objects(storage_objects, client_shell, cluster) +@pytest.fixture +def container(default_wallet: str, client_shell: Shell, cluster: Cluster) -> str: + cid = create_container(default_wallet, shell=client_shell, endpoint=cluster.default_rpc_endpoint) + yield cid + delete_container( + default_wallet, cid, shell=client_shell, endpoint=cluster.default_rpc_endpoint + ) + @pytest.mark.grpc_api class TestObjectApi(ClusterTestBase): @@ -233,10 +243,22 @@ def test_search_object_api( wallet = storage_objects[0].wallet_file_path cid = storage_objects[0].cid + def _generate_filters_expressions(attrib_dict: dict[str, str]): + return [f"{filter_key} EQ {filter_val}" for filter_key, filter_val in attrib_dict.items()] + test_table = [ - (OBJECT_ATTRIBUTES[1], oids[1:2]), - (OBJECT_ATTRIBUTES[2], oids[2:3]), - (COMMON_ATTRIBUTE, oids[1:3]), + ( + _generate_filters_expressions(OBJECT_ATTRIBUTES[1]), + oids[1:2] + ), + ( + _generate_filters_expressions(OBJECT_ATTRIBUTES[2]), + oids[2:3] + ), + ( + _generate_filters_expressions(COMMON_ATTRIBUTE), + oids[1:3] + ), ] with allure.step("Search objects"): @@ -252,13 +274,13 @@ def test_search_object_api( assert sorted(oids) == sorted(result) # search by test table - for filter, expected_oids in 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, + filters=_filter, expected_objects_list=expected_oids, root=True, ) @@ -337,6 +359,65 @@ def test_object_search_should_return_tombstone_items( object_type == "TOMBSTONE" ), f"Object wasn't deleted properly. Found object {tombstone_oid} with type {object_type}" + @allure.title("Validate objects search by common prefix") + def test_search_object_api_common_prefix(self, default_wallet: str, simple_object_size: int, container: str): + FILEPATH_ATTR_NAME = "FilePath" + NUMBER_OF_OBJECTS = 5 + wallet = default_wallet + + objects = {} + for _ in range(NUMBER_OF_OBJECTS): + file_path = generate_file(simple_object_size) + + with allure.step("Put objects"): + objects[file_path] = put_object_to_random_node( + wallet=wallet, + path=file_path, + cid=container, + shell=self.shell, + cluster=self.cluster, + attributes={FILEPATH_ATTR_NAME: file_path} + ) + all_oids = sorted(objects.values()) + + for common_prefix, expected_oids in ( + ('/', all_oids), + (os.path.join(os.getcwd(), ASSETS_DIR), all_oids), + (os.path.join(os.getcwd(), ASSETS_DIR, TEST_FILES_DIR), all_oids), + (file_path, [objects[file_path]]) + ): + with allure.step(f"Search objects by path: {common_prefix}"): + search_object( + wallet, + container, + shell=self.shell, + endpoint=self.cluster.default_rpc_endpoint, + filters=[f"{FILEPATH_ATTR_NAME} COMMON_PREFIX {common_prefix}"], + expected_objects_list=expected_oids, + root=True, + fail_on_assert=True + ) + + for common_prefix in ( + f"{file_path}/o123" + '/COMMON_PREFIX', + '?', + '213' + ): + + with allure.step(f"Search objects by path: {common_prefix}"): + with pytest.raises(AssertionError): + search_object( + wallet, + container, + shell=self.shell, + endpoint=self.cluster.default_rpc_endpoint, + filters=[f"{FILEPATH_ATTR_NAME} COMMON_PREFIX {common_prefix}"], + expected_objects_list=expected_oids, + root=True, + fail_on_assert=True + ) + @allure.title("Validate native object API get_range_hash") @pytest.mark.grpc_api def test_object_get_range_hash( diff --git a/robot/resources/lib/python_keywords/neofs_verbs.py b/robot/resources/lib/python_keywords/neofs_verbs.py index a27774ef2..a62ce0da8 100644 --- a/robot/resources/lib/python_keywords/neofs_verbs.py +++ b/robot/resources/lib/python_keywords/neofs_verbs.py @@ -437,13 +437,14 @@ def search_object( shell: Shell, endpoint: str, bearer: str = "", - filters: Optional[dict] = None, + filters: Optional[list] = None, expected_objects_list: Optional[list] = None, wallet_config: Optional[str] = None, xhdr: Optional[dict] = None, session: Optional[str] = None, phy: bool = False, root: bool = False, + fail_on_assert = False ) -> list: """ SEARCH an Object. @@ -454,13 +455,14 @@ def search_object( shell: executor for cli command bearer: path to Bearer Token file, appends to `--bearer` key endpoint: NeoFS endpoint to send request to, appends to `--rpc-endpoint` key - filters: key=value pairs to filter Objects + filters: list of filter objects expected_objects_list: a list of ObjectIDs to compare found Objects with wallet_config: path to the wallet config xhdr: Request X-Headers in form of Key=Value session: path to a JSON-encoded container session token phy: Search physically stored objects. root: Search for user objects. + fail_on_assert: fail if expected_objects_list is not matched to the found objects list. Returns: list of found ObjectIDs @@ -473,9 +475,7 @@ def search_object( cid=cid, bearer=bearer, xhdr=xhdr, - filters=[f"{filter_key} EQ {filter_val}" for filter_key, filter_val in filters.items()] - if filters - else None, + filters=filters, session=session, phy=phy, root=root, @@ -490,10 +490,10 @@ def search_object( f"is equal for expected list '{expected_objects_list}'" ) else: - logger.warning( - f"Found object list {found_objects} " - f"is not equal to expected list '{expected_objects_list}'" - ) + warning = f"Found object list {found_objects} is not equal to expected list '{expected_objects_list}'" + logger.warning(warning) + if fail_on_assert: + raise AssertionError(warning) return found_objects