[#127]: Large Object assrtions moved from python to robot
Signed-off-by: anastasia prasolova <anastasia@nspcc.ru>
This commit is contained in:
parent
040f648c61
commit
15dd59ddad
12 changed files with 240 additions and 218 deletions
74
robot/resources/lib/python/complex_object_actions.py
Normal file
74
robot/resources/lib/python/complex_object_actions.py
Normal file
|
@ -0,0 +1,74 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
"""
|
||||
This module contains functions which are used for Large Object assemling:
|
||||
getting Last Object and split and getting Link Object. It is not enough to
|
||||
simply perform a "raw" HEAD request, as noted in the issue:
|
||||
https://github.com/nspcc-dev/neofs-node/issues/1304. Therefore, the reliable
|
||||
retrival of the aforementioned objects must be done this way: send direct
|
||||
"raw" HEAD request to the every Storage Node and return the desired OID on
|
||||
first non-null response.
|
||||
"""
|
||||
|
||||
from common import NEOFS_NETMAP
|
||||
import neofs_verbs
|
||||
|
||||
from robot.api.deco import keyword
|
||||
from robot.api import logger
|
||||
from robot.libraries.BuiltIn import BuiltIn
|
||||
|
||||
ROBOT_AUTO_KEYWORDS = False
|
||||
|
||||
|
||||
@keyword('Get Link Object')
|
||||
def get_link_object(wallet: str, cid: str, oid: str):
|
||||
"""
|
||||
Args:
|
||||
wallet (str): path to the wallet on whose behalf the Storage Nodes
|
||||
are requested
|
||||
cid (str): Container ID which stores the Large Object
|
||||
oid (str): Large Object ID
|
||||
Returns:
|
||||
(str): Link Object ID
|
||||
When no Link Object ID is found after all Storage Nodes polling,
|
||||
the function throws a native robot error.
|
||||
"""
|
||||
for node in NEOFS_NETMAP:
|
||||
try:
|
||||
resp = neofs_verbs.head_object(wallet, cid, oid,
|
||||
endpoint=node,
|
||||
is_raw=True,
|
||||
is_direct=True)
|
||||
if resp['link']:
|
||||
return resp['link']
|
||||
except Exception:
|
||||
logger.info(f"No Link Object found on {node}; continue")
|
||||
BuiltIn().fail(f"No Link Object for {cid}/{oid} found among all Storage Nodes")
|
||||
return None
|
||||
|
||||
|
||||
@keyword('Get Last Object')
|
||||
def get_last_object(wallet: str, cid: str, oid: str):
|
||||
"""
|
||||
Args:
|
||||
wallet (str): path to the wallet on whose behalf the Storage Nodes
|
||||
are requested
|
||||
cid (str): Container ID which stores the Large Object
|
||||
oid (str): Large Object ID
|
||||
Returns:
|
||||
(str): Last Object ID
|
||||
When no Last Object ID is found after all Storage Nodes polling,
|
||||
the function throws a native robot error.
|
||||
"""
|
||||
for node in NEOFS_NETMAP:
|
||||
try:
|
||||
resp = neofs_verbs.head_object(wallet, cid, oid,
|
||||
endpoint=node,
|
||||
is_raw=True,
|
||||
is_direct=True)
|
||||
if resp['lastPart']:
|
||||
return resp['lastPart']
|
||||
except Exception:
|
||||
logger.info(f"No Last Object found on {node}; continue")
|
||||
BuiltIn().fail(f"No Last Object for {cid}/{oid} found among all Storage Nodes")
|
||||
return None
|
|
@ -174,183 +174,6 @@ def container_existing(private_key: str, cid: str):
|
|||
return
|
||||
|
||||
|
||||
|
||||
@keyword('Get Split objects')
|
||||
def get_component_objects(private_key: str, cid: str, oid: str):
|
||||
logger.info("Collect Split objects list from Linked object.")
|
||||
split_id = ""
|
||||
for node in NEOFS_NETMAP:
|
||||
try:
|
||||
parsed_header_virtual = neofs_verbs.head_object(private_key, cid, oid, options=' --ttl 1',
|
||||
endpoint=node, is_raw=True)
|
||||
|
||||
if 'link' in parsed_header_virtual.keys():
|
||||
return _collect_split_objects_from_header(private_key, cid, parsed_header_virtual)
|
||||
|
||||
elif 'split' in parsed_header_virtual['header'].keys():
|
||||
logger.info(f"parsed_header_virtual: !@ {parsed_header_virtual}" )
|
||||
split_id = parsed_header_virtual['header']['splitID']
|
||||
|
||||
except:
|
||||
logger.warn("Linking object has not been found.")
|
||||
|
||||
# Get all existing objects
|
||||
full_obj_list = neofs_verbs.search_object(private_key, cid, None, None, None, None, '--phy')
|
||||
|
||||
# Search expected Linking object
|
||||
for targer_oid in full_obj_list:
|
||||
header_parsed = neofs_verbs.head_object(private_key, cid, targer_oid, is_raw=True)
|
||||
if header_parsed['header']['split']:
|
||||
if header_parsed['header']['split']['splitID'] == split_id and 'children' in header_parsed['header']['split'].keys():
|
||||
logger.info("Linking object has been found in additional check (head of all objects).")
|
||||
return _collect_split_objects_from_header(private_key, cid, parsed_header_virtual)
|
||||
|
||||
|
||||
raise Exception("Linking object is not found at all - all existed objects have been headed.")
|
||||
|
||||
def _collect_split_objects_from_header(private_key, cid, parsed_header):
|
||||
header_link_parsed = neofs_verbs.head_object(private_key, cid, parsed_header['link'])
|
||||
return header_link_parsed['header']['split']['children']
|
||||
|
||||
|
||||
@keyword('Verify Split Chain')
|
||||
def verify_split_chain(wif: str, cid: str, oid: str):
|
||||
|
||||
header_virtual_parsed = dict()
|
||||
header_last_parsed = dict()
|
||||
|
||||
marker_last_obj = 0
|
||||
marker_link_obj = 0
|
||||
|
||||
final_verif_data = dict()
|
||||
|
||||
# Get Latest object
|
||||
logger.info("Collect Split objects information and verify chain of the objects.")
|
||||
for node in NEOFS_NETMAP:
|
||||
try:
|
||||
parsed_header_virtual = neofs_verbs.head_object(wif, cid, oid, options=' --ttl 1',
|
||||
endpoint=node, is_raw=True)
|
||||
logger.info(f"header {parsed_header_virtual}")
|
||||
|
||||
if 'lastPart' in parsed_header_virtual.keys():
|
||||
header_last_parsed = neofs_verbs.head_object(wif, cid,
|
||||
parsed_header_virtual['lastPart'],
|
||||
is_raw=True)
|
||||
marker_last_obj = 1
|
||||
|
||||
# Recursive chain validation up to the first object
|
||||
final_verif_data = _verify_child_link(wif, cid, oid, header_last_parsed['header'], final_verif_data)
|
||||
break
|
||||
logger.info(f"Found Split Object with header:\n\t{parsed_header_virtual}")
|
||||
logger.info("Continue to search Last Split Object")
|
||||
|
||||
except Exception as exc:
|
||||
logger.info(f"Failed while collectiong Split Objects: {exc}")
|
||||
continue
|
||||
|
||||
if marker_last_obj == 0:
|
||||
raise Exception("Last object has not been found")
|
||||
|
||||
# Get Linking object
|
||||
logger.info("Compare Split objects result information with Linking object.")
|
||||
for node in NEOFS_NETMAP:
|
||||
try:
|
||||
parsed_header_virtual = neofs_verbs.head_object(wif, cid, oid, options=' --ttl 1',
|
||||
endpoint=node, is_raw=True)
|
||||
if 'link' in parsed_header_virtual.keys():
|
||||
header_link_parsed = neofs_verbs.head_object(wif, cid,
|
||||
parsed_header_virtual['link'],
|
||||
is_raw=True)
|
||||
marker_link_obj = 1
|
||||
|
||||
reversed_list = final_verif_data['header']['split']['children'][::-1]
|
||||
|
||||
if header_link_parsed['header']['split']['children'] == reversed_list:
|
||||
logger.info(f"Split objects list from Linked Object is equal to expected "
|
||||
f"{', '.join(header_link_parsed['header']['split']['children'])}")
|
||||
else:
|
||||
raise Exception(f"Split objects list from Linking Object "
|
||||
f"({', '.join(header_link_parsed['header']['split']['children'])}) "
|
||||
f"is not equal to expected ({', '.join(reversed_list)})")
|
||||
|
||||
if int(header_link_parsed['header']['payloadLength']) == 0:
|
||||
logger.info("Linking object Payload is equal to expected - zero size.")
|
||||
else:
|
||||
raise Exception("Linking object Payload is not equal to expected. Should be zero.")
|
||||
|
||||
if header_link_parsed['header']['objectType'] == 'REGULAR':
|
||||
logger.info("Linking Object Type is 'regular' as expected.")
|
||||
else:
|
||||
raise Exception("Object Type is not 'regular'.")
|
||||
|
||||
if header_link_parsed['header']['split']['children'] == final_verif_data['split']['children']:
|
||||
logger.info(f"Linking Object Split ID is equal to expected {final_verif_data['split']['children']}.")
|
||||
else:
|
||||
raise Exception(f"Split ID from Linking Object ({header_link_parsed['header']['split']['children']}) "
|
||||
f"is not equal to expected ({final_verif_data['split']['children']})")
|
||||
|
||||
break
|
||||
logger.info(f"Found Linking Object with header:\n\t{parsed_header_virtual}")
|
||||
logger.info("Continue to search Linking Object")
|
||||
except RuntimeError as e:
|
||||
logger.info(f"Failed while collecting Split Object: {e}")
|
||||
continue
|
||||
|
||||
if marker_link_obj == 0:
|
||||
raise Exception("Linked object has not been found")
|
||||
|
||||
|
||||
logger.info("Compare Split objects result information with Virtual object.")
|
||||
|
||||
header_virtual_parsed = neofs_verbs.head_object(wif, cid, oid)
|
||||
|
||||
if int(header_virtual_parsed['header']['payloadLength']) == int(final_verif_data['payloadLength']):
|
||||
logger.info(f"Split objects PayloadLength are equal to Virtual Object Payload "
|
||||
f"{header_virtual_parsed['header']['payloadLength']}")
|
||||
else:
|
||||
raise Exception(f"Split objects PayloadLength from Virtual Object "
|
||||
f"({header_virtual_parsed['header']['payloadLength']}) is not equal "
|
||||
f"to expected ({final_verif_data['payloadLength']})")
|
||||
|
||||
if header_link_parsed['header']['objectType'] == 'REGULAR':
|
||||
logger.info("Virtual Object Type is 'regular' as expected.")
|
||||
else:
|
||||
raise Exception("Object Type is not 'regular'.")
|
||||
|
||||
|
||||
def _verify_child_link(wif: str, cid: str, oid: str, header_last_parsed: dict, final_verif_data: dict):
|
||||
|
||||
if 'payloadLength' in final_verif_data.keys():
|
||||
final_verif_data['payloadLength'] = int(final_verif_data['payloadLength']) + int(header_last_parsed['payloadLength'])
|
||||
else:
|
||||
final_verif_data['payloadLength'] = int(header_last_parsed['payloadLength'])
|
||||
|
||||
if header_last_parsed['objectType'] != 'REGULAR':
|
||||
raise Exception("Object Type is not 'regular'.")
|
||||
|
||||
if 'split' in final_verif_data.keys():
|
||||
if final_verif_data['split']['splitID'] != header_last_parsed['split']['splitID']:
|
||||
raise Exception(f"Object Split ID ({header_last_parsed['split']['splitID']}) "
|
||||
f"is not expected ({final_verif_data['split']['splitID']}).")
|
||||
else:
|
||||
final_verif_data['split']['splitID'] = header_last_parsed['split']['splitID']
|
||||
|
||||
if 'children' in final_verif_data['split'].keys():
|
||||
final_verif_data['split']['children'].append(header_last_parsed['split']['children'])
|
||||
else:
|
||||
final_verif_data['split']['children'] = []
|
||||
final_verif_data['split']['children'].append(header_last_parsed['split']['children'])
|
||||
|
||||
if 'previous' in header_last_parsed['split'].keys():
|
||||
parsed_header_virtual = neofs_verbs.head_object(wif, cid, header_last_parsed['split']['previous'], is_raw=True)
|
||||
|
||||
final_verif_data = _verify_child_link(wif, cid, oid, parsed_header_virtual, final_verif_data)
|
||||
else:
|
||||
logger.info("Chain of the objects has been parsed from the last object ot the first.")
|
||||
|
||||
return final_verif_data
|
||||
|
||||
|
||||
@keyword('Verify Head Tombstone')
|
||||
def verify_head_tombstone(private_key: str, cid: str, oid_ts: str, oid: str, addr: str):
|
||||
# TODO: replace with HEAD from neofs_verbs.py
|
||||
|
@ -540,9 +363,6 @@ def find_in_nodes_Log(line: str, nodes_logs_time: dict):
|
|||
return 1
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@keyword('Put Storagegroup')
|
||||
def put_storagegroup(private_key: str, cid: str, bearer_token: str="", *oid_list):
|
||||
|
||||
|
|
|
@ -215,7 +215,7 @@ def search_object(wif: str, cid: str, keys: str="", bearer: str="", filters: dic
|
|||
@keyword('Head object')
|
||||
def head_object(wif: str, cid: str, oid: str, bearer_token: str="",
|
||||
options:str="", endpoint: str="", json_output: bool = True,
|
||||
is_raw: bool = False):
|
||||
is_raw: bool = False, is_direct: bool = False):
|
||||
'''
|
||||
HEAD an Object.
|
||||
|
||||
|
@ -230,6 +230,8 @@ def head_object(wif: str, cid: str, oid: str, bearer_token: str="",
|
|||
turns into `--json` key
|
||||
is_raw(optional, bool): send "raw" request or not; this flag
|
||||
turns into `--raw` key
|
||||
is_direct(optional, bool): send request directly to the node or not; this flag
|
||||
turns into `--ttl 1` key
|
||||
Returns:
|
||||
depending on the `json_output` parameter value, the function returns
|
||||
(dict): HEAD response in JSON format
|
||||
|
@ -243,6 +245,7 @@ def head_object(wif: str, cid: str, oid: str, bearer_token: str="",
|
|||
f'{"--bearer " + bearer_token if bearer_token else ""} '
|
||||
f'{"--json" if json_output else ""} '
|
||||
f'{"--raw" if is_raw else ""} '
|
||||
f'{"--ttl 1" if is_direct else ""}'
|
||||
)
|
||||
output = _cmd_run(cmd)
|
||||
|
||||
|
|
20
robot/resources/lib/robot/complex_object_operations.robot
Normal file
20
robot/resources/lib/robot/complex_object_operations.robot
Normal file
|
@ -0,0 +1,20 @@
|
|||
*** Settings ***
|
||||
Variables common.py
|
||||
|
||||
Library neofs_verbs.py
|
||||
Library complex_object_operations.py
|
||||
|
||||
|
||||
*** Keywords ***
|
||||
|
||||
Get Object Parts By Link Object
|
||||
[Documentation] The keyword accepts the ID of a Large Object, retrieves its split
|
||||
... header and returns all Part Object IDs from Link Object.
|
||||
|
||||
[Arguments] ${WIF} ${CID} ${LARGE_OID}
|
||||
|
||||
|
||||
&{RESPONSE} = Get Link Object ${WIF} ${CID} ${LARGE_OID}
|
||||
&{LINK_HEADER} = Head Object ${WIF} ${CID} ${RESPONSE.link} is_raw=True
|
||||
|
||||
[Return] ${LINK_HEADER.header.split.children}
|
|
@ -9,6 +9,7 @@ Library Collections
|
|||
Resource common_steps_acl_basic.robot
|
||||
Resource payment_operations.robot
|
||||
Resource setup_teardown.robot
|
||||
Resource complex_object_operations.robot
|
||||
|
||||
|
||||
*** Test cases ***
|
||||
|
@ -47,7 +48,8 @@ Check Private Container
|
|||
${SG_OID_INV} = Put Storagegroup ${USER_KEY} ${PRIV_CID} ${EMPTY} ${S_OID_USER}
|
||||
${SG_OID} = Put Storagegroup ${USER_KEY} ${PRIV_CID} ${EMPTY} ${S_OID_USER}
|
||||
List Storagegroup ${USER_KEY} ${PRIV_CID} ${EMPTY} ${SG_OID} ${SG_OID_INV}
|
||||
@{EXPECTED_OIDS} = Run Keyword If "${RUN_TYPE}" == "Complex" Get Split objects ${USER_KEY} ${PRIV_CID} ${S_OID_USER}
|
||||
@{EXPECTED_OIDS} = Run Keyword If "${RUN_TYPE}" == "Complex"
|
||||
... Get Object Parts By Link Object ${USER_KEY} ${PRIV_CID} ${S_OID_USER}
|
||||
... ELSE IF "${RUN_TYPE}" == "Simple" Create List ${S_OID_USER}
|
||||
Get Storagegroup ${USER_KEY} ${PRIV_CID} ${SG_OID} ${EMPTY} ${EMPTY} @{EXPECTED_OIDS}
|
||||
Delete Storagegroup ${USER_KEY} ${PRIV_CID} ${SG_OID} ${EMPTY}
|
||||
|
@ -67,7 +69,8 @@ Check Private Container
|
|||
# System group key (Storage Node)
|
||||
${SG_OID_SN} = Put Storagegroup ${NEOFS_SN_WIF} ${PRIV_CID} ${EMPTY} ${S_OID_USER}
|
||||
List Storagegroup ${NEOFS_SN_WIF} ${PRIV_CID} ${EMPTY} ${SG_OID_SN} ${SG_OID_INV}
|
||||
@{EXPECTED_OIDS} = Run Keyword If "${RUN_TYPE}" == "Complex" Get Split objects ${NEOFS_SN_WIF} ${PRIV_CID} ${S_OID_USER}
|
||||
@{EXPECTED_OIDS} = Run Keyword If "${RUN_TYPE}" == "Complex"
|
||||
... Get Object Parts By Link Object ${NEOFS_SN_WIF} ${PRIV_CID} ${S_OID_USER}
|
||||
... ELSE IF "${RUN_TYPE}" == "Simple" Create List ${S_OID_USER}
|
||||
Get Storagegroup ${NEOFS_SN_WIF} ${PRIV_CID} ${SG_OID_SN} ${EMPTY} ${EMPTY} @{EXPECTED_OIDS}
|
||||
Run Keyword And Expect Error *
|
||||
|
@ -77,7 +80,8 @@ Check Private Container
|
|||
# System group key (Inner Ring Node)
|
||||
${SG_OID_IR} = Put Storagegroup ${NEOFS_IR_WIF} ${PRIV_CID} ${EMPTY} ${S_OID_USER}
|
||||
List Storagegroup ${NEOFS_IR_WIF} ${PRIV_CID} ${EMPTY} ${SG_OID_SN} ${SG_OID_IR} ${SG_OID_INV}
|
||||
@{EXPECTED_OIDS} = Run Keyword If "${RUN_TYPE}" == "Complex" Get Split objects ${USER_KEY} ${PRIV_CID} ${S_OID_USER}
|
||||
@{EXPECTED_OIDS} = Run Keyword If "${RUN_TYPE}" == "Complex"
|
||||
... Get Object Parts By Link Object ${USER_KEY} ${PRIV_CID} ${S_OID_USER}
|
||||
... ELSE IF "${RUN_TYPE}" == "Simple" Create List ${S_OID_USER}
|
||||
Get Storagegroup ${NEOFS_IR_WIF} ${PRIV_CID} ${SG_OID_IR} ${EMPTY} ${EMPTY} @{EXPECTED_OIDS}
|
||||
Run Keyword And Expect Error *
|
||||
|
|
|
@ -9,6 +9,7 @@ Library contract_keywords.py
|
|||
Resource common_steps_acl_basic.robot
|
||||
Resource payment_operations.robot
|
||||
Resource setup_teardown.robot
|
||||
Resource complex_object_operations.robot
|
||||
|
||||
|
||||
*** Test cases ***
|
||||
|
@ -50,7 +51,8 @@ Check Public Container
|
|||
FOR ${ROLE_KEY} IN @{ROLES_KEYS_PASS}
|
||||
${SG_OID_USERS} = Put Storagegroup ${ROLE_KEY} ${PUBLIC_CID} ${EMPTY} ${S_OID}
|
||||
List Storagegroup ${ROLE_KEY} ${PUBLIC_CID} ${EMPTY} ${SG_OID_USERS}
|
||||
@{EXPECTED_OIDS} = Run Keyword If "${RUN_TYPE}" == "Complex" Get Split objects ${ROLE_KEY} ${PUBLIC_CID} ${S_OID}
|
||||
@{EXPECTED_OIDS} = Run Keyword If "${RUN_TYPE}" == "Complex"
|
||||
... Get Object Parts By Link Object ${ROLE_KEY} ${PUBLIC_CID} ${S_OID}
|
||||
... ELSE IF "${RUN_TYPE}" == "Simple" Create List ${S_OID}
|
||||
Get Storagegroup ${ROLE_KEY} ${PUBLIC_CID} ${SG_OID_USERS} ${EMPTY} ${EMPTY} @{EXPECTED_OIDS}
|
||||
Delete Storagegroup ${ROLE_KEY} ${PUBLIC_CID} ${SG_OID_USERS} ${EMPTY}
|
||||
|
@ -59,7 +61,8 @@ Check Public Container
|
|||
FOR ${ROLE_KEY} IN @{ROLES_KEYS_SYS}
|
||||
${SG_OID_SYS} = Put Storagegroup ${ROLE_KEY} ${PUBLIC_CID} ${EMPTY} ${S_OID}
|
||||
List Storagegroup ${ROLE_KEY} ${PUBLIC_CID} ${EMPTY} ${SG_OID_SYS}
|
||||
@{EXPECTED_OIDS} = Run Keyword If "${RUN_TYPE}" == "Complex" Get Split objects ${ROLE_KEY} ${PUBLIC_CID} ${S_OID}
|
||||
@{EXPECTED_OIDS} = Run Keyword If "${RUN_TYPE}" == "Complex"
|
||||
... Get Object Parts By Link Object ${ROLE_KEY} ${PUBLIC_CID} ${S_OID}
|
||||
... ELSE IF "${RUN_TYPE}" == "Simple" Create List ${S_OID}
|
||||
Get Storagegroup ${ROLE_KEY} ${PUBLIC_CID} ${SG_OID_SYS} ${EMPTY} ${EMPTY} @{EXPECTED_OIDS}
|
||||
Run Keyword And Expect Error *
|
||||
|
|
|
@ -8,6 +8,7 @@ Library payment_neogo.py
|
|||
Resource common_steps_acl_basic.robot
|
||||
Resource payment_operations.robot
|
||||
Resource setup_teardown.robot
|
||||
Resource complex_object_operations.robot
|
||||
|
||||
|
||||
*** Test cases ***
|
||||
|
@ -50,7 +51,8 @@ Check Read-Only Container
|
|||
${SG_OID_INV} = Put Storagegroup ${USER_KEY} ${READONLY_CID} ${EMPTY} ${S_OID_USER}
|
||||
${SG_OID_1} = Put Storagegroup ${USER_KEY} ${READONLY_CID} ${EMPTY} ${S_OID_USER}
|
||||
List Storagegroup ${USER_KEY} ${READONLY_CID} ${EMPTY} ${SG_OID_1} ${SG_OID_INV}
|
||||
@{EXPECTED_OIDS} = Run Keyword If "${RUN_TYPE}" == "Complex" Get Split objects ${USER_KEY} ${READONLY_CID} ${S_OID_USER}
|
||||
@{EXPECTED_OIDS} = Run Keyword If "${RUN_TYPE}" == "Complex"
|
||||
... Get Object Parts By Link Object ${USER_KEY} ${READONLY_CID} ${S_OID_USER}
|
||||
... ELSE IF "${RUN_TYPE}" == "Simple" Create List ${S_OID_USER}
|
||||
Get Storagegroup ${USER_KEY} ${READONLY_CID} ${SG_OID_1} ${EMPTY} ${EMPTY} @{EXPECTED_OIDS}
|
||||
Delete Storagegroup ${USER_KEY} ${READONLY_CID} ${SG_OID_1} ${EMPTY}
|
||||
|
@ -58,7 +60,8 @@ Check Read-Only Container
|
|||
Run Keyword And Expect Error *
|
||||
... Put Storagegroup ${OTHER_KEY} ${READONLY_CID} ${EMPTY} ${S_OID_USER}
|
||||
List Storagegroup ${OTHER_KEY} ${READONLY_CID} ${EMPTY} ${SG_OID_INV}
|
||||
@{EXPECTED_OIDS} = Run Keyword If "${RUN_TYPE}" == "Complex" Get Split objects ${USER_KEY} ${READONLY_CID} ${S_OID_USER}
|
||||
@{EXPECTED_OIDS} = Run Keyword If "${RUN_TYPE}" == "Complex"
|
||||
... Get Object Parts By Link Object ${USER_KEY} ${READONLY_CID} ${S_OID_USER}
|
||||
... ELSE IF "${RUN_TYPE}" == "Simple" Create List ${S_OID_USER}
|
||||
Get Storagegroup ${OTHER_KEY} ${READONLY_CID} ${SG_OID_INV} ${EMPTY} ${EMPTY} @{EXPECTED_OIDS}
|
||||
Run Keyword And Expect Error *
|
||||
|
@ -66,7 +69,8 @@ Check Read-Only Container
|
|||
|
||||
${SG_OID_IR} = Put Storagegroup ${NEOFS_IR_WIF} ${READONLY_CID} ${EMPTY} ${S_OID_USER}
|
||||
List Storagegroup ${NEOFS_IR_WIF} ${READONLY_CID} ${EMPTY} ${SG_OID_INV} ${SG_OID_IR}
|
||||
@{EXPECTED_OIDS} = Run Keyword If "${RUN_TYPE}" == "Complex" Get Split objects ${USER_KEY} ${READONLY_CID} ${S_OID_USER}
|
||||
@{EXPECTED_OIDS} = Run Keyword If "${RUN_TYPE}" == "Complex"
|
||||
... Get Object Parts By Link Object ${USER_KEY} ${READONLY_CID} ${S_OID_USER}
|
||||
... ELSE IF "${RUN_TYPE}" == "Simple" Create List ${S_OID_USER}
|
||||
Get Storagegroup ${NEOFS_IR_WIF} ${READONLY_CID} ${SG_OID_IR} ${EMPTY} ${EMPTY} @{EXPECTED_OIDS}
|
||||
Run Keyword And Expect Error *
|
||||
|
|
|
@ -8,6 +8,7 @@ Library payment_neogo.py
|
|||
Resource common_steps_acl_basic.robot
|
||||
Resource payment_operations.robot
|
||||
Resource setup_teardown.robot
|
||||
Resource complex_object_operations.robot
|
||||
|
||||
|
||||
*** Test cases ***
|
||||
|
@ -47,7 +48,8 @@ Check Read-Only Container
|
|||
${SG_OID_INV} = Put Storagegroup ${USER_KEY} ${READONLY_CID} ${EMPTY} ${S_OID_USER}
|
||||
${SG_OID_1} = Put Storagegroup ${USER_KEY} ${READONLY_CID} ${EMPTY} ${S_OID_USER}
|
||||
List Storagegroup ${USER_KEY} ${READONLY_CID} ${EMPTY} ${SG_OID_1} ${SG_OID_INV}
|
||||
@{EXPECTED_OIDS} = Run Keyword If "${RUN_TYPE}" == "Complex" Get Split objects ${USER_KEY} ${READONLY_CID} ${S_OID_USER}
|
||||
@{EXPECTED_OIDS} = Run Keyword If "${RUN_TYPE}" == "Complex"
|
||||
... Get Object Parts By Link Object ${USER_KEY} ${READONLY_CID} ${S_OID_USER}
|
||||
... ELSE IF "${RUN_TYPE}" == "Simple" Create List ${S_OID_USER}
|
||||
Get Storagegroup ${USER_KEY} ${READONLY_CID} ${SG_OID_1} ${EMPTY} ${EMPTY} @{EXPECTED_OIDS}
|
||||
Delete Storagegroup ${USER_KEY} ${READONLY_CID} ${SG_OID_1} ${EMPTY}
|
||||
|
@ -56,7 +58,8 @@ Check Read-Only Container
|
|||
Run Keyword And Expect Error *
|
||||
... Put Storagegroup ${OTHER_KEY} ${READONLY_CID} ${EMPTY} ${S_OID_USER}
|
||||
List Storagegroup ${OTHER_KEY} ${READONLY_CID} ${EMPTY} ${SG_OID_INV}
|
||||
@{EXPECTED_OIDS} = Run Keyword If "${RUN_TYPE}" == "Complex" Get Split objects ${USER_KEY} ${READONLY_CID} ${S_OID_USER}
|
||||
@{EXPECTED_OIDS} = Run Keyword If "${RUN_TYPE}" == "Complex"
|
||||
... Get Object Parts By Link Object ${USER_KEY} ${READONLY_CID} ${S_OID_USER}
|
||||
... ELSE IF "${RUN_TYPE}" == "Simple" Create List ${S_OID_USER}
|
||||
Get Storagegroup ${OTHER_KEY} ${READONLY_CID} ${SG_OID_INV} ${EMPTY} ${EMPTY} @{EXPECTED_OIDS}
|
||||
Run Keyword And Expect Error *
|
||||
|
@ -65,7 +68,8 @@ Check Read-Only Container
|
|||
|
||||
${SG_OID_IR} = Put Storagegroup ${NEOFS_IR_WIF} ${READONLY_CID} ${EMPTY} ${S_OID_USER}
|
||||
List Storagegroup ${NEOFS_IR_WIF} ${READONLY_CID} ${EMPTY} ${SG_OID_INV} ${SG_OID_IR}
|
||||
@{EXPECTED_OIDS} = Run Keyword If "${RUN_TYPE}" == "Complex" Get Split objects ${USER_KEY} ${READONLY_CID} ${S_OID_USER}
|
||||
@{EXPECTED_OIDS} = Run Keyword If "${RUN_TYPE}" == "Complex"
|
||||
... Get Object Parts By Link Object ${USER_KEY} ${READONLY_CID} ${S_OID_USER}
|
||||
... ELSE IF "${RUN_TYPE}" == "Simple" Create List ${S_OID_USER}
|
||||
Get Storagegroup ${NEOFS_IR_WIF} ${READONLY_CID} ${SG_OID_IR} ${EMPTY} ${EMPTY} @{EXPECTED_OIDS}
|
||||
Run Keyword And Expect Error *
|
||||
|
|
|
@ -11,6 +11,7 @@ Resource eacl_tables.robot
|
|||
Resource common_steps_acl_bearer.robot
|
||||
Resource payment_operations.robot
|
||||
Resource setup_teardown.robot
|
||||
Resource complex_object_operations.robot
|
||||
|
||||
|
||||
*** Test cases ***
|
||||
|
@ -50,7 +51,8 @@ Check eACL Deny and Allow All Bearer
|
|||
${SG_OID_INV} = Put Storagegroup ${USER_KEY} ${CID} ${EMPTY} ${S_OID_USER}
|
||||
${SG_OID_1} = Put Storagegroup ${USER_KEY} ${CID} ${EMPTY} ${S_OID_USER}
|
||||
List Storagegroup ${USER_KEY} ${CID} ${EMPTY} ${SG_OID_1} ${SG_OID_INV}
|
||||
@{EXPECTED_OIDS} = Run Keyword If "${RUN_TYPE}" == "Complex" Get Split objects ${USER_KEY} ${CID} ${S_OID_USER}
|
||||
@{EXPECTED_OIDS} = Run Keyword If "${RUN_TYPE}" == "Complex"
|
||||
... Get Object Parts By Link Object ${USER_KEY} ${CID} ${S_OID_USER}
|
||||
... ELSE IF "${RUN_TYPE}" == "Simple" Create List ${S_OID_USER}
|
||||
Get Storagegroup ${USER_KEY} ${CID} ${SG_OID_1} ${EMPTY} ${EMPTY} @{EXPECTED_OIDS}
|
||||
Delete Storagegroup ${USER_KEY} ${CID} ${SG_OID_1} ${EMPTY}
|
||||
|
|
|
@ -13,6 +13,7 @@ Library Process
|
|||
Resource setup_teardown.robot
|
||||
Resource payment_operations.robot
|
||||
Resource storage.robot
|
||||
Resource complex_object_operations.robot
|
||||
|
||||
*** Variables ***
|
||||
${CONTAINER_WAIT_INTERVAL} = 1 min
|
||||
|
@ -69,7 +70,7 @@ Drop command in control group
|
|||
Get object ${USER_KEY} ${PRIV_CID} ${C_OID} ${EMPTY} s_file_read
|
||||
Head object ${USER_KEY} ${PRIV_CID} ${C_OID}
|
||||
|
||||
@{SPLIT_OIDS} = Get Split objects ${USER_KEY} ${PRIV_CID} ${C_OID}
|
||||
@{SPLIT_OIDS} = Get Object Parts By Link Object ${USER_KEY} ${PRIV_CID} ${C_OID}
|
||||
FOR ${CHILD_OID} IN @{SPLIT_OIDS}
|
||||
Drop object ${NODE} ${WIF} ${PRIV_CID} ${CHILD_OID}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
Variables common.py
|
||||
|
||||
Library neofs_verbs.py
|
||||
Library complex_object_actions.py
|
||||
Library neofs.py
|
||||
Library payment_neogo.py
|
||||
Library contract_keywords.py
|
||||
|
@ -15,6 +16,7 @@ Resource payment_operations.robot
|
|||
${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
|
||||
|
||||
|
||||
*** Test cases ***
|
||||
|
@ -66,15 +68,23 @@ NeoFS Complex Object Operations
|
|||
Search object ${WIF} ${CID} --root filters=${FILE_USR_HEADER} expected_objects_list=${S_OBJ_H}
|
||||
Search object ${WIF} ${CID} --root filters=${FILE_USR_HEADER_OTH} expected_objects_list=${S_OBJ_H_OTH}
|
||||
|
||||
Head object ${WIF} ${CID} ${S_OID}
|
||||
&{RESPONSE} = Head object ${WIF} ${CID} ${H_OID}
|
||||
&{S_RESPONSE} = Head object ${WIF} ${CID} ${S_OID}
|
||||
&{H_RESPONSE} = Head object ${WIF} ${CID} ${H_OID}
|
||||
Dictionary Should Contain Sub Dictionary
|
||||
... ${RESPONSE}[header][attributes]
|
||||
... ${H_RESPONSE}[header][attributes]
|
||||
... ${FILE_USR_HEADER}
|
||||
... msg="There are no User Headers in HEAD response"
|
||||
|
||||
Verify Split Chain ${WIF} ${CID} ${S_OID}
|
||||
Verify Split Chain ${WIF} ${CID} ${H_OID}
|
||||
${PAYLOAD_LENGTH} ${SPLIT_ID} ${SPLIT_OBJECTS} = Restore Large Object By Last
|
||||
... ${WIF} ${CID} ${S_OID}
|
||||
${H_PAYLOAD_LENGTH} ${H_SPLIT_ID} ${H_SPLIT_OBJECTS} = Restore Large Object By Last
|
||||
... ${WIF} ${CID} ${H_OID}
|
||||
|
||||
Compare With Link Object ${WIF} ${CID} ${S_OID} ${SPLIT_ID} ${SPLIT_OBJECTS}
|
||||
Compare With Link Object ${WIF} ${CID} ${H_OID} ${H_SPLIT_ID} ${H_SPLIT_OBJECTS}
|
||||
|
||||
Should Be Equal As Numbers ${S_RESPONSE.header.payloadLength} ${PAYLOAD_LENGTH}
|
||||
Should Be Equal As Numbers ${H_RESPONSE.header.payloadLength} ${H_PAYLOAD_LENGTH}
|
||||
|
||||
${TOMBSTONE_S} = Delete object ${WIF} ${CID} ${S_OID}
|
||||
${TOMBSTONE_H} = Delete object ${WIF} ${CID} ${H_OID}
|
||||
|
@ -86,9 +96,85 @@ NeoFS Complex Object Operations
|
|||
# we assume that during this time objects must be deleted
|
||||
Sleep ${CLEANUP_TIMEOUT}
|
||||
|
||||
Run Keyword And Expect Error "rpc error: status: code = 1024 message = object already removed"
|
||||
... Get object ${WIF} ${CID} ${S_OID} ${EMPTY} ${GET_OBJ_S}
|
||||
Run Keyword And Expect Error "rpc error: status: code = 1024 message = object already removed"
|
||||
... Get object ${WIF} ${CID} ${H_OID} ${EMPTY} ${GET_OBJ_H}
|
||||
${ERR_MSG} = Run Keyword And Expect Error *
|
||||
... Get object ${WIF} ${CID} ${S_OID}
|
||||
Should Contain ${ERR_MSG} ${ALREADY_REMOVED_ERROR}
|
||||
${ERR_MSG} = Run Keyword And Expect Error *
|
||||
... Get object ${WIF} ${CID} ${H_OID}
|
||||
Should Contain ${ERR_MSG} ${ALREADY_REMOVED_ERROR}
|
||||
|
||||
[Teardown] Teardown object_complex
|
||||
|
||||
|
||||
*** Keywords ***
|
||||
|
||||
Restore Large Object By Last
|
||||
[Documentation] In this keyword we assemble Large Object from its parts. First, we search for the
|
||||
... Last Object; then, we try to restore the Large Object using Split Chain. We check
|
||||
... that all Object Parts have identical SplitID, accumulate total payload length and
|
||||
... compile a list of Object Parts. For the first part of split we also check if is
|
||||
... has the only `splitID` field in the split header.
|
||||
... The keyword returns total payload length, SplitID and list of Part Objects for
|
||||
... these data might be verified by other keywords.
|
||||
|
||||
[Arguments] ${WIF} ${CID} ${LARGE_OID}
|
||||
|
||||
${LAST_OID} = Get Last Object ${WIF} ${CID} ${LARGE_OID}
|
||||
&{LAST_OBJ_HEADER} = Head Object ${WIF} ${CID} ${LAST_OID} is_raw=True
|
||||
Should Be Equal ${LARGE_OID} ${LAST_OBJ_HEADER.header.split.parent}
|
||||
|
||||
${SPLIT_ID} = Set Variable ${LAST_OBJ_HEADER.header.split.splitID}
|
||||
${PART_OID} = Set Variable ${LAST_OBJ_HEADER.objectID}
|
||||
${PAYLOAD_LENGTH} = Set Variable 0
|
||||
@{PART_OBJECTS} = Create List
|
||||
|
||||
FOR ${i} IN RANGE 1000
|
||||
&{SPLIT_HEADER} = Head object ${WIF} ${CID} ${PART_OID} is_raw=True
|
||||
|
||||
${PAYLOAD_LENGTH} = Evaluate ${PAYLOAD_LENGTH} + ${SPLIT_HEADER.header.payloadLength}
|
||||
|
||||
# Every Object of the given split contains the same SplitID
|
||||
Should Be Equal ${SPLIT_HEADER.header.split.splitID} ${SPLIT_ID}
|
||||
Should Be Equal ${SPLIT_HEADER.header.objectType} REGULAR
|
||||
|
||||
Append To List ${PART_OBJECTS} ${PART_OID}
|
||||
|
||||
# If we have reached the First Object, it has no `previous` field.
|
||||
# Asserting this condition and exiting the loop.
|
||||
${PASSED} = Run Keyword And Return Status
|
||||
... Should Be Equal
|
||||
... ${SPLIT_HEADER.header.split.previous} ${None}
|
||||
|
||||
Exit For Loop If ${PASSED}
|
||||
${PART_OID} = Set Variable ${SPLIT_HEADER.header.split.previous}
|
||||
END
|
||||
|
||||
[Return] ${PAYLOAD_LENGTH} ${SPLIT_ID} ${PART_OBJECTS}
|
||||
|
||||
|
||||
Compare With Link Object
|
||||
[Documentation] The keyword accepts Large Object SplitID and its Part Objects as
|
||||
... a parameters. Then it requests the Link Object and verifies that
|
||||
... a Split Chain which it stores is equal to the Part Objects list.
|
||||
... In this way we check that Part Objects list restored from Last
|
||||
... Object and the Split Chain from Link Object are equal and the
|
||||
... system is able to restore the Large Object using any of these ways.
|
||||
|
||||
[Arguments] ${WIF} ${CID} ${LARGE_OID} ${SPLIT_ID} ${SPLIT_OBJECTS}
|
||||
|
||||
${LINK_OID} = Get Link Object ${WIF} ${CID} ${LARGE_OID}
|
||||
&{LINK_HEADER} = Head Object ${WIF} ${CID} ${LINK_OID} is_raw=True
|
||||
|
||||
Reverse List ${SPLIT_OBJECTS}
|
||||
Lists Should Be Equal
|
||||
... ${LINK_HEADER.header.split.children}
|
||||
... ${SPLIT_OBJECTS}
|
||||
|
||||
Should Be Equal As Numbers
|
||||
... ${LINK_HEADER.header.payloadLength} 0
|
||||
|
||||
Should Be Equal
|
||||
... ${LINK_HEADER.header.objectType} REGULAR
|
||||
|
||||
Should Be Equal
|
||||
... ${LINK_HEADER.header.split.splitID} ${SPLIT_ID}
|
||||
|
|
|
@ -9,6 +9,7 @@ Library Collections
|
|||
Resource common_steps_object.robot
|
||||
Resource setup_teardown.robot
|
||||
Resource payment_operations.robot
|
||||
Resource complex_object_operations.robot
|
||||
|
||||
*** Variables ***
|
||||
${UNEXIST_OID} = B2DKvkHnLnPvapbDgfpU1oVUPuXQo5LTfKVxmNDZXQff
|
||||
|
@ -38,7 +39,7 @@ NeoFS Complex Storagegroup
|
|||
Log Storage group with 1 object
|
||||
${SG_OID_1} = Put Storagegroup ${WIF} ${CID} ${EMPTY} ${S_OID_1}
|
||||
List Storagegroup ${WIF} ${CID} ${EMPTY} ${SG_OID_1}
|
||||
@{SPLIT_OBJ_1} = Get Split objects ${WIF} ${CID} ${S_OID_1}
|
||||
@{SPLIT_OBJ_1} = Get Object Parts By Link Object ${WIF} ${CID} ${S_OID_1}
|
||||
Get Storagegroup ${WIF} ${CID} ${SG_OID_1} ${EMPTY} ${COMPLEX_OBJ_SIZE} @{SPLIT_OBJ_1}
|
||||
${Tombstone} = Delete Storagegroup ${WIF} ${CID} ${SG_OID_1} ${EMPTY}
|
||||
Verify Head tombstone ${WIF} ${CID} ${Tombstone} ${SG_OID_1} ${ADDR}
|
||||
|
@ -49,7 +50,7 @@ NeoFS Complex Storagegroup
|
|||
Log Storage group with 2 objects
|
||||
${SG_OID_2} = Put Storagegroup ${WIF} ${CID} ${EMPTY} @{S_OBJ_ALL}
|
||||
List Storagegroup ${WIF} ${CID} ${EMPTY} ${SG_OID_2}
|
||||
@{SPLIT_OBJ_2} = Get Split objects ${WIF} ${CID} ${S_OID_2}
|
||||
@{SPLIT_OBJ_2} = Get Object Parts By Link Object ${WIF} ${CID} ${S_OID_2}
|
||||
@{SPLIT_OBJ_ALL} = Combine Lists ${SPLIT_OBJ_1} ${SPLIT_OBJ_2}
|
||||
${EXPECTED_SIZE} = Evaluate 2*${COMPLEX_OBJ_SIZE}
|
||||
Get Storagegroup ${WIF} ${CID} ${SG_OID_2} ${EMPTY} ${EXPECTED_SIZE} @{SPLIT_OBJ_ALL}
|
||||
|
|
Loading…
Reference in a new issue