From e4c1c23dddc4cccd4469651068aeb8dd55d9988a Mon Sep 17 00:00:00 2001 From: anastasia prasolova Date: Thu, 26 May 2022 12:44:13 +0300 Subject: [PATCH] [#205] storage policy validation reconsidered Signed-off-by: anastasia prasolova --- robot/resources/lib/python/neofs.py | 63 +------------ robot/resources/lib/python/neofs_verbs.py | 7 +- robot/resources/lib/python/storage_policy.py | 79 ++++++++++++++++ .../resources/lib/python/utility_keywords.py | 3 +- .../acl/acl_extended_deny_replication.robot | 16 ++-- .../integration/network/netmap_simple.robot | 93 +++++++++++-------- .../integration/network/replication.robot | 37 ++++---- .../integration/object/object_complex.robot | 40 ++++---- .../integration/object/object_simple.robot | 21 ++--- 9 files changed, 203 insertions(+), 156 deletions(-) create mode 100644 robot/resources/lib/python/storage_policy.py diff --git a/robot/resources/lib/python/neofs.py b/robot/resources/lib/python/neofs.py index bdf66cdd..1c769234 100644 --- a/robot/resources/lib/python/neofs.py +++ b/robot/resources/lib/python/neofs.py @@ -32,7 +32,7 @@ def get_scripthash(wif: str): @keyword('Stop nodes') -def stop_nodes(down_num: int, *nodes_list): +def stop_nodes(down_num: int, nodes_list: list): # select nodes to stop from list nodes = random.sample(nodes_list, down_num) @@ -44,11 +44,11 @@ def stop_nodes(down_num: int, *nodes_list): client = docker.APIClient() client.stop(node) - return stop_nodes + return nodes @keyword('Start nodes') -def start_nodes(*nodes_list): +def start_nodes(nodes_list: list): for node in nodes_list: m = re.search(r'(s\d+).', node) @@ -89,38 +89,6 @@ def get_nodes_without_object(wallet: str, cid: str, oid: str): return nodes_list -@keyword('Validate storage policy for object') -def validate_storage_policy_for_object(wallet: str, expected_copies: int, cid, oid, - expected_node_list=[], storage_nodes=[]): - storage_nodes = storage_nodes if len(storage_nodes) != 0 else NEOFS_NETMAP - copies = 0 - found_nodes = [] - oid = oid.strip() - - for node in storage_nodes: - res = _search_object(node, wallet, cid, oid) - if res: - if oid in res: - copies += 1 - found_nodes.append(node) - - if copies != expected_copies: - raise Exception("Object copies is not match storage policy." - f"Found: {copies}, expected: {expected_copies}.") - else: - logger.info(f"Found copies: {copies}, expected: {expected_copies}") - - logger.info(f"Found nodes: {found_nodes}") - - if expected_node_list: - if sorted(found_nodes) == sorted(expected_node_list): - logger.info(f"Found node list '{found_nodes}' " - f"is equal for expected list '{expected_node_list}'") - else: - raise Exception(f"Found node list '{found_nodes}' " - f"is not equal to expected list '{expected_node_list}'") - - @keyword('Verify Head Tombstone') def verify_head_tombstone(wallet: str, cid: str, oid_ts: str, oid: str, addr: str): # TODO: replace with HEAD from neofs_verbs.py @@ -212,7 +180,7 @@ def get_logs_latest_timestamp(): log_line = client_api.logs(container, tail=1) m = re.search(r'(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d+Z)', str(log_line)) - if m != None: + if m is not None: timestamp = m.group(1) timestamp_date = datetime.fromisoformat(timestamp[:-1]) @@ -307,29 +275,6 @@ def sign_session_token(session_token: str, wallet: str, to_file: str=''): _cmd_run(cmd) -def _parse_oid(input_str: str): - """ - This function parses OID from given CLI output. The input string we - expect: - Object successfully stored - ID: 4MhrLA7RXTBXCsaNnbahYVAPuoQdiUPuyNEWnywvoSEs - CID: HeZu2DXBuPve6HXbuHZx64knS7KcGtfSj2L59Li72kkg - We want to take 'ID' value from the string. - - Parameters: - - input_str: a string with command run output - """ - try: - # taking second string from command output - snd_str = input_str.split('\n')[1] - except: - logger.error(f"Got empty input: {input_str}") - splitted = snd_str.split(": ") - if len(splitted) != 2: - raise Exception(f"no OID was parsed from command output: \t{snd_str}") - return splitted[1] - - def _search_object(node:str, wallet: str, cid:str, oid: str): cmd = ( f'{NEOFS_CLI_EXEC} --rpc-endpoint {node} --wallet {wallet} --ttl 1 ' diff --git a/robot/resources/lib/python/neofs_verbs.py b/robot/resources/lib/python/neofs_verbs.py index 9275da5f..ba0236c6 100644 --- a/robot/resources/lib/python/neofs_verbs.py +++ b/robot/resources/lib/python/neofs_verbs.py @@ -247,7 +247,12 @@ def head_object(wallet: str, cid: str, oid: str, bearer_token: str="", f'{"--raw" if is_raw else ""} ' f'{"--ttl 1" if is_direct else ""}' ) - output = _cmd_run(cmd) + output = None + try: + output = _cmd_run(cmd) + except Exception as exc: + logger.info(f"Head request failed with output: {output}") + return None if not json_output: return output diff --git a/robot/resources/lib/python/storage_policy.py b/robot/resources/lib/python/storage_policy.py new file mode 100644 index 00000000..41aede73 --- /dev/null +++ b/robot/resources/lib/python/storage_policy.py @@ -0,0 +1,79 @@ +#!/usr/bin/python3 + +''' + This module contains keywords which are used for asserting + that storage policies are kept. +''' + +from common import NEOFS_NETMAP +import complex_object_actions +import neofs_verbs + +from robot.api.deco import keyword + +ROBOT_AUTO_KEYWORDS = False + + +@keyword('Get Object Copies') +def get_object_copies(complexity: str, wallet: str, cid: str, oid: str): + """ + The function performs requests to all nodes of the container and + finds out if they store a copy of the object. The procedure is + different for simple and complex object, so the function requires + a sign of object complexity. + Args: + complexity (str): the tag of object size and complexity, + [Simple|Complex] + wallet (str): the path to the wallet on whose behalf the + copies are got + cid (str): ID of the container + oid (str): ID of the Object + Returns: + (int): the number of object copies in the container + """ + return (get_simple_object_copies(wallet, cid, oid) if complexity == "Simple" + else get_complex_object_copies(wallet, cid, oid)) + + +@keyword('Get Simple Object Copies') +def get_simple_object_copies(wallet: str, cid: str, oid: str): + """ + To figure out the number of a simple object copies, only direct + HEAD requests should be made to the every node of the container. + We consider non-empty HEAD response as a stored object copy. + Args: + wallet (str): the path to the wallet on whose behalf the + copies are got + cid (str): ID of the container + oid (str): ID of the Object + Returns: + (int): the number of object copies in the container + """ + copies = 0 + for node in NEOFS_NETMAP: + response = neofs_verbs.head_object(wallet, cid, oid, + endpoint=node, + is_direct=True) + if response: + copies += 1 + return copies + + +@keyword('Get Complex Object Copies') +def get_complex_object_copies(wallet: str, cid: str, oid: str): + """ + To figure out the number of a complex object copies, we firstly + need to retrieve its Last object. We consider that the number of + complex object copies is equal to the number of its last object + copies. When we have the Last object ID, the task is reduced + to getting simple object copies. + Args: + wallet (str): the path to the wallet on whose behalf the + copies are got + cid (str): ID of the container + oid (str): ID of the Object + Returns: + (int): the number of object copies in the container + """ + last_oid = complex_object_actions.get_last_object(wallet, cid, oid) + return get_simple_object_copies(wallet, cid, last_oid) diff --git a/robot/resources/lib/python/utility_keywords.py b/robot/resources/lib/python/utility_keywords.py index e6a3ccc0..2b13e1c3 100644 --- a/robot/resources/lib/python/utility_keywords.py +++ b/robot/resources/lib/python/utility_keywords.py @@ -49,9 +49,8 @@ def get_file_hash(filename: str): with open(filename, "rb") as out: for block in iter(lambda: out.read(blocksize), b""): file_hash.update(block) - logger.info(f"Hash: {file_hash.hexdigest()}") return file_hash.hexdigest() - + @keyword('Get Docker Logs') def get_container_logs(testcase_name: str) -> None: diff --git a/robot/testsuites/integration/acl/acl_extended_deny_replication.robot b/robot/testsuites/integration/acl/acl_extended_deny_replication.robot index 63debc73..83cac162 100644 --- a/robot/testsuites/integration/acl/acl_extended_deny_replication.robot +++ b/robot/testsuites/integration/acl/acl_extended_deny_replication.robot @@ -1,11 +1,12 @@ *** Settings *** Variables common.py +Library acl.py Library container.py +Library contract_keywords.py Library neofs.py Library neofs_verbs.py -Library acl.py -Library contract_keywords.py +Library storage_policy.py Library utility_keywords.py Resource eacl_tables.robot @@ -17,8 +18,6 @@ Resource storage.robot *** Variables *** ${FULL_PLACEMENT_RULE} = REP 4 IN X CBF 1 SELECT 4 FROM * AS X ${EXPECTED_COPIES} = ${4} -${DEPOSIT} = ${30} - *** Test cases *** eACL Deny Replication Operations @@ -41,7 +40,8 @@ eACL Deny Replication Operations ${OID} = Put object ${WALLET} ${FILE} ${CID} - Validate storage policy for object ${WALLET} ${EXPECTED_COPIES} ${CID} ${OID} + ${COPIES} = Get Object Copies Simple ${WALLET} ${CID} ${OID} + Should Be Equal As Numbers ${EXPECTED_COPIES} ${COPIES} Set eACL ${WALLET} ${CID} ${EACL_DENY_ALL_USER} @@ -52,9 +52,11 @@ eACL Deny Replication Operations Drop object ${NODE} ${WALLET_STORAGE} ${CID} ${OID} Tick Epoch + Sleep ${NEOFS_CONTRACT_CACHE_TIMEOUT} # We assume that during one epoch object should be replicated - Wait Until Keyword Succeeds ${NEOFS_EPOCH_TIMEOUT} 1m - ... Validate storage policy for object ${WALLET_STORAGE} ${EXPECTED_COPIES} ${CID} ${OID} + ${COPIES} = Get Object Copies Simple ${WALLET_STORAGE} ${CID} ${OID} + Should Be Equal As Numbers ${EXPECTED_COPIES} ${COPIES} + ... msg="Dropped object should be replicated in one epoch" [Teardown] Teardown acl_deny_replication diff --git a/robot/testsuites/integration/network/netmap_simple.robot b/robot/testsuites/integration/network/netmap_simple.robot index 02828f78..732a1d24 100644 --- a/robot/testsuites/integration/network/netmap_simple.robot +++ b/robot/testsuites/integration/network/netmap_simple.robot @@ -4,14 +4,14 @@ Variables common.py Library container.py Library neofs.py Library neofs_verbs.py +Library storage_policy.py Library utility_keywords.py +Library Collections + Resource payment_operations.robot Resource setup_teardown.robot -*** Variables *** -${CONTAINER_WAIT_INTERVAL} = 1 min - *** Test cases *** NeoFS Simple Netmap [Documentation] Testcase to validate NeoFS Netmap. @@ -21,66 +21,77 @@ NeoFS Simple Netmap [Setup] Setup ${WALLET} ${_} ${_} = Prepare Wallet And Deposit - ${FILE} ${_} = Generate file ${SIMPLE_OBJ_SIZE} - Validate Policy ${WALLET} ${FILE} REP 2 IN X CBF 2 SELECT 2 FROM * AS X 2 @{EMPTY} + Validate Object Copies ${WALLET} REP 2 IN X CBF 2 SELECT 2 FROM * AS X 2 - Validate Policy ${WALLET} ${FILE} REP 2 IN X CBF 1 SELECT 2 FROM * AS X 2 @{EMPTY} + Validate Object Copies ${WALLET} REP 2 IN X CBF 1 SELECT 2 FROM * AS X 2 - Validate Policy ${WALLET} ${FILE} REP 3 IN X CBF 1 SELECT 3 FROM * AS X 3 @{EMPTY} + Validate Object Copies ${WALLET} REP 3 IN X CBF 1 SELECT 3 FROM * AS X 3 - Validate Policy ${WALLET} ${FILE} REP 1 IN X CBF 1 SELECT 1 FROM * AS X 1 @{EMPTY} + Validate Object Copies ${WALLET} REP 1 IN X CBF 1 SELECT 1 FROM * AS X 1 - Validate Policy ${WALLET} ${FILE} REP 1 IN X CBF 2 SELECT 1 FROM * AS X 1 @{EMPTY} + Validate Object Copies ${WALLET} REP 1 IN X CBF 2 SELECT 1 FROM * AS X 1 - Validate Policy ${WALLET} ${FILE} REP 4 IN X CBF 1 SELECT 4 FROM * AS X 4 @{EMPTY} + Validate Object Copies ${WALLET} REP 4 IN X CBF 1 SELECT 4 FROM * AS X 4 - Validate Policy ${WALLET} ${FILE} REP 2 IN X CBF 1 SELECT 4 FROM * AS X 2 @{EMPTY} + Validate Object Copies ${WALLET} REP 2 IN X CBF 1 SELECT 4 FROM * AS X 2 - @{EXPECTED} = Create List s01.neofs.devenv:8080 s02.neofs.devenv:8080 s03.neofs.devenv:8080 s04.neofs.devenv:8080 - Validate Policy ${WALLET} ${FILE} REP 4 IN X CBF 1 SELECT 4 FROM * AS X 4 @{EXPECTED} + @{EXPECTED} = Create List s01.neofs.devenv:8080 s02.neofs.devenv:8080 s03.neofs.devenv:8080 s04.neofs.devenv:8080 + Validate Selected Nodes ${WALLET} REP 4 IN X CBF 1 SELECT 4 FROM * AS X 4 @{EXPECTED} - @{EXPECTED} = Create List s03.neofs.devenv:8080 - Validate Policy ${WALLET} ${FILE} REP 1 IN LOC_PLACE CBF 1 SELECT 1 FROM LOC_SW AS LOC_PLACE FILTER Country EQ Sweden AS LOC_SW + @{EXPECTED} = Create List s03.neofs.devenv:8080 + Validate Selected Nodes ${WALLET} REP 1 IN LOC_PLACE CBF 1 SELECT 1 FROM LOC_SW AS LOC_PLACE FILTER Country EQ Sweden AS LOC_SW ... 1 @{EXPECTED} - @{EXPECTED} = Create List s02.neofs.devenv:8080 - Validate Policy ${WALLET} ${FILE} REP 1 CBF 1 SELECT 1 FROM LOC_SPB FILTER 'UN-LOCODE' EQ 'RU LED' AS LOC_SPB 1 @{EXPECTED} + @{EXPECTED} = Create List s02.neofs.devenv:8080 + Validate Selected Nodes ${WALLET} REP 1 CBF 1 SELECT 1 FROM LOC_SPB FILTER 'UN-LOCODE' EQ 'RU LED' AS LOC_SPB 1 @{EXPECTED} - @{EXPECTED} = Create List s01.neofs.devenv:8080 s02.neofs.devenv:8080 - Validate Policy ${WALLET} ${FILE} REP 1 IN LOC_SPB_PLACE REP 1 IN LOC_MSK_PLACE CBF 1 SELECT 1 FROM LOC_SPB AS LOC_SPB_PLACE SELECT 1 FROM LOC_MSK AS LOC_MSK_PLACE FILTER 'UN-LOCODE' EQ 'RU LED' AS LOC_SPB FILTER 'UN-LOCODE' EQ 'RU MOW' AS LOC_MSK - ... 2 @{EXPECTED} + @{EXPECTED} = Create List s01.neofs.devenv:8080 s02.neofs.devenv:8080 + Validate Selected Nodes ${WALLET} + ... REP 1 IN LOC_SPB_PLACE REP 1 IN LOC_MSK_PLACE CBF 1 SELECT 1 FROM LOC_SPB AS LOC_SPB_PLACE SELECT 1 FROM LOC_MSK AS LOC_MSK_PLACE FILTER 'UN-LOCODE' EQ 'RU LED' AS LOC_SPB FILTER 'UN-LOCODE' EQ 'RU MOW' AS LOC_MSK + ... 2 @{EXPECTED} - @{EXPECTED} = Create List s01.neofs.devenv:8080 s02.neofs.devenv:8080 s03.neofs.devenv:8080 s04.neofs.devenv:8080 - Validate Policy ${WALLET} ${FILE} REP 4 CBF 1 SELECT 4 FROM LOC_EU FILTER Continent EQ Europe AS LOC_EU 4 @{EXPECTED} + @{EXPECTED} = Create List s01.neofs.devenv:8080 s02.neofs.devenv:8080 s03.neofs.devenv:8080 s04.neofs.devenv:8080 + Validate Selected Nodes ${WALLET} REP 4 CBF 1 SELECT 4 FROM LOC_EU FILTER Continent EQ Europe AS LOC_EU 4 @{EXPECTED} - @{EXPECTED} = Create List s02.neofs.devenv:8080 - Validate Policy ${WALLET} ${FILE} REP 1 CBF 1 SELECT 1 FROM LOC_SPB FILTER 'UN-LOCODE' NE 'RU MOW' AND 'UN-LOCODE' NE 'SE STO' AND 'UN-LOCODE' NE 'FI HEL' AS LOC_SPB - ... 1 @{EXPECTED} + @{EXPECTED} = Create List s02.neofs.devenv:8080 + Validate Selected Nodes ${WALLET} + ... REP 1 CBF 1 SELECT 1 FROM LOC_SPB FILTER 'UN-LOCODE' NE 'RU MOW' AND 'UN-LOCODE' NE 'SE STO' AND 'UN-LOCODE' NE 'FI HEL' AS LOC_SPB + ... 1 @{EXPECTED} - @{EXPECTED} = Create List s01.neofs.devenv:8080 s02.neofs.devenv:8080 - Validate Policy ${WALLET} ${FILE} REP 2 CBF 1 SELECT 2 FROM LOC_RU FILTER SubDivCode NE 'AB' AND SubDivCode NE '18' AS LOC_RU 2 @{EXPECTED} + @{EXPECTED} = Create List s01.neofs.devenv:8080 s02.neofs.devenv:8080 + Validate Selected Nodes ${WALLET} REP 2 CBF 1 SELECT 2 FROM LOC_RU FILTER SubDivCode NE 'AB' AND SubDivCode NE '18' AS LOC_RU 2 @{EXPECTED} - @{EXPECTED} = Create List s01.neofs.devenv:8080 s02.neofs.devenv:8080 - Validate Policy ${WALLET} ${FILE} REP 2 CBF 1 SELECT 2 FROM LOC_RU FILTER Country EQ 'Russia' AS LOC_RU 2 @{EXPECTED} + @{EXPECTED} = Create List s01.neofs.devenv:8080 s02.neofs.devenv:8080 + Validate Selected Nodes ${WALLET} REP 2 CBF 1 SELECT 2 FROM LOC_RU FILTER Country EQ 'Russia' AS LOC_RU 2 @{EXPECTED} - @{EXPECTED} = Create List s03.neofs.devenv:8080 s04.neofs.devenv:8080 - Validate Policy ${WALLET} ${FILE} REP 2 CBF 1 SELECT 2 FROM LOC_EU FILTER Country NE 'Russia' AS LOC_EU 2 @{EXPECTED} + @{EXPECTED} = Create List s03.neofs.devenv:8080 s04.neofs.devenv:8080 + Validate Selected Nodes ${WALLET} REP 2 CBF 1 SELECT 2 FROM LOC_EU FILTER Country NE 'Russia' AS LOC_EU 2 @{EXPECTED} - Log Put operation should be failed with error "not enough nodes to SELECT from: 'X'" - Run Keyword And Expect Error * - ... Validate Policy ${WALLET} ${FILE} REP 2 IN X CBF 2 SELECT 6 FROM * AS X 2 @{EMPTY} + ${ERR} = Run Keyword And Expect Error * + ... Validate Selected Nodes ${WALLET} REP 2 IN X CBF 2 SELECT 6 FROM * AS X 2 + Should Contain ${ERR} code = 1024 message = netmap: not enough nodes to SELECT from [Teardown] Teardown netmap_simple *** Keywords *** -Validate Policy - [Arguments] ${WALLET} ${FILE} ${POLICY} ${EXPECTED_VAL} @{EXPECTED_LIST} +Validate Object Copies + [Arguments] ${WALLET} ${POLICY} ${EXPECTED_COPIES} - Log Container with rule ${POLICY} + ${FILE} + ... ${_} = Generate file ${SIMPLE_OBJ_SIZE} + ${CID} = Create container ${WALLET} rule=${POLICY} + ${OID} = Put object ${WALLET} ${FILE} ${CID} + ${COPIES} = Get Simple Object Copies ${WALLET} ${CID} ${OID} + Should Be Equal As Numbers ${EXPECTED_COPIES} ${COPIES} + [Return] ${CID} ${OID} - ${CID} = Create container ${WALLET} rule=${POLICY} - ${S_OID} = Put object ${WALLET} ${FILE} ${CID} - Validate storage policy for object ${WALLET} ${EXPECTED_VAL} ${CID} ${S_OID} ${EXPECTED_LIST} - Get object ${WALLET} ${CID} ${S_OID} ${EMPTY} s_file_read + +Validate Selected Nodes + [Arguments] ${WALLET} ${POLICY} ${EXPECTED_COPIES} @{EXPECTED_NODES} + + ${CID} + ... ${OID} = Validate Object Copies ${WALLET} ${POLICY} ${EXPECTED_COPIES} + ${NODES} = Get Nodes With Object ${WALLET} ${CID} ${OID} + Lists Should Be Equal ${EXPECTED_NODES} ${NODES} diff --git a/robot/testsuites/integration/network/replication.robot b/robot/testsuites/integration/network/replication.robot index 9a2616e0..0402423b 100644 --- a/robot/testsuites/integration/network/replication.robot +++ b/robot/testsuites/integration/network/replication.robot @@ -3,9 +3,10 @@ Variables common.py Variables wellknown_acl.py Library container.py +Library contract_keywords.py Library neofs.py Library neofs_verbs.py -Library contract_keywords.py +Library storage_policy.py Library utility_keywords.py Library Collections @@ -15,7 +16,6 @@ Resource setup_teardown.robot *** Variables *** ${EXPECTED_COPIES} = ${2} -${CHECK_INTERVAL} = 1 min *** Test cases *** NeoFS Object Replication @@ -26,7 +26,7 @@ NeoFS Object Replication [Setup] Setup Log Check replication mechanism - Check Replication ${EMPTY} + Check Replication Log Check Sticky Bit with SYSTEM Group via replication mechanism Check Replication ${STICKYBIT_PUB_ACL} @@ -34,7 +34,7 @@ NeoFS Object Replication *** Keywords *** Check Replication - [Arguments] ${ACL} + [Arguments] ${ACL}=${EMPTY} ${WALLET} ${_} ${_} = Prepare Wallet And Deposit ${CID} = Create Container ${WALLET} basic_acl=${ACL} @@ -42,36 +42,41 @@ Check Replication ${FILE} ${_} = Generate file ${SIMPLE_OBJ_SIZE} ${S_OID} = Put Object ${WALLET} ${FILE} ${CID} - Validate storage policy for object ${WALLET} ${EXPECTED_COPIES} ${CID} ${S_OID} + + ${COPIES} = Get Object Copies Simple ${WALLET} ${CID} ${S_OID} + Should Be Equal ${EXPECTED_COPIES} ${COPIES} @{NODES_OBJ} = Get nodes with Object ${WALLET} ${CID} ${S_OID} ${NODES_LOG_TIME} = Get Nodes Log Latest Timestamp - @{NODES_OBJ_STOPPED} = Stop nodes 1 @{NODES_OBJ} - @{NETMAP} = Convert To List ${NEOFS_NETMAP} - Remove Values From List ${NETMAP} @{NODES_OBJ_STOPPED} + @{NODES_OBJ_STOPPED} = Stop nodes 1 ${NODES_OBJ} + @{NETMAP} = Convert To List ${NEOFS_NETMAP} + Remove Values From List ${NETMAP} ${NODES_OBJ_STOPPED} # We expect that during two epochs the missed copy will be replicated. FOR ${i} IN RANGE 2 + ${COPIES} = Get Object Copies Simple ${WALLET} ${CID} ${S_OID} ${PASSED} = Run Keyword And Return Status - ... Validate storage policy for object ${WALLET} ${EXPECTED_COPIES} - ... ${CID} ${S_OID} ${EMPTY} ${NETMAP} + ... Should Be Equal ${EXPECTED_COPIES} ${COPIES} Exit For Loop If ${PASSED} Tick Epoch - Sleep ${CHECK_INTERVAL} + Sleep ${NEOFS_CONTRACT_CACHE_TIMEOUT} END - Run Keyword Unless ${PASSED} Fail Keyword failed: Validate storage policy for object ${S_OID} in container ${CID} + Run Keyword Unless ${PASSED} Fail + ... Storage policy for object ${S_OID} in container ${CID} isn't valid Find in Nodes Log object successfully replicated ${NODES_LOG_TIME} - Start nodes @{NODES_OBJ_STOPPED} + Start nodes ${NODES_OBJ_STOPPED} Tick Epoch # We have 2 or 3 copies. Expected behaviour: during two epochs potential 3rd copy should be removed. FOR ${i} IN RANGE 2 + ${COPIES} = Get Object Copies Simple ${WALLET} ${CID} ${S_OID} ${PASSED} = Run Keyword And Return Status - ... Validate storage policy for object ${WALLET} ${EXPECTED_COPIES} ${CID} ${S_OID} + ... Should Be Equal ${EXPECTED_COPIES} ${COPIES} Exit For Loop If ${PASSED} Tick Epoch - Sleep ${CHECK_INTERVAL} + Sleep ${NEOFS_CONTRACT_CACHE_TIMEOUT} END - Run Keyword Unless ${PASSED} Fail Keyword failed: Validate storage policy for object ${S_OID} in container ${CID} + Run Keyword Unless ${PASSED} Fail + ... Storage policy for object ${S_OID} in container ${CID} isn't valid diff --git a/robot/testsuites/integration/object/object_complex.robot b/robot/testsuites/integration/object/object_complex.robot index 5b139748..b60883f3 100644 --- a/robot/testsuites/integration/object/object_complex.robot +++ b/robot/testsuites/integration/object/object_complex.robot @@ -1,22 +1,24 @@ *** Settings *** Variables common.py -Library neofs_verbs.py + Library container.py Library complex_object_actions.py -Library neofs.py Library contract_keywords.py -Library Collections +Library neofs_verbs.py +Library neofs.py +Library storage_policy.py Library utility_keywords.py +Library Collections + Resource setup_teardown.robot Resource payment_operations.robot *** Variables *** ${CLEANUP_TIMEOUT} = 10s &{FILE_USR_HEADER} = key1=1 key2=abc -&{FILE_USR_HEADER_OTH} = key1=2 -${ALREADY_REMOVED_ERROR} = code = 1024 message = object already removed +${ALREADY_REMOVED_ERROR} = code = 2052 message = object already removed *** Test cases *** @@ -34,19 +36,13 @@ NeoFS Complex Object Operations ${S_OID} = Put object ${WALLET} ${FILE} ${CID} ${H_OID} = Put object ${WALLET} ${FILE} ${CID} user_headers=${FILE_USR_HEADER} - ${H_OID_OTH} = Put object ${WALLET} ${FILE} ${CID} user_headers=${FILE_USR_HEADER_OTH} - Should Be True '${S_OID}'!='${H_OID}' and '${H_OID}'!='${H_OID_OTH}' + Should Not Be Equal ${H_OID} ${S_OID} - Validate storage policy for object ${WALLET} 2 ${CID} ${S_OID} - Validate storage policy for object ${WALLET} 2 ${CID} ${H_OID} - Validate storage policy for object ${WALLET} 2 ${CID} ${H_OID_OTH} - - @{S_OBJ_ALL} = Create List ${S_OID} ${H_OID} ${H_OID_OTH} - @{S_OBJ_H} = Create List ${H_OID} - @{S_OBJ_H_OTH} = Create List ${H_OID_OTH} - - Search Object ${WALLET} ${CID} --root expected_objects_list=${S_OBJ_ALL} + ${COPIES} = Get Complex Object Copies ${WALLET} ${CID} ${S_OID} + Should Be Equal As Numbers 2 ${COPIES} + ${COPIES} = Get Complex Object Copies ${WALLET} ${CID} ${H_OID} + Should Be Equal As Numbers 2 ${COPIES} ${GET_OBJ_S} = Get object ${WALLET} ${CID} ${S_OID} ${GET_OBJ_H} = Get object ${WALLET} ${CID} ${H_OID} @@ -63,9 +59,11 @@ NeoFS Complex Object Operations Get Range ${WALLET} ${CID} ${S_OID} s_get_range ${EMPTY} 0:10 Get Range ${WALLET} ${CID} ${H_OID} h_get_range ${EMPTY} 0:10 + @{S_OBJ_ALL} = Create List ${S_OID} ${H_OID} + @{S_OBJ_H} = Create List ${H_OID} + Search object ${WALLET} ${CID} --root expected_objects_list=${S_OBJ_ALL} Search object ${WALLET} ${CID} --root filters=${FILE_USR_HEADER} expected_objects_list=${S_OBJ_H} - Search object ${WALLET} ${CID} --root filters=${FILE_USR_HEADER_OTH} expected_objects_list=${S_OBJ_H_OTH} &{S_RESPONSE} = Head object ${WALLET} ${CID} ${S_OID} &{H_RESPONSE} = Head object ${WALLET} ${CID} ${H_OID} @@ -74,9 +72,13 @@ NeoFS Complex Object Operations ... ${FILE_USR_HEADER} ... msg="There are no User Headers in HEAD response" - ${PAYLOAD_LENGTH} ${SPLIT_ID} ${SPLIT_OBJECTS} = Restore Large Object By Last + ${PAYLOAD_LENGTH} + ... ${SPLIT_ID} + ... ${SPLIT_OBJECTS} = Restore Large Object By Last ... ${WALLET} ${CID} ${S_OID} - ${H_PAYLOAD_LENGTH} ${H_SPLIT_ID} ${H_SPLIT_OBJECTS} = Restore Large Object By Last + ${H_PAYLOAD_LENGTH} + ... ${H_SPLIT_ID} + ... ${H_SPLIT_OBJECTS} = Restore Large Object By Last ... ${WALLET} ${CID} ${H_OID} Compare With Link Object ${WALLET} ${CID} ${S_OID} ${SPLIT_ID} ${SPLIT_OBJECTS} diff --git a/robot/testsuites/integration/object/object_simple.robot b/robot/testsuites/integration/object/object_simple.robot index 9ae4b3fd..a0debd88 100644 --- a/robot/testsuites/integration/object/object_simple.robot +++ b/robot/testsuites/integration/object/object_simple.robot @@ -1,20 +1,21 @@ *** Settings *** Variables common.py -Library neofs.py -Library neofs_verbs.py Library container.py Library contract_keywords.py -Library Collections +Library neofs.py +Library neofs_verbs.py +Library storage_policy.py Library utility_keywords.py +Library Collections + Resource payment_operations.robot Resource setup_teardown.robot *** Variables *** ${CLEANUP_TIMEOUT} = 10s &{FILE_USR_HEADER} = key1=1 key2=abc -&{FILE_USR_HEADER_OTH} = key1=2 *** Test cases *** @@ -32,15 +33,14 @@ NeoFS Simple Object Operations ${S_OID} = Put object ${WALLET} ${FILE} ${CID} ${H_OID} = Put object ${WALLET} ${FILE} ${CID} user_headers=${FILE_USR_HEADER} - ${H_OID_OTH} = Put object ${WALLET} ${FILE} ${CID} user_headers=${FILE_USR_HEADER_OTH} - Validate storage policy for object ${WALLET} 2 ${CID} ${S_OID} - Validate storage policy for object ${WALLET} 2 ${CID} ${H_OID} - Validate storage policy for object ${WALLET} 2 ${CID} ${H_OID_OTH} + ${COPIES} = Get Simple Object Copies ${WALLET} ${CID} ${S_OID} + Should Be Equal As Numbers 2 ${COPIES} + ${COPIES} = Get Simple Object Copies ${WALLET} ${CID} ${H_OID} + Should Be Equal As Numbers 2 ${COPIES} - @{S_OBJ_ALL} = Create List ${S_OID} ${H_OID} ${H_OID_OTH} + @{S_OBJ_ALL} = Create List ${S_OID} ${H_OID} @{S_OBJ_H} = Create List ${H_OID} - @{S_OBJ_H_OTH} = Create List ${H_OID_OTH} ${GET_OBJ_S} = Get object ${WALLET} ${CID} ${S_OID} ${GET_OBJ_H} = Get object ${WALLET} ${CID} ${H_OID} @@ -59,7 +59,6 @@ NeoFS Simple Object Operations Search object ${WALLET} ${CID} expected_objects_list=${S_OBJ_ALL} Search object ${WALLET} ${CID} filters=${FILE_USR_HEADER} expected_objects_list=${S_OBJ_H} - Search object ${WALLET} ${CID} filters=${FILE_USR_HEADER_OTH} expected_objects_list=${S_OBJ_H_OTH} Head object ${WALLET} ${CID} ${S_OID} &{RESPONSE} = Head object ${WALLET} ${CID} ${H_OID}