diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..afb92583 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,42 @@ +# This is a basic workflow to help you get started with Actions + +name: Unit tests + +# Controls when the workflow will run +on: + # Triggers the workflow on push or pull request events but only for the master branch + push: + branches: [ master ] + pull_request: + branches: [ master ] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + test: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Set up Python 3.12 + uses: actions/setup-python@v4 + with: + python-version: '3.12' + + - name: Install Poetry + uses: snok/install-poetry@76e04a911780d5b312d89783f7b1cd627778900a + with: + version: '1.8.3' + + - name: Install project dependencies + run: poetry install --with web-backend + + - name: Verify Docker installation + run: docker --version + + - name: Run tests + run: poetry run pytest argus diff --git a/poetry.lock b/poetry.lock index cc7c94f2..972cc2f4 100644 --- a/poetry.lock +++ b/poetry.lock @@ -27,11 +27,7 @@ files = [ [package.dependencies] lazy-object-proxy = ">=1.4.0" -typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.11\""} -wrapt = [ - {version = ">=1.11,<2", markers = "python_version < \"3.11\""}, - {version = ">=1.14,<2", markers = "python_version >= \"3.11\""}, -] +wrapt = {version = ">=1.14,<2", markers = "python_version >= \"3.11\""} [[package]] name = "asttokens" @@ -360,20 +356,6 @@ docs = ["myst-parser (==0.18.0)", "sphinx (==5.1.1)"] ssh = ["paramiko (>=2.4.3)"] websockets = ["websocket-client (>=1.3.0)"] -[[package]] -name = "exceptiongroup" -version = "1.2.1" -description = "Backport of PEP 654 (exception groups)" -optional = false -python-versions = ">=3.7" -files = [ - {file = "exceptiongroup-1.2.1-py3-none-any.whl", hash = "sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad"}, - {file = "exceptiongroup-1.2.1.tar.gz", hash = "sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16"}, -] - -[package.extras] -test = ["pytest (>=6)"] - [[package]] name = "executing" version = "2.0.1" @@ -538,7 +520,6 @@ files = [ [package.dependencies] colorama = {version = "*", markers = "sys_platform == \"win32\""} decorator = "*" -exceptiongroup = {version = "*", markers = "python_version < \"3.11\""} jedi = ">=0.16" matplotlib-inline = "*" pexpect = {version = ">4.3", markers = "sys_platform != \"win32\" and sys_platform != \"emscripten\""} @@ -546,7 +527,6 @@ prompt-toolkit = ">=3.0.41,<3.1.0" pygments = ">=2.4.0" stack-data = "*" traitlets = ">=5.13.0" -typing-extensions = {version = ">=4.6", markers = "python_version < \"3.12\""} [package.extras] all = ["ipython[black,doc,kernel,matplotlib,nbconvert,nbformat,notebook,parallel,qtconsole]", "ipython[test,test-extra]"] @@ -966,14 +946,10 @@ files = [ [package.dependencies] astroid = ">=2.15.8,<=2.17.0-dev0" colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} -dill = [ - {version = ">=0.2", markers = "python_version < \"3.11\""}, - {version = ">=0.3.6", markers = "python_version >= \"3.11\""}, -] +dill = {version = ">=0.3.6", markers = "python_version >= \"3.11\""} isort = ">=4.2.5,<6" mccabe = ">=0.6,<0.8" platformdirs = ">=2.2.0" -tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} tomlkit = ">=0.10.1" [package.extras] @@ -1305,17 +1281,6 @@ files = [ {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, ] -[[package]] -name = "tomli" -version = "2.0.1" -description = "A lil' TOML parser" -optional = false -python-versions = ">=3.7" -files = [ - {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, - {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, -] - [[package]] name = "tomlkit" version = "0.12.5" @@ -1342,17 +1307,6 @@ files = [ docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"] test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0,<8.2)", "pytest-mock", "pytest-mypy-testing"] -[[package]] -name = "typing-extensions" -version = "4.12.0" -description = "Backported and Experimental Type Hints for Python 3.8+" -optional = false -python-versions = ">=3.8" -files = [ - {file = "typing_extensions-4.12.0-py3-none-any.whl", hash = "sha256:b349c66bea9016ac22978d800cfff206d5f9816951f12a7d0ec5578b0a819594"}, - {file = "typing_extensions-4.12.0.tar.gz", hash = "sha256:8cbcdc8606ebcb0d95453ad7dc5065e6237b6aa230a31e81d0f440c30fed5fd8"}, -] - [[package]] name = "urllib3" version = "2.2.3" @@ -1526,5 +1480,5 @@ email = ["email-validator"] [metadata] lock-version = "2.0" -python-versions = "^3.10" -content-hash = "8335d42eb7590747cac26172abf8268ba429f20f4df71e5bbd37c004d2f71d9a" +python-versions = "^3.12" +content-hash = "fac2f257f66a0d9957e4c9d124c928b5504ee7a3789b0d68abb6ffab94d5e0ec" diff --git a/pyproject.toml b/pyproject.toml index 6beb19d2..09f9cb0e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,7 @@ optional = true [tool.poetry.dependencies] requests = "^2.26.0" -python = "^3.10" +python = "^3.12" click = "^8.1.3" [tool.poetry.scripts] diff --git a/tests/.gitkeep b/tests/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/conftest.py b/tests/conftest.py deleted file mode 100644 index 7a3d5d38..00000000 --- a/tests/conftest.py +++ /dev/null @@ -1,429 +0,0 @@ -from datetime import datetime, timedelta -from uuid import UUID, uuid4 -import logging -from time import sleep, time -from os import urandom -from random import choice -from subprocess import run -from unittest.mock import MagicMock -import pytest -import docker -import cassandra.cluster -import cassandra.cqlengine.management -import cassandra.cqlengine.connection -from cassandra.cqlengine import management - -from mocks.mock_cluster import MockCluster -from argus.db.testrun import TestRunInfo, TestDetails, TestResourcesSetup, TestLogs, TestResults, TestResources -from argus.db.interface import ArgusDatabase -from argus.db.config import Config -from argus.db.db_types import PackageVersion, NemesisRunInfo, EventsBySeverity, NodeDescription, TestStatus, \ - NemesisStatus, ColumnInfo, CollectionHint -from argus.db.cloud_types import AWSSetupDetails, CloudNodesInfo, CloudInstanceDetails, CloudResource, ResourceState, \ - BaseCloudSetupDetails -from argus.backend.models.web import ArgusRelease, ArgusGroup, ArgusTest - -LOGGER = logging.getLogger(__name__) - - -@pytest.fixture(scope="function") -def mock_cluster(monkeypatch): - monkeypatch.setattr(cassandra.cluster, "Cluster", MockCluster) - - -@pytest.fixture(scope="function") -def mock_cql_engine(monkeypatch): - monkeypatch.setattr(cassandra.cqlengine.connection, "register_connection", MagicMock()) - monkeypatch.setattr(cassandra.cqlengine.management, "sync_table", MagicMock()) - - -@pytest.fixture(scope="function") -def argus_interface_default(): - database = ArgusDatabase.get() - yield database - database.destroy() - - -@pytest.fixture(scope="function") -def preset_test_resource_setup(): - sct_runner_info = CloudInstanceDetails(public_ip="1.1.1.1", region="us-east-1", - provider="aws", private_ip="10.10.10.1", creation_time=7734) - db_node = CloudNodesInfo(image_id="ami-abcdef99", instance_type="spot", - node_amount=6, post_behaviour="keep-on-failure") - loader_node = CloudNodesInfo(image_id="ami-deadbeef", instance_type="spot", - node_amount=2, post_behaviour="terminate") - monitor_node = CloudNodesInfo(image_id="ami-abdcef60", instance_type="spot", - node_amount=1, post_behaviour="keep-on-failure") - - aws_setup = AWSSetupDetails(db_node=db_node, loader_node=loader_node, monitor_node=monitor_node) - - setup = TestResourcesSetup(sct_runner_host=sct_runner_info, region_name=["us-east-1"], - cloud_setup=aws_setup) - - return setup - - -@pytest.fixture(scope="function") -def preset_test_resources_setup_schema(): - return { - "sct_runner_host": ColumnInfo(name="sct_runner_host", type=CloudInstanceDetails, value=None, constraints=[]), - "region_name": ColumnInfo(name="region_name", type=CollectionHint, value=CollectionHint(list[str]), - constraints=[]), - "cloud_setup": ColumnInfo(name="cloud_setup", type=BaseCloudSetupDetails, value=None, constraints=[]), - } - - -@pytest.fixture(scope="function") -def preset_test_resources_setup_serialized(): - return { - "sct_runner_host": { - "public_ip": "1.1.1.1", - "region": "us-east-1", - "provider": "aws", - "private_ip": "10.10.10.1", - "creation_time": 7734, - "termination_time": 0, - "termination_reason": "", - "shards_amount": 0, - - }, - "region_name": ["us-east-1"], - "cloud_setup": { - "backend": "aws", - "db_node": { - "image_id": "ami-abcdef99", - "instance_type": "spot", - "node_amount": 6, - "post_behaviour": "keep-on-failure", - }, - "loader_node": { - "image_id": "ami-deadbeef", - "instance_type": "spot", - "node_amount": 2, - "post_behaviour": "terminate", - }, - "monitor_node": { - "image_id": "ami-abdcef60", - "instance_type": "spot", - "node_amount": 1, - "post_behaviour": "keep-on-failure", - }, - } - } - - -@pytest.fixture(scope="function") -def preset_test_details(): - details = TestDetails(scm_revision_id="abcde", started_by="someone", - build_job_url="https://job.tld/1", start_time=datetime.utcfromtimestamp(1600000000), yaml_test_duration=120, - config_files=["some-test.yaml"], scylla_version="4.0-rc1", - packages=[PackageVersion(name="package-server", version="1.0", date="2021-10-01", - revision_id="dfcedb3", build_id="dfeeeffffff330fddd")]) - return details - - -@pytest.fixture(scope="function") -def preset_test_details_schema(): - return { - "scm_revision_id": ColumnInfo(name="scm_revision_id", type=str, value=None, constraints=[]), - "started_by": ColumnInfo(name="started_by", type=str, value=None, constraints=[]), - "build_job_url": ColumnInfo(name="build_job_url", type=str, value=None, constraints=[]), - "start_time": ColumnInfo(name="start_time", type=datetime, value=None, constraints=[]), - "yaml_test_duration": ColumnInfo(name="yaml_test_duration", type=int, value=None, constraints=[]), - "config_files": ColumnInfo(name="config_files", type=CollectionHint, value=CollectionHint(list[str]), - constraints=[]), - "packages": ColumnInfo(name="packages", type=CollectionHint, value=CollectionHint(list[PackageVersion]), - constraints=[]), - "scylla_version": ColumnInfo(name="scylla_version", type=str, value=None, - constraints=[]), - "end_time": ColumnInfo(name="end_time", type=datetime, value=None, constraints=[]) - } - - -@pytest.fixture(scope="function") -def preset_test_details_serialized(): - return { - "scm_revision_id": "abcde", - "started_by": "someone", - "build_job_url": "https://job.tld/1", - "start_time": datetime.utcfromtimestamp(1600000000), - "yaml_test_duration": 120, - "config_files": ["some-test.yaml"], - "packages": [{ - "name": "package-server", - "version": "1.0", - "date": "2021-10-01", - "revision_id": "dfcedb3", - "build_id": "dfeeeffffff330fddd", - }], - "scylla_version": "4.0-rc1", - "end_time": datetime(1970, 1, 1, 0, 0), - } - - -@pytest.fixture(scope="function") -def preset_test_logs(): - logs = TestLogs() - logs.add_log(log_type="example", log_url="http://example.com") - - return logs - - -@pytest.fixture(scope="function") -def preset_test_logs_schema(): - return { - "logs": ColumnInfo(name="logs", type=CollectionHint, value=CollectionHint(list[tuple[str, str]]), - constraints=[]) - } - - -@pytest.fixture(scope="function") -def preset_test_logs_serialized(): - return { - "logs": [("example", "http://example.com")] - } - - -@pytest.fixture(scope="function") -def preset_test_resources(): - resources = TestResources() - - instance_info = CloudInstanceDetails(public_ip="1.1.1.1", region="us-east-1", - provider="aws", private_ip="10.10.10.1", creation_time=7734, shards_amount=10,) - resource = CloudResource(name="example_resource", state=ResourceState.RUNNING, - instance_info=instance_info, resource_type="example_type") - - resources.attach_resource(resource) - - return resources - - -@pytest.fixture(scope="function") -def preset_test_resources_schema(): - return { - "allocated_resources": ColumnInfo(name="allocated_resources", type=CollectionHint, - value=CollectionHint(list[CloudResource]), constraints=[]), - } - - -@pytest.fixture(scope="function") -def preset_test_resources_serialized(): - return { - "allocated_resources": [{ - "name": "example_resource", - "state": "running", - "resource_type": "example_type", - "instance_info": { - "public_ip": "1.1.1.1", - "region": "us-east-1", - "provider": "aws", - "private_ip": "10.10.10.1", - "creation_time": 7734, - "termination_time": 0, - "termination_reason": "", - "shards_amount": 10, - } - }], - } - - -@pytest.fixture(scope="function") -def preset_test_results(): - results = TestResults(TestStatus.CREATED) - - node_description = NodeDescription(ip="1.1.1.1", shards=10, name="example_node") - nemesis = NemesisRunInfo("Nemesis", "disrupt_everything", 100, target_node=node_description, - status=NemesisStatus.RUNNING, - start_time=16000) - - nemesis.complete("Something went wrong...") - - results.add_event(event_severity="ERROR", event_message="Something went wrong...") - results.add_nemesis(nemesis=nemesis) - results.add_screenshot("https://example.com/screenshot.jpg") - results.status = TestStatus.FAILED - return results - - -@pytest.fixture(scope="function") -def preset_test_results_schema(): - return { - "status": ColumnInfo(name="status", type=str, value=None, constraints=[]), - "events": ColumnInfo(name="events", type=CollectionHint, value=CollectionHint(list[EventsBySeverity]), - constraints=[]), - "nemesis_data": ColumnInfo(name="nemesis_data", type=CollectionHint, - value=CollectionHint(list[NemesisRunInfo]), constraints=[]), - "screenshots": ColumnInfo(name="screenshots", type=CollectionHint, - value=CollectionHint(list[str]), constraints=[]), - } - - -@pytest.fixture(scope="function") -def preset_test_results_serialized(): - return { - "status": "failed", - "events": [ - { - "severity": "ERROR", - "event_amount": 1, - "last_events": ["Something went wrong..."] - } - ], - "nemesis_data": [ - { - "class_name": "Nemesis", - "name": "disrupt_everything", - "duration": 100, - "target_node": { - "ip": "1.1.1.1", - "shards": 10, - "name": "example_node", - }, - "status": "failed", - "start_time": 16000, - "end_time": 16001, - "stack_trace": "Something went wrong..." - } - ], - "screenshots": [ - "https://example.com/screenshot.jpg", - ] - } - - -@pytest.fixture(scope="function") -def simple_primary_key(): - return { - "$tablekeys$": { - "id": (UUID, "partition"), - "timer": (int, "clustering"), - }, - "$clustering_order$": { - "id": "DESC" - }, - "$indices$": { - - } - } - - -@pytest.fixture(scope="function") -def completed_testrun(preset_test_resource_setup: TestResourcesSetup): # pylint: disable=redefined-outer-name - # pylint: disable=too-many-locals - scylla_package = PackageVersion("scylla-db", "4.4", "20210901", "deadbeef") - details = TestDetails(scm_revision_id="773413dead", started_by="k0machi", - build_job_url="https://notarealjob.url/jobs/argus-test/argus/argus-testing", - start_time=(datetime.utcnow() - timedelta(hours=1)).replace(microsecond=0), yaml_test_duration=240, config_files=["tests/config.yaml"], - packages=[scylla_package]) - details.set_test_end_time() - setup = preset_test_resource_setup - logs = TestLogs() - logs.add_log(log_type="syslog", log_url="https://thisisdefinitelyans3bucket.com/logz-abcdef331.tar.gz") - resources = TestResources() - - created_resources = [] - - for requested_node in [setup.cloud_setup.db_node, setup.cloud_setup.loader_node, setup.cloud_setup.monitor_node]: - for node_number in range(1, requested_node.node_amount + 1): - entropy = urandom(4).hex(sep=":", bytes_per_sep=1).split(":") - random_ip = ".".join([str(int(byte, 16)) for byte in entropy]) - instance_details = CloudInstanceDetails(public_ip=random_ip, provider="aws", region="us-east-1", - private_ip="10.10.10.1", shards_amount=8) - resource = CloudResource(name=f"argus-testing_{requested_node.instance_type}_{node_number}", - state=ResourceState.RUNNING, instance_info=instance_details, - resource_type="db-node") - resources.attach_resource(resource) - created_resources.append(resource) - - terminated = choice(created_resources) - resources.detach_resource(terminated, reason="Test reason") - - nemeses_names = ["SisyphusMonkey", "ChaosMonkey", "NotVeryCoolMonkey"] - nemesis_runs = [] - - for _ in range(6): - node = choice(resources.allocated_resources) - node_description = NodeDescription(name=node.name, ip=node.instance_info.public_ip, shards=10) - nemesis = NemesisRunInfo( - class_name=choice(nemeses_names), - name="disrupt_something", - duration=42, - target_node=node_description, - status=NemesisStatus.SUCCEEDED, - start_time=int(time()), - end_time=int(time() + 30), - ) - nemesis_runs.append(nemesis) - - events = EventsBySeverity(severity="INFO", event_amount=66000, last_events=["Nothing here after all"]) - screenshots = ["https://example.com/screenshot.jpg"] - results = TestResults(status=TestStatus.PASSED, nemesis_data=nemesis_runs, - events=[events], screenshots=screenshots) - - run_info = TestRunInfo(details=details, setup=setup, logs=logs, resources=resources, results=results) - - return run_info - - -@pytest.fixture(scope="class") -def scylla_cluster() -> list[str]: - docker_session = docker.from_env() - prefix = "pytest_scylla_cluster" - LOGGER.info("Starting docker cluster...") - cluster_start = run(args=[ - "docker-compose", - "-p", prefix, - "-f", "tests/scylladb-cluster/docker-compose.yml", - "up", - "-d" - ], check=True, capture_output=True) - LOGGER.info("Started docker cluster.\nSTDOUT:\n%s", cluster_start.stdout.decode(encoding="utf-8")) - interval = 90 - LOGGER.info("Sleeping for %s seconds to let cluster catch up", interval) - sleep(interval) - all_containers = docker_session.containers.list(all=True) - cluster = [container for container in all_containers if container.name.startswith("pytest_scylla_cluster")] - contact_points = [node.attrs["NetworkSettings"]["Networks"][f"{prefix}_scylla_bridge"]["IPAddress"] for node in - cluster] - LOGGER.debug("Contact points: %s", contact_points) - yield contact_points - LOGGER.info("Stopping docker cluster...") - cluster_stop = run(args=[ - "docker-compose", - "-p", prefix, - "-f", "tests/scylladb-cluster/docker-compose.yml", - "down" - ], check=True, capture_output=True) - LOGGER.info("Stopped docker cluster.\nSTDOUT:\n%s", cluster_stop.stdout.decode(encoding="utf-8")) - - -@pytest.fixture(scope="class") -def argus_database(scylla_cluster: list[str]): # pylint: disable=redefined-outer-name - config = Config(username="scylla", password="scylla", contact_points=scylla_cluster, keyspace_name="argus_testruns") - database = ArgusDatabase.from_config(config) - yield database - ArgusDatabase.destroy() - - -@pytest.fixture(scope="class") -def argus_with_release(argus_database: ArgusDatabase) -> tuple[ArgusDatabase, tuple[ArgusRelease, ArgusGroup, ArgusTest]]: - for model in [ArgusTest, ArgusGroup, ArgusRelease]: - management.sync_table(model, keyspaces=(argus_database._current_keyspace,), - connections=(argus_database.CQL_ENGINE_CONNECTION_NAME,)) - release = ArgusRelease() - release.name = "argus-test" - release.using(connection=argus_database.CQL_ENGINE_CONNECTION_NAME).save() - - group = ArgusGroup() - group.name = 'arbitrary-group' - group.release_id = release.id - group.using(connection=argus_database.CQL_ENGINE_CONNECTION_NAME).save() - - test = ArgusTest() - test.name = 'argus-testing' - test.group_id = group.id - test.release_id = release.id - test.build_system_id = 'argus-test/argus/argus-testing' - test.using(connection=argus_database.CQL_ENGINE_CONNECTION_NAME).save() - - return argus_database, (release, group, test) diff --git a/tests/mocks/.gitkeep b/tests/mocks/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/mocks/mock_cluster.py b/tests/mocks/mock_cluster.py deleted file mode 100644 index 263b0e2d..00000000 --- a/tests/mocks/mock_cluster.py +++ /dev/null @@ -1,79 +0,0 @@ -import logging -from typing import Union, Any -from cassandra.auth import AuthProvider - -LOGGER = logging.getLogger(__name__) - - -class MockPreparedStatement: - def __init__(self, query: str): - self.log = logging.getLogger(self.__class__.__name__) - self.query_string = query - self.parameters = None - - def bind(self, parameters: Union[tuple, list]): - self.parameters = parameters - - def query(self): - return self.query_string - - -class MockCluster(): - MOCK_NO_CONNECTION = False - - def __init__(self, contact_points: tuple[str] = None, auth_provider: AuthProvider = None, load_balancing_policy=None, - execution_profiles=None, *args, **kwargs): - self.contact_points = contact_points - self.log = logging.getLogger(self.__class__.__name__) - self.sessions = [] - self.load_balancing_policy = load_balancing_policy - self.auth_provider = auth_provider - self.execution_profiles = execution_profiles - - def connect(self): - self.log.info("Connecting to cluster: %s", self.contact_points) - if self.MOCK_NO_CONNECTION: - raise OSError("timed out") - session = MockSession(hosts=self.contact_points, cluster=self) - self.sessions.append(session) - return session - - def shutdown(self): - for sess in self.sessions: - sess.shutdown() - return True - - -class MockSession(): - MOCK_RESULT_SET = None - MOCK_CURRENT_KEYSPACE = None - MOCK_LAST_QUERY: Any = None - - def __init__(self, hosts=None, cluster=None, *args, **kwargs): - self.hosts = hosts - self.cluster = cluster - self.log = logging.getLogger(self.__class__.__name__) - self.executed_queries = [] - self.prepared_statements = [] - self.keyspace = None - self.is_shutdown = False - - def shutdown(self): - self.log.info("Shutting down session %s... ", hex(id(self))) - self.is_shutdown = True - - def prepare(self, query: str): - self.log.info("Prepare statement added: %s", query) - self.prepared_statements.append(query) - return MockPreparedStatement(query) - - def execute(self, query: Union[str, MockPreparedStatement], parameters: Union[tuple, list] = None, execution_profile="default", timeout=0): - self.log.info("Executing query %s with parameters: %s, using profile %s", query, parameters, execution_profile) - self.executed_queries.append((query, parameters)) - self.__class__.MOCK_LAST_QUERY = (query, parameters) - return self.MOCK_RESULT_SET - - def set_keyspace(self, keyspace: str): - self.log.info("Setting keyspace to %s", keyspace) - self.keyspace = keyspace - self.__class__.MOCK_CURRENT_KEYSPACE = keyspace diff --git a/tests/scylladb-cluster/docker-compose.yml b/tests/scylladb-cluster/docker-compose.yml deleted file mode 100644 index 2dfcb448..00000000 --- a/tests/scylladb-cluster/docker-compose.yml +++ /dev/null @@ -1,27 +0,0 @@ -version: "3.7" -services: - scylla-a: - image: "scylladb/scylla:4.5.2" - networks: - scylla_bridge: - aliases: - - initialnode - command: --smp 1 --overprovisioned 1 - - scylla-b: - image: "scylladb/scylla:4.5.2" - networks: - scylla_bridge: - depends_on: - - scylla-a - command: --smp 1 --overprovisioned 1 --seeds="initialnode" - scylla-c: - image: "scylladb/scylla:4.5.2" - networks: - scylla_bridge: - depends_on: - - scylla-a - command: --smp 1 --overprovisioned 1 --seeds="initialnode" -networks: - scylla_bridge: - driver: bridge diff --git a/tests/test_cloud_types.py b/tests/test_cloud_types.py deleted file mode 100644 index efbd2ed5..00000000 --- a/tests/test_cloud_types.py +++ /dev/null @@ -1,36 +0,0 @@ -import pytest -from pydantic import ValidationError -from argus.db.cloud_types import CloudResource, CloudInstanceDetails, ResourceState - - -def test_cloud_instance_details_ip_validation_valid_ip(): - instance_info = CloudInstanceDetails(provider="aws", region="eu-west-1", public_ip="127.0.0.1", - private_ip="10.10.10.1") - - assert instance_info.public_ip == "127.0.0.1" and instance_info.private_ip == "10.10.10.1" - - -def test_cloud_instance_details_ip_validation_invalid_ip(): - with pytest.raises(ValidationError): - CloudInstanceDetails(provider="aws", region="eu-west-1", public_ip="iodizing", private_ip="although") - - -def test_cloud_instance_details_ip_validation_valid_notation_invalid_octects(): - with pytest.raises(ValidationError): - CloudInstanceDetails(provider="aws", region="eu-west-1", public_ip="256.725.513.999", - private_ip="521.231.132.5436") - - -def test_cloud_resource_enum_only_state(): - instance_info = CloudInstanceDetails(provider="aws", region="eu-west-1", public_ip="127.0.0.1", - private_ip="10.10.10.1") - with pytest.raises(ValidationError): - CloudResource(name="test", state="ASPARAGUS", instance_info=instance_info, resource_type="test type") - - -def test_cloud_resource_state_coercion(): - instance_info = CloudInstanceDetails(provider="aws", region="eu-west-1", public_ip="127.0.0.1", - private_ip="10.10.10.1") - resource = CloudResource(name="test", state="running", instance_info=instance_info, resource_type="test type") - - assert resource.state == ResourceState.RUNNING diff --git a/tests/test_db_interface.py b/tests/test_db_interface.py deleted file mode 100644 index 54020e9a..00000000 --- a/tests/test_db_interface.py +++ /dev/null @@ -1,167 +0,0 @@ -import json -from uuid import UUID, uuid4 -import logging - -import pytest -from mocks.mock_cluster import MockSession -from argus.db.config import Config -from argus.db.interface import ArgusDatabase, ArgusInterfaceNameError, \ - ArgusInterfaceSchemaError - -LOGGER = logging.getLogger(__name__) - - -def test_interface_connection(mock_cluster, mock_cql_engine): # pylint: disable=unused-argument - database = ArgusDatabase.get() - assert not database.session.is_shutdown - ArgusDatabase.destroy() - assert database.session.is_shutdown - - -def test_interface_from_config(mock_cluster, mock_cql_engine): # pylint: disable=unused-argument - database = ArgusDatabase.from_config( - config=Config(username="a", password="a", contact_points=["127.0.0.1", "127.0.0.2", "127.0.0.3"], - keyspace_name="example")) - database.destroy() - - assert MockSession.MOCK_CURRENT_KEYSPACE == "example" - - -def test_interface_is_singleton(mock_cluster, mock_cql_engine, argus_interface_default): # pylint: disable=unused-argument - database = ArgusDatabase.get() - - assert id(argus_interface_default) == id(database) - - -def test_inteface_supported_types(mock_cluster, mock_cql_engine, argus_interface_default): # pylint: disable=unused-argument - for typecls in [int, float, str, UUID]: - assert argus_interface_default.is_native_type(typecls) - - -def test_interface_schema_init(mock_cluster, mock_cql_engine, preset_test_details_schema, simple_primary_key, argus_interface_default): - # pylint: disable=unused-argument - schema = { - **simple_primary_key, - **preset_test_details_schema, - } - - argus_interface_default.init_table("test_table", schema) - # pylint: disable=unsubscriptable-object - assert MockSession.MOCK_LAST_QUERY[0] == "CREATE TABLE IF NOT EXISTS test_table" \ - "(scm_revision_id varchar , started_by varchar , " \ - "build_job_url varchar , start_time timestamp ," \ - " yaml_test_duration varint , config_files list , " \ - "packages list> , " \ - "scylla_version varchar , end_time timestamp , " \ - "PRIMARY KEY (id, timer)) WITH CLUSTERING ORDER BY (id DESC)" - - -def test_interface_init_table_twice(mock_cluster, mock_cql_engine, preset_test_details_schema, simple_primary_key, - argus_interface_default): - # pylint: disable=unused-argument - schema = { - **simple_primary_key, - **preset_test_details_schema, - } - - argus_interface_default.init_table("test_table", schema) - second_result = argus_interface_default.init_table("test_table", schema) - - assert second_result[1] == "Table test_table already initialized" - - -def test_interface_prepare_cache(mock_cluster, mock_cql_engine, argus_interface_default): # pylint: disable=unused-argument - statement = argus_interface_default.prepare_query_for_table("example", "test", "SELECT * FROM example") - cached_statement = argus_interface_default.prepared_statements.get("example_test") - - assert id(statement) == id(cached_statement) - - -def test_interface_keyspace_naming(mock_cluster, mock_cql_engine): # pylint: disable=unused-argument - with pytest.raises(ArgusInterfaceNameError): - ArgusDatabase.from_config( - Config(username="a", password="b", contact_points=["127.0.0.1"], keyspace_name="has.a.dot")) - - -def test_interface_fetch(monkeypatch, mock_cluster, mock_cql_engine, argus_interface_default): # pylint: disable=unused-argument - class ResultSet: - # pylint: disable=too-few-public-methods - @staticmethod - def one(): - return True - - monkeypatch.setattr(MockSession, "MOCK_RESULT_SET", ResultSet()) - result = argus_interface_default.fetch("example", uuid4()) - - assert result - - -def test_interface_fetch_non_existing(monkeypatch, mock_cluster, mock_cql_engine, argus_interface_default): - # pylint: disable=unused-argument - class ResultSet: - # pylint: disable=too-few-public-methods - @staticmethod - def one(): - return None - - monkeypatch.setattr(MockSession, "MOCK_RESULT_SET", ResultSet()) - - result = argus_interface_default.fetch("example", uuid4()) - assert not result - - -def test_interface_insert(mock_cluster, mock_cql_engine, argus_interface_default): # pylint: disable=unused-argument - data = { - "id": str(uuid4()), - "column": "value", - "number": 30, - "float": 1.5, - "list": [1, 2, 3], - } - argus_interface_default.insert("example", data) - parameters = MockSession.MOCK_LAST_QUERY[1][0] # pylint: disable=unsubscriptable-object - - assert json.loads(parameters) == data - - -def test_interface_update(mock_cluster, mock_cql_engine, simple_primary_key, preset_test_details_schema, preset_test_details_serialized, - argus_interface_default): - # pylint: disable=unused-argument - schema = { - **simple_primary_key, - **preset_test_details_schema, - } - - argus_interface_default.init_table("test_table", schema) - test_id = str(uuid4()) - data = { - "id": test_id, - "timer": 42, - **preset_test_details_serialized - } - - argus_interface_default.update("test_table", data) - assert str(MockSession.MOCK_LAST_QUERY[1][-2:][0]) == test_id # pylint: disable=unsubscriptable-object - - -def test_interface_update_uninitialized_table(mock_cluster, mock_cql_engine, simple_primary_key, preset_test_details_schema, - preset_test_details_serialized, argus_interface_default): - # pylint: disable=unused-argument - with pytest.raises(ArgusInterfaceSchemaError): - argus_interface_default.update("test_table", {}) - - -def test_interface_update_missing_primary_keys(mock_cluster, mock_cql_engine, simple_primary_key, preset_test_details_schema, - preset_test_details_serialized, argus_interface_default): - # pylint: disable=unused-argument - schema = { - **simple_primary_key, - **preset_test_details_schema, - } - - argus_interface_default.init_table("test_table", schema) - data = { - **preset_test_details_serialized - } - with pytest.raises(ArgusInterfaceSchemaError): - argus_interface_default.update("test_table", data) diff --git a/tests/test_db_types.py b/tests/test_db_types.py deleted file mode 100644 index 03b65480..00000000 --- a/tests/test_db_types.py +++ /dev/null @@ -1,93 +0,0 @@ -import pytest -from argus.db.db_types import NodeDescription, NemesisStatus, NemesisRunInfo -from pydantic import ValidationError -from dataclasses import asdict -from collections import namedtuple -from time import time - - -def test_node_description(): - node = NodeDescription(name="test", ip="1.1.1.1", shards=10) - assert asdict(node) == { - "name": "test", - "ip": "1.1.1.1", - "shards": 10, - } - - -def test_node_description_invalid_ip_address(): - with pytest.raises(ValidationError): - NodeDescription(name="test", ip="666.666.666.666", shards=10) - - -def test_node_description_recreate_from_udt_set(): - nodedescription = namedtuple("NodeDescription", ["name", "ip", "shards"]) - udt = nodedescription(name="test", ip="1.1.1.1", shards=10) - node = NodeDescription.from_db_udt(udt) - - assert asdict(node) == udt._asdict() - - -def test_nemesis_run_info(): - start_time = int(time()) - nem_dict = { - "class_name": "SisyphusMonkey", - "name": "disrupt_me", - "duration": 400, - "target_node": { - "name": "test", - "ip": "1.1.1.1", - "shards": 10, - }, - "status": "started", - "start_time": start_time, - "end_time": 0, - "stack_trace": "" - } - node = NodeDescription(name="test", ip="1.1.1.1", shards=10) - nem = NemesisRunInfo("SisyphusMonkey", "disrupt_me", 400, target_node=node, status=NemesisStatus.STARTED, - start_time=start_time) - - assert asdict(nem) == nem_dict - - -def test_nemesis_run_complete_success(): - start_time = int(time()) - node = NodeDescription(name="test", ip="1.1.1.1", shards=10) - nem = NemesisRunInfo("SisyphusMonkey", "disrupt_me", 400, target_node=node, status=NemesisStatus.STARTED, - start_time=start_time) - - nem.complete() - - assert nem.nemesis_status == NemesisStatus.SUCCEEDED - - -def test_nemesis_run_complete_failure(): - start_time = int(time()) - node = NodeDescription(name="test", ip="1.1.1.1", shards=10) - nem = NemesisRunInfo("SisyphusMonkey", "disrupt_me", 400, target_node=node, status=NemesisStatus.STARTED, - start_time=start_time) - traceback = "Traceback: something happened" - nem.complete(traceback) - - assert nem.nemesis_status == NemesisStatus.FAILED and nem.stack_trace == traceback - - -def test_nemesis_run_state_enumerated_only(): - start_time = int(time()) - node = NodeDescription(name="test", ip="1.1.1.1", shards=10) - nem = NemesisRunInfo("SisyphusMonkey", "disrupt_me", 400, target_node=node, status=NemesisStatus.STARTED, - start_time=start_time) - with pytest.raises(ValueError): - nem.nemesis_status = "AGJKSDHGKJSG" - - -def test_nemesis_run_state_valid_enum_coercible(): - start_time = int(time()) - node = NodeDescription(name="test", ip="1.1.1.1", shards=10) - nem = NemesisRunInfo("SisyphusMonkey", "disrupt_me", 400, target_node=node, status=NemesisStatus.STARTED, - start_time=start_time) - - nem.nemesis_status = "running" - - assert nem.nemesis_status == NemesisStatus.RUNNING diff --git a/tests/test_e2e_argus.py b/tests/test_e2e_argus.py deleted file mode 100644 index df880998..00000000 --- a/tests/test_e2e_argus.py +++ /dev/null @@ -1,172 +0,0 @@ -from random import choice -import datetime -import logging -from time import sleep -from uuid import uuid4, UUID -import pytest -from argus.db.testrun import TestRun, TestRunInfo, TestRunWithHeartbeat -from argus.db.db_types import TestInvestigationStatus -from argus.db.interface import ArgusDatabase -from argus.backend.models.web import ArgusRelease, ArgusGroup, ArgusTest, ArgusSchedule, ArgusScheduleAssignee, \ - ArgusScheduleGroup, ArgusScheduleTest - -LOGGER = logging.getLogger(__name__) - - -class TestEndToEnd: - @staticmethod - @pytest.mark.docker_required - def test_serialize_deserialize(completed_testrun: TestRunInfo, argus_database: ArgusDatabase): - TestRun.set_argus(argus_database) - test_id = uuid4() - test_run = TestRun(test_id=test_id, build_id='argus-test/argus/argus-testing', assignee=None, - run_info=completed_testrun, investigation_status=TestInvestigationStatus.INVESTIGATED) - - test_run.save() - - res = argus_database.fetch(table_name=TestRun.table_name(), run_id=test_id) - LOGGER.debug("Fetched: %s", res) - LOGGER.info("Rebuilding object...") - - rebuilt_test_run = TestRun.from_db_row(res) - - assert rebuilt_test_run.serialize() == test_run.serialize() - - @staticmethod - @pytest.mark.docker_required - def test_recreate_from_id(completed_testrun: TestRunInfo, argus_database: ArgusDatabase): - TestRun.set_argus(argus_database) - test_id = uuid4() - test_run = TestRun(test_id=test_id, build_id='argus-test/argus/argus-testing', assignee=None, - run_info=completed_testrun, investigation_status=TestInvestigationStatus.INVESTIGATED) - - test_run.save() - - rebuilt_test_run = TestRun.from_id(test_id) - - assert rebuilt_test_run.serialize() == test_run.serialize() - - @staticmethod - @pytest.mark.docker_required - def test_heartbeat_thread(completed_testrun: TestRunInfo, argus_database: ArgusDatabase): - TestRunWithHeartbeat.set_argus(argus_database) - test_id = uuid4() - test_run = TestRunWithHeartbeat(test_id=test_id, build_id='argus-test/argus/argus-testing', assignee=None, - run_info=completed_testrun, investigation_status=TestInvestigationStatus.INVESTIGATED, - heartbeat_interval=8) - - test_run.save() - sleep(test_run.heartbeat_interval + test_run.heartbeat_interval // 2) - new_heartbeat = argus_database.session.execute(f"SELECT heartbeat FROM {TestRun.table_name()} WHERE id = %s", - parameters=(test_run.id,)).one()["heartbeat"] - # pylint: disable=protected-access - test_run._shutdown_event.set() - LOGGER.info("Awaiting heartbeat thread exit") - test_run.thread.join(timeout=10) - assert new_heartbeat == test_run.heartbeat - - @staticmethod - @pytest.mark.docker_required - def test_update(completed_testrun: TestRunInfo, argus_database: ArgusDatabase): - TestRun.set_argus(argus_database) - test_id = uuid4() - test_run = TestRun(test_id=test_id, build_id='argus-test/argus/argus-testing', assignee=None, - run_info=completed_testrun, investigation_status=TestInvestigationStatus.INVESTIGATED) - test_run.save() - - resource = choice(test_run.run_info.resources.allocated_resources) - test_run.run_info.resources.detach_resource(resource) - test_run.save() - - row = argus_database.fetch(table_name=TestRun.table_name(), run_id=test_id) - - rebuilt_testrun = TestRun.from_db_row(row) - - assert test_run.serialize() == rebuilt_testrun.serialize() - - @staticmethod - @pytest.mark.docker_required - def test_auto_assign_run_by_group(completed_testrun: TestRunInfo, - argus_with_release: tuple[ArgusDatabase, tuple[ArgusRelease, ArgusGroup, ArgusTest]]): - group_assignee_user = uuid4() - argus_database, [release, group, test] = argus_with_release - - today = datetime.datetime.utcnow() - this_monday = today - datetime.timedelta(today.weekday() + 1) - next_week = this_monday + datetime.timedelta(8) - - schedule = ArgusSchedule() - schedule.release_id = release.id - schedule.period_start = this_monday - schedule.period_end = next_week - schedule.using(connection=argus_database.CQL_ENGINE_CONNECTION_NAME).save() - - scheduled_group = ArgusScheduleGroup() - scheduled_group.schedule_id = schedule.id - scheduled_group.release_id = release.id - scheduled_group.group_id = group.id - scheduled_group.using(connection=argus_database.CQL_ENGINE_CONNECTION_NAME).save() - - scheduled_assignee = ArgusScheduleAssignee() - scheduled_assignee.schedule_id = schedule.id - scheduled_assignee.release_id = release.id - scheduled_assignee.assignee = group_assignee_user - scheduled_assignee.using(connection=argus_database.CQL_ENGINE_CONNECTION_NAME).save() - - TestRun.set_argus(argus_database) - test_id = uuid4() - test_run = TestRun(test_id=test_id, build_id=test.build_system_id, assignee=None, - run_info=completed_testrun, investigation_status=TestInvestigationStatus.INVESTIGATED) - test_run.save() - assert group_assignee_user == test_run.assignee - - row = argus_database.fetch(table_name=TestRun.table_name(), run_id=test_id) - rebuilt_testrun = TestRun.from_db_row(row) - assert group_assignee_user == rebuilt_testrun.assignee - - scheduled_assignee.using(connection=argus_database.CQL_ENGINE_CONNECTION_NAME).delete() - scheduled_group.using(connection=argus_database.CQL_ENGINE_CONNECTION_NAME).delete() - schedule.using(connection=argus_database.CQL_ENGINE_CONNECTION_NAME).delete() - - @staticmethod - @pytest.mark.docker_required - def test_auto_assign_run_by_test_name(completed_testrun: TestRunInfo, - argus_with_release: tuple[ArgusDatabase, tuple[ArgusRelease, ArgusGroup, ArgusTest]]): - test_assignee_user = uuid4() - argus_database, [release, _, test] = argus_with_release - - today = datetime.datetime.utcnow() - this_monday = today - datetime.timedelta(today.weekday() + 1) - next_week = this_monday + datetime.timedelta(8) - - schedule = ArgusSchedule() - schedule.release_id = release.id - schedule.period_start = this_monday - schedule.period_end = next_week - schedule.using(connection=argus_database.CQL_ENGINE_CONNECTION_NAME).save() - - scheduled_test = ArgusScheduleTest() - scheduled_test.schedule_id = schedule.id - scheduled_test.release_id = release.id - scheduled_test.test_id = test.id - scheduled_test.using(connection=argus_database.CQL_ENGINE_CONNECTION_NAME).save() - - scheduled_assignee = ArgusScheduleAssignee() - scheduled_assignee.schedule_id = schedule.id - scheduled_assignee.release_id = release.id - scheduled_assignee.assignee = test_assignee_user - scheduled_assignee.using(connection=argus_database.CQL_ENGINE_CONNECTION_NAME).save() - - TestRun.set_argus(argus_database) - test_id = uuid4() - test_run = TestRun(test_id=test_id, build_id=test.build_system_id, assignee=None, - run_info=completed_testrun, investigation_status=TestInvestigationStatus.INVESTIGATED) - test_run.save() - assert test_assignee_user == test_run.assignee - - row = argus_database.fetch(table_name=TestRun.table_name(), run_id=test_id) - rebuilt_testrun = TestRun.from_db_row(row) - assert test_assignee_user == rebuilt_testrun.assignee - scheduled_assignee.using(connection=argus_database.CQL_ENGINE_CONNECTION_NAME).delete() - scheduled_test.using(connection=argus_database.CQL_ENGINE_CONNECTION_NAME).delete() - schedule.using(connection=argus_database.CQL_ENGINE_CONNECTION_NAME).delete() diff --git a/tests/test_testinfo.py b/tests/test_testinfo.py deleted file mode 100644 index 58b2863e..00000000 --- a/tests/test_testinfo.py +++ /dev/null @@ -1,246 +0,0 @@ -from collections import namedtuple -import pytest -from argus.db.testrun import TestDetails, TestResourcesSetup, TestResources, TestLogs, TestResults, TestInfoValueError -from argus.db.db_types import TestStatus, NodeDescription, NemesisRunInfo, NemesisStatus -from argus.db.cloud_types import CloudInstanceDetails, ResourceState, CloudResource - - -def test_details_schema_dump(preset_test_details_schema: dict): - schema = TestDetails.schema() - assert schema == preset_test_details_schema - - -def test_details_serialization(preset_test_details: TestDetails, preset_test_details_serialized: dict): - dump = preset_test_details.serialize() - - assert dump == preset_test_details_serialized - - -def test_details_validation_invalid_packages(): - with pytest.raises(TestInfoValueError): - TestDetails(scm_revision_id="abcde", started_by="someone", - build_job_url="https://job.tld/1", start_time=1600000000, yaml_test_duration=120, - config_files=["some-test.yaml"], - packages=["peckege", 123]) - - -def test_details_no_exception_on_empty_package_list(): - TestDetails(scm_revision_id="abcde", started_by="someone", - build_job_url="https://job.tld/1", start_time=1600000000, yaml_test_duration=120, - config_files=["some-test.yaml"], - packages=[]) - - -def test_details_ctor_from_named_tuple(preset_test_details): - ResultSet = namedtuple("Row", - ["scm_revision_id", "started_by", "build_job_url", "start_time", - "yaml_test_duration", "config_files", "packages", "scylla_version", "end_time"]) - PackageMapped = namedtuple("PackageMapped", ["name", "version", "date", "revision_id", "build_id"]) - package = PackageMapped("package-server", "1.0", "2021-10-01", "dfcedb3", "dfeeeffffff330fddd") - row = ResultSet(preset_test_details.scm_revision_id, - preset_test_details.started_by, - preset_test_details.build_job_url, - preset_test_details.start_time, - preset_test_details.yaml_test_duration, - preset_test_details.config_files, - [package], - preset_test_details.scylla_version, - preset_test_details.end_time) - - new_test_details = TestDetails.from_db_row(row) - assert new_test_details.serialize() == preset_test_details.serialize() - - -def test_resources_setup_schema_dump(preset_test_resources_setup_schema: dict): - schema = TestResourcesSetup.schema() - assert schema == preset_test_resources_setup_schema - - -def test_resources_setup_serialization(preset_test_resource_setup, - preset_test_resources_setup_serialized: dict): - assert preset_test_resource_setup.serialize() == preset_test_resources_setup_serialized - - -def test_resources_setup_ctor_from_named_tuple(preset_test_resource_setup: TestResourcesSetup): - CloudNodeMapped = namedtuple("CloudNodeMapped", ["image_id", "instance_type", "node_amount", "post_behaviour"]) - CloudSetupMapped = namedtuple("CloudSetupMapped", ["backend", "db_node", "loader_node", "monitor_node"]) - CloudInstanceDetailsMapped = namedtuple("CloudInstanceDetailsMapped", [ - "public_ip", "region", "provider", "private_ip", "creation_time", - "termination_time", "termination_reason", "shards_amount" - ]) - ResourceSetupRow = namedtuple("ResourceSetupRow", ["sct_runner_host", "region_name", "cloud_setup"]) - - db_node = CloudNodeMapped(image_id="ami-abcdef99", instance_type="spot", - node_amount=6, post_behaviour="keep-on-failure") - loader_node = CloudNodeMapped(image_id="ami-deadbeef", instance_type="spot", - node_amount=2, post_behaviour="terminate") - monitor_node = CloudNodeMapped(image_id="ami-abdcef60", instance_type="spot", - node_amount=1, post_behaviour="keep-on-failure") - - cloud_setup = CloudSetupMapped(backend="aws", db_node=db_node, loader_node=loader_node, monitor_node=monitor_node) - - sct_runner_info = CloudInstanceDetailsMapped(public_ip="1.1.1.1", region="us-east-1", provider="aws", - private_ip="10.10.10.1", creation_time=7734, termination_time=0, - termination_reason="", shards_amount=0) - - mapped_setup = ResourceSetupRow(sct_runner_host=sct_runner_info, region_name=["us-east-1"], cloud_setup=cloud_setup) - - new_setup = TestResourcesSetup.from_db_row(mapped_setup) - - assert new_setup.serialize() == preset_test_resource_setup.serialize() - - -def test_logs_schema_dump(preset_test_logs_schema: dict): - assert TestLogs.schema() == preset_test_logs_schema - - -def test_logs_serialization(preset_test_logs: TestLogs, preset_test_logs_serialized: dict): - assert preset_test_logs.serialize() == preset_test_logs_serialized - - -def test_logs_add_log(preset_test_logs: TestLogs): - log_pair = ("another_example", "http://eggsample.com") - preset_test_logs.add_log(*log_pair) - - assert log_pair in preset_test_logs.logs - - -def test_logs_ctor_from_named_tuple(preset_test_logs: TestLogs): - MappedLogs = namedtuple("MappedLogs", ["logs"]) - mapped_logs = MappedLogs([("example", "http://example.com")]) - - new_logs = TestLogs.from_db_row(mapped_logs) - assert new_logs.serialize() == preset_test_logs.serialize() - - -def test_resources_schema_dump(preset_test_resources_schema: dict): - assert TestResources.schema() == preset_test_resources_schema - - -def test_resources_serialization(preset_test_resources: TestResources, preset_test_resources_serialized: dict): - assert preset_test_resources.serialize() == preset_test_resources_serialized - - -def test_resources_attach(preset_test_resources: TestResources): - instance_info = CloudInstanceDetails(public_ip="1.1.1.2", region="us-east-1", - provider="aws", private_ip="10.10.10.1") - resource = CloudResource(name="example_resource_2", state=ResourceState.RUNNING, - instance_info=instance_info, resource_type="example_type") - - preset_test_resources.attach_resource(resource) - - assert resource in preset_test_resources.allocated_resources - - -def test_resources_attach_detach(preset_test_resources: TestResources): - instance_info = CloudInstanceDetails(public_ip="1.1.1.2", region="us-east-1", - provider="aws", private_ip="10.10.10.1",) - resource = CloudResource(name="example_resource_2", state=ResourceState.RUNNING, - instance_info=instance_info, resource_type="example_type") - - preset_test_resources.attach_resource(resource) - - assert resource in preset_test_resources.allocated_resources - - preset_test_resources.detach_resource(resource) - assert resource.state == ResourceState.TERMINATED - - -def test_resources_ctor_from_named_tuple(preset_test_resources): - CloudInstanceDetailsMapped = namedtuple("CloudInstanceDetailsMapped", [ - "provider", "region", "public_ip", "private_ip", "creation_time", "termination_time", - "termination_reason", "shards_amount"]) - CloudResourceMapped = namedtuple("CloudResourceMapped", ["name", "state", "instance_info", "resource_type"]) - instance_info = CloudInstanceDetailsMapped(public_ip="1.1.1.1", region="us-east-1", provider="aws", - private_ip="10.10.10.1", creation_time=7734, termination_time=0, - termination_reason="", shards_amount=10) - resource = CloudResourceMapped(name="example_resource", state=ResourceState.RUNNING.value, - instance_info=instance_info, resource_type="example_type") - - ResourceSetupRow = namedtuple("ResourcesRow", ["allocated_resources", "leftover_resources", "terminated_resources"]) - - row = ResourceSetupRow([resource], [resource], []) - - new_resources = TestResources.from_db_row(row) - - assert new_resources.serialize() == preset_test_resources.serialize() - - -def test_results_schema_dump(preset_test_results_schema: dict): - assert TestResults.schema() == preset_test_results_schema - - -def test_results_serialization(monkeypatch: pytest.MonkeyPatch, preset_test_results: TestResults, - preset_test_results_serialized: dict): - monkeypatch.setattr("time.time", lambda: 16001) - preset_test_results.nemesis_data[0].complete("Something went wrong...") - - assert preset_test_results.serialize() == preset_test_results_serialized - - -def test_results_set_status(preset_test_results): - preset_test_results.status = TestStatus.RUNNING - - assert preset_test_results.status == TestStatus.RUNNING - - -def test_results_set_status_incorrect_enum(preset_test_results): - with pytest.raises(ValueError): - preset_test_results.status = "ASDJKDGHKJSD" - - -def test_results_set_status_coercion_to_enum(preset_test_results): - preset_test_results.status = "failed" - - assert preset_test_results.status == TestStatus.FAILED - - -def test_results_add_nemesis(preset_test_results): - node_description = NodeDescription(ip="1.1.1.1", shards=10, name="example_node") - nemesis = NemesisRunInfo("ChaosMonkey", "disrupt_delete_usr", 30, target_node=node_description, - status=NemesisStatus.RUNNING, - start_time=16000) - - preset_test_results.add_nemesis(nemesis) - - assert nemesis in preset_test_results.nemesis_data - - -def test_results_add_event_with_severity(preset_test_results): - preset_test_results.add_event(event_severity="DEBUG", event_message="test_message") - - value = next(ev for ev in preset_test_results.events if ev.severity == "DEBUG") - - assert "test_message" in value.last_events and value.event_amount == 1 - - -def test_results_add_events_with_same_severity(preset_test_results): - preset_test_results.add_event(event_severity="DEBUG", event_message="test_message") - value = next(ev for ev in preset_test_results.events if ev.severity == "DEBUG") - preset_test_results.add_event(event_severity="DEBUG", event_message="test_message_2") - - assert "test_message" in value.last_events and "test_message_2" in value.last_events and value.event_amount == 2 - - -def test_results_ctor_from_named_tuple(preset_test_results, monkeypatch): - monkeypatch.setattr("time.time", lambda: 16001) - preset_test_results.nemesis_data[0].complete("Something went wrong...") - - ResultsMapped = namedtuple("ResultsMapped", ["status", "events", "nemesis_data", "screenshots"]) - EventsMapped = namedtuple("EventsMapped", ["severity", "event_amount", "last_events"]) - NemesisRunMapped = namedtuple("NemesisRunMapped", - ["class_name", "name", "duration", "target_node", "status", - "start_time", "end_time", "stack_trace"]) - NodeDescriptionMapped = namedtuple("NodeDescriptionMapped", ["ip", "shards", "name"]) - - node_description = NodeDescriptionMapped(ip="1.1.1.1", shards=10, name="example_node") - nemesis = NemesisRunMapped("Nemesis", "disrupt_everything", 100, target_node=node_description, - status=NemesisStatus.FAILED.value, start_time=16000, end_time=16001, - stack_trace="Something went wrong...") - event = EventsMapped(severity="ERROR", event_amount=1, last_events=["Something went wrong..."]) - screeshots = ["https://example.com/screenshot.jpg"] - row = ResultsMapped(status=TestStatus.FAILED.value, events=[event], nemesis_data=[nemesis], screenshots=screeshots) - - new_test_result = TestResults.from_db_row(row) - - assert new_test_result.serialize() == preset_test_results.serialize() diff --git a/tests/test_threaded_test_run.py b/tests/test_threaded_test_run.py deleted file mode 100644 index 2fdc8d6b..00000000 --- a/tests/test_threaded_test_run.py +++ /dev/null @@ -1,50 +0,0 @@ -from uuid import uuid4 -import logging -import time -import pytest -from mocks.mock_cluster import MockSession -from argus.db.testrun import TestRunWithHeartbeat, TestRunInfo -from argus.db.interface import ArgusDatabase - -LOGGER = logging.getLogger(__name__) - - -class FakeCursor: - # pylint: disable=too-few-public-methods - @staticmethod - def one(): - return True - - -def test_heartbeat_thread(completed_testrun: TestRunInfo, mock_cluster: ArgusDatabase, monkeypatch: pytest.MonkeyPatch, mock_cql_engine): - # pylint: disable=unused-argument - monkeypatch.setattr(MockSession, "MOCK_RESULT_SET", FakeCursor()) - test_id = uuid4() - assignee = uuid4() - test_run = TestRunWithHeartbeat(test_id=test_id, build_id="argus-test/argus/argus-testing", assignee=assignee, - run_info=completed_testrun, heartbeat_interval=3) - - old_ts = test_run.heartbeat - for i in range(1, 4): - LOGGER.info("Checking timestamp %s", i) - time.sleep(5) - new_ts = test_run.heartbeat - assert new_ts != old_ts - old_ts = new_ts - - test_run.shutdown() - time.sleep(0.5) - assert not test_run._thread.is_alive() # pylint: disable=protected-access - - -def test_heartbeat_thread_shutdown(completed_testrun: TestRunInfo, mock_cluster: ArgusDatabase, - monkeypatch: pytest.MonkeyPatch, mock_cql_engine): - # pylint: disable=unused-argument - monkeypatch.setattr(MockSession, "MOCK_RESULT_SET", FakeCursor()) - test_id = uuid4() - assignee = uuid4() - test_run = TestRunWithHeartbeat(test_id=test_id, build_id="argus-test/argus/argus-testing", assignee=assignee, - run_info=completed_testrun, heartbeat_interval=15) - - test_run.shutdown() - assert not test_run._thread.is_alive() # pylint: disable=protected-access