[#184]: neofs verbs divided from neofs.py; HEAD responses are now

proccessed as JSON

Signed-off-by: anastasia prasolova <anastasia@nspcc.ru>
This commit is contained in:
anastasia prasolova 2022-03-15 14:58:59 +03:00 committed by Anastasia Prasolova
parent e5d6662905
commit 7a21456201
43 changed files with 667 additions and 494 deletions

View file

@ -19,6 +19,7 @@ def _cmd_run(cmd, timeout=30):
in case of failure returns error message.
"""
try:
logger.info(f"Executing command: {cmd}")
compl_proc = subprocess.run(cmd, check=True, universal_newlines=True,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT, timeout=timeout,
shell=True)

View file

@ -0,0 +1,113 @@
#!/usr/bin/python3
'''
When doing requests to NeoFS, we get JSON output as an automatically decoded
structure from protobuf. Some fields are decoded with boilerplates and binary
values are Base64-encoded.
This module contains functions which rearrange the structure and reencode binary
data from Base64 to Base58.
'''
import base64
import base58
ROBOT_AUTO_KEYWORDS = False
def decode_simple_header(data: dict):
'''
This function reencodes Simple Object header and its attributes.
'''
try:
data = decode_common_fields(data)
# object attributes view normalization
ugly_attrs = data["header"]["attributes"]
data["header"]["attributes"] = {}
for attr in ugly_attrs:
data["header"]["attributes"][attr["key"]] = attr["value"]
except Exception as exc:
raise ValueError(f"failed to decode JSON output: {exc}") from exc
return data
def decode_split_header(data: dict):
'''
This function rearranges Complex Object header.
The header holds SplitID, a random unique
number, which is common among all splitted objects, and IDs of the Linking
Object and the last splitted Object.
'''
try:
data["splitId"] = json_reencode(data["splitId"])
data["lastPart"] = json_reencode(data["lastPart"]["value"])
data["link"] = json_reencode(data["link"]["value"])
except Exception as exc:
raise ValueError(f"failed to decode JSON output: {exc}") from exc
return data
def decode_linking_object(data: dict):
'''
This function reencodes Linking Object header.
It contains IDs of child Objects and Split Chain data.
'''
try:
data = decode_simple_header(data)
# reencoding Child Object IDs
# { 'value': <Base58 encoded OID> } -> <Base64 encoded OID>
for ind, val in enumerate(data['header']['split']['children']):
data['header']['split']['children'][ind] = json_reencode(val['value'])
data['header']['split']['splitID'] = json_reencode(data['header']['split']['splitID'])
data['header']['split']['previous'] = (
json_reencode(data['header']['split']['previous']['value'])
if data['header']['split']['previous'] else None
)
data['header']['split']['parent'] = (
json_reencode(data['header']['split']['parent']['value'])
if data['header']['split']['parent'] else None
)
except Exception as exc:
raise ValueError(f"failed to decode JSON output: {exc}") from exc
return data
def decode_storage_group(data: dict):
'''
This function reencodes Storage Group header.
'''
try:
data = decode_common_fields(data)
except Exception as exc:
raise ValueError(f"failed to decode JSON output: {exc}") from exc
return data
def json_reencode(data: str):
'''
According to JSON protocol, binary data (Object/Container/Storage Group IDs, etc)
is converted to string via Base58 encoder. But we usually operate with Base64-encoded
format.
This function reencodes given Base58 string into the Base64 one.
'''
return base58.b58encode(base64.b64decode(data)).decode("utf-8")
def decode_common_fields(data: dict):
'''
Despite of type (simple/complex Object, Storage Group, etc) every Object
header contains several common fields.
This function rearranges these fields.
'''
# reencoding binary IDs
data["objectID"] = json_reencode(data["objectID"]["value"])
data["header"]["containerID"] = json_reencode(data["header"]["containerID"]["value"])
data["header"]["ownerID"] = json_reencode(data["header"]["ownerID"]["value"])
data["header"]["homomorphicHash"] = json_reencode(data["header"]["homomorphicHash"]["sum"])
data["header"]["payloadHash"] = json_reencode(data["header"]["payloadHash"]["sum"])
data["header"]["version"] = (
f"{data['header']['version']['major']}{data['header']['version']['minor']}"
)
return data

View file

@ -1,7 +1,6 @@
#!/usr/bin/python3.8
#!/usr/bin/python3
import base64
import binascii
from datetime import datetime
import hashlib
import json
@ -11,13 +10,15 @@ import random
import uuid
import docker
import base58
from functools import reduce
from neo3 import wallet
from common import *
from robot.api.deco import keyword
from robot.api import logger
from cli_helpers import _run_with_passwd, _cmd_run
import neofs_verbs
import json_transformers
ROBOT_AUTO_KEYWORDS = False
@ -67,7 +68,7 @@ def get_nodes_with_object(private_key: str, cid: str, oid: str):
for node in NEOFS_NETMAP:
search_res = _search_object(node, private_key, cid, oid)
if search_res:
if re.search(fr'({oid})', search_res):
if oid in search_res:
nodes_list.append(node)
logger.info(f"Nodes with object: {nodes_list}")
@ -98,11 +99,12 @@ def validate_storage_policy_for_object(private_key: str, expected_copies: int, c
storage_nodes = storage_nodes if len(storage_nodes) != 0 else NEOFS_NETMAP
copies = 0
found_nodes = []
oid = oid.strip()
for node in storage_nodes:
search_res = _search_object(node, private_key, cid, oid)
if search_res:
if re.search(fr'({oid})', search_res):
if oid in search_res:
copies += 1
found_nodes.append(node)
@ -121,21 +123,6 @@ def validate_storage_policy_for_object(private_key: str, expected_copies: int, c
raise Exception(f"Found node list '{found_nodes}' is not equal to expected list '{expected_node_list}'")
@keyword('Get Range')
def get_range(private_key: str, cid: str, oid: str, range_file: str, bearer: str,
range_cut: str, options:str=""):
bearer_token = ""
if bearer:
bearer_token = f"--bearer {bearer}"
Cmd = (
f'{NEOFS_CLI_EXEC} --rpc-endpoint {NEOFS_ENDPOINT} --wallet {private_key} '
f'object range --cid {cid} --oid {oid} {bearer_token} --range {range_cut} '
f'--file {ASSETS_DIR}/{range_file} {options}'
)
logger.info(f"Cmd: {Cmd}")
_cmd_run(Cmd)
@keyword('Create container')
def create_container(private_key: str, basic_acl:str, rule:str, user_headers: str='', session: str=''):
@ -187,39 +174,6 @@ def container_existing(private_key: str, cid: str):
return
@keyword('Search object')
def search_object(private_key: str, cid: str, keys: str="", bearer: str="", filters: dict={},
expected_objects_list=[], options:str=""):
bearer_token = ""
filters_result = ""
if bearer:
bearer_token = f"--bearer {bearer}"
if filters:
filters_result += "--filters "
logger.info(filters)
for k, v in filters.items():
filters_result += f"'{k} EQ {v}' "
object_cmd = (
f'{NEOFS_CLI_EXEC} --rpc-endpoint {NEOFS_ENDPOINT} --wallet {private_key} '
f'object search {keys} --cid {cid} {bearer_token} {filters_result} {options}'
)
logger.info(f"Cmd: {object_cmd}")
output = _cmd_run(object_cmd)
found_objects = re.findall(r'(\w{43,44})', output)
if expected_objects_list:
if sorted(found_objects) == sorted(expected_objects_list):
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} ",
f"is not equal to expected list '{expected_objects_list}'")
return found_objects
@keyword('Get Split objects')
def get_component_objects(private_key: str, cid: str, oid: str):
@ -227,36 +181,36 @@ def get_component_objects(private_key: str, cid: str, oid: str):
split_id = ""
for node in NEOFS_NETMAP:
try:
header_virtual = head_object(private_key, cid, oid, options=' --ttl 1',
parsed_header_virtual = neofs_verbs.head_object(private_key, cid, oid, options=' --ttl 1',
endpoint=node, is_raw=True)
if header_virtual:
parsed_header_virtual = parse_object_virtual_raw_header(header_virtual)
if 'Linking object' in parsed_header_virtual.keys():
return _collect_split_objects_from_header(private_key, cid, parsed_header_virtual)
if 'link' in parsed_header_virtual.keys():
return _collect_split_objects_from_header(private_key, cid, parsed_header_virtual)
elif 'Split ID' in parsed_header_virtual.keys():
logger.info(f"parsed_header_virtual: !@ {parsed_header_virtual}" )
split_id = parsed_header_virtual['Split ID']
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 = search_object(private_key, cid, None, None, None, None, '--phy')
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 = head_object(private_key, cid, targer_oid, is_raw=True)
if header_parsed['Split ID'] == split_id and 'Split ChildID' in header_parsed.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)
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 = head_object(private_key, cid, parsed_header['Linking object'], is_raw=True)
return header_link_parsed['Split ChildID']
header_link_parsed = neofs_verbs.head_object(private_key, cid, parsed_header['link'])
return header_link_parsed['header']['split']['children']
@keyword('Verify Split Chain')
@ -274,19 +228,18 @@ def verify_split_chain(wif: str, cid: str, oid: str):
logger.info("Collect Split objects information and verify chain of the objects.")
for node in NEOFS_NETMAP:
try:
header_virtual = head_object(wif, cid, oid, options=' --ttl 1',
endpoint=node, json_output=False, is_raw=True)
parsed_header_virtual = parse_object_virtual_raw_header(header_virtual)
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 'Last object' in parsed_header_virtual.keys():
header_last = head_object(wif, cid,
parsed_header_virtual['Last object'],
is_raw=True, json_output=False)
header_last_parsed = _get_raw_split_information(header_last)
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, final_verif_data)
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")
@ -302,41 +255,39 @@ def verify_split_chain(wif: str, cid: str, oid: str):
logger.info("Compare Split objects result information with Linking object.")
for node in NEOFS_NETMAP:
try:
header_virtual = head_object(wif, cid, oid, options=' --ttl 1',
endpoint=node, json_output=False, is_raw=True)
parsed_header_virtual = parse_object_virtual_raw_header(header_virtual)
if 'Linking object' in parsed_header_virtual.keys():
header_link = head_object(wif, cid,
parsed_header_virtual['Linking object'],
is_raw=True, json_output=False)
header_link_parsed = _get_raw_split_information(header_link)
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['ID List'][::-1]
reversed_list = final_verif_data['header']['split']['children'][::-1]
if header_link_parsed['Split ChildID'] == reversed_list:
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['Split ChildID'])}")
f"{', '.join(header_link_parsed['header']['split']['children'])}")
else:
raise Exception(f"Split objects list from Linking Object "
f"({', '.join(header_link_parsed['Split ChildID'])}) "
f"({', '.join(header_link_parsed['header']['split']['children'])}) "
f"is not equal to expected ({', '.join(reversed_list)})")
if int(header_link_parsed['PayloadLength']) == 0:
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['Type'] == 'regular':
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['Split ID'] == final_verif_data['Split ID']:
logger.info(f"Linking Object Split ID is equal to expected {final_verif_data['Split ID']}.")
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['Split ID']}) "
f"is not equal to expected ({final_verif_data['Split ID']})")
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}")
@ -351,100 +302,47 @@ def verify_split_chain(wif: str, cid: str, oid: str):
logger.info("Compare Split objects result information with Virtual object.")
header_virtual = head_object(wif, cid, oid, json_output=False)
header_virtual_parsed = _get_raw_split_information(header_virtual)
header_virtual_parsed = neofs_verbs.head_object(wif, cid, oid)
if int(header_virtual_parsed['PayloadLength']) == int(final_verif_data['PayloadLength']):
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['PayloadLength']}")
f"{header_virtual_parsed['header']['payloadLength']}")
else:
raise Exception(f"Split objects PayloadLength from Virtual Object "
f"({header_virtual_parsed['PayloadLength']}) is not equal "
f"to expected ({final_verif_data['PayloadLength']})")
f"({header_virtual_parsed['header']['payloadLength']}) is not equal "
f"to expected ({final_verif_data['payloadLength']})")
if header_link_parsed['Type'] == 'regular':
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 _get_raw_split_information(header):
result_header = dict()
# Header - Constant attributes
# ID
m = re.search(r'^ID: (\w+)', header)
if m is not None:
result_header['ID'] = m.group(1)
else:
raise Exception(f"no ID was parsed from object header: \t{header}")
# Type
m = re.search(r'Type:\s+(\w+)', header)
if m is not None:
result_header['Type'] = m.group(1)
else:
raise Exception(f"no Type was parsed from object header: \t{header}")
# PayloadLength
m = re.search(r'Size: (\d+)', header)
if m is not None:
result_header['PayloadLength'] = m.group(1)
else:
raise Exception(f"no PayloadLength was parsed from object header: \t{header}")
# Header - Optional attributes
# SplitID
m = re.search(r'Split ID:\s+([\w-]+)', header)
if m is not None:
result_header['Split ID'] = m.group(1)
# Split PreviousID
m = re.search(r'Split PreviousID:\s+(\w+)', header)
if m is not None:
result_header['Split PreviousID'] = m.group(1)
# Split ParentID
m = re.search(r'Split ParentID:\s+(\w+)', header)
if m is not None:
result_header['Split ParentID'] = m.group(1)
# Split ChildID list
found_objects = re.findall(r'Split ChildID:\s+(\w+)', header)
if found_objects:
result_header['Split ChildID'] = found_objects
logger.info(f"Result: {result_header}")
return result_header
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'])
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'])
final_verif_data['payloadLength'] = int(header_last_parsed['payloadLength'])
if header_last_parsed['Type'] != 'regular':
if header_last_parsed['objectType'] != 'REGULAR':
raise Exception("Object Type is not 'regular'.")
if 'Split ID' in final_verif_data.keys():
if final_verif_data['Split ID'] != header_last_parsed['Split ID']:
raise Exception(f"Object Split ID ({header_last_parsed['Split ID']}) is not expected ({final_verif_data['Split ID']}).")
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 ID'] = header_last_parsed['Split ID']
final_verif_data['split']['splitID'] = header_last_parsed['split']['splitID']
if 'ID List' in final_verif_data.keys():
final_verif_data['ID List'].append(header_last_parsed['ID'])
if 'children' in final_verif_data['split'].keys():
final_verif_data['split']['children'].append(header_last_parsed['split']['children'])
else:
final_verif_data['ID List'] = []
final_verif_data['ID List'].append(header_last_parsed['ID'])
final_verif_data['split']['children'] = []
final_verif_data['split']['children'].append(header_last_parsed['split']['children'])
if 'Split PreviousID' in header_last_parsed.keys():
header_virtual = head_object(wif, cid, header_last_parsed['Split PreviousID'], is_raw=True, json_output=False)
parsed_header_virtual = _get_raw_split_information(header_virtual)
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:
@ -455,9 +353,10 @@ def _verify_child_link(wif: str, cid: str, oid: str, header_last_parsed: dict, f
@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
object_cmd = (
f'{NEOFS_CLI_EXEC} --rpc-endpoint {NEOFS_ENDPOINT} --wallet {private_key} '
f'object head --cid {cid} --oid {oid_ts} --json --no-progress'
f'object head --cid {cid} --oid {oid_ts} --json'
)
logger.info(f"Cmd: {object_cmd}")
output = _cmd_run(object_cmd)
@ -466,13 +365,13 @@ def verify_head_tombstone(private_key: str, cid: str, oid_ts: str, oid: str, add
# Header verification
header_cid = full_headers["header"]["containerID"]["value"]
if (_json_cli_decode(header_cid) == cid):
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.")
header_owner = full_headers["header"]["ownerID"]["value"]
if (_json_cli_decode(header_owner) == addr):
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.")
@ -490,79 +389,18 @@ def verify_head_tombstone(private_key: str, cid: str, oid_ts: str, oid: str, add
raise Exception("Header Session Type is not expected.")
header_session_cid = full_headers["header"]["sessionToken"]["body"]["object"]["address"]["containerID"]["value"]
if (_json_cli_decode(header_session_cid) == cid):
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.")
header_session_oid = full_headers["header"]["sessionToken"]["body"]["object"]["address"]["objectID"]["value"]
if (_json_cli_decode(header_session_oid) == oid):
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.")
def _json_cli_decode(data: str):
return base58.b58encode(base64.b64decode(data)).decode("utf-8")
@keyword('Head object')
def head_object(private_key: str, cid: str, oid: str, bearer_token: str="",
options:str="", endpoint: str="", json_output: bool = True,
is_raw: bool = False):
cmd = (
f'{NEOFS_CLI_EXEC} --rpc-endpoint {endpoint if endpoint else NEOFS_ENDPOINT} '
f'--wallet {private_key} '
f'object head --cid {cid} --oid {oid} {options} '
f'{"--bearer " + bearer_token if bearer_token else ""} '
f'{"--json" if json_output else ""} '
f'{"--raw" if is_raw else ""}'
)
logger.info(f"cmd: {cmd}")
output = _cmd_run(cmd)
if json_output:
decoded = json.loads(output)
output = _decode_json_output(decoded)
return output
def _decode_json_output(data: dict):
'''
We get JSON output as an automatically decoded structure from
protobuf. Some fields are decoded with boilerplates and binary
values are Base64-encoded.
This function rearranges the structure and reencodes binary
data from Base64 to Base58.
Args:
data (dict): a dictionary which neofs-cli returns to reencode.
Returns:
dict: dictionary which contains data in a more organized form.
'''
try:
# reencoding binary IDs
data["objectID"] = _json_cli_decode(data["objectID"]["value"])
data["header"]["containerID"] = _json_cli_decode(data["header"]["containerID"]["value"])
data["header"]["ownerID"] = _json_cli_decode(data["header"]["ownerID"]["value"])
data["header"]["homomorphicHash"] = _json_cli_decode(data["header"]["homomorphicHash"]["sum"])
data["header"]["payloadHash"] = _json_cli_decode(data["header"]["payloadHash"]["sum"])
data["header"]["version"] = f"{data['header']['version']['major']}{data['header']['version']['minor']}"
# object attributes view normalization
ugly_attrs = data["header"]["attributes"]
data["header"]["attributes"] = {}
for attr in ugly_attrs:
data["header"]["attributes"][attr["key"]] = attr["value"]
except Exception as exc:
raise RuntimeError(f"failed to decode JSON output: {exc}") from exc
return data
@keyword('Get container attributes')
def get_container_attributes(private_key: str, cid: str, endpoint: str="", json_output: bool = False):
@ -577,28 +415,6 @@ def get_container_attributes(private_key: str, cid: str, endpoint: str="", json_
output = _cmd_run(container_cmd)
return output
# TODO: replace with JSON parser when https://github.com/nspcc-dev/neofs-node/issues/1233
# is done
@keyword('Parse Object Virtual Raw Header')
def parse_object_virtual_raw_header(header: str):
result_header = dict()
m = re.search(r'Split ID:\s+([\w-]+)', header)
if m != None:
if m.start() != m.end(): # e.g., if match found something
result_header['Split ID'] = m.group(1)
m = re.search(r'Linking object:\s+(\w+)', header)
if m != None:
if m.start() != m.end(): # e.g., if match found something
result_header['Linking object'] = m.group(1)
m = re.search(r'Last object:\s+(\w+)', header)
if m != None:
if m.start() != m.end(): # e.g., if match found something
result_header['Last object'] = m.group(1)
logger.info(f"Result: {result_header}")
@keyword('Decode Container Attributes Json')
def decode_container_attributes_json(header):
@ -619,22 +435,6 @@ def decode_container_attributes_json(header):
return result_header
@keyword('Delete object')
def delete_object(private_key: str, cid: str, oid: str, bearer: str="", options: str=""):
bearer_token = ""
if bearer:
bearer_token = f"--bearer {bearer}"
object_cmd = (
f'{NEOFS_CLI_EXEC} --rpc-endpoint {NEOFS_ENDPOINT} --wallet {private_key} '
f'object delete --cid {cid} --oid {oid} {bearer_token} {options}'
)
logger.info(f"Cmd: {object_cmd}")
output = _cmd_run(object_cmd)
tombstone = _parse_oid(output)
return tombstone
@keyword('Delete Container')
# TODO: make the error message about a non-found container more user-friendly https://github.com/nspcc-dev/neofs-contract/issues/121
@ -654,41 +454,6 @@ def get_file_hash(filename : str):
return file_hash
@keyword('Put object')
def put_object(private_key: str, path: str, cid: str, bearer: str="", user_headers: dict={},
endpoint: str="", options: str="" ):
if not endpoint:
endpoint = random.sample(NEOFS_NETMAP, 1)[0]
if bearer:
bearer = f"--bearer {bearer}"
putobject_cmd = (
f'{NEOFS_CLI_EXEC} --rpc-endpoint {endpoint} --wallet {private_key} object '
f'put --no-progress --file {path} --cid {cid} {bearer} {options} '
f'{"--attributes " + _dict_to_attrs(user_headers) if user_headers else ""}'
)
logger.info(f"cmd: {putobject_cmd}")
output = _cmd_run(putobject_cmd)
oid = _parse_oid(output)
return oid
def _dict_to_attrs(attrs: dict):
'''
This function takes dictionary of object attributes and converts them
into the string. The string is passed to `--attibutes` key of the
neofs-cli.
Args:
attrs (dict): object attirbutes in {"a": "b", "c": "d"} format.
Returns:
(str): string in "a=b,c=d" format.
'''
return reduce(lambda a,b: f"{a},{b}", map(lambda i: f"{i}={attrs[i]}", attrs))
@keyword('Get control endpoint with wif')
def get_control_endpoint_with_wif(endpoint_number: str = ''):
if endpoint_number == '':
@ -775,45 +540,6 @@ def find_in_nodes_Log(line: str, nodes_logs_time: dict):
return 1
@keyword('Get Range Hash')
def get_range_hash(private_key: str, cid: str, oid: str, bearer_token: str,
range_cut: str, options: str=""):
if bearer_token:
bearer_token = f"--bearer {bearer_token}"
object_cmd = (
f'{NEOFS_CLI_EXEC} --rpc-endpoint {NEOFS_ENDPOINT} --wallet {private_key} '
f'object hash --cid {cid} --oid {oid} --range {range_cut} '
f'{bearer_token} {options}'
)
logger.info(f"Cmd: {object_cmd}")
_cmd_run(object_cmd)
@keyword('Get object')
def get_object(private_key: str, cid: str, oid: str, bearer_token: str="",
write_object: str="", endpoint: str="", options: str="" ):
if not write_object:
write_object = str(uuid.uuid4())
file_path = f"{ASSETS_DIR}/{write_object}"
logger.info("Going to get the object")
if not endpoint:
endpoint = random.sample(NEOFS_NETMAP, 1)[0]
if bearer_token:
bearer_token = f"--bearer {bearer_token}"
object_cmd = (
f'{NEOFS_CLI_EXEC} --rpc-endpoint {endpoint} --wallet {private_key} '
f'object get --cid {cid} --oid {oid} --file {file_path} {bearer_token} '
f'{options}'
)
logger.info(f"Cmd: {object_cmd}")
_cmd_run(object_cmd)
return file_path
@ -1022,20 +748,10 @@ def _parse_cid(input_str: str):
def _search_object(node:str, private_key: str, cid:str, oid: str):
if oid:
oid_cmd = "--oid %s" % oid
Cmd = (
f'{NEOFS_CLI_EXEC} --rpc-endpoint {node} --wallet {private_key} --ttl 1 '
f'object search --root --cid {cid} {oid_cmd}'
f'object search --root --cid {cid} --oid {oid}'
)
output = _cmd_run(Cmd)
if re.search(fr'{oid}', output):
return oid
else:
logger.info("Object is not found.")
if re.search(r'local node is outside of object placement', output):
logger.info("Server is not presented in container.")
elif ( re.search(r'timed out after 30 seconds', output) or re.search(r'no route to host', output) or re.search(r'i/o timeout', output)):
logger.warn("Node is unavailable")
return output

View file

@ -0,0 +1,297 @@
#!/usr/bin/python3
'''
This module contains wrappers for NeoFS verbs executed via neofs-cli.
'''
import json
import os
import re
import random
import uuid
from functools import reduce
from common import NEOFS_ENDPOINT, ASSETS_DIR, NEOFS_NETMAP
from cli_helpers import _cmd_run
import json_transformers
from robot.api.deco import keyword
from robot.api import logger
ROBOT_AUTO_KEYWORDS = False
# path to neofs-cli executable
NEOFS_CLI_EXEC = os.getenv('NEOFS_CLI_EXEC', 'neofs-cli')
@keyword('Get object')
def get_object(wif: str, cid: str, oid: str, bearer_token: str="",
write_object: str="", endpoint: str="", options: str="" ):
'''
GET from NeoFS.
Args:
wif (str): WIF of the 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
write_object (optional, str): path to downloaded file, appends to `--file` key
endpoint (optional, str): NeoFS endpoint to send request to, appends to `--rpc-endpoint` key
options (optional, str): any options which `neofs-cli object get` accepts
Returns:
(str): path to downloaded file
'''
if not write_object:
write_object = str(uuid.uuid4())
file_path = f"{ASSETS_DIR}/{write_object}"
if not endpoint:
endpoint = random.sample(NEOFS_NETMAP, 1)[0]
cmd = (
f'{NEOFS_CLI_EXEC} --rpc-endpoint {endpoint} --wallet {wif} '
f'object get --cid {cid} --oid {oid} --file {file_path} '
f'{"--bearer " + bearer_token if bearer_token else ""} '
f'{options}'
)
_cmd_run(cmd)
return file_path
@keyword('Get Range Hash')
def get_range_hash(wif: 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
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
options (optional, str): any options which `neofs-cli object hash` accepts
Returns:
None
'''
cmd = (
f'{NEOFS_CLI_EXEC} --rpc-endpoint {NEOFS_ENDPOINT} --wallet {wif} '
f'object hash --cid {cid} --oid {oid} --range {range_cut} '
f'{"--bearer " + bearer_token if bearer_token else ""} '
f'{options}'
)
_cmd_run(cmd)
@keyword('Put object')
def put_object(wif: str, path: str, cid: str, bearer: str="", user_headers: dict={},
endpoint: str="", options: str="" ):
'''
PUT of given file.
Args:
wif (str): WIF of the 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
user_headers (optional, dict): Object attributes, append to `--attributes` key
endpoint(optional, str): NeoFS endpoint to send request to
options (optional, str): any options which `neofs-cli object put` accepts
Returns:
(str): ID of uploaded Object
'''
if not endpoint:
endpoint = random.sample(NEOFS_NETMAP, 1)[0]
cmd = (
f'{NEOFS_CLI_EXEC} --rpc-endpoint {endpoint} --wallet {wif} '
f'object put --file {path} --cid {cid} {options} '
f'{"--bearer " + bearer if bearer else ""} '
f'{"--attributes " + _dict_to_attrs(user_headers) if user_headers else ""}'
)
output = _cmd_run(cmd)
# splitting CLI output to lines and taking the penultimate line
id_str = output.strip().split('\n')[-2]
oid = id_str.split(':')[1]
return oid.strip()
@keyword('Delete object')
def delete_object(wif: 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
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
options (optional, str): any options which `neofs-cli object delete` accepts
Returns:
(str): Tombstone ID
'''
cmd = (
f'{NEOFS_CLI_EXEC} --rpc-endpoint {NEOFS_ENDPOINT} --wallet {wif} '
f'object delete --cid {cid} --oid {oid} {options}'
f'{"--bearer " + bearer if bearer else ""} '
)
output = _cmd_run(cmd)
id_str = output.split('\n')[1]
tombstone = id_str.split(':')[1]
return tombstone.strip()
@keyword('Get Range')
def get_range(wif: str, cid: str, oid: str, range_file: str, bearer: str,
range_cut: str, options:str=""):
'''
GETRANGE an Object.
Args:
wif (str): WIF of the 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
options (optional, str): any options which `neofs-cli object range` accepts
Returns:
None
'''
cmd = (
f'{NEOFS_CLI_EXEC} --rpc-endpoint {NEOFS_ENDPOINT} --wallet {wif} '
f'object range --cid {cid} --oid {oid} --range {range_cut} '
f'--file {ASSETS_DIR}/{range_file} {options}'
f'{"--bearer " + bearer if bearer else ""} '
)
_cmd_run(cmd)
@keyword('Search object')
def search_object(wif: str, cid: str, keys: str="", bearer: str="", filters: dict={},
expected_objects_list=[], options:str=""):
'''
GETRANGE an Object.
Args:
wif (str): WIF of the 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
'''
filters_result = ""
if filters:
filters_result += "--filters "
logger.info(filters)
for key, value in filters.items():
filters_result += f"'{key} EQ {value}' "
cmd = (
f'{NEOFS_CLI_EXEC} --rpc-endpoint {NEOFS_ENDPOINT} --wallet {wif} '
f'object search {keys} --cid {cid} {filters_result} {options}'
f'{"--bearer " + bearer if bearer else ""} '
)
output = _cmd_run(cmd)
found_objects = re.findall(r'(\w{43,44})', output)
if expected_objects_list:
if sorted(found_objects) == sorted(expected_objects_list):
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} ",
f"is not equal to expected list '{expected_objects_list}'")
return found_objects
@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):
'''
HEAD an Object.
Args:
wif (str): WIF of the 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
options (optional, str): any options which `neofs-cli object head` accepts
endpoint(optional, str): NeoFS endpoint to send request to
json_output(optional, bool): return reponse in JSON format or not; this flag
turns into `--json` key
is_raw(optional, bool): send "raw" request or not; this flag
turns into `--raw` key
Returns:
depending on the `json_output` parameter value, the function returns
(dict): HEAD response in JSON format
or
(str): HEAD response as a plain text
'''
cmd = (
f'{NEOFS_CLI_EXEC} --rpc-endpoint {endpoint if endpoint else NEOFS_ENDPOINT} '
f'--wallet {wif} '
f'object head --cid {cid} --oid {oid} {options} '
f'{"--bearer " + bearer_token if bearer_token else ""} '
f'{"--json" if json_output else ""} '
f'{"--raw" if is_raw else ""}'
)
output = _cmd_run(cmd)
if not json_output:
return output
decoded = ""
try:
decoded = json.loads(output)
except Exception as exc:
# If we failed to parse output as JSON, the cause might be
# the plain text string in the beginning of the output.
# Here we cut off first string and try to parse again.
logger.info(f"failed to parse output: {exc}")
logger.info("parsing output in another way")
fst_line_idx = output.find('\n')
decoded = json.loads(output[fst_line_idx:])
# If response is Complex Object header, it has `splitId` key
if 'splitId' in decoded.keys():
logger.info("decoding split header")
return json_transformers.decode_split_header(decoded)
# If response is Last or Linking Object header,
# it has `header` dictionary and non-null `split` dictionary
if 'split' in decoded['header'].keys():
if decoded['header']['split']:
logger.info("decoding linking object")
return json_transformers.decode_linking_object(decoded)
if decoded['header']['objectType'] == 'STORAGE_GROUP':
logger.info("decoding storage group")
return json_transformers.decode_storage_group(decoded)
logger.info("decoding simple header")
return json_transformers.decode_simple_header(decoded)
def _dict_to_attrs(attrs: dict):
'''
This function takes dictionary of object attributes and converts them
into the string. The string is passed to `--attibutes` key of the
neofs-cli.
Args:
attrs (dict): object attirbutes in {"a": "b", "c": "d"} format.
Returns:
(str): string in "a=b,c=d" format.
'''
return reduce(lambda a,b: f"{a},{b}", map(lambda i: f"{i}={attrs[i]}", attrs))

View file

@ -4,6 +4,7 @@ Variables eacl_object_filters.py
Library acl.py
Library neofs.py
Library neofs_verbs.py
Library Collections
Resource common_steps_acl_basic.robot
@ -91,7 +92,7 @@ Check eACL Deny and Allow All
Compose eACL Custom
[Arguments] ${CID} ${HEADER_DICT} ${MATCH_TYPE} ${FILTER} ${ACCESS} ${ROLE}
${filter_value} = Get From dictionary ${HEADER_DICT}[header] ${EACL_OBJ_FILTERS}[${FILTER}]
${filter_value} = Get From dictionary ${HEADER_DICT} ${EACL_OBJ_FILTERS}[${FILTER}]
${filters} = Set Variable obj:${FILTER}${MATCH_TYPE}${filter_value}
${rule_get}= Set Variable ${ACCESS} get ${filters} ${ROLE}
@ -112,8 +113,12 @@ Object Header Decoded
[Arguments] ${USER_KEY} ${CID} ${OID}
&{HEADER} = Head Object ${USER_KEY} ${CID} ${OID}
# FIXME
# 'objectID' key repositioning in dictionary for the calling keyword might
# work uniformly with any key from 'header'
Set To Dictionary ${HEADER}[header] objectID ${HEADER}[objectID]
[Return] &{HEADER}
[Return] &{HEADER}[header]
Check eACL Filters with MatchType String Equal
[Arguments] ${FILTER}

View file

@ -2,6 +2,7 @@
Variables common.py
Library neofs.py
Library neofs_verbs.py
Library payment_neogo.py
Resource common_steps_acl_basic.robot

View file

@ -2,6 +2,7 @@
Variables common.py
Library neofs.py
Library neofs_verbs.py
Library payment_neogo.py
Library Collections
@ -13,20 +14,20 @@ Resource setup_teardown.robot
*** Test cases ***
Basic ACL Operations for Private Container
[Documentation] Testcase to validate NeoFS operations with ACL for Private Container.
[Tags] ACL NeoFS NeoCLI
[Tags] ACL
[Timeout] 20 min
[Setup] Setup
${WALLET} ${ADDR} ${USER_KEY} = Prepare Wallet And Deposit
${WALLET_OTH} ${ADDR_OTH} ${OTHER_KEY} = Prepare Wallet And Deposit
${_} ${_} ${USER_KEY} = Prepare Wallet And Deposit
${_} ${_} ${OTHER_KEY} = Prepare Wallet And Deposit
${PRIV_CID} = Create Private Container ${USER_KEY}
${FILE_S} ${FILE_S_HASH} = Generate file ${SIMPLE_OBJ_SIZE}
${FILE_S} ${_} = Generate file ${SIMPLE_OBJ_SIZE}
Check Private Container Simple ${USER_KEY} ${FILE_S} ${PRIV_CID} ${OTHER_KEY}
${PRIV_CID} = Create Private Container ${USER_KEY}
${FILE_S} ${FILE_S_HASH} = Generate file ${COMPLEX_OBJ_SIZE}
${FILE_S} ${_} = Generate file ${COMPLEX_OBJ_SIZE}
Check Private Container Complex ${USER_KEY} ${FILE_S} ${PRIV_CID} ${OTHER_KEY}
[Teardown] Teardown acl_basic_private_container_storagegroup
@ -38,7 +39,7 @@ Check Private Container
[Arguments] ${RUN_TYPE} ${USER_KEY} ${FILE_S} ${PRIV_CID} ${OTHER_KEY}
# Put target object to use in storage groups
${S_OID_USER} = Put object ${USER_KEY} ${FILE_S} ${PRIV_CID} ${EMPTY} ${EMPTY}
${S_OID_USER} = Put object ${USER_KEY} ${FILE_S} ${PRIV_CID}
# Storage group Operations (Put, List, Get, Delete) with different Keys

View file

@ -2,6 +2,7 @@
Variables common.py
Library neofs.py
Library neofs_verbs.py
Library payment_neogo.py
Resource common_steps_acl_basic.robot
@ -12,20 +13,20 @@ Resource setup_teardown.robot
*** Test cases ***
Basic ACL Operations for Public Container
[Documentation] Testcase to validate NeoFS operations with ACL for Public Container.
[Tags] ACL NeoFS NeoCLI
[Tags] ACL
[Timeout] 20 min
[Setup] Setup
${WALLET} ${ADDR} ${USER_KEY} = Prepare Wallet And Deposit
${WALLET_OTH} ${ADDR_OTH} ${OTHER_KEY} = Prepare Wallet And Deposit
${_} ${_} ${USER_KEY} = Prepare Wallet And Deposit
${_} ${_} ${OTHER_KEY} = Prepare Wallet And Deposit
${PUBLIC_CID} = Create Public Container ${USER_KEY}
${FILE_S} ${FILE_S_HASH} = Generate file ${SIMPLE_OBJ_SIZE}
${FILE_S} ${_} = Generate file ${SIMPLE_OBJ_SIZE}
Check Public Container ${USER_KEY} ${FILE_S} ${PUBLIC_CID} ${OTHER_KEY}
${PUBLIC_CID} = Create Public Container ${USER_KEY}
${FILE_S} ${FILE_S_HASH} = Generate file ${COMPLEX_OBJ_SIZE}
${FILE_S} ${_} = Generate file ${COMPLEX_OBJ_SIZE}
Check Public Container ${USER_KEY} ${FILE_S} ${PUBLIC_CID} ${OTHER_KEY}
[Teardown] Teardown acl_basic_public_container
@ -37,10 +38,10 @@ Check Public Container
[Arguments] ${USER_KEY} ${FILE_S} ${PUBLIC_CID} ${OTHER_KEY}
# Put
${S_OID_USER} = Put Object ${USER_KEY} ${FILE_S} ${PUBLIC_CID} ${EMPTY} ${EMPTY}
${S_OID_OTHER} = Put Object ${OTHER_KEY} ${FILE_S} ${PUBLIC_CID} ${EMPTY} ${EMPTY}
${S_OID_SYS_IR} = Put Object ${NEOFS_IR_WIF} ${FILE_S} ${PUBLIC_CID} ${EMPTY} ${EMPTY}
${S_OID_SYS_SN} = Put Object ${NEOFS_SN_WIF} ${FILE_S} ${PUBLIC_CID} ${EMPTY} ${EMPTY}
${S_OID_USER} = Put Object ${USER_KEY} ${FILE_S} ${PUBLIC_CID}
${S_OID_OTHER} = Put Object ${OTHER_KEY} ${FILE_S} ${PUBLIC_CID}
${S_OID_SYS_IR} = Put Object ${NEOFS_IR_WIF} ${FILE_S} ${PUBLIC_CID}
${S_OID_SYS_SN} = Put Object ${NEOFS_SN_WIF} ${FILE_S} ${PUBLIC_CID}
# Get
Get Object ${USER_KEY} ${PUBLIC_CID} ${S_OID_USER} ${EMPTY} s_file_read
@ -65,32 +66,32 @@ Check Public Container
# Search
@{S_OBJ_PRIV} = Create List ${S_OID_USER} ${S_OID_OTHER} ${S_OID_SYS_SN} ${S_OID_SYS_IR}
Search object ${USER_KEY} ${PUBLIC_CID} --root ${EMPTY} ${EMPTY} ${S_OBJ_PRIV}
Search object ${OTHER_KEY} ${PUBLIC_CID} --root ${EMPTY} ${EMPTY} ${S_OBJ_PRIV}
Search object ${NEOFS_IR_WIF} ${PUBLIC_CID} --root ${EMPTY} ${EMPTY} ${S_OBJ_PRIV}
Search object ${NEOFS_SN_WIF} ${PUBLIC_CID} --root ${EMPTY} ${EMPTY} ${S_OBJ_PRIV}
Search object ${USER_KEY} ${PUBLIC_CID} keys=--root expected_objects_list=${S_OBJ_PRIV}
Search object ${OTHER_KEY} ${PUBLIC_CID} keys=--root expected_objects_list=${S_OBJ_PRIV}
Search object ${NEOFS_IR_WIF} ${PUBLIC_CID} keys=--root expected_objects_list=${S_OBJ_PRIV}
Search object ${NEOFS_SN_WIF} ${PUBLIC_CID} keys=--root expected_objects_list=${S_OBJ_PRIV}
# Head
Head Object ${USER_KEY} ${PUBLIC_CID} ${S_OID_USER} ${EMPTY} ${EMPTY}
Head Object ${OTHER_KEY} ${PUBLIC_CID} ${S_OID_USER} ${EMPTY} ${EMPTY}
Head Object ${NEOFS_IR_WIF} ${PUBLIC_CID} ${S_OID_USER} ${EMPTY} ${EMPTY}
Head Object ${NEOFS_SN_WIF} ${PUBLIC_CID} ${S_OID_USER} ${EMPTY} ${EMPTY}
Head Object ${USER_KEY} ${PUBLIC_CID} ${S_OID_USER}
Head Object ${OTHER_KEY} ${PUBLIC_CID} ${S_OID_USER}
Head Object ${NEOFS_IR_WIF} ${PUBLIC_CID} ${S_OID_USER}
Head Object ${NEOFS_SN_WIF} ${PUBLIC_CID} ${S_OID_USER}
Head Object ${USER_KEY} ${PUBLIC_CID} ${S_OID_OTHER} ${EMPTY} ${EMPTY}
Head Object ${OTHER_KEY} ${PUBLIC_CID} ${S_OID_OTHER} ${EMPTY} ${EMPTY}
Head Object ${NEOFS_IR_WIF} ${PUBLIC_CID} ${S_OID_OTHER} ${EMPTY} ${EMPTY}
Head Object ${NEOFS_SN_WIF} ${PUBLIC_CID} ${S_OID_OTHER} ${EMPTY} ${EMPTY}
Head Object ${USER_KEY} ${PUBLIC_CID} ${S_OID_OTHER}
Head Object ${OTHER_KEY} ${PUBLIC_CID} ${S_OID_OTHER}
Head Object ${NEOFS_IR_WIF} ${PUBLIC_CID} ${S_OID_OTHER}
Head Object ${NEOFS_SN_WIF} ${PUBLIC_CID} ${S_OID_OTHER}
Head Object ${USER_KEY} ${PUBLIC_CID} ${S_OID_SYS_SN} ${EMPTY} ${EMPTY}
Head Object ${OTHER_KEY} ${PUBLIC_CID} ${S_OID_SYS_SN} ${EMPTY} ${EMPTY}
Head Object ${NEOFS_IR_WIF} ${PUBLIC_CID} ${S_OID_SYS_SN} ${EMPTY} ${EMPTY}
Head Object ${NEOFS_SN_WIF} ${PUBLIC_CID} ${S_OID_SYS_SN} ${EMPTY} ${EMPTY}
Head Object ${USER_KEY} ${PUBLIC_CID} ${S_OID_SYS_SN}
Head Object ${OTHER_KEY} ${PUBLIC_CID} ${S_OID_SYS_SN}
Head Object ${NEOFS_IR_WIF} ${PUBLIC_CID} ${S_OID_SYS_SN}
Head Object ${NEOFS_SN_WIF} ${PUBLIC_CID} ${S_OID_SYS_SN}
# Delete
Delete object ${USER_KEY} ${PUBLIC_CID} ${S_OID_SYS_IR} ${EMPTY}
Delete Object ${OTHER_KEY} ${PUBLIC_CID} ${S_OID_SYS_SN} ${EMPTY}
Delete object ${USER_KEY} ${PUBLIC_CID} ${S_OID_SYS_IR}
Delete Object ${OTHER_KEY} ${PUBLIC_CID} ${S_OID_SYS_SN}
Run Keyword And Expect Error *
... Delete object ${NEOFS_IR_WIF} ${PUBLIC_CID} ${S_OID_USER} ${EMPTY}
... Delete object ${NEOFS_IR_WIF} ${PUBLIC_CID} ${S_OID_USER}
Run Keyword And Expect Error *
... Delete object ${NEOFS_SN_WIF} ${PUBLIC_CID} ${S_OID_OTHER} ${EMPTY}
... Delete object ${NEOFS_SN_WIF} ${PUBLIC_CID} ${S_OID_OTHER}

View file

@ -2,6 +2,7 @@
Variables common.py
Library neofs.py
Library neofs_verbs.py
Library payment_neogo.py
Library contract_keywords.py
@ -13,20 +14,20 @@ Resource setup_teardown.robot
*** Test cases ***
Basic ACL Operations for Public Container
[Documentation] Testcase to validate NeoFS operations with ACL for Public Container.
[Tags] ACL NeoFS NeoCLI
[Tags] ACL
[Timeout] 20 min
[Setup] Setup
${WALLET} ${ADDR} ${USER_KEY} = Prepare Wallet And Deposit
${WALLET_OTH} ${ADDR_OTH} ${OTHER_KEY} = Prepare Wallet And Deposit
${_} ${_} ${USER_KEY} = Prepare Wallet And Deposit
${_} ${_} ${OTHER_KEY} = Prepare Wallet And Deposit
${PUBLIC_CID} = Create Public Container ${USER_KEY}
${FILE_S} ${FILE_S_HASH} = Generate file ${SIMPLE_OBJ_SIZE}
${FILE_S} ${_} = Generate file ${SIMPLE_OBJ_SIZE}
Check Public Container Simple ${USER_KEY} ${FILE_S} ${PUBLIC_CID} ${OTHER_KEY}
${PUBLIC_CID} = Create Public Container ${USER_KEY}
${FILE_S} ${FILE_S_HASH} = Generate file ${COMPLEX_OBJ_SIZE}
${FILE_S} ${_} = Generate file ${COMPLEX_OBJ_SIZE}
Check Public Container Complex ${USER_KEY} ${FILE_S} ${PUBLIC_CID} ${OTHER_KEY}
[Teardown] Teardown acl_basic_public_container_storagegroup
@ -41,7 +42,7 @@ Check Public Container
Log Storage group Operations for each Role keys
# Put target object to use in storage groups
${S_OID} = Put object ${USER_KEY} ${FILE_S} ${PUBLIC_CID} ${EMPTY} ${EMPTY}
${S_OID} = Put object ${USER_KEY} ${FILE_S} ${PUBLIC_CID}
@{ROLES_KEYS_PASS} = Create List ${USER_KEY} ${OTHER_KEY}
@{ROLES_KEYS_SYS} = Create List ${NEOFS_IR_WIF} ${NEOFS_SN_WIF}

View file

@ -2,6 +2,7 @@
Variables common.py
Library neofs.py
Library neofs_verbs.py
Library payment_neogo.py
Resource common_steps_acl_basic.robot
@ -12,20 +13,20 @@ Resource setup_teardown.robot
*** Test cases ***
Basic ACL Operations for Read-Only Container
[Documentation] Testcase to validate NeoFS operations with ACL for Read-Only Container.
[Tags] ACL NeoFS NeoCLI
[Tags] ACL
[Timeout] 20 min
[Setup] Setup
${WALLET} ${ADDR} ${USER_KEY} = Prepare Wallet And Deposit
${WALLET_OTH} ${ADDR_OTH} ${OTHER_KEY} = Prepare Wallet And Deposit
${_} ${_} ${USER_KEY} = Prepare Wallet And Deposit
${_} ${_} ${OTHER_KEY} = Prepare Wallet And Deposit
${READONLY_CID} = Create Read-Only Container ${USER_KEY}
${FILE_S} ${FILE_S_HASH} = Generate file ${SIMPLE_OBJ_SIZE}
${FILE_S} ${_} = Generate file ${SIMPLE_OBJ_SIZE}
Check Read-Only Container Simple ${USER_KEY} ${FILE_S} ${READONLY_CID} ${OTHER_KEY}
${READONLY_CID} = Create Read-Only Container ${USER_KEY}
${FILE_S} ${FILE_S_HASH} = Generate file ${COMPLEX_OBJ_SIZE}
${FILE_S} ${_} = Generate file ${COMPLEX_OBJ_SIZE}
Check Read-Only Container Complex ${USER_KEY} ${FILE_S} ${READONLY_CID} ${OTHER_KEY}
[Teardown] Teardown acl_basic_readonly_container
@ -38,11 +39,11 @@ Check Read-Only Container
[Arguments] ${RUN_TYPE} ${USER_KEY} ${FILE_S} ${READONLY_CID} ${OTHER_KEY}
# Put
${S_OID_USER} = Put Object ${USER_KEY} ${FILE_S} ${READONLY_CID} ${EMPTY} ${EMPTY}
${S_OID_USER} = Put Object ${USER_KEY} ${FILE_S} ${READONLY_CID}
Run Keyword And Expect Error *
... Put object ${OTHER_KEY} ${FILE_S} ${READONLY_CID} ${EMPTY} ${EMPTY}
${S_OID_SYS_IR} = Put Object ${NEOFS_IR_WIF} ${FILE_S} ${READONLY_CID} ${EMPTY} ${EMPTY}
${S_OID_SYS_SN} = Put object ${NEOFS_SN_WIF} ${FILE_S} ${READONLY_CID} ${EMPTY} ${EMPTY}
... Put object ${OTHER_KEY} ${FILE_S} ${READONLY_CID}
${S_OID_SYS_IR} = Put Object ${NEOFS_IR_WIF} ${FILE_S} ${READONLY_CID}
${S_OID_SYS_SN} = Put object ${NEOFS_SN_WIF} ${FILE_S} ${READONLY_CID}
# Storage group Operations (Put, List, Get, Delete)
@ -94,23 +95,23 @@ Check Read-Only Container
# Search
@{S_OBJ_RO} = Create List ${S_OID_USER} ${S_OID_SYS_SN} ${S_OID_SYS_IR}
Search Object ${USER_KEY} ${READONLY_CID} --root ${EMPTY} ${EMPTY} ${S_OBJ_RO}
Search Object ${OTHER_KEY} ${READONLY_CID} --root ${EMPTY} ${EMPTY} ${S_OBJ_RO}
Search Object ${NEOFS_IR_WIF} ${READONLY_CID} --root ${EMPTY} ${EMPTY} ${S_OBJ_RO}
Search Object ${NEOFS_SN_WIF} ${READONLY_CID} --root ${EMPTY} ${EMPTY} ${S_OBJ_RO}
Search Object ${USER_KEY} ${READONLY_CID} keys=--root expected_objects_list=${S_OBJ_RO}
Search Object ${OTHER_KEY} ${READONLY_CID} keys=--root expected_objects_list=${S_OBJ_RO}
Search Object ${NEOFS_IR_WIF} ${READONLY_CID} keys=--root expected_objects_list=${S_OBJ_RO}
Search Object ${NEOFS_SN_WIF} ${READONLY_CID} keys=--root expected_objects_list=${S_OBJ_RO}
# Head
Head Object ${USER_KEY} ${READONLY_CID} ${S_OID_USER} ${EMPTY} ${EMPTY}
Head Object ${OTHER_KEY} ${READONLY_CID} ${S_OID_USER} ${EMPTY} ${EMPTY}
Head Object ${NEOFS_IR_WIF} ${READONLY_CID} ${S_OID_USER} ${EMPTY} ${EMPTY}
Head Object ${NEOFS_SN_WIF} ${READONLY_CID} ${S_OID_USER} ${EMPTY} ${EMPTY}
Head Object ${USER_KEY} ${READONLY_CID} ${S_OID_USER}
Head Object ${OTHER_KEY} ${READONLY_CID} ${S_OID_USER}
Head Object ${NEOFS_IR_WIF} ${READONLY_CID} ${S_OID_USER}
Head Object ${NEOFS_SN_WIF} ${READONLY_CID} ${S_OID_USER}
# Delete
Run Keyword And Expect Error *
... Delete object ${OTHER_KEY} ${READONLY_CID} ${S_OID_USER} ${EMPTY}
... Delete object ${OTHER_KEY} ${READONLY_CID} ${S_OID_USER}
Run Keyword And Expect Error *
... Delete object ${NEOFS_IR_WIF} ${READONLY_CID} ${S_OID_USER} ${EMPTY}
... Delete object ${NEOFS_IR_WIF} ${READONLY_CID} ${S_OID_USER}
Run Keyword And Expect Error *
... Delete object ${NEOFS_SN_WIF} ${READONLY_CID} ${S_OID_USER} ${EMPTY}
Delete Object ${USER_KEY} ${READONLY_CID} ${S_OID_USER} ${EMPTY}
... Delete object ${NEOFS_SN_WIF} ${READONLY_CID} ${S_OID_USER}
Delete Object ${USER_KEY} ${READONLY_CID} ${S_OID_USER}

View file

@ -2,6 +2,7 @@
Variables common.py
Library neofs.py
Library neofs_verbs.py
Library payment_neogo.py
Resource common_steps_acl_basic.robot
@ -12,20 +13,20 @@ Resource setup_teardown.robot
*** Test cases ***
Basic ACL Operations for Read-Only Container
[Documentation] Testcase to validate NeoFS operations with ACL for Read-Only Container.
[Tags] ACL NeoFS NeoCLI
[Tags] ACL
[Timeout] 20 min
[Setup] Setup
${WALLET} ${ADDR} ${USER_KEY} = Prepare Wallet And Deposit
${WALLET_OTH} ${ADDR_OTH} ${OTHER_KEY} = Prepare Wallet And Deposit
${_} ${_} ${USER_KEY} = Prepare Wallet And Deposit
${_} ${_} ${OTHER_KEY} = Prepare Wallet And Deposit
${READONLY_CID} = Create Read-Only Container ${USER_KEY}
${FILE_S} ${FILE_S_HASH} = Generate file ${SIMPLE_OBJ_SIZE}
${FILE_S} ${_} = Generate file ${SIMPLE_OBJ_SIZE}
Check Read-Only Container Simple ${USER_KEY} ${FILE_S} ${READONLY_CID} ${OTHER_KEY}
${READONLY_CID} = Create Read-Only Container ${USER_KEY}
${FILE_S} ${FILE_S_HASH} = Generate file ${COMPLEX_OBJ_SIZE}
${FILE_S} ${_} = Generate file ${COMPLEX_OBJ_SIZE}
Check Read-Only Container Complex ${USER_KEY} ${FILE_S} ${READONLY_CID} ${OTHER_KEY}
@ -39,7 +40,7 @@ Check Read-Only Container
[Arguments] ${RUN_TYPE} ${USER_KEY} ${FILE_S} ${READONLY_CID} ${OTHER_KEY}
# Put target object to use in storage groups
${S_OID_USER} = Put object ${USER_KEY} ${FILE_S} ${READONLY_CID} ${EMPTY} ${EMPTY}
${S_OID_USER} = Put object ${USER_KEY} ${FILE_S} ${READONLY_CID}
# Storage group Operations (Put, List, Get, Delete) for Read-only container

View file

@ -3,6 +3,7 @@ Variables common.py
Library Collections
Library neofs.py
Library neofs_verbs.py
Library acl.py
Library payment_neogo.py

View file

@ -4,6 +4,7 @@ Variables common.py
Library Collections
Library acl.py
Library neofs.py
Library neofs_verbs.py
Library payment_neogo.py
Resource eacl_tables.robot
@ -15,13 +16,13 @@ Resource setup_teardown.robot
*** Test cases ***
BearerToken Operations
[Documentation] Testcase to validate NeoFS operations with BearerToken.
[Tags] ACL NeoFS NeoCLI BearerToken
[Tags] ACL BearerToken
[Timeout] 20 min
[Setup] Setup
${WALLET} ${ADDR} ${USER_KEY} = Prepare Wallet And Deposit
${_} ${_} ${USER_KEY} = Prepare Wallet And Deposit
Log Check Bearer token with simple object
${FILE_S} = Generate file ${SIMPLE_OBJ_SIZE}
Check eACL Deny and Allow All Bearer Simple ${USER_KEY} ${FILE_S}
@ -39,10 +40,10 @@ BearerToken Operations
Check eACL Deny and Allow All Bearer
[Arguments] ${RUN_TYPE} ${USER_KEY} ${FILE_S}
${CID} = Create Container Public ${USER_KEY}
${S_OID_USER} = Put object ${USER_KEY} ${FILE_S} ${CID} ${EMPTY} ${FILE_USR_HEADER}
Prepare eACL Role rules ${CID}
${S_OID_USER} = Put object ${USER_KEY} ${FILE_S} ${CID}
Prepare eACL Role rules ${CID}
# Storage group Operations (Put, List, Get, Delete)

View file

@ -4,6 +4,7 @@ Variables common.py
Library Collections
Library acl.py
Library neofs.py
Library neofs_verbs.py
Library payment_neogo.py
Resource eacl_tables.robot
@ -59,7 +60,7 @@ Check Bearer Сompound Get
${CID} = Create Container Public ${USER_KEY}
Prepare eACL Role rules ${CID}
${S_OID_USER} = Put object ${USER_KEY} ${FILE_S} ${CID} user_headers=${USER_HEADER}
@{S_OBJ_H} = Create List ${S_OID_USER}
@{S_OBJ_H} = Create List ${S_OID_USER}
${S_OID_USER} = Put object ${USER_KEY} ${FILE_S} ${CID} user_headers=${USER_HEADER}
Put object ${KEY} ${FILE_S} ${CID} user_headers=${ANOTHER_HEADER}

View file

@ -3,6 +3,7 @@ Variables common.py
Library Collections
Library neofs.py
Library neofs_verbs.py
Library acl.py
Library payment_neogo.py
@ -50,7 +51,7 @@ Check eACL Deny and Allow All Bearer Filter OID Equal
${S_OID_USER} = Put object ${USER_KEY} ${FILE_S} ${CID} user_headers=${USER_HEADER}
${S_OID_USER_2} = Put object ${USER_KEY} ${FILE_S} ${CID}
${D_OID_USER} = Put object ${USER_KEY} ${FILE_S} ${CID} user_headers=${USER_HEADER_DEL}
@{S_OBJ_H} = Create List ${S_OID_USER}
@{S_OBJ_H} = Create List ${S_OID_USER}
Put object ${USER_KEY} ${FILE_S} ${CID} user_headers=${ANOTHER_HEADER}
Get object ${USER_KEY} ${CID} ${S_OID_USER} ${EMPTY} local_file_eacl

View file

@ -3,6 +3,7 @@ Variables common.py
Library Collections
Library neofs.py
Library neofs_verbs.py
Library acl.py
Library payment_neogo.py
@ -47,7 +48,7 @@ Check eACL Deny and Allow All Bearer Filter OID NotEqual
${S_OID_USER} = Put object ${USER_KEY} ${FILE_S} ${CID} user_headers=${USER_HEADER}
${S_OID_USER_2} = Put object ${USER_KEY} ${FILE_S} ${CID}
${D_OID_USER} = Put object ${USER_KEY} ${FILE_S} ${CID}
@{S_OBJ_H} = Create List ${S_OID_USER}
@{S_OBJ_H} = Create List ${S_OID_USER}
Put object ${USER_KEY} ${FILE_S} ${CID}
Get object ${USER_KEY} ${CID} ${S_OID_USER} ${EMPTY} local_file_eacl

View file

@ -4,6 +4,7 @@ Variables common.py
Library Collections
Library acl.py
Library neofs.py
Library neofs_verbs.py
Library payment_neogo.py
Resource eacl_tables.robot
@ -45,7 +46,7 @@ Check eACL Deny and Allow All Bearer Filter UserHeader Equal
${S_OID_USER} = Put object ${USER_KEY} ${FILE_S} ${CID} user_headers=${USER_HEADER}
${S_OID_USER_2} = Put object ${USER_KEY} ${FILE_S} ${CID}
${D_OID_USER} = Put object ${USER_KEY} ${FILE_S} ${CID} user_headers=${USER_HEADER_DEL}
@{S_OBJ_H} = Create List ${S_OID_USER}
@{S_OBJ_H} = Create List ${S_OID_USER}
Put object ${USER_KEY} ${FILE_S} ${CID} user_headers=${ANOTHER_HEADER}
Get object ${USER_KEY} ${CID} ${S_OID_USER} ${EMPTY} local_file_eacl

View file

@ -3,6 +3,7 @@ Variables common.py
Library Collections
Library neofs.py
Library neofs_verbs.py
Library acl.py
Library payment_neogo.py
@ -46,7 +47,7 @@ Check eACL Deny and Allow All Bearer Filter UserHeader NotEqual
${S_OID_USER} = Put object ${USER_KEY} ${FILE_S} ${CID} user_headers=${ANOTHER_HEADER}
${S_OID_USER_2} = Put object ${USER_KEY} ${FILE_S} ${CID} user_headers=${USER_HEADER}
${D_OID_USER} = Put object ${USER_KEY} ${FILE_S} ${CID} user_headers=${USER_HEADER_DEL}
@{S_OBJ_H} = Create List ${S_OID_USER_2}
@{S_OBJ_H} = Create List ${S_OID_USER_2}
Put object ${USER_KEY} ${FILE_S} ${CID}
Get object ${USER_KEY} ${CID} ${S_OID_USER} ${EMPTY} local_file_eacl

View file

@ -3,6 +3,7 @@ Variables common.py
Library Collections
Library neofs.py
Library neofs_verbs.py
Library acl.py
Library payment_neogo.py

View file

@ -3,6 +3,7 @@ Variables common.py
Library Collections
Library neofs.py
Library neofs_verbs.py
Library acl.py
Library payment_neogo.py

View file

@ -4,6 +4,7 @@ Variables common.py
Library Collections
Library acl.py
Library neofs.py
Library neofs_verbs.py
Library payment_neogo.py
Resource eacl_tables.robot
@ -48,7 +49,7 @@ Check eACL Deny and Allow All Bearer Filter Requst Equal
${S_OID_USER} = Put object ${USER_KEY} ${FILE_S} ${CID} user_headers=${USER_HEADER}
${S_OID_USER_2} = Put object ${USER_KEY} ${FILE_S} ${CID}
${D_OID_USER} = Put object ${USER_KEY} ${FILE_S} ${CID} user_headers=${USER_HEADER_DEL}
@{S_OBJ_H} = Create List ${S_OID_USER}
@{S_OBJ_H} = Create List ${S_OID_USER}
Put object ${USER_KEY} ${FILE_S} ${CID}
Get object ${USER_KEY} ${CID} ${S_OID_USER} ${EMPTY} local_file_eacl
@ -71,7 +72,7 @@ Check eACL Deny and Allow All Bearer Filter Requst Equal
${rule6}= Create Dictionary Operation=GETRANGE Access=ALLOW Role=USER Filters=${filters}
${rule7}= Create Dictionary Operation=GETRANGEHASH Access=ALLOW Role=USER Filters=${filters}
${eACL_gen}= Create List ${rule1} ${rule2} ${rule3} ${rule4} ${rule5} ${rule6} ${rule7}
${EACL_TOKEN} = Form BearerToken File ${USER_KEY} ${CID} ${eACL_gen}
Run Keyword And Expect Error ${EACL_ERROR_MSG}

View file

@ -4,6 +4,7 @@ Variables common.py
Library Collections
Library acl.py
Library neofs.py
Library neofs_verbs.py
Library payment_neogo.py
Resource eacl_tables.robot
@ -46,7 +47,7 @@ Check eACL Deny and Allow All Bearer Filter Requst NotEqual
${S_OID_USER} = Put object ${USER_KEY} ${FILE_S} ${CID} user_headers=${USER_HEADER}
${S_OID_USER_2} = Put object ${USER_KEY} ${FILE_S} ${CID}
${D_OID_USER} = Put object ${USER_KEY} ${FILE_S} ${CID} user_headers=${USER_HEADER_DEL}
@{S_OBJ_H} = Create List ${S_OID_USER}
@{S_OBJ_H} = Create List ${S_OID_USER}
Put object ${USER_KEY} ${FILE_S} ${CID} user_headers=${ANOTHER_USER_HEADER}
Get object ${USER_KEY} ${CID} ${S_OID_USER} ${EMPTY} local_file_eacl

View file

@ -1,10 +1,8 @@
*** Settings ***
Variables common.py
Library Collections
Library neofs.py
Library payment_neogo.py
Library acl.py
Resource common_steps_acl_extended.robot
Resource payment_operations.robot
@ -19,7 +17,7 @@ Extended ACL Operations
[Setup] Setup
${WALLET} ${ADDR} ${USER_KEY} = Prepare Wallet And Deposit
${WALLET} ${ADDR} ${USER_KEY} = Prepare Wallet And Deposit
${WALLET_OTH} ${ADDR_OTH} ${OTHER_KEY} = Prepare Wallet And Deposit
Log Check extended ACL with simple object
@ -37,4 +35,4 @@ Extended ACL Operations
Check eACL Deny and Allow All Other
[Arguments] ${USER_KEY} ${OTHER_KEY}
Check eACL Deny and Allow All ${OTHER_KEY} ${EACL_DENY_ALL_OTHERS} ${EACL_ALLOW_ALL_OTHERS} ${USER_KEY}
Check eACL Deny and Allow All ${OTHER_KEY} ${EACL_DENY_ALL_OTHERS} ${EACL_ALLOW_ALL_OTHERS} ${USER_KEY}

View file

@ -4,6 +4,7 @@ Variables common.py
Library Collections
Library acl.py
Library neofs.py
Library neofs_verbs.py
Library payment_neogo.py
Resource common_steps_acl_extended.robot

View file

@ -3,6 +3,7 @@ Variables common.py
Library Collections
Library neofs.py
Library neofs_verbs.py
Library payment_neogo.py
Library acl.py
@ -19,7 +20,7 @@ Resource eacl_tables.robot
*** Test cases ***
Extended ACL Operations
[Documentation] Testcase to validate NeoFS operations with extended ACL.
[Tags] ACL eACL NeoFS NeoCLI
[Tags] ACL eACL
[Timeout] 20 min
[Setup] Setup

View file

@ -14,7 +14,7 @@ Resource eacl_tables.robot
*** Test cases ***
Extended ACL Operations
[Documentation] Testcase to validate NeoFS operations with extended ACL.
[Tags] ACL eACL NeoFS NeoCLI
[Tags] ACL eACL
[Timeout] 20 min
[Setup] Setup

View file

@ -3,6 +3,7 @@ Variables common.py
Library Collections
Library neofs.py
Library neofs_verbs.py
Library payment_neogo.py
Library acl.py

View file

@ -3,6 +3,7 @@ Variables common.py
Library Collections
Library neofs.py
Library neofs_verbs.py
Library acl.py
Library payment_neogo.py

View file

@ -3,6 +3,7 @@ Variables common.py
Library acl.py
Library neofs.py
Library neofs_verbs.py
Library payment_neogo.py
Library Collections
Library contract_keywords.py
@ -16,8 +17,8 @@ Resource eacl_tables.robot
${PATH} = testfile
&{USER_HEADER} = key1=1 key2=abc
&{ANOTHER_HEADER} = key1=oth key2=oth
${ID_FILTER} = $Object:objectID
${CUSTOM_FILTER} = $Object:key1
${ID_FILTER} = $Object:objectID
${CUSTOM_FILTER} = $Object:key1
*** Test cases ***
Extended ACL Operations
@ -96,7 +97,7 @@ Check eACL MatchType String Equal Request Allow
${CID} = Create Container Public ${USER_KEY}
${S_OID_USER} = Put Object ${USER_KEY} ${FILE_S} ${CID}
Get Object ${OTHER_KEY} ${CID} ${S_OID_USER} ${EMPTY} ${PATH}
Set eACL ${USER_KEY} ${CID} ${EACL_XHEADER_ALLOW_ALL}
# The current ACL cache lifetime is 30 sec
@ -141,7 +142,7 @@ Check eACL MatchType String Equal Object
&{HEADER_DICT} = Head Object ${USER_KEY} ${CID} ${S_OID_USER}
${ID_value} = Get From dictionary ${HEADER_DICT} ${EACL_OBJ_FILTERS}[${ID_FILTER}]
${filters} = Set Variable obj:${ID_FILTER}=${ID_value}
${rule1} = Set Variable deny get ${filters} others
${eACL_gen} = Create List ${rule1}
@ -154,7 +155,7 @@ Check eACL MatchType String Equal Object
Log Set eACL for Deny GET operation with StringEqual Object Extended User Header
${S_OID_USER_OTH} = Put object ${USER_KEY} ${FILE_S} ${CID} user_headers=${ANOTHER_HEADER}
${filters} = Set Variable obj:${CUSTOM_FILTER}=1
${rule1} = Set Variable deny get ${filters} others
${eACL_gen} = Create List ${rule1}
@ -178,10 +179,10 @@ Check eACL MatchType String Not Equal Object
Get object ${OTHER_KEY} ${CID} ${S_OID_OTHER} ${EMPTY} ${PATH}
Log Set eACL for Deny GET operation with StringNotEqual Object ID
&{HEADER_DICT} = Head object ${USER_KEY} ${CID} ${S_OID_USER}
${ID_value} = Get From Dictionary ${HEADER_DICT} ${EACL_OBJ_FILTERS}[${ID_FILTER}]
${filters} = Set Variable obj:${ID_FILTER}!=${ID_value}
${rule1} = Set Variable deny get ${filters} others
${eACL_gen} = Create List ${rule1}
@ -194,8 +195,8 @@ Check eACL MatchType String Not Equal Object
Log Set eACL for Deny GET operation with StringEqual Object Extended User Header
${S_OID_USER_OTH} = Put object ${USER_KEY} ${FILE_S} ${CID} user_headers=${ANOTHER_HEADER}
${S_OID_USER_OTH} = Put object ${USER_KEY} ${FILE_S} ${CID} user_headers=${ANOTHER_HEADER}
${filters} = Set Variable obj:${CUSTOM_FILTER}!=1
${rule1} = Set Variable deny get ${filters} others
${eACL_gen} = Create List ${rule1}

View file

@ -5,11 +5,11 @@ Resource setup_teardown.robot
*** Test cases ***
Container ID Object Filter for Extended ACL
[Documentation] Testcase to validate if $Object:containerID eACL filter is correctly handled.
[Tags] ACL eACL NeoFS NeoCLI
[Tags] ACL eACL
[Timeout] 20 min
[Setup] Setup
Log Check eACL containerID Filter with MatchType String Equal
Check eACL Filters with MatchType String Equal $Object:containerID

View file

@ -1,10 +1,10 @@
*** Settings ***
Variables common.py
Library Collections
Library neofs.py
Library payment_neogo.py
Library String
Library Collections
Resource setup_teardown.robot
Resource payment_operations.robot
@ -26,7 +26,7 @@ Duplicated Container Attributes
[Setup] Setup
${WALLET} ${ADDR} ${USER_KEY} = Init Wallet with Address ${ASSETS_DIR}
${_} ${ADDR} ${USER_KEY} = Init Wallet with Address ${ASSETS_DIR}
Payment Operations ${ADDR} ${USER_KEY}
######################################################
@ -53,7 +53,10 @@ Duplicated Container Attributes
Wait Until Keyword Succeeds ${MORPH_BLOCK_TIME} ${CONTAINER_WAIT_INTERVAL}
... Container Existing ${USER_KEY} ${CID}
${ATTRIBUTES} = Get container attributes ${USER_KEY} ${CID} ${EMPTY} json_output=True
${ATTRIBUTES_DICT} = Decode Container Attributes Json ${ATTRIBUTES}
Verify Head Attribute ${ATTRIBUTES_DICT} ${ATTR_SINGLE}
&{ATTRIBUTES_DICT} = Decode Container Attributes Json ${ATTRIBUTES}
List Should Contain Value
... ${ATTRIBUTES_DICT}[Attributes]
... ${ATTR_SINGLE}
... "No expected container attributes found"
[Teardown] Teardown container_attributes

View file

@ -16,13 +16,13 @@ ${CONTAINER_WAIT_INTERVAL} = 1 min
*** Test Cases ***
Delete Containers
[Documentation] Testcase to check if containers can be deleted.
[Tags] Container NeoFS NeoCLI
[Tags] Container
[Timeout] 10 min
[Setup] Setup
${WALLET} ${ADDR} ${USER_KEY} = Prepare Wallet And Deposit
${WALLET_OTH} ${ADDR_OTH} ${OTHER_KEY} = Prepare Wallet And Deposit
${_} ${_} ${USER_KEY} = Prepare Wallet And Deposit
${_} ${_} ${OTHER_KEY} = Prepare Wallet And Deposit
${CID} = Create container ${USER_KEY} ${PRIVATE_ACL_F} ${COMMON_PLACEMENT_RULE}
Wait Until Keyword Succeeds ${MORPH_BLOCK_TIME} ${CONTAINER_WAIT_INTERVAL}
@ -41,6 +41,6 @@ Delete Containers
... Get container attributes ${USER_KEY} ${CID}
Log If one tries to delete an already deleted container, they should expect success.
Delete Container ${CID} ${USER_KEY}
Delete Container ${CID} ${USER_KEY}
[Teardown] Teardown container_delete

View file

@ -2,12 +2,13 @@
Variables common.py
Variables wellknown_acl.py
Library Process
Library contract_keywords.py
Library neofs.py
Library String
Library neofs_verbs.py
Library payment_neogo.py
Library String
Library Process
Resource setup_teardown.robot
Resource payment_operations.robot

View file

@ -2,6 +2,7 @@
Variables common.py
Library neofs.py
Library neofs_verbs.py
Library payment_neogo.py
Library wallet_keywords.py
Library rpc_call_keywords.py
@ -92,6 +93,6 @@ Validate Policy
${CID} = Create container ${PRIV_KEY} ${EMPTY} ${POLICY}
Wait Until Keyword Succeeds ${MORPH_BLOCK_TIME} ${CONTAINER_WAIT_INTERVAL}
... Container Existing ${PRIV_KEY} ${CID}
${S_OID} = Put object ${PRIV_KEY} ${FILE} ${CID} ${EMPTY} ${EMPTY}
${S_OID} = Put object ${PRIV_KEY} ${FILE} ${CID}
Validate storage policy for object ${PRIV_KEY} ${EXPECTED_VAL} ${CID} ${S_OID} ${EXPECTED_LIST}
Get object ${PRIV_KEY} ${CID} ${S_OID} ${EMPTY} s_file_read

View file

@ -5,6 +5,7 @@ Variables wellknown_acl.py
Library Collections
Library payment_neogo.py
Library neofs.py
Library neofs_verbs.py
Library wallet_keywords.py
Library rpc_call_keywords.py
Library contract_keywords.py
@ -25,10 +26,10 @@ NeoFS Object Replication
[Timeout] 25 min
[Setup] Setup
Log Check replication mechanism
Check Replication ${EMPTY}
Log Check Sticky Bit with SYSTEM Group via replication mechanism
Log Check Sticky Bit with SYSTEM Group via replication mechanism
Check Replication ${STICKYBIT_PUB_ACL}
[Teardown] Teardown replication
@ -37,7 +38,7 @@ NeoFS Object Replication
Check Replication
[Arguments] ${ACL}
${WALLET} ${ADDR} ${WIF} = Prepare Wallet And Deposit
${_} ${_} ${WIF} = Prepare Wallet And Deposit
${CID} = Create Container ${WIF} ${ACL} ${PLACEMENT_RULE}
Wait Until Keyword Succeeds ${MORPH_BLOCK_TIME} ${CONTAINER_WAIT_INTERVAL}
... Container Existing ${WIF} ${CID}
@ -45,7 +46,7 @@ Check Replication
${FILE} = Generate file of bytes ${SIMPLE_OBJ_SIZE}
${FILE_HASH} = Get file hash ${FILE}
${S_OID} = Put Object ${WIF} ${FILE} ${CID} ${EMPTY} ${EMPTY}
${S_OID} = Put Object ${WIF} ${FILE} ${CID}
Validate storage policy for object ${WIF} ${EXPECTED_COPIES} ${CID} ${S_OID}
@{NODES_OBJ} = Get nodes with Object ${WIF} ${CID} ${S_OID}

View file

@ -2,10 +2,11 @@
Variables common.py
Variables wellknown_acl.py
Library Collections
Library neofs.py
Library neofs_verbs.py
Library payment_neogo.py
Library String
Library Collections
Resource setup_teardown.robot
Resource payment_operations.robot

View file

@ -1,6 +1,7 @@
*** Settings ***
Variables common.py
Library neofs_verbs.py
Library neofs.py
Library payment_neogo.py
Library contract_keywords.py

View file

@ -2,6 +2,7 @@
Variables common.py
Library neofs.py
Library neofs_verbs.py
Library payment_neogo.py
Library contract_keywords.py
@ -35,12 +36,12 @@ NeoFS Simple Object Operations
# Failed on attempt to create epoch from the past
Run Keyword And Expect Error *
... Put object ${WIF} ${FILE} ${CID} ${EMPTY} __NEOFS__EXPIRATION_EPOCH=${EPOCH_PRE}
... Put object ${WIF} ${FILE} ${CID} options= --attributes __NEOFS__EXPIRATION_EPOCH=${EPOCH_PRE}
# Put object with different expiration epoch numbers (current, next, and from the distant future)
${OID_CUR} = Put object ${WIF} ${FILE} ${CID} ${EMPTY} __NEOFS__EXPIRATION_EPOCH=${EPOCH}
${OID_NXT} = Put object ${WIF} ${FILE} ${CID} ${EMPTY} __NEOFS__EXPIRATION_EPOCH=${EPOCH_NEXT}
${OID_PST} = Put object ${WIF} ${FILE} ${CID} ${EMPTY} __NEOFS__EXPIRATION_EPOCH=${EPOCH_POST}
${OID_CUR} = Put object ${WIF} ${FILE} ${CID} options= --attributes __NEOFS__EXPIRATION_EPOCH=${EPOCH}
${OID_NXT} = Put object ${WIF} ${FILE} ${CID} options= --attributes __NEOFS__EXPIRATION_EPOCH=${EPOCH_NEXT}
${OID_PST} = Put object ${WIF} ${FILE} ${CID} options= --attributes __NEOFS__EXPIRATION_EPOCH=${EPOCH_POST}
# Check objects for existence
Get object ${WIF} ${CID} ${OID_CUR} ${EMPTY} file_read_cur

View file

@ -2,6 +2,7 @@
Variables common.py
Library neofs.py
Library neofs_verbs.py
Library payment_neogo.py
Library contract_keywords.py
Library Collections
@ -25,7 +26,7 @@ NeoFS Simple Object Operations
[Setup] Setup
${WALLET} ${ADDR} ${WIF} = Init Wallet with Address ${ASSETS_DIR}
Payment Operations ${ADDR} ${WIF}
Payment Operations ${ADDR} ${WIF}
${CID} = Prepare container ${WIF}
${FILE} = Generate file of bytes ${SIMPLE_OBJ_SIZE}

View file

@ -1,9 +1,10 @@
*** Settings ***
Variables common.py
Library Collections
Library neofs.py
Library neofs_verbs.py
Library payment_neogo.py
Library Collections
Resource common_steps_object.robot
Resource setup_teardown.robot
@ -11,11 +12,12 @@ Resource payment_operations.robot
*** Variables ***
${UNEXIST_OID} = B2DKvkHnLnPvapbDgfpU1oVUPuXQo5LTfKVxmNDZXQff
&{USER_HEADER} = key1=1 key2=2
*** Test cases ***
NeoFS Complex Storagegroup
[Documentation] Testcase to validate NeoFS operations with Storagegroup.
[Tags] Object NeoFS NeoCLI
[Tags] Object
[Timeout] 20 min
[Setup] Setup
@ -28,8 +30,8 @@ NeoFS Complex Storagegroup
${FILE_HASH_S} = Get file hash ${FILE_S}
# Put two Simple Object
${S_OID_1} = Put object ${WIF} ${FILE_S} ${CID} ${EMPTY} ${EMPTY}
${S_OID_2} = Put object ${WIF} ${FILE_S} ${CID} ${EMPTY} ${FILE_USR_HEADER}
${S_OID_1} = Put object ${WIF} ${FILE_S} ${CID}
${S_OID_2} = Put object ${WIF} ${FILE_S} ${CID} user_headers=&{USER_HEADER}
@{S_OBJ_ALL} = Create List ${S_OID_1} ${S_OID_2}

View file

@ -2,6 +2,7 @@
Variables common.py
Library neofs.py
Library neofs_verbs.py
Library payment_neogo.py
Resource common_steps_object.robot
@ -10,6 +11,7 @@ Resource payment_operations.robot
*** Variables ***
${UNEXIST_OID} = B2DKvkHnLnPvapbDgfpU1oVUPuXQo5LTfKVxmNDZXQff
&{USER_HEADER} = key1=1 key2=2
*** Test cases ***
NeoFS Simple Storagegroup
@ -28,8 +30,8 @@ NeoFS Simple Storagegroup
# Put two Simple Object
${S_OID_1} = Put object ${WIF} ${FILE_S} ${CID} ${EMPTY} ${EMPTY}
${S_OID_2} = Put object ${WIF} ${FILE_S} ${CID} ${EMPTY} ${FILE_USR_HEADER}
${S_OID_1} = Put object ${WIF} ${FILE_S} ${CID}
${S_OID_2} = Put object ${WIF} ${FILE_S} ${CID} user_headers=&{USER_HEADER}
@{S_OBJ_ALL} = Create List ${S_OID_1} ${S_OID_2}

View file

@ -3,6 +3,7 @@ Variables common.py
Variables wellknown_acl.py
Library neofs.py
Library neofs_verbs.py
Library http_gate.py
Resource payment_operations.robot
@ -33,8 +34,8 @@ NeoFS HTTP Gateway
${FILE_HASH} = Get file hash ${FILE}
${FILE_L_HASH} = Get file hash ${FILE_L}
${S_OID} = Put object ${WIF} ${FILE} ${CID} ${EMPTY} ${EMPTY}
${L_OID} = Put object ${WIF} ${FILE_L} ${CID} ${EMPTY} ${EMPTY}
${S_OID} = Put object ${WIF} ${FILE} ${CID}
${L_OID} = Put object ${WIF} ${FILE_L} ${CID}
# By request from Service team - try to GET object from the node without object
@ -44,8 +45,10 @@ NeoFS HTTP Gateway
${GET_OBJ_S} = Get object ${WIF} ${CID} ${S_OID} ${EMPTY} s_file_read ${NODE}
${FILEPATH} = Get via HTTP Gate ${CID} ${S_OID}
Verify file hash ${GET_OBJ_S} ${FILE_HASH}
Verify file hash ${FILEPATH} ${FILE_HASH}
${PLAIN_FILE_HASH} = Get file hash ${GET_OBJ_S}
${GATE_FILE_HASH} = Get file hash ${FILEPATH}
Should Be Equal ${FILE_HASH} ${PLAIN_FILE_HASH}
Should Be Equal ${FILE_HASH} ${GATE_FILE_HASH}
@{GET_NODE_LIST} = Get nodes without object ${WIF} ${CID} ${L_OID}
${NODE} = Evaluate random.choice($GET_NODE_LIST) random
@ -53,7 +56,9 @@ NeoFS HTTP Gateway
${GET_OBJ_L} = Get object ${WIF} ${CID} ${L_OID} ${EMPTY} l_file_read ${NODE}
${FILEPATH} = Get via HTTP Gate ${CID} ${L_OID}
Verify file hash ${GET_OBJ_L} ${FILE_L_HASH}
Verify file hash ${FILEPATH} ${FILE_L_HASH}
${PLAIN_FILE_HASH} = Get file hash ${GET_OBJ_L}
${GATE_FILE_HASH} = Get file hash ${FILEPATH}
Should Be Equal ${FILE_L_HASH} ${PLAIN_FILE_HASH}
Should Be Equal ${FILE_L_HASH} ${GATE_FILE_HASH}
[Teardown] Teardown http_gate

View file

@ -58,6 +58,8 @@ Objects in NeoFS S3 Gateway
${OBJ_PATH} = Get object S3 ${S3_CLIENT} ${NEW_BUCKET} ${S3_OBJECT_KEY}
Verify file hash ${OBJ_PATH} ${FILE_S3_HASH}
${HASH} = Get file hash ${OBJ_PATH}
Should Be Equal ${FILE_S3_HASH} ${HASH}
#TODO: Solve the issue on CopyObject #260 https://github.com/nspcc-dev/neofs-s3-gw/issues/260