[#363] Updates for sanity scope

Signed-off-by: a.berezin <a.berezin@yadro.com>
This commit is contained in:
Andrey Berezin 2025-01-28 13:05:59 +03:00 committed by Andrey Berezin
parent a841251e06
commit 35f60af47d
8 changed files with 14 additions and 88 deletions

View file

@ -10,6 +10,7 @@ markers =
staging: test to be excluded from run in verifier/pr-validation/sanity jobs and run test in staging job staging: test to be excluded from run in verifier/pr-validation/sanity jobs and run test in staging job
sanity: test runs in sanity testrun sanity: test runs in sanity testrun
smoke: test runs in smoke testrun smoke: test runs in smoke testrun
exclude_sanity: tests which should not be in sanity scope
# controlling markers # controlling markers
order: manual control of test order order: manual control of test order
logs_after_session: Make the last test in session logs_after_session: Make the last test in session

View file

@ -1,11 +1,10 @@
import logging import logging
import random import random
from datetime import datetime, timedelta, timezone from datetime import datetime
from typing import Optional from typing import Optional
import allure import allure
import pytest import pytest
from dateutil import parser
from frostfs_testlib import plugins, reporter from frostfs_testlib import plugins, reporter
from frostfs_testlib.cli import FrostfsCli from frostfs_testlib.cli import FrostfsCli
from frostfs_testlib.clients import AwsCliClient, Boto3ClientWrapper, S3ClientWrapper, S3HttpClient from frostfs_testlib.clients import AwsCliClient, Boto3ClientWrapper, S3ClientWrapper, S3HttpClient
@ -22,7 +21,6 @@ from frostfs_testlib.steps.cli.object import get_netmap_netinfo
from frostfs_testlib.steps.epoch import ensure_fresh_epoch from frostfs_testlib.steps.epoch import ensure_fresh_epoch
from frostfs_testlib.storage.cluster import Cluster, ClusterNode from frostfs_testlib.storage.cluster import Cluster, ClusterNode
from frostfs_testlib.storage.controllers.cluster_state_controller import ClusterStateController from frostfs_testlib.storage.controllers.cluster_state_controller import ClusterStateController
from frostfs_testlib.storage.dataclasses.frostfs_services import StorageNode
from frostfs_testlib.storage.dataclasses.object_size import ObjectSize from frostfs_testlib.storage.dataclasses.object_size import ObjectSize
from frostfs_testlib.storage.dataclasses.policy import PlacementPolicy from frostfs_testlib.storage.dataclasses.policy import PlacementPolicy
from frostfs_testlib.storage.dataclasses.wallet import WalletInfo from frostfs_testlib.storage.dataclasses.wallet import WalletInfo
@ -30,7 +28,7 @@ from frostfs_testlib.storage.grpc_operations.client_wrappers import CliClientWra
from frostfs_testlib.storage.grpc_operations.interfaces import GrpcClientWrapper from frostfs_testlib.storage.grpc_operations.interfaces import GrpcClientWrapper
from frostfs_testlib.testing.cluster_test_base import ClusterTestBase from frostfs_testlib.testing.cluster_test_base import ClusterTestBase
from frostfs_testlib.testing.parallel import parallel from frostfs_testlib.testing.parallel import parallel
from frostfs_testlib.testing.test_control import cached_fixture, run_optionally, wait_for_success from frostfs_testlib.testing.test_control import cached_fixture, run_optionally
from frostfs_testlib.utils import env_utils, string_utils, version_utils from frostfs_testlib.utils import env_utils, string_utils, version_utils
from frostfs_testlib.utils.file_utils import TestFile, generate_file from frostfs_testlib.utils.file_utils import TestFile, generate_file
@ -40,7 +38,6 @@ from ..resources.common import TEST_CYCLES_COUNT
logger = logging.getLogger("NeoLogger") logger = logging.getLogger("NeoLogger")
SERVICE_ACTIVE_TIME = 20
WALLTETS_IN_POOL = 2 WALLTETS_IN_POOL = 2
@ -155,7 +152,11 @@ def complex_object_size(max_object_size: int) -> ObjectSize:
# By default we want all tests to be executed with both object sizes # By default we want all tests to be executed with both object sizes
# This can be overriden in choosen tests if needed # This can be overriden in choosen tests if needed
@pytest.fixture( @pytest.fixture(
scope="session", params=[pytest.param("simple", marks=pytest.mark.simple), pytest.param("complex", marks=pytest.mark.complex)] scope="session",
params=[
pytest.param("simple", marks=[pytest.mark.simple, pytest.mark.exclude_sanity]),
pytest.param("complex", marks=pytest.mark.complex),
],
) )
def object_size(simple_object_size: ObjectSize, complex_object_size: ObjectSize, request: pytest.FixtureRequest) -> ObjectSize: def object_size(simple_object_size: ObjectSize, complex_object_size: ObjectSize, request: pytest.FixtureRequest) -> ObjectSize:
if request.param == "simple": if request.param == "simple":
@ -291,7 +292,7 @@ def credentials_provider(cluster: Cluster) -> CredentialsProvider:
@pytest.fixture( @pytest.fixture(
scope="session", scope="session",
params=[ params=[
pytest.param(AwsCliClient, marks=[pytest.mark.aws, pytest.mark.weekly]), pytest.param(AwsCliClient, marks=[pytest.mark.aws, pytest.mark.weekly, pytest.mark.exclude_sanity]),
pytest.param(Boto3ClientWrapper, marks=[pytest.mark.boto3, pytest.mark.nightly]), pytest.param(Boto3ClientWrapper, marks=[pytest.mark.boto3, pytest.mark.nightly]),
], ],
) )
@ -416,44 +417,11 @@ def session_start_time(configure_testlib):
return start_time return start_time
@allure.title("[Autouse/Session] After deploy healthcheck")
@pytest.fixture(scope="session", autouse=True)
@run_optionally(optionals.OPTIONAL_AUTOUSE_FIXTURES_ENABLED)
def after_deploy_healthcheck(cluster: Cluster):
with reporter.step("Wait for cluster readiness after deploy"):
parallel(readiness_on_node, cluster.cluster_nodes)
@pytest.fixture(scope="session") @pytest.fixture(scope="session")
def rpc_endpoint(cluster: Cluster): def rpc_endpoint(cluster: Cluster):
return cluster.default_rpc_endpoint return cluster.default_rpc_endpoint
@wait_for_success(60 * SERVICE_ACTIVE_TIME * 3, 60, title="Wait for {cluster_node} readiness")
def readiness_on_node(cluster_node: ClusterNode):
if "skip_readiness_check" in cluster_node.host.config.attributes and cluster_node.host.config.attributes["skip_readiness_check"]:
return
# TODO: Move to healtcheck classes
svc_name = cluster_node.service(StorageNode).get_service_systemctl_name()
with reporter.step(f"Check service {svc_name} is active"):
result = cluster_node.host.get_shell().exec(f"systemctl is-active {svc_name}")
assert "active" == result.stdout.strip(), f"Service {svc_name} should be in active state"
with reporter.step(f"Check service {svc_name} is active more than {SERVICE_ACTIVE_TIME} minutes"):
result = cluster_node.host.get_shell().exec(f"systemctl show {svc_name} --property ActiveEnterTimestamp | cut -d '=' -f 2")
start_time = parser.parse(result.stdout.strip())
current_time = datetime.now(tz=timezone.utc)
active_time = current_time - start_time
active_minutes = active_time.seconds // 60
active_seconds = active_time.seconds - active_minutes * 60
assert active_time > timedelta(
minutes=SERVICE_ACTIVE_TIME
), f"Service should be in active state more than {SERVICE_ACTIVE_TIME} minutes, current {active_minutes}m:{active_seconds}s"
@reporter.step("Prepare default user with wallet") @reporter.step("Prepare default user with wallet")
@pytest.fixture(scope="session") @pytest.fixture(scope="session")
@cached_fixture(optionals.OPTIONAL_CACHE_FIXTURES) @cached_fixture(optionals.OPTIONAL_CACHE_FIXTURES)

View file

@ -59,7 +59,7 @@ class TestContainer(ClusterTestBase):
self.tick_epoch() self.tick_epoch()
wait_for_container_deletion(wallet, cid, self.shell, rpc_endpoint) wait_for_container_deletion(wallet, cid, self.shell, rpc_endpoint)
@allure.title("Delete container without force (name={name})") @allure.title("Delete container without force")
@pytest.mark.smoke @pytest.mark.smoke
def test_container_deletion_no_force(self, container: str, default_wallet: WalletInfo, rpc_endpoint: str): def test_container_deletion_no_force(self, container: str, default_wallet: WalletInfo, rpc_endpoint: str):
with reporter.step("Delete container and check it was deleted"): with reporter.step("Delete container and check it was deleted"):
@ -68,6 +68,7 @@ class TestContainer(ClusterTestBase):
wait_for_container_deletion(default_wallet, container, self.shell, rpc_endpoint) wait_for_container_deletion(default_wallet, container, self.shell, rpc_endpoint)
@allure.title("Parallel container creation and deletion") @allure.title("Parallel container creation and deletion")
@pytest.mark.exclude_sanity
def test_container_creation_deletion_parallel(self, default_wallet: WalletInfo, rpc_endpoint: str): def test_container_creation_deletion_parallel(self, default_wallet: WalletInfo, rpc_endpoint: str):
containers_count = 3 containers_count = 3
wallet = default_wallet wallet = default_wallet

View file

@ -424,7 +424,6 @@ class TestMaintenanceMode(ClusterTestBase):
with pytest.raises(RuntimeError, match=node_under_maintenance_error): with pytest.raises(RuntimeError, match=node_under_maintenance_error):
put_object(default_wallet, file_path, cid, self.shell, endpoint) put_object(default_wallet, file_path, cid, self.shell, endpoint)
@pytest.mark.sanity
@allure.title("MAINTENANCE and OFFLINE mode transitions") @allure.title("MAINTENANCE and OFFLINE mode transitions")
def test_mode_transitions( def test_mode_transitions(
self, self,

View file

@ -314,6 +314,7 @@ class TestObjectApi(ClusterTestBase):
assert sorted(expected_oids) == sorted(result) assert sorted(expected_oids) == sorted(result)
@allure.title("Search objects with removed items (obj_size={object_size})") @allure.title("Search objects with removed items (obj_size={object_size})")
@pytest.mark.exclude_sanity
def test_object_search_should_return_tombstone_items( def test_object_search_should_return_tombstone_items(
self, self,
default_wallet: WalletInfo, default_wallet: WalletInfo,

View file

@ -22,7 +22,6 @@ OBJECT_ATTRIBUTES = {"common_key": "common_value"}
WAIT_FOR_REPLICATION = 60 WAIT_FOR_REPLICATION = 60
# Adding failover mark because it may make cluster unhealthy # Adding failover mark because it may make cluster unhealthy
@pytest.mark.sanity
@pytest.mark.failover @pytest.mark.failover
@pytest.mark.replication @pytest.mark.replication
class TestReplication(ClusterTestBase): class TestReplication(ClusterTestBase):

View file

@ -1,7 +1,6 @@
import allure import allure
import pytest import pytest
from frostfs_testlib import reporter from frostfs_testlib import reporter
from frostfs_testlib.steps.cli.object import put_object_to_random_node
from frostfs_testlib.steps.epoch import get_epoch from frostfs_testlib.steps.epoch import get_epoch
from frostfs_testlib.steps.http_gate import ( from frostfs_testlib.steps.http_gate import (
attr_into_header, attr_into_header,
@ -19,55 +18,12 @@ from frostfs_testlib.storage.dataclasses.wallet import WalletInfo
from frostfs_testlib.testing.cluster_test_base import ClusterTestBase from frostfs_testlib.testing.cluster_test_base import ClusterTestBase
from frostfs_testlib.utils.file_utils import TestFile, generate_file, get_file_hash from frostfs_testlib.utils.file_utils import TestFile, generate_file, get_file_hash
from ....helpers.container_request import REP_1_1_1_PUBLIC, REP_2_2_2_PUBLIC, requires_container from ....helpers.container_request import REP_2_2_2_PUBLIC, requires_container
from ....helpers.utility import wait_for_gc_pass_on_storage_nodes from ....helpers.utility import wait_for_gc_pass_on_storage_nodes
OBJECT_NOT_FOUND_ERROR = "not found" OBJECT_NOT_FOUND_ERROR = "not found"
@allure.link(
"https://git.frostfs.info/TrueCloudLab/frostfs-http-gw#frostfs-http-gateway",
name="frostfs-http-gateway",
)
@allure.link("https://git.frostfs.info/TrueCloudLab/frostfs-http-gw#uploading", name="uploading")
@allure.link("https://git.frostfs.info/TrueCloudLab/frostfs-http-gw#downloading", name="downloading")
@pytest.mark.nightly
@pytest.mark.sanity
@pytest.mark.http_gate
class TestHttpGate(ClusterTestBase):
@allure.title("Put over gRPC, Get over HTTP (object_size={object_size})")
@requires_container(REP_1_1_1_PUBLIC)
def test_put_grpc_get_http(self, default_wallet: WalletInfo, container: str, test_file: TestFile):
"""
Test that object can be put using gRPC interface and get using HTTP.
Steps:
1. Create object.
2. Put object using gRPC (frostfs-cli).
3. Download object using HTTP gate (https://git.frostfs.info/TrueCloudLab/frostfs-http-gw#downloading).
4. Get object using gRPC (frostfs-cli).
5. Compare hashes for got object.
6. Compare hashes for got and original objects.
Expected result:
Hashes must be the same.
"""
with reporter.step("Put object using gRPC"):
object_id = put_object_to_random_node(default_wallet, test_file.path, container, self.shell, self.cluster)
with reporter.step("Get object and check hash"):
verify_object_hash(
object_id,
test_file.path,
default_wallet,
container,
self.shell,
self.cluster.storage_nodes,
self.cluster.cluster_nodes[0],
)
@allure.link( @allure.link(
"https://git.frostfs.info/TrueCloudLab/frostfs-http-gw#frostfs-http-gateway", "https://git.frostfs.info/TrueCloudLab/frostfs-http-gw#frostfs-http-gateway",
name="frostfs-http-gateway", name="frostfs-http-gateway",

View file

@ -18,6 +18,7 @@ def _check_version_format(version):
@allure.title("Check binaries versions") @allure.title("Check binaries versions")
@pytest.mark.nightly
@pytest.mark.check_binaries @pytest.mark.check_binaries
def test_binaries_versions(hosting: Hosting): def test_binaries_versions(hosting: Hosting):
""" """