argus-alm 0.12.4b1__tar.gz → 0.12.5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/PKG-INFO +1 -1
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/controller/client_api.py +11 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/controller/testrun_api.py +11 -0
- argus_alm-0.12.5/argus/backend/models/result.py +41 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/models/web.py +4 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/plugins/core.py +4 -2
- argus_alm-0.12.5/argus/backend/plugins/driver_matrix_tests/controller.py +24 -0
- argus_alm-0.12.5/argus/backend/plugins/driver_matrix_tests/model.py +175 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/plugins/driver_matrix_tests/raw_types.py +0 -27
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/plugins/driver_matrix_tests/service.py +0 -18
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/plugins/driver_matrix_tests/udt.py +13 -14
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/plugins/sct/testrun.py +7 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/service/client_service.py +18 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/service/testrun.py +19 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/client/base.py +16 -0
- argus_alm-0.12.5/argus/client/driver_matrix_tests/client.py +216 -0
- argus_alm-0.12.5/argus/client/generic_result.py +99 -0
- argus_alm-0.12.5/argus/client/generic_result_old.py +143 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/pyproject.toml +1 -2
- argus_alm-0.12.4b1/argus/backend/plugins/driver_matrix_tests/controller.py +0 -63
- argus_alm-0.12.4b1/argus/backend/plugins/driver_matrix_tests/model.py +0 -421
- argus_alm-0.12.4b1/argus/client/driver_matrix_tests/cli.py +0 -110
- argus_alm-0.12.4b1/argus/client/driver_matrix_tests/client.py +0 -79
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/LICENSE +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/README.md +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/__init__.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/.gitkeep +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/__init__.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/cli.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/controller/__init__.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/controller/admin.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/controller/admin_api.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/controller/api.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/controller/auth.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/controller/main.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/controller/notification_api.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/controller/notifications.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/controller/team.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/controller/team_ui.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/controller/view_api.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/db.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/error_handlers.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/events/event_processors.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/models/__init__.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/plugins/__init__.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/plugins/driver_matrix_tests/plugin.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/plugins/generic/model.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/plugins/generic/plugin.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/plugins/generic/types.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/plugins/loader.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/plugins/sct/controller.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/plugins/sct/plugin.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/plugins/sct/resource_setup.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/plugins/sct/service.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/plugins/sct/types.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/plugins/sct/udt.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/plugins/sirenada/model.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/plugins/sirenada/plugin.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/plugins/sirenada/types.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/service/admin.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/service/argus_service.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/service/build_system_monitor.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/service/event_service.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/service/jenkins_service.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/service/notification_manager.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/service/release_manager.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/service/stats.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/service/team_manager_service.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/service/user.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/service/views.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/template_filters.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/util/common.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/util/config.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/util/encoders.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/util/enums.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/util/logsetup.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/util/module_loaders.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/util/send_email.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/client/__init__.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/client/generic/cli.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/client/generic/client.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/client/sct/client.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/client/sct/types.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/client/sirenada/client.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/db/.gitkeep +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/db/argus_json.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/db/cloud_types.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/db/config.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/db/db_types.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/db/interface.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/db/testrun.py +0 -0
- {argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/db/utils.py +0 -0
|
@@ -90,3 +90,14 @@ def run_finalize(run_type: str, run_id: str):
|
|
|
90
90
|
"status": "ok",
|
|
91
91
|
"response": result
|
|
92
92
|
}
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
@bp.route("/testrun/<string:run_type>/<string:run_id>/submit_results", methods=["POST"])
|
|
96
|
+
@api_login_required
|
|
97
|
+
def submit_results(run_type: str, run_id: str):
|
|
98
|
+
payload = get_payload(request)
|
|
99
|
+
result = ClientService().submit_results(run_type=run_type, run_id=run_id, results=payload)
|
|
100
|
+
return {
|
|
101
|
+
"status": "ok",
|
|
102
|
+
"response": result
|
|
103
|
+
}
|
|
@@ -63,6 +63,17 @@ def test_run_activity(run_id: str):
|
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
|
|
66
|
+
|
|
67
|
+
@bp.route("/run/<string:test_id>/<string:run_id>/fetch_results", methods=["GET"])
|
|
68
|
+
@api_login_required
|
|
69
|
+
def fetch_results(test_id: str, run_id: str):
|
|
70
|
+
tables = TestRunService().fetch_results(test_id=UUID(test_id), run_id=UUID(run_id))
|
|
71
|
+
return {
|
|
72
|
+
"status": "ok",
|
|
73
|
+
"tables": tables
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
|
|
66
77
|
@bp.route("/test/<string:test_id>/run/<string:run_id>/status/set", methods=["POST"])
|
|
67
78
|
@api_login_required
|
|
68
79
|
def set_testrun_status(test_id: str, run_id: str):
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
from cassandra.cqlengine import columns
|
|
2
|
+
from cassandra.cqlengine.models import Model
|
|
3
|
+
from cassandra.cqlengine.usertype import UserType
|
|
4
|
+
from enum import Enum
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Status(Enum):
|
|
8
|
+
PASS = 0
|
|
9
|
+
WARNING = 1
|
|
10
|
+
ERROR = 2
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class ColumnMetadata(UserType):
|
|
14
|
+
name = columns.Ascii()
|
|
15
|
+
unit = columns.Text()
|
|
16
|
+
type = columns.Ascii()
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class ArgusGenericResultMetadata(Model):
|
|
20
|
+
__table_name__ = "generic_result_metadata_v1"
|
|
21
|
+
test_id = columns.UUID(partition_key=True)
|
|
22
|
+
name = columns.Text(required=True, primary_key=True)
|
|
23
|
+
description = columns.Text()
|
|
24
|
+
columns_meta = columns.List(value_type=columns.UserDefinedType(ColumnMetadata))
|
|
25
|
+
rows_meta = columns.List(value_type=columns.Ascii())
|
|
26
|
+
|
|
27
|
+
def __init__(self, **kwargs):
|
|
28
|
+
kwargs["columns_meta"] = [ColumnMetadata(**col) for col in kwargs.pop('columns_meta', [])]
|
|
29
|
+
super().__init__(**kwargs)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class ArgusGenericResultData(Model):
|
|
33
|
+
__table_name__ = "generic_result_data_v1"
|
|
34
|
+
test_id = columns.UUID(partition_key=True)
|
|
35
|
+
name = columns.Text(partition_key=True)
|
|
36
|
+
run_id = columns.UUID(primary_key=True)
|
|
37
|
+
column = columns.Ascii(primary_key=True, index=True)
|
|
38
|
+
row = columns.Ascii(primary_key=True, index=True)
|
|
39
|
+
sut_timestamp = columns.DateTime() # for sorting
|
|
40
|
+
value = columns.Double()
|
|
41
|
+
status = columns.Ascii()
|
|
@@ -6,6 +6,8 @@ from cassandra.cqlengine.usertype import UserType
|
|
|
6
6
|
from cassandra.cqlengine import columns
|
|
7
7
|
from cassandra.util import uuid_from_time, unix_time_from_uuid1 # pylint: disable=no-name-in-module
|
|
8
8
|
|
|
9
|
+
from argus.backend.models.result import ArgusGenericResultMetadata, ArgusGenericResultData
|
|
10
|
+
|
|
9
11
|
|
|
10
12
|
def uuid_now():
|
|
11
13
|
return uuid_from_time(datetime.utcnow())
|
|
@@ -377,6 +379,8 @@ USED_MODELS: list[Model] = [
|
|
|
377
379
|
ArgusScheduleAssignee,
|
|
378
380
|
ArgusScheduleGroup,
|
|
379
381
|
ArgusScheduleTest,
|
|
382
|
+
ArgusGenericResultMetadata,
|
|
383
|
+
ArgusGenericResultData,
|
|
380
384
|
]
|
|
381
385
|
|
|
382
386
|
USED_TYPES: list[UserType] = [
|
|
@@ -30,7 +30,7 @@ class PluginModelBase(Model):
|
|
|
30
30
|
_plugin_name = "unknown"
|
|
31
31
|
# Metadata
|
|
32
32
|
build_id = columns.Text(required=True, partition_key=True)
|
|
33
|
-
start_time = columns.DateTime(required=True, primary_key=True, clustering_order="DESC", default=datetime.
|
|
33
|
+
start_time = columns.DateTime(required=True, primary_key=True, clustering_order="DESC", default=datetime.now, custom_index=True)
|
|
34
34
|
id = columns.UUID(index=True, required=True)
|
|
35
35
|
release_id = columns.UUID(index=True)
|
|
36
36
|
group_id = columns.UUID(index=True)
|
|
@@ -105,7 +105,7 @@ class PluginModelBase(Model):
|
|
|
105
105
|
assignees = ArgusScheduleAssignee.filter(
|
|
106
106
|
schedule_id=schedule.id
|
|
107
107
|
).all()
|
|
108
|
-
assignees_uuids.
|
|
108
|
+
assignees_uuids.extend([assignee.assignee for assignee in assignees])
|
|
109
109
|
|
|
110
110
|
return assignees_uuids[0] if len(assignees_uuids) > 0 else None
|
|
111
111
|
|
|
@@ -213,6 +213,8 @@ class PluginModelBase(Model):
|
|
|
213
213
|
def finish_run(self, payload: dict = None):
|
|
214
214
|
raise NotImplementedError()
|
|
215
215
|
|
|
216
|
+
def sut_timestamp(self) -> float:
|
|
217
|
+
raise NotImplementedError()
|
|
216
218
|
|
|
217
219
|
class PluginInfoBase:
|
|
218
220
|
# pylint: disable=too-few-public-methods
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from flask import Blueprint, request
|
|
2
|
+
|
|
3
|
+
from argus.backend.error_handlers import handle_api_exception
|
|
4
|
+
from argus.backend.service.user import api_login_required
|
|
5
|
+
from argus.backend.plugins.driver_matrix_tests.service import DriverMatrixService
|
|
6
|
+
|
|
7
|
+
bp = Blueprint("driver_matrix_api", __name__, url_prefix="/driver_matrix")
|
|
8
|
+
bp.register_error_handler(Exception, handle_api_exception)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@bp.route("/test_report", methods=["GET"])
|
|
12
|
+
@api_login_required
|
|
13
|
+
def driver_matrix_test_report():
|
|
14
|
+
|
|
15
|
+
build_id = request.args.get("buildId")
|
|
16
|
+
if not build_id:
|
|
17
|
+
raise Exception("No build id provided")
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
result = DriverMatrixService().tested_versions_report(build_id=build_id)
|
|
21
|
+
return {
|
|
22
|
+
"status": "ok",
|
|
23
|
+
"response": result
|
|
24
|
+
}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
from functools import reduce
|
|
4
|
+
import re
|
|
5
|
+
from uuid import UUID
|
|
6
|
+
from cassandra.cqlengine import columns
|
|
7
|
+
from argus.backend.db import ScyllaCluster
|
|
8
|
+
from argus.backend.models.web import ArgusRelease
|
|
9
|
+
from argus.backend.plugins.core import PluginModelBase
|
|
10
|
+
from argus.backend.plugins.driver_matrix_tests.udt import TestCollection, TestSuite, TestCase, EnvironmentInfo
|
|
11
|
+
from argus.backend.plugins.driver_matrix_tests.raw_types import RawMatrixTestResult
|
|
12
|
+
from argus.backend.util.enums import TestStatus
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class DriverMatrixPluginError(Exception):
|
|
16
|
+
pass
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass(init=True, repr=True, frozen=True)
|
|
20
|
+
class DriverMatrixRunSubmissionRequest():
|
|
21
|
+
schema_version: str
|
|
22
|
+
run_id: str
|
|
23
|
+
job_name: str
|
|
24
|
+
job_url: str
|
|
25
|
+
test_environment: dict[str, str]
|
|
26
|
+
matrix_results: list[RawMatrixTestResult]
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class DriverTestRun(PluginModelBase):
|
|
30
|
+
_plugin_name = "driver-matrix-tests"
|
|
31
|
+
__table_name__ = "driver_test_run"
|
|
32
|
+
scylla_version = columns.Text()
|
|
33
|
+
test_collection = columns.List(value_type=columns.UserDefinedType(user_type=TestCollection))
|
|
34
|
+
environment_info = columns.List(value_type=columns.UserDefinedType(user_type=EnvironmentInfo))
|
|
35
|
+
|
|
36
|
+
_no_upstream = ["rust"]
|
|
37
|
+
|
|
38
|
+
_artifact_fnames = {
|
|
39
|
+
"cpp": r"TEST-(?P<driver_name>[\w]*)-(?P<version>[\d\.-]*)",
|
|
40
|
+
"gocql": r"xunit\.(?P<driver_name>[\w]*)\.(?P<proto>v\d)\.(?P<version>[v\d\.]*)",
|
|
41
|
+
"python": r"pytest\.(?P<driver_name>[\w]*)\.(?P<proto>v\d)\.(?P<version>[\d\.]*)",
|
|
42
|
+
"java": r"TEST-(?P<version>[\d\.\w-]*)",
|
|
43
|
+
"rust": r"(?P<driver_name>rust)_results_v(?P<version>[\d\w\-.]*)",
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
@classmethod
|
|
47
|
+
def _stats_query(cls) -> str:
|
|
48
|
+
return ("SELECT id, test_id, group_id, release_id, status, start_time, build_job_url, build_id, "
|
|
49
|
+
f"assignee, end_time, investigation_status, heartbeat, scylla_version FROM {cls.table_name()} WHERE build_id IN ? PER PARTITION LIMIT 15")
|
|
50
|
+
|
|
51
|
+
@classmethod
|
|
52
|
+
def get_distinct_product_versions(cls, release: ArgusRelease) -> list[str]:
|
|
53
|
+
cluster = ScyllaCluster.get()
|
|
54
|
+
statement = cluster.prepare(f"SELECT scylla_version FROM {cls.table_name()} WHERE release_id = ?")
|
|
55
|
+
rows = cluster.session.execute(query=statement, parameters=(release.id,))
|
|
56
|
+
unique_versions = {r["scylla_version"] for r in rows if r["scylla_version"]}
|
|
57
|
+
|
|
58
|
+
return sorted(list(unique_versions), reverse=True)
|
|
59
|
+
|
|
60
|
+
@classmethod
|
|
61
|
+
def load_test_run(cls, run_id: UUID) -> 'DriverTestRun':
|
|
62
|
+
return cls.get(id=run_id)
|
|
63
|
+
|
|
64
|
+
@classmethod
|
|
65
|
+
def parse_driver_name(cls, raw_file_name: str) -> str:
|
|
66
|
+
for test, pattern in cls._artifact_fnames.items():
|
|
67
|
+
match = re.match(pattern, raw_file_name)
|
|
68
|
+
if not match:
|
|
69
|
+
continue
|
|
70
|
+
driver_info = match.groupdict()
|
|
71
|
+
if test == "java":
|
|
72
|
+
version = driver_info["version"]
|
|
73
|
+
return "scylla" if len(version.split(".")) > 3 or "scylla" in version else "datastax"
|
|
74
|
+
else:
|
|
75
|
+
return driver_info["driver_name"]
|
|
76
|
+
return "unknown_driver"
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
@classmethod
|
|
80
|
+
def submit_run(cls, request_data: dict) -> 'DriverTestRun':
|
|
81
|
+
req = DriverMatrixRunSubmissionRequest(**request_data)
|
|
82
|
+
run = cls()
|
|
83
|
+
run.id = req.run_id # pylint: disable=invalid-name
|
|
84
|
+
run.build_id = req.job_name
|
|
85
|
+
run.build_job_url = req.job_url
|
|
86
|
+
run.assign_categories()
|
|
87
|
+
try:
|
|
88
|
+
run.assignee = run.get_scheduled_assignee()
|
|
89
|
+
except Exception: # pylint: disable=broad-except
|
|
90
|
+
run.assignee = None
|
|
91
|
+
for key, value in req.test_environment.items():
|
|
92
|
+
env_info = EnvironmentInfo()
|
|
93
|
+
env_info.key = key
|
|
94
|
+
env_info.value = value
|
|
95
|
+
run.environment_info.append(env_info)
|
|
96
|
+
|
|
97
|
+
run.scylla_version = req.test_environment.get("scylla-version")
|
|
98
|
+
run.test_collection = []
|
|
99
|
+
|
|
100
|
+
for result in req.matrix_results:
|
|
101
|
+
collection = TestCollection()
|
|
102
|
+
collection.name = result.get("name")
|
|
103
|
+
collection.driver = cls.parse_driver_name(collection.name)
|
|
104
|
+
collection.tests_total = result.get("tests")
|
|
105
|
+
collection.failures = result.get("failures")
|
|
106
|
+
collection.errors = result.get("errors")
|
|
107
|
+
collection.skipped = result.get("skipped")
|
|
108
|
+
collection.passed = result.get("passed")
|
|
109
|
+
collection.disabled = result.get("disabled")
|
|
110
|
+
collection.time = result.get("time")
|
|
111
|
+
timestamp = result.get("timestamp")
|
|
112
|
+
# TODO: Not needed once python>=3.11
|
|
113
|
+
timestamp = timestamp[0:-1] if timestamp[-1] == "Z" else timestamp
|
|
114
|
+
collection.timestamp = datetime.fromisoformat(timestamp)
|
|
115
|
+
for raw_suite in result.get("suites"):
|
|
116
|
+
suite = TestSuite()
|
|
117
|
+
suite.name = raw_suite.get("name")
|
|
118
|
+
suite.tests_total = raw_suite.get("tests")
|
|
119
|
+
suite.failures = raw_suite.get("failures")
|
|
120
|
+
suite.errors = raw_suite.get("errors")
|
|
121
|
+
suite.skipped = raw_suite.get("skipped")
|
|
122
|
+
suite.passed = raw_suite.get("passed")
|
|
123
|
+
suite.disabled = raw_suite.get("disabled")
|
|
124
|
+
suite.time = raw_suite.get("time")
|
|
125
|
+
|
|
126
|
+
for raw_case in raw_suite.get("cases"):
|
|
127
|
+
case = TestCase()
|
|
128
|
+
case.name = raw_case.get("name")
|
|
129
|
+
case.status = raw_case.get("status")
|
|
130
|
+
case.time = raw_case.get("time")
|
|
131
|
+
case.classname = raw_case.get("classname")
|
|
132
|
+
case.message = raw_case.get("message")
|
|
133
|
+
suite.cases.append(case)
|
|
134
|
+
|
|
135
|
+
collection.suites.append(suite)
|
|
136
|
+
run.test_collection.append(collection)
|
|
137
|
+
|
|
138
|
+
run.status = run._determine_run_status().value
|
|
139
|
+
run.save()
|
|
140
|
+
return run
|
|
141
|
+
|
|
142
|
+
def get_resources(self) -> list:
|
|
143
|
+
return []
|
|
144
|
+
|
|
145
|
+
def get_nemeses(self) -> list:
|
|
146
|
+
return []
|
|
147
|
+
|
|
148
|
+
def _determine_run_status(self):
|
|
149
|
+
if len(self.test_collection) < 2:
|
|
150
|
+
return TestStatus.FAILED
|
|
151
|
+
|
|
152
|
+
driver_types = {collection.driver for collection in self.test_collection}
|
|
153
|
+
if len(driver_types) <= 1 and not any(driver for driver in self._no_upstream if driver in driver_types):
|
|
154
|
+
return TestStatus.FAILED
|
|
155
|
+
|
|
156
|
+
failure_count = reduce(lambda acc, val: acc + (val.failures + val.errors), self.test_collection, 0)
|
|
157
|
+
if failure_count > 0:
|
|
158
|
+
return TestStatus.FAILED
|
|
159
|
+
|
|
160
|
+
return TestStatus.PASSED
|
|
161
|
+
|
|
162
|
+
def change_status(self, new_status: TestStatus):
|
|
163
|
+
raise DriverMatrixPluginError("This method is obsolete. Status is now determined on submission.")
|
|
164
|
+
|
|
165
|
+
def get_events(self) -> list:
|
|
166
|
+
return []
|
|
167
|
+
|
|
168
|
+
def submit_product_version(self, version: str):
|
|
169
|
+
self.scylla_version = version
|
|
170
|
+
|
|
171
|
+
def finish_run(self, payload: dict = None):
|
|
172
|
+
self.end_time = datetime.utcnow()
|
|
173
|
+
|
|
174
|
+
def submit_logs(self, logs: list[dict]):
|
|
175
|
+
pass
|
{argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/plugins/driver_matrix_tests/raw_types.py
RENAMED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
from dataclasses import dataclass
|
|
2
1
|
from typing import TypedDict
|
|
3
|
-
from uuid import UUID
|
|
4
2
|
|
|
5
3
|
|
|
6
4
|
class RawMatrixTestCase(TypedDict):
|
|
@@ -35,28 +33,3 @@ class RawMatrixTestResult(TypedDict):
|
|
|
35
33
|
time: float
|
|
36
34
|
timestamp: str
|
|
37
35
|
suites: list[RawMatrixTestSuite]
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
@dataclass(init=True, frozen=True)
|
|
41
|
-
class DriverMatrixSubmitResultRequest():
|
|
42
|
-
schema_version: str
|
|
43
|
-
run_id: UUID
|
|
44
|
-
driver_type: str
|
|
45
|
-
driver_name: str
|
|
46
|
-
raw_xml: str
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
@dataclass(init=True, frozen=True)
|
|
50
|
-
class DriverMatrixSubmitFailureRequest():
|
|
51
|
-
schema_version: str
|
|
52
|
-
run_id: UUID
|
|
53
|
-
driver_type: str
|
|
54
|
-
driver_name: str
|
|
55
|
-
failure_reason: str
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
@dataclass(init=True, frozen=True)
|
|
59
|
-
class DriverMatrixSubmitEnvRequest():
|
|
60
|
-
schema_version: str
|
|
61
|
-
run_id: UUID
|
|
62
|
-
raw_env: str
|
{argus_alm-0.12.4b1 → argus_alm-0.12.5}/argus/backend/plugins/driver_matrix_tests/service.py
RENAMED
|
@@ -1,13 +1,8 @@
|
|
|
1
|
-
import base64
|
|
2
|
-
import logging
|
|
3
|
-
from uuid import UUID
|
|
4
1
|
from argus.backend.db import ScyllaCluster
|
|
5
2
|
from argus.backend.models.web import ArgusRelease, ArgusTest
|
|
6
3
|
from argus.backend.plugins.driver_matrix_tests.model import DriverTestRun
|
|
7
4
|
|
|
8
5
|
|
|
9
|
-
LOGGER = logging.getLogger(__name__)
|
|
10
|
-
|
|
11
6
|
class DriverMatrixService:
|
|
12
7
|
def tested_versions_report(self, build_id: str) -> dict:
|
|
13
8
|
db = ScyllaCluster.get()
|
|
@@ -45,16 +40,3 @@ class DriverMatrixService:
|
|
|
45
40
|
"versions": version_map,
|
|
46
41
|
}
|
|
47
42
|
return response
|
|
48
|
-
|
|
49
|
-
def submit_driver_result(self, run_id: UUID | str, driver_name: str, driver_type: str, raw_xml: str) -> bool:
|
|
50
|
-
xml_data = base64.decodebytes(bytes(raw_xml, encoding="utf-8"))
|
|
51
|
-
DriverTestRun.submit_driver_result(UUID(run_id), driver_name, driver_type, xml_data)
|
|
52
|
-
return True
|
|
53
|
-
|
|
54
|
-
def submit_driver_failure(self, run_id: UUID | str, driver_name: str, driver_type: str, failure_reason: str) -> bool:
|
|
55
|
-
DriverTestRun.submit_driver_failure(UUID(run_id), driver_name, driver_type, failure_reason)
|
|
56
|
-
return True
|
|
57
|
-
|
|
58
|
-
def submit_env_info(self, run_id: UUID | str, raw_env: str) -> bool:
|
|
59
|
-
DriverTestRun.submit_env_info(UUID(run_id), raw_env)
|
|
60
|
-
return True
|
|
@@ -12,12 +12,12 @@ class TestCase(UserType):
|
|
|
12
12
|
|
|
13
13
|
class TestSuite(UserType):
|
|
14
14
|
name = columns.Text()
|
|
15
|
-
tests_total = columns.Integer(
|
|
16
|
-
failures = columns.Integer(
|
|
17
|
-
disabled = columns.Integer(
|
|
18
|
-
skipped = columns.Integer(
|
|
19
|
-
passed = columns.Integer(
|
|
20
|
-
errors = columns.Integer(
|
|
15
|
+
tests_total = columns.Integer()
|
|
16
|
+
failures = columns.Integer()
|
|
17
|
+
disabled = columns.Integer()
|
|
18
|
+
skipped = columns.Integer()
|
|
19
|
+
passed = columns.Integer()
|
|
20
|
+
errors = columns.Integer()
|
|
21
21
|
time = columns.Float()
|
|
22
22
|
cases = columns.List(value_type=columns.UserDefinedType(user_type=TestCase))
|
|
23
23
|
|
|
@@ -25,15 +25,14 @@ class TestSuite(UserType):
|
|
|
25
25
|
class TestCollection(UserType):
|
|
26
26
|
name = columns.Text()
|
|
27
27
|
driver = columns.Text()
|
|
28
|
-
tests_total = columns.Integer(
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
errors = columns.Integer(default=lambda: 0)
|
|
28
|
+
tests_total = columns.Integer()
|
|
29
|
+
failures = columns.Integer()
|
|
30
|
+
disabled = columns.Integer()
|
|
31
|
+
skipped = columns.Integer()
|
|
32
|
+
passed = columns.Integer()
|
|
33
|
+
errors = columns.Integer()
|
|
35
34
|
timestamp = columns.DateTime()
|
|
36
|
-
time = columns.Float(
|
|
35
|
+
time = columns.Float()
|
|
37
36
|
suites = columns.List(value_type=columns.UserDefinedType(user_type=TestSuite))
|
|
38
37
|
|
|
39
38
|
|
|
@@ -249,6 +249,13 @@ class SCTTestRun(PluginModelBase):
|
|
|
249
249
|
|
|
250
250
|
self._collect_event_message(event, event_message)
|
|
251
251
|
|
|
252
|
+
def sut_timestamp(self) -> float:
|
|
253
|
+
"""converts scylla-server date to timestamp and adds revision in subseconds precision to diffirentiate
|
|
254
|
+
scylla versions from the same day. It's not perfect, but we don't know exact version time."""
|
|
255
|
+
scylla_package = [package for package in self.packages if package.name == "scylla-server"][0]
|
|
256
|
+
return (datetime.strptime(scylla_package.date, '%Y%m%d').timestamp()
|
|
257
|
+
+ int(scylla_package.revision_id, 16) % 1000000 / 1000000)
|
|
258
|
+
|
|
252
259
|
|
|
253
260
|
class SCTJunitReports(Model):
|
|
254
261
|
test_id = columns.UUID(primary_key=True, partition_key=True, required=True)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from uuid import UUID
|
|
2
2
|
from argus.backend.db import ScyllaCluster
|
|
3
|
+
from argus.backend.models.result import ArgusGenericResultMetadata, ArgusGenericResultData
|
|
3
4
|
from argus.backend.plugins.core import PluginModelBase
|
|
4
5
|
from argus.backend.plugins.loader import AVAILABLE_PLUGINS
|
|
5
6
|
from argus.backend.util.enums import TestStatus
|
|
@@ -69,3 +70,20 @@ class ClientService:
|
|
|
69
70
|
run.save()
|
|
70
71
|
|
|
71
72
|
return "Finalized"
|
|
73
|
+
|
|
74
|
+
def submit_results(self, run_type: str, run_id: str, results: dict) -> str:
|
|
75
|
+
model = self.get_model(run_type)
|
|
76
|
+
run = model.load_test_run(UUID(run_id))
|
|
77
|
+
ArgusGenericResultMetadata(test_id=run.test_id, **results["meta"]).save()
|
|
78
|
+
if results.get("sut_timestamp", 0) == 0:
|
|
79
|
+
results["sut_timestamp"] = run.sut_timestamp() # automatic sut_timestamp
|
|
80
|
+
table_name = results["meta"]["name"]
|
|
81
|
+
sut_timestamp = results["sut_timestamp"]
|
|
82
|
+
for cell in results["results"]:
|
|
83
|
+
ArgusGenericResultData(test_id=run.test_id,
|
|
84
|
+
run_id=run.id,
|
|
85
|
+
name=table_name,
|
|
86
|
+
sut_timestamp=sut_timestamp,
|
|
87
|
+
**cell
|
|
88
|
+
).save()
|
|
89
|
+
return "Submitted"
|
|
@@ -13,6 +13,7 @@ from flask import g
|
|
|
13
13
|
from cassandra.query import BatchStatement, ConsistencyLevel
|
|
14
14
|
from cassandra.cqlengine.query import BatchQuery
|
|
15
15
|
from argus.backend.db import ScyllaCluster
|
|
16
|
+
from argus.backend.models.result import ArgusGenericResultMetadata, ArgusGenericResultData
|
|
16
17
|
|
|
17
18
|
from argus.backend.models.web import (
|
|
18
19
|
ArgusEvent,
|
|
@@ -306,6 +307,24 @@ class TestRunService:
|
|
|
306
307
|
}
|
|
307
308
|
return response
|
|
308
309
|
|
|
310
|
+
def fetch_results(self, test_id: UUID, run_id: UUID) -> dict:
|
|
311
|
+
query_fields = ["column", "row", "value", "status"]
|
|
312
|
+
tables_meta = ArgusGenericResultMetadata.filter(test_id=test_id)
|
|
313
|
+
tables = []
|
|
314
|
+
for table in tables_meta:
|
|
315
|
+
cells = ArgusGenericResultData.objects.filter(test_id=test_id, run_id=run_id, name=table.name).only(query_fields)
|
|
316
|
+
if not cells:
|
|
317
|
+
continue
|
|
318
|
+
tables.append({'meta': {
|
|
319
|
+
'name': table.name,
|
|
320
|
+
'description': table.description,
|
|
321
|
+
'columns_meta': table.columns_meta,
|
|
322
|
+
'rows_meta': table.rows_meta
|
|
323
|
+
},
|
|
324
|
+
'cells': [{k:v for k,v in cell.items() if k in query_fields} for cell in cells]})
|
|
325
|
+
|
|
326
|
+
return tables
|
|
327
|
+
|
|
309
328
|
def submit_github_issue(self, issue_url: str, test_id: UUID, run_id: UUID):
|
|
310
329
|
user_tokens = UserOauthToken.filter(user_id=g.user.id).all()
|
|
311
330
|
token = None
|
|
@@ -7,6 +7,7 @@ from uuid import UUID
|
|
|
7
7
|
import requests
|
|
8
8
|
|
|
9
9
|
from argus.backend.util.enums import TestStatus
|
|
10
|
+
from argus.client.generic_result import GenericResultTable
|
|
10
11
|
from argus.client.sct.types import LogLink
|
|
11
12
|
|
|
12
13
|
JSON = dict[str, Any] | list[Any] | int | str | float | bool | Type[None]
|
|
@@ -28,6 +29,8 @@ class ArgusClient:
|
|
|
28
29
|
SET_STATUS = "/testrun/$type/$id/set_status"
|
|
29
30
|
SET_PRODUCT_VERSION = "/testrun/$type/$id/update_product_version"
|
|
30
31
|
SUBMIT_LOGS = "/testrun/$type/$id/logs/submit"
|
|
32
|
+
SUBMIT_RESULTS = "/testrun/$type/$id/submit_results"
|
|
33
|
+
FETCH_RESULTS = "/testrun/$type/$id/fetch_results"
|
|
31
34
|
FINALIZE = "/testrun/$type/$id/finalize"
|
|
32
35
|
|
|
33
36
|
def __init__(self, auth_token: str, base_url: str, api_version="v1") -> None:
|
|
@@ -190,3 +193,16 @@ class ArgusClient:
|
|
|
190
193
|
}
|
|
191
194
|
)
|
|
192
195
|
self.check_response(response)
|
|
196
|
+
|
|
197
|
+
def submit_results(self, result: GenericResultTable) -> None:
|
|
198
|
+
response = self.post(
|
|
199
|
+
endpoint=self.Routes.SUBMIT_RESULTS,
|
|
200
|
+
location_params={"type": self.test_type, "id": str(self.run_id)},
|
|
201
|
+
body={
|
|
202
|
+
**self.generic_body,
|
|
203
|
+
"run_id": str(self.run_id),
|
|
204
|
+
** result.as_dict(),
|
|
205
|
+
}
|
|
206
|
+
)
|
|
207
|
+
self.check_response(response)
|
|
208
|
+
|