forked from TrueCloudLab/frostfs-testlib
[#270] Updates related to testing platform
Signed-off-by: a.berezin <a.berezin@yadro.com>
This commit is contained in:
parent
166e44da9c
commit
7a500330de
8 changed files with 168 additions and 34 deletions
108
.devenv.hosting.yaml
Normal file
108
.devenv.hosting.yaml
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
hosts:
|
||||||
|
- address: localhost
|
||||||
|
attributes:
|
||||||
|
sudo_shell: false
|
||||||
|
plugin_name: docker
|
||||||
|
healthcheck_plugin_name: basic
|
||||||
|
attributes:
|
||||||
|
skip_readiness_check: True
|
||||||
|
force_transactions: True
|
||||||
|
services:
|
||||||
|
- name: frostfs-storage_01
|
||||||
|
attributes:
|
||||||
|
container_name: s01
|
||||||
|
config_path: /etc/frostfs/storage/config.yml
|
||||||
|
wallet_path: ../frostfs-dev-env/services/storage/wallet01.json
|
||||||
|
local_wallet_config_path: ./TemporaryDir/empty-password.yml
|
||||||
|
local_wallet_path: ../frostfs-dev-env/services/storage/wallet01.json
|
||||||
|
wallet_password: ""
|
||||||
|
volume_name: storage_storage_s01
|
||||||
|
endpoint_data0: s01.frostfs.devenv:8080
|
||||||
|
control_endpoint: s01.frostfs.devenv:8081
|
||||||
|
un_locode: "RU MOW"
|
||||||
|
- name: frostfs-storage_02
|
||||||
|
attributes:
|
||||||
|
container_name: s02
|
||||||
|
config_path: /etc/frostfs/storage/config.yml
|
||||||
|
wallet_path: ../frostfs-dev-env/services/storage/wallet02.json
|
||||||
|
local_wallet_config_path: ./TemporaryDir/empty-password.yml
|
||||||
|
local_wallet_path: ../frostfs-dev-env/services/storage/wallet02.json
|
||||||
|
wallet_password: ""
|
||||||
|
volume_name: storage_storage_s02
|
||||||
|
endpoint_data0: s02.frostfs.devenv:8080
|
||||||
|
control_endpoint: s02.frostfs.devenv:8081
|
||||||
|
un_locode: "RU LED"
|
||||||
|
- name: frostfs-storage_03
|
||||||
|
attributes:
|
||||||
|
container_name: s03
|
||||||
|
config_path: /etc/frostfs/storage/config.yml
|
||||||
|
wallet_path: ../frostfs-dev-env/services/storage/wallet03.json
|
||||||
|
local_wallet_config_path: ./TemporaryDir/empty-password.yml
|
||||||
|
local_wallet_path: ../frostfs-dev-env/services/storage/wallet03.json
|
||||||
|
wallet_password: ""
|
||||||
|
volume_name: storage_storage_s03
|
||||||
|
endpoint_data0: s03.frostfs.devenv:8080
|
||||||
|
control_endpoint: s03.frostfs.devenv:8081
|
||||||
|
un_locode: "SE STO"
|
||||||
|
- name: frostfs-storage_04
|
||||||
|
attributes:
|
||||||
|
container_name: s04
|
||||||
|
config_path: /etc/frostfs/storage/config.yml
|
||||||
|
wallet_path: ../frostfs-dev-env/services/storage/wallet04.json
|
||||||
|
local_wallet_config_path: ./TemporaryDir/empty-password.yml
|
||||||
|
local_wallet_path: ../frostfs-dev-env/services/storage/wallet04.json
|
||||||
|
wallet_password: ""
|
||||||
|
volume_name: storage_storage_s04
|
||||||
|
endpoint_data0: s04.frostfs.devenv:8080
|
||||||
|
control_endpoint: s04.frostfs.devenv:8081
|
||||||
|
un_locode: "FI HEL"
|
||||||
|
- name: frostfs-s3_01
|
||||||
|
attributes:
|
||||||
|
container_name: s3_gate
|
||||||
|
config_path: ../frostfs-dev-env/services/s3_gate/.s3.env
|
||||||
|
wallet_path: ../frostfs-dev-env/services/s3_gate/wallet.json
|
||||||
|
local_wallet_config_path: ./TemporaryDir/password-s3.yml
|
||||||
|
local_wallet_path: ../frostfs-dev-env/services/s3_gate/wallet.json
|
||||||
|
wallet_password: "s3"
|
||||||
|
endpoint_data0: https://s3.frostfs.devenv:8080
|
||||||
|
- name: frostfs-http_01
|
||||||
|
attributes:
|
||||||
|
container_name: http_gate
|
||||||
|
config_path: ../frostfs-dev-env/services/http_gate/.http.env
|
||||||
|
wallet_path: ../frostfs-dev-env/services/http_gate/wallet.json
|
||||||
|
local_wallet_config_path: ./TemporaryDir/password-other.yml
|
||||||
|
local_wallet_path: ../frostfs-dev-env/services/http_gate/wallet.json
|
||||||
|
wallet_password: "one"
|
||||||
|
endpoint_data0: http://http.frostfs.devenv
|
||||||
|
- name: frostfs-ir_01
|
||||||
|
attributes:
|
||||||
|
container_name: ir01
|
||||||
|
config_path: ../frostfs-dev-env/services/ir/.ir.env
|
||||||
|
wallet_path: ../frostfs-dev-env/services/ir/az.json
|
||||||
|
local_wallet_config_path: ./TemporaryDir/password-other.yml
|
||||||
|
local_wallet_path: ../frostfs-dev-env/services/ir/az.json
|
||||||
|
wallet_password: "one"
|
||||||
|
- name: neo-go_01
|
||||||
|
attributes:
|
||||||
|
container_name: morph_chain
|
||||||
|
config_path: ../frostfs-dev-env/services/morph_chain/protocol.privnet.yml
|
||||||
|
wallet_path: ../frostfs-dev-env/services/morph_chain/node-wallet.json
|
||||||
|
local_wallet_config_path: ./TemporaryDir/password-other.yml
|
||||||
|
local_wallet_path: ../frostfs-dev-env/services/morph_chain/node-wallet.json
|
||||||
|
wallet_password: "one"
|
||||||
|
endpoint_internal0: http://morph-chain.frostfs.devenv:30333
|
||||||
|
- name: main-chain_01
|
||||||
|
attributes:
|
||||||
|
container_name: main_chain
|
||||||
|
config_path: ../frostfs-dev-env/services/chain/protocol.privnet.yml
|
||||||
|
wallet_path: ../frostfs-dev-env/services/chain/node-wallet.json
|
||||||
|
local_wallet_config_path: ./TemporaryDir/password-other.yml
|
||||||
|
local_wallet_path: ../frostfs-dev-env/services/chain/node-wallet.json
|
||||||
|
wallet_password: "one"
|
||||||
|
endpoint_internal0: http://main-chain.frostfs.devenv:30333
|
||||||
|
- name: coredns_01
|
||||||
|
attributes:
|
||||||
|
container_name: coredns
|
||||||
|
clis:
|
||||||
|
- name: frostfs-cli
|
||||||
|
exec_path: frostfs-cli
|
|
@ -89,4 +89,7 @@ push = false
|
||||||
filterwarnings = [
|
filterwarnings = [
|
||||||
"ignore:Blowfish has been deprecated:cryptography.utils.CryptographyDeprecationWarning",
|
"ignore:Blowfish has been deprecated:cryptography.utils.CryptographyDeprecationWarning",
|
||||||
]
|
]
|
||||||
testpaths = ["tests"]
|
testpaths = ["tests"]
|
||||||
|
|
||||||
|
[project.entry-points.pytest11]
|
||||||
|
testlib = "frostfs_testlib"
|
|
@ -1 +1,3 @@
|
||||||
__version__ = "2.0.1"
|
__version__ = "2.0.1"
|
||||||
|
|
||||||
|
from .fixtures import configure_testlib, hosting
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from frostfs_testlib.analytics import test_case
|
from frostfs_testlib.analytics import test_case
|
||||||
from frostfs_testlib.analytics.test_case import TestCasePriority
|
from frostfs_testlib.analytics.test_case import TestCasePriority
|
||||||
from frostfs_testlib.analytics.test_collector import TestCase, TestCaseCollector
|
from frostfs_testlib.analytics.test_collector import TestCase, TestCaseCollector
|
||||||
from frostfs_testlib.analytics.test_exporter import TestExporter
|
from frostfs_testlib.analytics.test_exporter import TСExporter
|
||||||
from frostfs_testlib.analytics.testrail_exporter import TestrailExporter
|
from frostfs_testlib.analytics.testrail_exporter import TestrailExporter
|
||||||
|
|
|
@ -3,7 +3,8 @@ from abc import ABC, abstractmethod
|
||||||
from frostfs_testlib.analytics.test_collector import TestCase
|
from frostfs_testlib.analytics.test_collector import TestCase
|
||||||
|
|
||||||
|
|
||||||
class TestExporter(ABC):
|
# TODO: REMOVE ME
|
||||||
|
class TСExporter(ABC):
|
||||||
test_cases_cache = []
|
test_cases_cache = []
|
||||||
test_suites_cache = []
|
test_suites_cache = []
|
||||||
|
|
||||||
|
@ -46,9 +47,7 @@ class TestExporter(ABC):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def update_test_case(
|
def update_test_case(self, test_case: TestCase, test_case_in_tms, test_suite, test_suite_section) -> None:
|
||||||
self, test_case: TestCase, test_case_in_tms, test_suite, test_suite_section
|
|
||||||
) -> None:
|
|
||||||
"""
|
"""
|
||||||
Update test case in TMS
|
Update test case in TMS
|
||||||
"""
|
"""
|
||||||
|
@ -60,9 +59,7 @@ class TestExporter(ABC):
|
||||||
|
|
||||||
for test_case in test_cases:
|
for test_case in test_cases:
|
||||||
test_suite = self.get_or_create_test_suite(test_case.suite_name)
|
test_suite = self.get_or_create_test_suite(test_case.suite_name)
|
||||||
test_section = self.get_or_create_suite_section(
|
test_section = self.get_or_create_suite_section(test_suite, test_case.suite_section_name)
|
||||||
test_suite, test_case.suite_section_name
|
|
||||||
)
|
|
||||||
test_case_in_tms = self.search_test_case_id(test_case.id)
|
test_case_in_tms = self.search_test_case_id(test_case.id)
|
||||||
steps = [{"content": value, "expected": " "} for key, value in test_case.steps.items()]
|
steps = [{"content": value, "expected": " "} for key, value in test_case.steps.items()]
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
from testrail_api import TestRailAPI
|
from testrail_api import TestRailAPI
|
||||||
|
|
||||||
from frostfs_testlib.analytics.test_collector import TestCase
|
from frostfs_testlib.analytics.test_collector import TestCase
|
||||||
from frostfs_testlib.analytics.test_exporter import TestExporter
|
from frostfs_testlib.analytics.test_exporter import TСExporter
|
||||||
|
|
||||||
|
|
||||||
class TestrailExporter(TestExporter):
|
class TestrailExporter(TСExporter):
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
tr_url: str,
|
tr_url: str,
|
||||||
|
@ -62,19 +62,13 @@ class TestrailExporter(TestExporter):
|
||||||
It's help do not call TMS each time then we search test case
|
It's help do not call TMS each time then we search test case
|
||||||
"""
|
"""
|
||||||
for test_suite in self.test_suites_cache:
|
for test_suite in self.test_suites_cache:
|
||||||
self.test_cases_cache.extend(
|
self.test_cases_cache.extend(self.api.cases.get_cases(self.tr_project_id, suite_id=test_suite["id"]))
|
||||||
self.api.cases.get_cases(self.tr_project_id, suite_id=test_suite["id"])
|
|
||||||
)
|
|
||||||
|
|
||||||
def search_test_case_id(self, test_case_id: str) -> object:
|
def search_test_case_id(self, test_case_id: str) -> object:
|
||||||
"""
|
"""
|
||||||
Find test cases in TestRail (cache) by ID
|
Find test cases in TestRail (cache) by ID
|
||||||
"""
|
"""
|
||||||
test_cases = [
|
test_cases = [test_case for test_case in self.test_cases_cache if test_case["custom_autotest_name"] == test_case_id]
|
||||||
test_case
|
|
||||||
for test_case in self.test_cases_cache
|
|
||||||
if test_case["custom_autotest_name"] == test_case_id
|
|
||||||
]
|
|
||||||
|
|
||||||
if len(test_cases) > 1:
|
if len(test_cases) > 1:
|
||||||
raise RuntimeError(f"Too many results found in test rail for id {test_case_id}")
|
raise RuntimeError(f"Too many results found in test rail for id {test_case_id}")
|
||||||
|
@ -87,9 +81,7 @@ class TestrailExporter(TestExporter):
|
||||||
"""
|
"""
|
||||||
Get suite name with exact name from Testrail or create if not exist
|
Get suite name with exact name from Testrail or create if not exist
|
||||||
"""
|
"""
|
||||||
test_rail_suites = [
|
test_rail_suites = [suite for suite in self.test_suites_cache if suite["name"] == test_suite_name]
|
||||||
suite for suite in self.test_suites_cache if suite["name"] == test_suite_name
|
|
||||||
]
|
|
||||||
|
|
||||||
if not test_rail_suites:
|
if not test_rail_suites:
|
||||||
test_rail_suite = self.api.suites.add_suite(
|
test_rail_suite = self.api.suites.add_suite(
|
||||||
|
@ -102,17 +94,13 @@ class TestrailExporter(TestExporter):
|
||||||
elif len(test_rail_suites) == 1:
|
elif len(test_rail_suites) == 1:
|
||||||
return test_rail_suites.pop()
|
return test_rail_suites.pop()
|
||||||
else:
|
else:
|
||||||
raise RuntimeError(
|
raise RuntimeError(f"Too many results found in test rail for suite name {test_suite_name}")
|
||||||
f"Too many results found in test rail for suite name {test_suite_name}"
|
|
||||||
)
|
|
||||||
|
|
||||||
def get_or_create_suite_section(self, test_rail_suite, section_name) -> object:
|
def get_or_create_suite_section(self, test_rail_suite, section_name) -> object:
|
||||||
"""
|
"""
|
||||||
Get suite section with exact name from Testrail or create new one if not exist
|
Get suite section with exact name from Testrail or create new one if not exist
|
||||||
"""
|
"""
|
||||||
test_rail_sections = [
|
test_rail_sections = [section for section in test_rail_suite["sections"] if section["name"] == section_name]
|
||||||
section for section in test_rail_suite["sections"] if section["name"] == section_name
|
|
||||||
]
|
|
||||||
|
|
||||||
if not test_rail_sections:
|
if not test_rail_sections:
|
||||||
test_rail_section = self.api.sections.add_section(
|
test_rail_section = self.api.sections.add_section(
|
||||||
|
@ -128,9 +116,7 @@ class TestrailExporter(TestExporter):
|
||||||
elif len(test_rail_sections) == 1:
|
elif len(test_rail_sections) == 1:
|
||||||
return test_rail_sections.pop()
|
return test_rail_sections.pop()
|
||||||
else:
|
else:
|
||||||
raise RuntimeError(
|
raise RuntimeError(f"Too many results found in test rail for section name {section_name}")
|
||||||
f"Too many results found in test rail for section name {section_name}"
|
|
||||||
)
|
|
||||||
|
|
||||||
def prepare_request_body(self, test_case: TestCase, test_suite, test_suite_section) -> dict:
|
def prepare_request_body(self, test_case: TestCase, test_suite, test_suite_section) -> dict:
|
||||||
"""
|
"""
|
||||||
|
@ -164,9 +150,7 @@ class TestrailExporter(TestExporter):
|
||||||
|
|
||||||
self.api.cases.add_case(**request_body)
|
self.api.cases.add_case(**request_body)
|
||||||
|
|
||||||
def update_test_case(
|
def update_test_case(self, test_case: TestCase, test_case_in_tms, test_suite, test_suite_section) -> None:
|
||||||
self, test_case: TestCase, test_case_in_tms, test_suite, test_suite_section
|
|
||||||
) -> None:
|
|
||||||
"""
|
"""
|
||||||
Update test case in Testrail
|
Update test case in Testrail
|
||||||
"""
|
"""
|
||||||
|
|
35
src/frostfs_testlib/fixtures.py
Normal file
35
src/frostfs_testlib/fixtures.py
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
from importlib.metadata import entry_points
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
from frostfs_testlib import reporter
|
||||||
|
from frostfs_testlib.hosting.hosting import Hosting
|
||||||
|
from frostfs_testlib.resources.common import HOSTING_CONFIG_FILE
|
||||||
|
from frostfs_testlib.storage import get_service_registry
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="session")
|
||||||
|
def configure_testlib():
|
||||||
|
reporter.get_reporter().register_handler(reporter.AllureHandler())
|
||||||
|
reporter.get_reporter().register_handler(reporter.StepsLogger())
|
||||||
|
logging.getLogger("paramiko").setLevel(logging.INFO)
|
||||||
|
|
||||||
|
# Register Services for cluster
|
||||||
|
registry = get_service_registry()
|
||||||
|
services = entry_points(group="frostfs.testlib.services")
|
||||||
|
for svc in services:
|
||||||
|
registry.register_service(svc.name, svc.load())
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="session")
|
||||||
|
def hosting(configure_testlib) -> Hosting:
|
||||||
|
with open(HOSTING_CONFIG_FILE, "r") as file:
|
||||||
|
hosting_config = yaml.full_load(file)
|
||||||
|
|
||||||
|
hosting_instance = Hosting()
|
||||||
|
hosting_instance.configure(hosting_config)
|
||||||
|
|
||||||
|
return hosting_instance
|
|
@ -46,3 +46,8 @@ with open(DEFAULT_WALLET_CONFIG, "w") as file:
|
||||||
MAX_REQUEST_ATTEMPTS = 5
|
MAX_REQUEST_ATTEMPTS = 5
|
||||||
RETRY_MODE = "standard"
|
RETRY_MODE = "standard"
|
||||||
CREDENTIALS_CREATE_TIMEOUT = "1m"
|
CREDENTIALS_CREATE_TIMEOUT = "1m"
|
||||||
|
|
||||||
|
|
||||||
|
HOSTING_CONFIG_FILE = os.getenv(
|
||||||
|
"HOSTING_CONFIG_FILE", os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "..", ".devenv.hosting.yaml"))
|
||||||
|
)
|
||||||
|
|
Loading…
Reference in a new issue