forked from TrueCloudLab/frostfs-testcases
Replace prepare_container*** fixtures with a function.
The change is motivated by variety of standard ACLs that will be hard to manage with set of fixtures. Remove logic that initializes wallet from remote devenv host. This setup action should be handled outside tests. Add ability to establish SSH connection using SSH key instead of password. Signed-off-by: Vladimir Domnich <v.domnich@yadro.com>
This commit is contained in:
parent
ffa40112a1
commit
84230d12e3
11 changed files with 142 additions and 199 deletions
|
@ -1,16 +1,15 @@
|
|||
#!/usr/bin/python3.8
|
||||
#!/usr/bin/python3.9
|
||||
|
||||
"""
|
||||
Helper functions to use with `neofs-cli`, `neo-go`
|
||||
and other CLIs.
|
||||
Helper functions to use with `neofs-cli`, `neo-go` and other CLIs.
|
||||
"""
|
||||
from typing import Union
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
from contextlib import suppress
|
||||
from datetime import datetime
|
||||
from json import dumps
|
||||
from textwrap import shorten
|
||||
from typing import Union
|
||||
|
||||
import allure
|
||||
import pexpect
|
||||
|
@ -19,21 +18,21 @@ from robot.api import logger
|
|||
ROBOT_AUTO_KEYWORDS = False
|
||||
|
||||
|
||||
def _cmd_run(cmd, timeout=30):
|
||||
def _cmd_run(cmd: str, timeout: int = 30) -> str:
|
||||
"""
|
||||
Runs given shell command <cmd>, in case of success returns its stdout,
|
||||
in case of failure returns error message.
|
||||
"""
|
||||
try:
|
||||
logger.info(f"Executing command: {cmd}")
|
||||
start_time = datetime.now()
|
||||
start_time = datetime.utcnow()
|
||||
compl_proc = subprocess.run(cmd, check=True, universal_newlines=True,
|
||||
stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
|
||||
timeout=timeout,
|
||||
shell=True)
|
||||
output = compl_proc.stdout
|
||||
return_code = compl_proc.returncode
|
||||
end_time = datetime.now()
|
||||
end_time = datetime.utcnow()
|
||||
logger.info(f"Output: {output}")
|
||||
_attach_allure_log(cmd, output, return_code, start_time, end_time)
|
||||
|
||||
|
@ -50,7 +49,7 @@ def _cmd_run(cmd, timeout=30):
|
|||
raise
|
||||
|
||||
|
||||
def _run_with_passwd(cmd):
|
||||
def _run_with_passwd(cmd: str) -> str:
|
||||
child = pexpect.spawn(cmd)
|
||||
child.delaybeforesend = 1
|
||||
child.expect(".*")
|
||||
|
@ -64,7 +63,7 @@ def _run_with_passwd(cmd):
|
|||
return cmd.decode()
|
||||
|
||||
|
||||
def _configure_aws_cli(cmd, key_id, access_key, out_format='json'):
|
||||
def _configure_aws_cli(cmd: str, key_id: str, access_key: str, out_format: str = "json") -> str:
|
||||
child = pexpect.spawn(cmd)
|
||||
child.delaybeforesend = 1
|
||||
|
||||
|
@ -87,7 +86,8 @@ def _configure_aws_cli(cmd, key_id, access_key, out_format='json'):
|
|||
return cmd.decode()
|
||||
|
||||
|
||||
def _attach_allure_log(cmd: str, output: str, return_code: int, start_time: datetime, end_time: datetime):
|
||||
def _attach_allure_log(cmd: str, output: str, return_code: int, start_time: datetime,
|
||||
end_time: datetime) -> None:
|
||||
if 'allure' in sys.modules:
|
||||
command_attachment = (
|
||||
f"COMMAND: '{cmd}'\n"
|
||||
|
@ -99,11 +99,11 @@ def _attach_allure_log(cmd: str, output: str, return_code: int, start_time: date
|
|||
allure.attach(command_attachment, 'Command execution', allure.attachment_type.TEXT)
|
||||
|
||||
|
||||
def log_command_execution(cmd: str, output: Union[str, dict]):
|
||||
def log_command_execution(cmd: str, output: Union[str, dict]) -> None:
|
||||
logger.info(f'{cmd}: {output}')
|
||||
if 'allure' in sys.modules:
|
||||
with suppress(Exception):
|
||||
json_output = dumps(output, indent=4, sort_keys=True)
|
||||
json_output = json.dumps(output, indent=4, sort_keys=True)
|
||||
output = json_output
|
||||
command_attachment = (
|
||||
f"COMMAND: '{cmd}'\n"
|
||||
|
|
|
@ -1,29 +1,28 @@
|
|||
#!/usr/bin/python3
|
||||
#!/usr/bin/python3.9
|
||||
|
||||
"""
|
||||
This module contains keywords which utilize `neofs-cli container`
|
||||
commands.
|
||||
This module contains keywords that utilize `neofs-cli container` commands.
|
||||
"""
|
||||
|
||||
import json
|
||||
import time
|
||||
from typing import Optional
|
||||
|
||||
from common import NEOFS_ENDPOINT, COMMON_PLACEMENT_RULE, NEOFS_CLI_EXEC, WALLET_CONFIG
|
||||
from cli_helpers import _cmd_run
|
||||
from data_formatters import dict_to_attrs
|
||||
import json_transformers
|
||||
from data_formatters import dict_to_attrs
|
||||
from cli_helpers import _cmd_run
|
||||
from common import NEOFS_ENDPOINT, NEOFS_CLI_EXEC, WALLET_CONFIG
|
||||
|
||||
from robot.api import logger
|
||||
from robot.api.deco import keyword
|
||||
|
||||
|
||||
ROBOT_AUTO_KEYWORDS = False
|
||||
|
||||
DEFAULT_PLACEMENT_RULE = "REP 2 IN X CBF 1 SELECT 4 FROM * AS X"
|
||||
|
||||
@keyword('Create Container')
|
||||
def create_container(wallet: str, rule: str = COMMON_PLACEMENT_RULE, basic_acl: str = '',
|
||||
attributes: dict = {}, session_token: str = '', session_wallet: str = '',
|
||||
options: str = ''):
|
||||
def create_container(wallet: str, rule: str = DEFAULT_PLACEMENT_RULE, basic_acl: str = '',
|
||||
attributes: Optional[dict] = None, session_token: str = '',
|
||||
session_wallet: str = '', options: str = '') -> str:
|
||||
"""
|
||||
A wrapper for `neofs-cli container create` call.
|
||||
|
||||
|
@ -74,7 +73,7 @@ def create_container(wallet: str, rule: str = COMMON_PLACEMENT_RULE, basic_acl:
|
|||
|
||||
|
||||
@keyword('List Containers')
|
||||
def list_containers(wallet: str):
|
||||
def list_containers(wallet: str) -> list[str]:
|
||||
"""
|
||||
A wrapper for `neofs-cli container list` call. It returns all the
|
||||
available containers for the given wallet.
|
||||
|
@ -92,12 +91,12 @@ def list_containers(wallet: str):
|
|||
|
||||
|
||||
@keyword('Get Container')
|
||||
def get_container(wallet: str, cid: str):
|
||||
def get_container(wallet: str, cid: str) -> dict:
|
||||
"""
|
||||
A wrapper for `neofs-cli container get` call. It extracts
|
||||
container attributes and rearranges them to more compact view.
|
||||
A wrapper for `neofs-cli container get` call. It extracts container's
|
||||
attributes and rearranges them into a more compact view.
|
||||
Args:
|
||||
wallet (str): a wallet on whose behalf we get the container
|
||||
wallet (str): path to a wallet on whose behalf we get the container
|
||||
cid (str): ID of the container to get
|
||||
Returns:
|
||||
(dict): dict of container attributes
|
||||
|
@ -112,19 +111,18 @@ def get_container(wallet: str, cid: str):
|
|||
for attr in container_info['attributes']:
|
||||
attributes[attr['key']] = attr['value']
|
||||
container_info['attributes'] = attributes
|
||||
container_info['ownerID'] = json_transformers.json_reencode(
|
||||
container_info['ownerID']['value'])
|
||||
container_info['ownerID'] = json_transformers.json_reencode(container_info['ownerID']['value'])
|
||||
return container_info
|
||||
|
||||
|
||||
@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
|
||||
def delete_container(wallet: str, cid: str):
|
||||
def delete_container(wallet: str, cid: str) -> None:
|
||||
"""
|
||||
A wrapper for `neofs-cli container delete` call.
|
||||
Args:
|
||||
wallet (str): a wallet on whose behalf we delete the container
|
||||
wallet (str): path to a wallet on whose behalf we delete the container
|
||||
cid (str): ID of the container to delete
|
||||
This function doesn't return anything.
|
||||
"""
|
||||
|
@ -136,27 +134,26 @@ def delete_container(wallet: str, cid: str):
|
|||
_cmd_run(cmd)
|
||||
|
||||
|
||||
def _parse_cid(ouptut: str):
|
||||
def _parse_cid(output: str) -> str:
|
||||
"""
|
||||
This function parses CID from given CLI output. The input string we
|
||||
expect:
|
||||
Parses container ID from a given CLI output. The input string we expect:
|
||||
container ID: 2tz86kVTDpJxWHrhw3h6PbKMwkLtBEwoqhHQCKTre1FN
|
||||
awaiting...
|
||||
container has been persisted on sidechain
|
||||
We want to take 'container ID' value from the string.
|
||||
|
||||
Args:
|
||||
ouptut (str): a command run output
|
||||
output (str): CLI output to parse
|
||||
|
||||
Returns:
|
||||
(str): extracted CID
|
||||
"""
|
||||
try:
|
||||
# taking first string from command output
|
||||
fst_str = ouptut.split('\n')[0]
|
||||
# taking first line from command's output
|
||||
first_line = output.split('\n')[0]
|
||||
except Exception:
|
||||
logger.error(f"Got empty output: {ouptut}")
|
||||
splitted = fst_str.split(": ")
|
||||
logger.error(f"Got empty output: {output}")
|
||||
splitted = first_line.split(": ")
|
||||
if len(splitted) != 2:
|
||||
raise ValueError(f"no CID was parsed from command output: \t{fst_str}")
|
||||
raise ValueError(f"no CID was parsed from command output: \t{first_line}")
|
||||
return splitted[1]
|
||||
|
|
|
@ -1,16 +1,8 @@
|
|||
"""
|
||||
A bunch of functions which might rearrange some data or
|
||||
change their representation.
|
||||
"""
|
||||
|
||||
from functools import reduce
|
||||
|
||||
|
||||
def dict_to_attrs(attrs: dict):
|
||||
def dict_to_attrs(attrs: dict) -> str:
|
||||
"""
|
||||
This function takes dictionary of object attributes and converts them
|
||||
into the string. The string is passed to `--attributes` key of the
|
||||
neofs-cli.
|
||||
This function takes a dictionary of object's attributes and converts them
|
||||
into string. The string is passed to `--attributes` key of neofs-cli.
|
||||
|
||||
Args:
|
||||
attrs (dict): object attributes in {"a": "b", "c": "d"} format.
|
||||
|
@ -18,4 +10,4 @@ def dict_to_attrs(attrs: dict):
|
|||
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))
|
||||
return ",".join(f"{key}={value}" for key, value in attrs.items())
|
||||
|
|
|
@ -1,32 +1,20 @@
|
|||
#!/usr/bin/python3.9
|
||||
|
||||
|
||||
import contract
|
||||
import sys
|
||||
from robot.api import logger
|
||||
from robot.api.deco import keyword
|
||||
from robot.libraries.BuiltIn import BuiltIn
|
||||
|
||||
from common import IR_WALLET_PATH, IR_WALLET_PASS, MORPH_ENDPOINT
|
||||
|
||||
ROBOT_AUTO_KEYWORDS = False
|
||||
|
||||
if "pytest" in sys.modules:
|
||||
import os
|
||||
|
||||
IR_WALLET_PATH = os.getenv("IR_WALLET_PATH")
|
||||
IR_WALLET_PASS = os.getenv("IR_WALLET_PASS")
|
||||
SIDECHAIN_EP = os.getenv("MORPH_ENDPOINT")
|
||||
else:
|
||||
IR_WALLET_PATH = BuiltIn().get_variable_value("${IR_WALLET_PATH}")
|
||||
IR_WALLET_PASS = BuiltIn().get_variable_value("${IR_WALLET_PASS}")
|
||||
SIDECHAIN_EP = BuiltIn().get_variable_value("${MORPH_ENDPOINT}")
|
||||
|
||||
|
||||
@keyword('Get Epoch')
|
||||
def get_epoch():
|
||||
epoch = int(contract.testinvoke_contract(
|
||||
contract.get_netmap_contract_hash(SIDECHAIN_EP),
|
||||
'epoch',
|
||||
SIDECHAIN_EP)
|
||||
contract.get_netmap_contract_hash(MORPH_ENDPOINT),
|
||||
"epoch",
|
||||
MORPH_ENDPOINT)
|
||||
)
|
||||
logger.info(f"Got epoch {epoch}")
|
||||
return epoch
|
||||
|
@ -36,6 +24,6 @@ def get_epoch():
|
|||
def tick_epoch():
|
||||
cur_epoch = get_epoch()
|
||||
return contract.invoke_contract_multisig(
|
||||
contract.get_netmap_contract_hash(SIDECHAIN_EP),
|
||||
contract.get_netmap_contract_hash(MORPH_ENDPOINT),
|
||||
f"newEpoch int:{cur_epoch+1}",
|
||||
IR_WALLET_PATH, IR_WALLET_PASS, SIDECHAIN_EP)
|
||||
IR_WALLET_PATH, IR_WALLET_PASS, MORPH_ENDPOINT)
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
#!/usr/bin/python3
|
||||
#!/usr/bin/python3.9
|
||||
|
||||
import os
|
||||
import uuid
|
||||
from enum import Enum
|
||||
from typing import Optional, List
|
||||
from typing import Optional
|
||||
|
||||
import urllib3
|
||||
from botocore.exceptions import ClientError
|
||||
|
@ -196,7 +196,7 @@ def create_multipart_upload_s3(s3_client, bucket_name: str, object_key: str) ->
|
|||
|
||||
|
||||
@keyword('List multipart uploads S3')
|
||||
def list_multipart_uploads_s3(s3_client, bucket_name: str) -> Optional[List[dict]]:
|
||||
def list_multipart_uploads_s3(s3_client, bucket_name: str) -> Optional[list[dict]]:
|
||||
try:
|
||||
response = s3_client.list_multipart_uploads(Bucket=bucket_name)
|
||||
log_command_execution('S3 List multipart upload', response)
|
||||
|
@ -240,7 +240,7 @@ def upload_part_s3(s3_client, bucket_name: str, object_key: str, upload_id: str,
|
|||
|
||||
|
||||
@keyword('List parts S3')
|
||||
def list_parts_s3(s3_client, bucket_name: str, object_key: str, upload_id: str) -> List[dict]:
|
||||
def list_parts_s3(s3_client, bucket_name: str, object_key: str, upload_id: str) -> list[dict]:
|
||||
try:
|
||||
response = s3_client.list_parts(UploadId=upload_id, Bucket=bucket_name, Key=object_key)
|
||||
log_command_execution('S3 List part', response)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue