[#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:
parent
e5d6662905
commit
7a21456201
43 changed files with 667 additions and 494 deletions
|
@ -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)
|
||||
|
|
113
robot/resources/lib/python/json_transformers.py
Normal file
113
robot/resources/lib/python/json_transformers.py
Normal 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
|
|
@ -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
|
||||
|
|
297
robot/resources/lib/python/neofs_verbs.py
Normal file
297
robot/resources/lib/python/neofs_verbs.py
Normal 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))
|
|
@ -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}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
Variables common.py
|
||||
|
||||
Library neofs.py
|
||||
Library neofs_verbs.py
|
||||
Library payment_neogo.py
|
||||
|
||||
Resource common_steps_acl_basic.robot
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ Variables common.py
|
|||
|
||||
Library Collections
|
||||
Library neofs.py
|
||||
Library neofs_verbs.py
|
||||
Library acl.py
|
||||
Library payment_neogo.py
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -3,6 +3,7 @@ Variables common.py
|
|||
|
||||
Library Collections
|
||||
Library neofs.py
|
||||
Library neofs_verbs.py
|
||||
Library acl.py
|
||||
Library payment_neogo.py
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ Variables common.py
|
|||
|
||||
Library Collections
|
||||
Library neofs.py
|
||||
Library neofs_verbs.py
|
||||
Library acl.py
|
||||
Library payment_neogo.py
|
||||
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -3,6 +3,7 @@ Variables common.py
|
|||
|
||||
Library Collections
|
||||
Library neofs.py
|
||||
Library neofs_verbs.py
|
||||
Library payment_neogo.py
|
||||
Library acl.py
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ Variables common.py
|
|||
|
||||
Library Collections
|
||||
Library neofs.py
|
||||
Library neofs_verbs.py
|
||||
Library acl.py
|
||||
Library payment_neogo.py
|
||||
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
*** Settings ***
|
||||
Variables common.py
|
||||
|
||||
Library neofs_verbs.py
|
||||
Library neofs.py
|
||||
Library payment_neogo.py
|
||||
Library contract_keywords.py
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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}
|
||||
|
||||
|
|
|
@ -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}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in a new issue