diff --git a/robot/resources/lib/python_keywords/json_transformers.py b/robot/resources/lib/python_keywords/json_transformers.py index b145979..2af13d2 100644 --- a/robot/resources/lib/python_keywords/json_transformers.py +++ b/robot/resources/lib/python_keywords/json_transformers.py @@ -92,6 +92,30 @@ def decode_storage_group(data: dict): return data +def decode_tombstone(data: dict): + ''' + This function reencodes Tombstone header. + ''' + try: + data = decode_simple_header(data) + data['header']['sessionToken'] = decode_session_token( + data['header']['sessionToken']) + except Exception as exc: + raise ValueError(f"failed to decode JSON output: {exc}") from exc + return data + + +def decode_session_token(data: dict): + ''' + This function reencodes a fragment of header which contains + information about session token. + ''' + data['body']['object']['address']['containerID'] = json_reencode( + data['body']['object']['address']['containerID']['value']) + data['body']['object']['address']['objectID'] = json_reencode( + data['body']['object']['address']['objectID']['value']) + return data + def json_reencode(data: str): ''' According to JSON protocol, binary data (Object/Container/Storage Group IDs, etc) @@ -103,6 +127,10 @@ def json_reencode(data: str): def encode_for_json(data: str): + ''' + This function encodes binary data for sending them as protobuf + structures. + ''' return base64.b64encode(base58.b58decode(data)).decode('utf-8') def decode_common_fields(data: dict): diff --git a/robot/resources/lib/python_keywords/neofs.py b/robot/resources/lib/python_keywords/neofs.py index bb56a89..e93d48a 100644 --- a/robot/resources/lib/python_keywords/neofs.py +++ b/robot/resources/lib/python_keywords/neofs.py @@ -1,20 +1,15 @@ #!/usr/bin/python3 -import base64 import json import os -import re import random -import uuid -import base58 from neo3 import wallet -from common import (NEOFS_NETMAP, WALLET_PASS, NEOFS_ENDPOINT, -NEOFS_NETMAP_DICT, ASSETS_DIR) -from cli_helpers import _cmd_run -import json_transformers +from common import NEOFS_NETMAP_DICT +import neofs_verbs from robot.api.deco import keyword from robot.api import logger +from robot.libraries.BuiltIn import BuiltIn ROBOT_AUTO_KEYWORDS = False @@ -30,52 +25,35 @@ def get_scripthash(wif: str): @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 - object_cmd = ( - f'{NEOFS_CLI_EXEC} --rpc-endpoint {NEOFS_ENDPOINT} --wallet {wallet} ' - f'--config {WALLET_PASS} object head --cid {cid} --oid {oid_ts} --json' - ) - output = _cmd_run(object_cmd) - full_headers = json.loads(output) - logger.info(f"Output: {full_headers}") +def verify_head_tombstone(wallet_path: str, cid: str, oid_ts: str, oid: str): + header = neofs_verbs.head_object(wallet_path, cid, oid_ts) + header = header['header'] - # Header verification - header_cid = full_headers["header"]["containerID"]["value"] - if json_transformers.json_reencode(header_cid) == cid: - logger.info(f"Header CID is expected: {cid} ({header_cid} in the output)") - else: - raise Exception("Header CID is not expected.") + BuiltIn().should_be_equal(header["containerID"], cid, + msg="Tombstone Header CID is wrong") - header_owner = full_headers["header"]["ownerID"]["value"] - if json_transformers.json_reencode(header_owner) == addr: - logger.info(f"Header ownerID is expected: {addr} ({header_owner} in the output)") - else: - raise Exception("Header ownerID is not expected.") + wlt_data = dict() + with open(wallet_path, 'r') as fout: + wlt_data = json.loads(fout.read()) + wlt = wallet.Wallet.from_json(wlt_data, password='') + addr = wlt.accounts[0].address - header_type = full_headers["header"]["objectType"] - if header_type == "TOMBSTONE": - logger.info(f"Header Type is expected: {header_type}") - else: - raise Exception("Header Type is not expected.") + BuiltIn().should_be_equal(header["ownerID"], addr, + msg="Tombstone Owner ID is wrong") - header_session_type = full_headers["header"]["sessionToken"]["body"]["object"]["verb"] - if header_session_type == "DELETE": - logger.info(f"Header Session Type is expected: {header_session_type}") - else: - raise Exception("Header Session Type is not expected.") + BuiltIn().should_be_equal(header["objectType"], 'TOMBSTONE', + msg="Header Type isn't Tombstone") - header_session_cid = full_headers["header"]["sessionToken"]["body"]["object"]["address"]["containerID"]["value"] - if json_transformers.json_reencode(header_session_cid) == cid: - logger.info(f"Header ownerID is expected: {addr} ({header_session_cid} in the output)") - else: - raise Exception("Header Session CID is not expected.") + BuiltIn().should_be_equal(header["sessionToken"]["body"]["object"]["verb"], 'DELETE', + msg="Header Session Type isn't DELETE") - header_session_oid = full_headers["header"]["sessionToken"]["body"]["object"]["address"]["objectID"]["value"] - if json_transformers.json_reencode(header_session_oid) == oid: - logger.info(f"Header Session OID (deleted object) is expected: {oid} ({header_session_oid} in the output)") - else: - raise Exception("Header Session OID (deleted object) is not expected.") + BuiltIn().should_be_equal(header["sessionToken"]["body"]["object"]["address"]["containerID"], + cid, + msg="Header Session ID is wrong") + + BuiltIn().should_be_equal(header["sessionToken"]["body"]["object"]["address"]["objectID"], + oid, + msg="Header Session OID is wrong") @keyword('Get control endpoint with wif') diff --git a/robot/resources/lib/python_keywords/neofs_verbs.py b/robot/resources/lib/python_keywords/neofs_verbs.py index d1a1705..266b306 100644 --- a/robot/resources/lib/python_keywords/neofs_verbs.py +++ b/robot/resources/lib/python_keywords/neofs_verbs.py @@ -31,7 +31,7 @@ def get_object(wallet: str, cid: str, oid: str, bearer_token: str="", GET from NeoFS. Args: - wif (str): WIF of the wallet on whose behalf GET is done + wallet (str): wallet on whose behalf GET is done cid (str): ID of Container where we get the Object from oid (str): Object ID bearer_token (optional, str): path to Bearer Token file, appends to `--bearer` key @@ -59,19 +59,20 @@ def get_object(wallet: str, cid: str, oid: str, bearer_token: str="", return file_path +# TODO: make `bearer_token` optional @keyword('Get Range Hash') -def get_range_hash(wallet: str, cid: str, oid: str, bearer_token: str, - range_cut: str, options: str=""): +def get_range_hash(wallet: str, cid: str, oid: str, bearer_token: str, range_cut: str, + options: str=""): ''' GETRANGEHASH of given Object. Args: - wif (str): WIF of the wallet on whose behalf GETRANGEHASH is done + wallet (str): wallet on whose behalf GETRANGEHASH is done cid (str): ID of Container where we get the Object from oid (str): Object ID - bearer_token (str): path to Bearer Token file, appends to `--bearer` key range_cut (str): Range to take hash from in the form offset1:length1,..., value to pass to the `--range` parameter + bearer_token (optional, str): path to Bearer Token file, appends to `--bearer` key options (optional, str): any options which `neofs-cli object hash` accepts Returns: None @@ -82,7 +83,9 @@ def get_range_hash(wallet: str, cid: str, oid: str, bearer_token: str, f'{"--bearer " + bearer_token if bearer_token else ""} ' f'{options}' ) - _cmd_run(cmd) + output = _cmd_run(cmd) + # cutting off output about range offset and length + return output.split(':')[1].strip() @keyword('Put object') @@ -92,7 +95,7 @@ def put_object(wallet: str, path: str, cid: str, bearer: str="", user_headers: d PUT of given file. Args: - wif (str): WIF of the wallet on whose behalf PUT is done + wallet (str): wallet on whose behalf PUT is done path (str): path to file to be PUT cid (str): ID of Container where we get the Object from bearer (optional, str): path to Bearer Token file, appends to `--bearer` key @@ -123,7 +126,7 @@ def delete_object(wallet: str, cid: str, oid: str, bearer: str="", options: str= DELETE an Object. Args: - wif (str): WIF of the wallet on whose behalf DELETE is done + wallet (str): wallet on whose behalf DELETE is done cid (str): ID of Container where we get the Object from oid (str): ID of Object we are going to delete bearer (optional, str): path to Bearer Token file, appends to `--bearer` key @@ -142,47 +145,52 @@ def delete_object(wallet: str, cid: str, oid: str, bearer: str="", options: str= return tombstone.strip() +# TODO: remove `file_path` parameter as it is a boilerplate +# TODO: make `bearer` an optional parameter @keyword('Get Range') -def get_range(wallet: str, cid: str, oid: str, range_file: str, bearer: str, - range_cut: str, options:str=""): +def get_range(wallet: str, cid: str, oid: str, file_path: str, bearer: str, range_cut: str, + options:str=""): ''' GETRANGE an Object. Args: - wif (str): WIF of the wallet on whose behalf GETRANGE is done + wallet (str): wallet on whose behalf GETRANGE is done cid (str): ID of Container where we get the Object from oid (str): ID of Object we are going to request - range_file (str): file where payload range data will be written - bearer (str): path to Bearer Token file, appends to `--bearer` key range_cut (str): range to take data from in the form offset:length + bearer (optional, str): path to Bearer Token file, appends to `--bearer` key options (optional, str): any options which `neofs-cli object range` accepts Returns: - None + (void) ''' + range_file = f"{ASSETS_DIR}/{uuid.uuid4()}" cmd = ( f'{NEOFS_CLI_EXEC} --rpc-endpoint {NEOFS_ENDPOINT} --wallet {wallet} ' f'object range --cid {cid} --oid {oid} --range {range_cut} --config {WALLET_PASS} ' - f'--file {ASSETS_DIR}/{range_file} {options} ' + f'{options} --file {range_file} ' f'{"--bearer " + bearer if bearer else ""} ' ) _cmd_run(cmd) + content = '' + with open(range_file, 'rb') as fout: + content = fout.read() + return range_file, content @keyword('Search object') def search_object(wallet: str, cid: str, keys: str="", bearer: str="", filters: dict={}, - expected_objects_list=[], options:str=""): + expected_objects_list=[]): ''' - GETRANGE an Object. + SEARCH an Object. Args: - wif (str): WIF of the wallet on whose behalf SEARCH is done + wallet (str): wallet on whose behalf SEARCH is done cid (str): ID of Container where we get the Object from keys(optional, str): any keys for Object SEARCH which `neofs-cli object search` accepts, e.g. `--oid` bearer (optional, str): path to Bearer Token file, appends to `--bearer` key filters (optional, dict): key=value pairs to filter Objects expected_objects_list (optional, list): a list of ObjectIDs to compare found Objects with - options (optional, str): any options which `neofs-cli object search` accepts Returns: (list): list of found ObjectIDs ''' @@ -194,7 +202,7 @@ def search_object(wallet: str, cid: str, keys: str="", bearer: str="", filters: cmd = ( f'{NEOFS_CLI_EXEC} --rpc-endpoint {NEOFS_ENDPOINT} --wallet {wallet} ' - f'object search {keys} --cid {cid} {filters_result} {options} --config {WALLET_PASS} ' + f'object search {keys} --cid {cid} {filters_result} --config {WALLET_PASS} ' f'{"--bearer " + bearer if bearer else ""}' ) output = _cmd_run(cmd) @@ -206,7 +214,7 @@ def search_object(wallet: str, cid: str, keys: str="", bearer: str="", filters: logger.info(f"Found objects list '{found_objects}' ", f"is equal for expected list '{expected_objects_list}'") else: - raise Exception(f"Found object list {found_objects} ", + logger.warn(f"Found object list {found_objects} ", f"is not equal to expected list '{expected_objects_list}'") return found_objects @@ -220,7 +228,7 @@ def head_object(wallet: str, cid: str, oid: str, bearer_token: str="", HEAD an Object. Args: - wif (str): WIF of the wallet on whose behalf HEAD is done + wallet (str): wallet on whose behalf HEAD is done cid (str): ID of Container where we get the Object from oid (str): ObjectID to HEAD bearer_token (optional, str): path to Bearer Token file, appends to `--bearer` key @@ -279,5 +287,9 @@ def head_object(wallet: str, cid: str, oid: str, bearer_token: str="", logger.info("decoding storage group") return json_transformers.decode_storage_group(decoded) + if decoded['header']['objectType'] == 'TOMBSTONE': + logger.info("decoding tombstone") + return json_transformers.decode_tombstone(decoded) + logger.info("decoding simple header") return json_transformers.decode_simple_header(decoded) diff --git a/robot/resources/lib/python_keywords/utility_keywords.py b/robot/resources/lib/python_keywords/utility_keywords.py index 2b13e1c..0a77b20 100644 --- a/robot/resources/lib/python_keywords/utility_keywords.py +++ b/robot/resources/lib/python_keywords/utility_keywords.py @@ -44,11 +44,9 @@ def get_file_hash(filename: str): Returns: (str): the hash of the file """ - blocksize = 65536 - file_hash = hashlib.md5() + file_hash = hashlib.sha256() with open(filename, "rb") as out: - for block in iter(lambda: out.read(blocksize), b""): - file_hash.update(block) + file_hash.update(out.read()) return file_hash.hexdigest() diff --git a/robot/resources/lib/robot/verbs.robot b/robot/resources/lib/robot/verbs.robot new file mode 100644 index 0000000..870af63 --- /dev/null +++ b/robot/resources/lib/robot/verbs.robot @@ -0,0 +1,65 @@ +*** Settings *** +Variables common.py + +Library contract_keywords.py +Library neofs.py +Library neofs_verbs.py +Library utility_keywords.py +Library Collections +Library OperatingSystem + +*** Variables *** +${CLEANUP_TIMEOUT} = 10s + +*** Keywords *** + +Run All Verbs Except Delete And Expect Success + [Arguments] ${WALLET} ${CID} ${COMPLEXITY} + + ${OBJ_SIZE} = Run Keyword If """${COMPLEXITY}""" == """Simple""" + ... Set Variable ${SIMPLE_OBJ_SIZE} + ... ELSE + ... Set Variable ${COMPLEX_OBJ_SIZE} + + ${FILE} ${FILE_HASH} = Generate file ${OBJ_SIZE} + + ${OID} = Put object ${WALLET} ${FILE} ${CID} + ${OBJ_PATH} = Get object ${WALLET} ${CID} ${OID} + ${DOWNLOADED_FILE_HASH} = + ... Get file hash ${OBJ_PATH} + Should Be Equal ${DOWNLOADED_FILE_HASH} ${FILE_HASH} + + # TODO: get rid of ${EMPTY} + ${RANGE_FILE} + ... ${DATA_RANGE} = + ... Get Range ${WALLET} ${CID} ${OID} ${EMPTY} ${EMPTY} 0:10 + ${FILE_CONTENT} = Get Binary File ${FILE} + Should Contain ${FILE_CONTENT} ${DATA_RANGE} + + # TODO: get rid of ${EMPTY} + ${RANGE_HASH} = Get Range Hash ${WALLET} ${CID} ${OID} ${EMPTY} 0:10 + ${GR_HASH} = Get File Hash ${RANGE_FILE} + Should Be Equal ${GR_HASH} ${RANGE_HASH} + + ${FOUND_OBJECTS} = Search object ${WALLET} ${CID} keys=${OID} + List Should Contain Value + ... ${FOUND_OBJECTS} + ... ${OID} + + &{RESPONSE} = Head object ${WALLET} ${CID} ${OID} + + [Return] ${OID} + +Delete Object And Validate Tombstone + [Arguments] ${WALLET} ${CID} ${OID} + + ${TOMBSTONE_ID} = Delete object ${WALLET} ${CID} ${OID} + Verify Head tombstone ${WALLET} ${CID} ${TOMBSTONE_ID} ${OID} + + Tick Epoch + # we assume that during this time objects must be deleted + Sleep ${CLEANUP_TIMEOUT} + + ${ERR} = Run Keyword And Expect Error * + ... Get object ${WALLET} ${CID} ${OID} + Should Contain ${ERR} code = 2052 message = object already removed diff --git a/robot/testsuites/integration/object/object_attributes.robot b/robot/testsuites/integration/object/object_attributes.robot index e21d0f1..78c29e1 100644 --- a/robot/testsuites/integration/object/object_attributes.robot +++ b/robot/testsuites/integration/object/object_attributes.robot @@ -18,45 +18,61 @@ ${ATTR_DUPLICATE} = FileType=jpg,FileType=png *** Test Cases *** -Duplicated Object Attributes - [Documentation] Testcase to check duplicated attributes. - [Tags] Object - [Timeout] 10 min +Object Attrubutes + [Timeout] 10 min + [Setup] Setup - [Setup] Setup + Check Various Object Attributes Simple + Check Various Object Attributes Complex + + [Teardown] Teardown object_attributes + + +*** Keywords *** + +Check Various Object Attributes + [Arguments] ${COMPLEXITY} ${WALLET} ${_} ${_} = Prepare Wallet And Deposit - ${PUBLIC_CID} = Create Container ${WALLET} basic_acl=${PUBLIC_ACL_F} - ${FILE_S} ${_} = Generate File ${SIMPLE_OBJ_SIZE} - + ${PUBLIC_CID} = Create Container ${WALLET} basic_acl=${PUBLIC_ACL_F} + ${OBJ_SIZE} = Run Keyword If """${COMPLEXITY}""" == """Simple""" + ... Set Variable ${SIMPLE_OBJ_SIZE} + ... ELSE + ... Set Variable ${COMPLEX_OBJ_SIZE} + ${FILE} ${_} = Generate File ${OBJ_SIZE} ################################################### # Checking that object attributes cannot duplicate ################################################### - Run Keyword And Expect Error * - ... Put object ${WALLET} ${FILE_S} ${PUBLIC_CID} user_headers=${ATTR_FILENAME} - # Robot doesn't allow to create a dictionary with the same keys, so using plain text option here - Run Keyword And Expect Error * - ... Put object ${WALLET} ${FILE_S} ${PUBLIC_CID} options=--attributes ${ATTR_DUPLICATE} + ${ERR} = Run Keyword And Expect Error * + ... Put object ${WALLET} ${FILE} ${PUBLIC_CID} user_headers=${ATTR_FILENAME} + Should Contain ${ERR} code = 1024 message = duplication of attributes detected + # Robot doesn't allow to create a dictionary with the same keys, + # so using plain text option here + ${ERR} = Run Keyword And Expect Error * + ... Put object ${WALLET} ${FILE} ${PUBLIC_CID} options=--attributes ${ATTR_DUPLICATE} + Should Contain ${ERR} code = 1024 message = duplication of attributes detected ################################################## # Checking that object cannot have empty attibute ################################################## - Run Keyword And Expect Error * - ... Put object ${WALLET} ${FILE_S} ${PUBLIC_CID} user_headers=${ATTR_NONE} + ${ERR} = Run Keyword And Expect Error * + ... Put object ${WALLET} ${FILE} ${PUBLIC_CID} user_headers=${ATTR_NONE} + Should Contain ${ERR} code = 1024 message = empty attribute value ##################################################### # Checking a successful step with a single attribute ##################################################### - ${OID} = Put object ${WALLET} ${FILE_S} ${PUBLIC_CID} user_headers=${ATTR_SINGLE} - ${HEADER} = Head object ${WALLET} ${PUBLIC_CID} ${OID} + ${OID} = Put object ${WALLET} ${FILE} ${PUBLIC_CID} user_headers=${ATTR_SINGLE} + ${HEADER} = Head object ${WALLET} ${PUBLIC_CID} ${OID} Dictionary Should Contain Sub Dictionary ... ${HEADER}[header][attributes] ... ${ATTR_SINGLE} ... msg="No expected User Attribute in HEAD response" - - [Teardown] Teardown object_attributes + ${FOUND_OIDS} = Search Object ${WALLET} ${PUBLIC_CID} filters=${ATTR_SINGLE} + Should Be Equal ${OID} ${FOUND_OIDS}[0] + ... msg="Cannot SEARCH an object by User Attribute" diff --git a/robot/testsuites/integration/object/object_complex.robot b/robot/testsuites/integration/object/object_complex.robot index b60883f..aeda164 100644 --- a/robot/testsuites/integration/object/object_complex.robot +++ b/robot/testsuites/integration/object/object_complex.robot @@ -13,13 +13,9 @@ Library utility_keywords.py Library Collections Resource setup_teardown.robot +Resource verbs.robot Resource payment_operations.robot -*** Variables *** -${CLEANUP_TIMEOUT} = 10s -&{FILE_USR_HEADER} = key1=1 key2=abc -${ALREADY_REMOVED_ERROR} = code = 2052 message = object already removed - *** Test cases *** NeoFS Complex Object Operations @@ -29,80 +25,26 @@ NeoFS Complex Object Operations [Setup] Setup - ${WALLET} ${ADDR} ${_} = Prepare Wallet And Deposit + ${WALLET} ${_} ${_} = Prepare Wallet And Deposit ${CID} = Create container ${WALLET} - ${FILE} ${FILE_HASH} = Generate file ${COMPLEX_OBJ_SIZE} + ${OID} = + ... Run All Verbs Except Delete And Expect Success + ... ${WALLET} ${CID} Complex - ${S_OID} = Put object ${WALLET} ${FILE} ${CID} - ${H_OID} = Put object ${WALLET} ${FILE} ${CID} user_headers=${FILE_USR_HEADER} - - Should Not Be Equal ${H_OID} ${S_OID} - - ${COPIES} = Get Complex Object Copies ${WALLET} ${CID} ${S_OID} + ${COPIES} = Get Complex Object Copies ${WALLET} ${CID} ${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} - - ${FILE_HASH_S} = Get file hash ${GET_OBJ_S} - ${FILE_HASH_H} = Get file hash ${GET_OBJ_H} - - Should Be Equal ${FILE_HASH_S} ${FILE_HASH} - Should Be Equal ${FILE_HASH_H} ${FILE_HASH} - - Get Range Hash ${WALLET} ${CID} ${S_OID} ${EMPTY} 0:10 - Get Range Hash ${WALLET} ${CID} ${H_OID} ${EMPTY} 0:10 - - 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} - - &{S_RESPONSE} = Head object ${WALLET} ${CID} ${S_OID} - &{H_RESPONSE} = Head object ${WALLET} ${CID} ${H_OID} - Dictionary Should Contain Sub Dictionary - ... ${H_RESPONSE}[header][attributes] - ... ${FILE_USR_HEADER} - ... msg="There are no User Headers in HEAD response" ${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 - ... ${WALLET} ${CID} ${H_OID} + ... ${SPLIT_OBJECTS} = + ... Restore Large Object By Last ${WALLET} ${CID} ${OID} + Compare With Link Object ${WALLET} ${CID} ${OID} ${SPLIT_ID} ${SPLIT_OBJECTS} + &{RESPONSE} = Head object ${WALLET} ${CID} ${OID} + Should Be Equal As Numbers ${RESPONSE.header.payloadLength} ${PAYLOAD_LENGTH} - Compare With Link Object ${WALLET} ${CID} ${S_OID} ${SPLIT_ID} ${SPLIT_OBJECTS} - Compare With Link Object ${WALLET} ${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 ${WALLET} ${CID} ${S_OID} - ${TOMBSTONE_H} = Delete object ${WALLET} ${CID} ${H_OID} - - Verify Head tombstone ${WALLET} ${CID} ${TOMBSTONE_S} ${S_OID} ${ADDR} - Verify Head tombstone ${WALLET} ${CID} ${TOMBSTONE_H} ${H_OID} ${ADDR} - - Tick Epoch - # we assume that during this time objects must be deleted - Sleep ${CLEANUP_TIMEOUT} - - ${ERR_MSG} = Run Keyword And Expect Error * - ... Get object ${WALLET} ${CID} ${S_OID} - Should Contain ${ERR_MSG} ${ALREADY_REMOVED_ERROR} - ${ERR_MSG} = Run Keyword And Expect Error * - ... Get object ${WALLET} ${CID} ${H_OID} - Should Contain ${ERR_MSG} ${ALREADY_REMOVED_ERROR} + Delete Object And Validate Tombstone + ... ${WALLET} ${CID} ${OID} [Teardown] Teardown object_complex diff --git a/robot/testsuites/integration/object/object_simple.robot b/robot/testsuites/integration/object/object_simple.robot index a0debd8..9e6e91c 100644 --- a/robot/testsuites/integration/object/object_simple.robot +++ b/robot/testsuites/integration/object/object_simple.robot @@ -2,21 +2,12 @@ Variables common.py Library container.py -Library contract_keywords.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 *** -${CLEANUP_TIMEOUT} = 10s -&{FILE_USR_HEADER} = key1=1 key2=abc - +Resource verbs.robot *** Test cases *** NeoFS Simple Object Operations @@ -26,61 +17,18 @@ NeoFS Simple Object Operations [Setup] Setup - ${WALLET} ${ADDR} ${_} = Prepare Wallet And Deposit + ${WALLET} ${_} ${_} = Prepare Wallet And Deposit ${CID} = Create container ${WALLET} - ${FILE} ${FILE_HASH} = Generate file ${SIMPLE_OBJ_SIZE} + ${OID} = + ... Run All Verbs Except Delete And Expect Success + ... ${WALLET} ${CID} Simple - ${S_OID} = Put object ${WALLET} ${FILE} ${CID} - ${H_OID} = Put object ${WALLET} ${FILE} ${CID} user_headers=${FILE_USR_HEADER} - - ${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} + ${COPIES} = Get Simple Object Copies ${WALLET} ${CID} ${OID} Should Be Equal As Numbers 2 ${COPIES} - @{S_OBJ_ALL} = Create List ${S_OID} ${H_OID} - @{S_OBJ_H} = Create List ${H_OID} + Delete Object And Validate Tombstone + ... ${WALLET} ${CID} ${OID} - ${GET_OBJ_S} = Get object ${WALLET} ${CID} ${S_OID} - ${GET_OBJ_H} = Get object ${WALLET} ${CID} ${H_OID} - - ${FILE_HASH_S} = Get file hash ${GET_OBJ_S} - ${FILE_HASH_H} = Get file hash ${GET_OBJ_H} - - Should Be Equal ${FILE_HASH_S} ${FILE_HASH} - Should Be Equal ${FILE_HASH_H} ${FILE_HASH} - - Get Range Hash ${WALLET} ${CID} ${S_OID} ${EMPTY} 0:10 - Get Range Hash ${WALLET} ${CID} ${H_OID} ${EMPTY} 0:10 - - Get Range ${WALLET} ${CID} ${S_OID} s_get_range ${EMPTY} 0:10 - Get Range ${WALLET} ${CID} ${H_OID} h_get_range ${EMPTY} 0:10 - - Search object ${WALLET} ${CID} expected_objects_list=${S_OBJ_ALL} - Search object ${WALLET} ${CID} filters=${FILE_USR_HEADER} expected_objects_list=${S_OBJ_H} - - Head object ${WALLET} ${CID} ${S_OID} - &{RESPONSE} = Head object ${WALLET} ${CID} ${H_OID} - Dictionary Should Contain Sub Dictionary - ... ${RESPONSE}[header][attributes] - ... ${FILE_USR_HEADER} - ... msg="There are no User Headers in HEAD response" - - ${TOMBSTONE_S} = Delete object ${WALLET} ${CID} ${S_OID} - ${TOMBSTONE_H} = Delete object ${WALLET} ${CID} ${H_OID} - - Verify Head tombstone ${WALLET} ${CID} ${TOMBSTONE_S} ${S_OID} ${ADDR} - Verify Head tombstone ${WALLET} ${CID} ${TOMBSTONE_H} ${H_OID} ${ADDR} - - Tick Epoch - # we assume that during this time objects must be deleted - Sleep ${CLEANUP_TIMEOUT} - - Run Keyword And Expect Error * - ... Get object ${WALLET} ${CID} ${S_OID} ${EMPTY} ${GET_OBJ_S} - - Run Keyword And Expect Error * - ... Get object ${WALLET} ${CID} ${H_OID} ${EMPTY} ${GET_OBJ_H} [Teardown] Teardown object_simple