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