argus-alm 0.12.9__py3-none-any.whl → 0.13.0__py3-none-any.whl

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.
Files changed (93) hide show
  1. argus/client/base.py +1 -1
  2. argus/client/driver_matrix_tests/cli.py +2 -2
  3. argus/client/driver_matrix_tests/client.py +1 -1
  4. argus/client/generic/cli.py +2 -2
  5. argus/client/generic_result.py +3 -2
  6. argus/client/sct/client.py +3 -3
  7. argus/client/sirenada/client.py +1 -1
  8. {argus_alm-0.12.9.dist-info → argus_alm-0.13.0.dist-info}/METADATA +2 -4
  9. argus_alm-0.13.0.dist-info/RECORD +20 -0
  10. argus/backend/.gitkeep +0 -0
  11. argus/backend/cli.py +0 -41
  12. argus/backend/controller/__init__.py +0 -0
  13. argus/backend/controller/admin.py +0 -20
  14. argus/backend/controller/admin_api.py +0 -354
  15. argus/backend/controller/api.py +0 -529
  16. argus/backend/controller/auth.py +0 -67
  17. argus/backend/controller/client_api.py +0 -108
  18. argus/backend/controller/main.py +0 -274
  19. argus/backend/controller/notification_api.py +0 -72
  20. argus/backend/controller/notifications.py +0 -13
  21. argus/backend/controller/team.py +0 -126
  22. argus/backend/controller/team_ui.py +0 -18
  23. argus/backend/controller/testrun_api.py +0 -482
  24. argus/backend/controller/view_api.py +0 -162
  25. argus/backend/db.py +0 -100
  26. argus/backend/error_handlers.py +0 -21
  27. argus/backend/events/event_processors.py +0 -34
  28. argus/backend/models/__init__.py +0 -0
  29. argus/backend/models/result.py +0 -138
  30. argus/backend/models/web.py +0 -389
  31. argus/backend/plugins/__init__.py +0 -0
  32. argus/backend/plugins/core.py +0 -225
  33. argus/backend/plugins/driver_matrix_tests/controller.py +0 -63
  34. argus/backend/plugins/driver_matrix_tests/model.py +0 -421
  35. argus/backend/plugins/driver_matrix_tests/plugin.py +0 -22
  36. argus/backend/plugins/driver_matrix_tests/raw_types.py +0 -62
  37. argus/backend/plugins/driver_matrix_tests/service.py +0 -60
  38. argus/backend/plugins/driver_matrix_tests/udt.py +0 -42
  39. argus/backend/plugins/generic/model.py +0 -79
  40. argus/backend/plugins/generic/plugin.py +0 -16
  41. argus/backend/plugins/generic/types.py +0 -13
  42. argus/backend/plugins/loader.py +0 -40
  43. argus/backend/plugins/sct/controller.py +0 -185
  44. argus/backend/plugins/sct/plugin.py +0 -38
  45. argus/backend/plugins/sct/resource_setup.py +0 -178
  46. argus/backend/plugins/sct/service.py +0 -491
  47. argus/backend/plugins/sct/testrun.py +0 -272
  48. argus/backend/plugins/sct/udt.py +0 -101
  49. argus/backend/plugins/sirenada/model.py +0 -113
  50. argus/backend/plugins/sirenada/plugin.py +0 -17
  51. argus/backend/service/admin.py +0 -27
  52. argus/backend/service/argus_service.py +0 -688
  53. argus/backend/service/build_system_monitor.py +0 -188
  54. argus/backend/service/client_service.py +0 -122
  55. argus/backend/service/event_service.py +0 -18
  56. argus/backend/service/jenkins_service.py +0 -240
  57. argus/backend/service/notification_manager.py +0 -150
  58. argus/backend/service/release_manager.py +0 -230
  59. argus/backend/service/results_service.py +0 -317
  60. argus/backend/service/stats.py +0 -540
  61. argus/backend/service/team_manager_service.py +0 -83
  62. argus/backend/service/testrun.py +0 -559
  63. argus/backend/service/user.py +0 -307
  64. argus/backend/service/views.py +0 -258
  65. argus/backend/template_filters.py +0 -27
  66. argus/backend/tests/__init__.py +0 -0
  67. argus/backend/tests/argus_web.test.yaml +0 -39
  68. argus/backend/tests/conftest.py +0 -44
  69. argus/backend/tests/results_service/__init__.py +0 -0
  70. argus/backend/tests/results_service/test_best_results.py +0 -70
  71. argus/backend/util/common.py +0 -65
  72. argus/backend/util/config.py +0 -38
  73. argus/backend/util/encoders.py +0 -41
  74. argus/backend/util/logsetup.py +0 -81
  75. argus/backend/util/module_loaders.py +0 -30
  76. argus/backend/util/send_email.py +0 -91
  77. argus/client/generic_result_old.py +0 -143
  78. argus/db/.gitkeep +0 -0
  79. argus/db/argus_json.py +0 -14
  80. argus/db/cloud_types.py +0 -125
  81. argus/db/config.py +0 -135
  82. argus/db/db_types.py +0 -139
  83. argus/db/interface.py +0 -370
  84. argus/db/testrun.py +0 -740
  85. argus/db/utils.py +0 -15
  86. argus_alm-0.12.9.dist-info/RECORD +0 -96
  87. /argus/{backend → common}/__init__.py +0 -0
  88. /argus/{backend/util → common}/enums.py +0 -0
  89. /argus/{backend/plugins/sct/types.py → common/sct_types.py} +0 -0
  90. /argus/{backend/plugins/sirenada/types.py → common/sirenada_types.py} +0 -0
  91. {argus_alm-0.12.9.dist-info → argus_alm-0.13.0.dist-info}/LICENSE +0 -0
  92. {argus_alm-0.12.9.dist-info → argus_alm-0.13.0.dist-info}/WHEEL +0 -0
  93. {argus_alm-0.12.9.dist-info → argus_alm-0.13.0.dist-info}/entry_points.txt +0 -0
@@ -1,421 +0,0 @@
1
- from dataclasses import dataclass
2
- from datetime import datetime
3
- from functools import reduce
4
- import logging
5
- from pprint import pformat
6
- import re
7
- from typing import Literal, TypedDict
8
- from uuid import UUID
9
- from xml.etree import ElementTree
10
- from cassandra.cqlengine import columns
11
- from argus.backend.db import ScyllaCluster
12
- from argus.backend.models.web import ArgusRelease
13
- from argus.backend.plugins.core import PluginModelBase
14
- from argus.backend.plugins.driver_matrix_tests.udt import TestCollection, TestSuite, TestCase, EnvironmentInfo
15
- from argus.backend.plugins.driver_matrix_tests.raw_types import RawMatrixTestResult
16
- from argus.backend.util.enums import TestStatus
17
-
18
-
19
- LOGGER = logging.getLogger(__name__)
20
-
21
- class DriverMatrixPluginError(Exception):
22
- pass
23
-
24
-
25
- @dataclass(init=True, repr=True, frozen=True)
26
- class DriverMatrixRunSubmissionRequest():
27
- schema_version: str
28
- run_id: str
29
- job_name: str
30
- job_url: str
31
- test_environment: dict[str, str]
32
- matrix_results: list[RawMatrixTestResult]
33
-
34
-
35
- @dataclass(init=True, repr=True, frozen=True)
36
- class DriverMatrixRunSubmissionRequestV2():
37
- schema_version: str
38
- run_id: str
39
- job_name: str
40
- job_url: str
41
-
42
-
43
- TestTypeType = Literal['java', 'cpp', 'python', 'gocql']
44
-
45
-
46
- class AdaptedXUnitData(TypedDict):
47
- timestamp: str
48
-
49
-
50
- def python_driver_matrix_adapter(xml: ElementTree.ElementTree) -> AdaptedXUnitData:
51
- testsuites = list(xml.getroot().iter("testsuite"))
52
-
53
- return {
54
- "timestamp": testsuites[0].attrib.get("timestamp"),
55
- }
56
-
57
-
58
- def java_driver_matrix_adapter(xml: ElementTree.ElementTree) -> AdaptedXUnitData:
59
- testsuites = xml.getroot()
60
- ts_now = datetime.utcnow().timestamp()
61
- try:
62
- time_taken = float(testsuites.attrib.get("time"))
63
- except ValueError:
64
- time_taken = 0.0
65
-
66
- timestamp = datetime.utcfromtimestamp(ts_now - time_taken).isoformat()
67
-
68
- return {
69
- "timestamp": timestamp,
70
- }
71
-
72
-
73
- def cpp_driver_matrix_adapter(xml: ElementTree.ElementTree) -> AdaptedXUnitData:
74
- testsuites = xml.getroot()
75
-
76
- return {
77
- "timestamp": testsuites.attrib.get("timestamp"),
78
- }
79
-
80
-
81
- def gocql_driver_matrix_adapter(xml: ElementTree.ElementTree) -> AdaptedXUnitData:
82
- testsuites = list(xml.getroot().iter("testsuite"))
83
-
84
- return {
85
- "timestamp": testsuites[0].attrib.get("timestamp"),
86
- }
87
-
88
-
89
- def generic_adapter(xml: ElementTree.ElementTree) -> AdaptedXUnitData:
90
- return {
91
- "timestamp": datetime.utcnow().isoformat()
92
- }
93
-
94
- class DriverTestRun(PluginModelBase):
95
- _plugin_name = "driver-matrix-tests"
96
- __table_name__ = "driver_test_run"
97
- scylla_version = columns.Text()
98
- test_collection = columns.List(value_type=columns.UserDefinedType(user_type=TestCollection))
99
- environment_info = columns.List(value_type=columns.UserDefinedType(user_type=EnvironmentInfo))
100
-
101
- _no_upstream = ["rust"]
102
-
103
- _TEST_ADAPTERS = {
104
- "java": java_driver_matrix_adapter,
105
- "cpp": cpp_driver_matrix_adapter,
106
- "python": python_driver_matrix_adapter,
107
- "gocql": gocql_driver_matrix_adapter,
108
- }
109
-
110
-
111
- _artifact_fnames = {
112
- "cpp": r"TEST-(?P<driver_name>[\w]*)-(?P<version>[\d\.-]*)",
113
- "gocql": r"xunit\.(?P<driver_name>[\w]*)\.(?P<proto>v\d)\.(?P<version>[v\d\.]*)",
114
- "python": r"pytest\.(?P<driver_name>[\w]*)\.(?P<proto>v\d)\.(?P<version>[\d\.]*)",
115
- "java": r"TEST-(?P<version>[\d\.\w-]*)",
116
- "rust": r"(?P<driver_name>rust)_results_v(?P<version>[\d\w\-.]*)",
117
- }
118
-
119
- @classmethod
120
- def _stats_query(cls) -> str:
121
- return ("SELECT id, test_id, group_id, release_id, status, start_time, build_job_url, build_id, "
122
- f"assignee, end_time, investigation_status, heartbeat, scylla_version FROM {cls.table_name()} WHERE build_id IN ? PER PARTITION LIMIT 15")
123
-
124
- @classmethod
125
- def get_distinct_product_versions(cls, release: ArgusRelease) -> list[str]:
126
- cluster = ScyllaCluster.get()
127
- statement = cluster.prepare(f"SELECT scylla_version FROM {cls.table_name()} WHERE release_id = ?")
128
- rows = cluster.session.execute(query=statement, parameters=(release.id,))
129
- unique_versions = {r["scylla_version"] for r in rows if r["scylla_version"]}
130
-
131
- return sorted(list(unique_versions), reverse=True)
132
-
133
- @classmethod
134
- def load_test_run(cls, run_id: UUID) -> 'DriverTestRun':
135
- return cls.get(id=run_id)
136
-
137
- @classmethod
138
- def parse_driver_name(cls, raw_file_name: str) -> str:
139
- for test, pattern in cls._artifact_fnames.items():
140
- match = re.match(pattern, raw_file_name)
141
- if not match:
142
- continue
143
- driver_info = match.groupdict()
144
- if test == "java":
145
- version = driver_info["version"]
146
- return "scylla" if len(version.split(".")) > 3 or "scylla" in version else "datastax"
147
- else:
148
- return driver_info["driver_name"]
149
- return "unknown_driver"
150
-
151
-
152
- @classmethod
153
- def submit_run(cls, request_data: dict) -> 'DriverTestRun':
154
- if request_data["schema_version"] == "v2":
155
- req = DriverMatrixRunSubmissionRequestV2(**request_data)
156
- else:
157
- return cls.submit_matrix_run(request_data)
158
-
159
- run = cls()
160
- run.id = req.run_id
161
- run.build_id = req.job_name
162
- run.build_job_url = req.job_url
163
- run.start_time = datetime.utcnow()
164
- run.assign_categories()
165
- try:
166
- run.assignee = run.get_scheduled_assignee()
167
- except Exception: # pylint: disable=broad-except
168
- run.assignee = None
169
-
170
- run.status = TestStatus.CREATED.value
171
- run.save()
172
- return run
173
-
174
- @classmethod
175
- def submit_driver_result(cls, run_id: UUID, driver_name: str, driver_type: TestTypeType, xml_data: str):
176
- run: DriverTestRun = cls.get(id=run_id)
177
-
178
- collection = run.parse_result_xml(driver_name, xml_data, driver_type)
179
- run.test_collection.append(collection)
180
-
181
- if run.status == TestStatus.CREATED:
182
- run.status = TestStatus.RUNNING.value
183
-
184
- run.save()
185
- return run
186
-
187
-
188
- @classmethod
189
- def submit_driver_failure(cls, run_id: UUID, driver_name: str, driver_type: TestTypeType, fail_message: str):
190
- run: DriverTestRun = cls.get(id=run_id)
191
-
192
- collection = TestCollection()
193
- collection.failures = 1
194
- collection.failure_message = fail_message
195
- collection.name = driver_name
196
- driver_info = run.get_driver_info(driver_name, driver_type)
197
- collection.driver = driver_info.get("driver_name")
198
- collection.tests_total = 1
199
- run.test_collection.append(collection)
200
-
201
- if run.status == TestStatus.CREATED:
202
- run.status = TestStatus.RUNNING.value
203
-
204
- run.save()
205
- return run
206
-
207
- @classmethod
208
- def submit_env_info(cls, run_id: UUID, env_data: str):
209
- run: DriverTestRun = cls.get(id=run_id)
210
- env = run.parse_build_environment(env_data)
211
-
212
- for key, value in env.items():
213
- env_info = EnvironmentInfo()
214
- env_info.key = key
215
- env_info.value = value
216
- run.environment_info.append(env_info)
217
-
218
- run.scylla_version = env.get("scylla-version")
219
-
220
- run.save()
221
- return run
222
-
223
- def parse_build_environment(self, raw_env: str) -> dict[str, str]:
224
- result = {}
225
- for line in raw_env.split("\n"):
226
- if not line:
227
- continue
228
- LOGGER.debug("ENV: %s", line)
229
- key, val = line.split(": ")
230
- result[key] = val.strip()
231
-
232
- return result
233
-
234
- def get_test_cases(self, cases: list[ElementTree.Element]) -> list[TestCase]:
235
- result = []
236
- for raw_case in cases:
237
- children = list(raw_case.findall("./*"))
238
- if len(children) > 0:
239
- status = children[0].tag
240
- message = f"{children[0].attrib.get('message', 'no-message')} ({children[0].attrib.get('type', 'no-type')})"
241
- else:
242
- status = "passed"
243
- message = ""
244
-
245
- case = TestCase()
246
- case.name = raw_case.attrib["name"]
247
- case.status = status
248
- case.time = float(raw_case.attrib.get("time", 0.0))
249
- case.classname = raw_case.attrib.get("classname", "")
250
- case.message = message
251
- result.append(case)
252
-
253
- return result
254
-
255
- def get_driver_info(self, xml_name: str, test_type: TestTypeType) -> dict[str, str]:
256
- if test_type == "cpp":
257
- filename_re = r"TEST-(?P<driver_name>[\w]*)-(?P<version>[\d\.]*)(\.xml)?"
258
- else:
259
- filename_re = r"(?P<name>[\w]*)\.(?P<driver_name>[\w]*)\.(?P<proto>v\d)\.(?P<version>[\d\.]*)(\.xml)?"
260
-
261
- match = re.match(filename_re, xml_name)
262
-
263
- return match.groupdict() if match else {}
264
-
265
- def get_passed_count(self, suite_attribs: dict[str, str]) -> int:
266
- if (pass_count := suite_attribs.get("passed")):
267
- return int(pass_count)
268
- total = int(suite_attribs.get("tests", 0))
269
- errors = int(suite_attribs.get("errors", 0))
270
- skipped = int(suite_attribs.get("skipped", 0))
271
- failures = int(suite_attribs.get("failures", 0))
272
-
273
- return total - errors - skipped - failures
274
-
275
- def parse_result_xml(self, name: str, xml_data: str, test_type: TestTypeType) -> TestCollection:
276
- xml: ElementTree.ElementTree = ElementTree.ElementTree(ElementTree.fromstring(xml_data))
277
- LOGGER.debug("%s", pformat(xml))
278
- testsuites = xml.getroot()
279
- adapted_data = self._TEST_ADAPTERS.get(test_type, generic_adapter)(xml)
280
-
281
- driver_info = self.get_driver_info(name, test_type)
282
- test_collection = TestCollection()
283
- test_collection.timestamp = datetime.fromisoformat(adapted_data["timestamp"][0:-1] if adapted_data["timestamp"][-1] == "Z" else adapted_data["timestamp"])
284
- test_collection.name = name
285
- test_collection.driver = driver_info.get("driver_name")
286
- test_collection.tests_total = 0
287
- test_collection.failures = 0
288
- test_collection.errors = 0
289
- test_collection.disabled = 0
290
- test_collection.skipped = 0
291
- test_collection.passed = 0
292
- test_collection.time = 0.0
293
- test_collection.suites = []
294
-
295
- for xml_suite in testsuites.iter("testsuite"):
296
- suite = TestSuite()
297
- suite.name = xml_suite.attrib["name"]
298
- suite.tests_total = int(xml_suite.attrib.get("tests", 0))
299
- suite.failures = int(xml_suite.attrib.get("failures", 0))
300
- suite.disabled = int(0)
301
- suite.passed = self.get_passed_count(xml_suite.attrib)
302
- suite.skipped = int(xml_suite.attrib.get("skipped", 0))
303
- suite.errors = int(xml_suite.attrib.get("errors", 0))
304
- suite.time = float(xml_suite.attrib["time"])
305
- suite.cases = self.get_test_cases(xml_suite.findall("testcase"))
306
-
307
- test_collection.suites.append(suite)
308
- test_collection.tests_total += suite.tests_total
309
- test_collection.failures += suite.failures
310
- test_collection.errors += suite.errors
311
- test_collection.disabled += suite.disabled
312
- test_collection.skipped += suite.skipped
313
- test_collection.passed += suite.passed
314
- test_collection.time += suite.time
315
-
316
- return test_collection
317
-
318
- @classmethod
319
- def submit_matrix_run(cls, request_data):
320
- # Legacy method
321
- req = DriverMatrixRunSubmissionRequest(**request_data)
322
- run = cls()
323
- run.id = req.run_id # pylint: disable=invalid-name
324
- run.build_id = req.job_name
325
- run.build_job_url = req.job_url
326
- run.assign_categories()
327
- try:
328
- run.assignee = run.get_scheduled_assignee()
329
- except Exception: # pylint: disable=broad-except
330
- run.assignee = None
331
- for key, value in req.test_environment.items():
332
- env_info = EnvironmentInfo()
333
- env_info.key = key
334
- env_info.value = value
335
- run.environment_info.append(env_info)
336
-
337
- run.scylla_version = req.test_environment.get("scylla-version")
338
- run.test_collection = []
339
-
340
- for result in req.matrix_results:
341
- collection = TestCollection()
342
- collection.name = result.get("name")
343
- collection.driver = cls.parse_driver_name(collection.name)
344
- collection.tests_total = result.get("tests")
345
- collection.failures = result.get("failures")
346
- collection.errors = result.get("errors")
347
- collection.skipped = result.get("skipped")
348
- collection.passed = result.get("passed")
349
- collection.disabled = result.get("disabled")
350
- collection.time = result.get("time")
351
- timestamp = result.get("timestamp")
352
- # TODO: Not needed once python>=3.11
353
- timestamp = timestamp[0:-1] if timestamp[-1] == "Z" else timestamp
354
- collection.timestamp = datetime.fromisoformat(timestamp)
355
- for raw_suite in result.get("suites"):
356
- suite = TestSuite()
357
- suite.name = raw_suite.get("name")
358
- suite.tests_total = raw_suite.get("tests")
359
- suite.failures = raw_suite.get("failures")
360
- suite.errors = raw_suite.get("errors")
361
- suite.skipped = raw_suite.get("skipped")
362
- suite.passed = raw_suite.get("passed")
363
- suite.disabled = raw_suite.get("disabled")
364
- suite.time = raw_suite.get("time")
365
-
366
- for raw_case in raw_suite.get("cases"):
367
- case = TestCase()
368
- case.name = raw_case.get("name")
369
- case.status = raw_case.get("status")
370
- case.time = raw_case.get("time")
371
- case.classname = raw_case.get("classname")
372
- case.message = raw_case.get("message")
373
- suite.cases.append(case)
374
-
375
- collection.suites.append(suite)
376
- run.test_collection.append(collection)
377
-
378
- run.status = run._determine_run_status().value
379
- run.save()
380
- return run
381
-
382
- def get_resources(self) -> list:
383
- return []
384
-
385
- def get_nemeses(self) -> list:
386
- return []
387
-
388
- def _determine_run_status(self):
389
- for collection in self.test_collection:
390
- # patch failure
391
- if collection.failure_message:
392
- return TestStatus.FAILED
393
-
394
- if len(self.test_collection) < 2:
395
- return TestStatus.FAILED
396
-
397
- driver_types = {collection.driver for collection in self.test_collection}
398
- if len(driver_types) <= 1 and not any(driver for driver in self._no_upstream if driver in driver_types):
399
- return TestStatus.FAILED
400
-
401
- failure_count = reduce(lambda acc, val: acc + (val.failures or 0 + val.errors or 0), self.test_collection, 0)
402
- if failure_count > 0:
403
- return TestStatus.FAILED
404
-
405
- return TestStatus.PASSED
406
-
407
- def change_status(self, new_status: TestStatus):
408
- self.status = new_status
409
-
410
- def get_events(self) -> list:
411
- return []
412
-
413
- def submit_product_version(self, version: str):
414
- self.scylla_version = version
415
-
416
- def finish_run(self, payload: dict = None):
417
- self.end_time = datetime.utcnow()
418
- self.status = self._determine_run_status().value
419
-
420
- def submit_logs(self, logs: list[dict]):
421
- pass
@@ -1,22 +0,0 @@
1
- from flask import Blueprint
2
-
3
- from argus.backend.plugins.core import PluginInfoBase, PluginModelBase
4
- from argus.backend.plugins.driver_matrix_tests.model import DriverTestRun
5
- from argus.backend.plugins.driver_matrix_tests.controller import bp as driver_matrix_api_bp
6
- from argus.backend.plugins.driver_matrix_tests.udt import TestCollection, EnvironmentInfo, TestCase, TestSuite
7
-
8
-
9
- class PluginInfo(PluginInfoBase):
10
- # pylint: disable=too-few-public-methods
11
- name: str = "driver-matrix-tests"
12
- model: PluginModelBase = DriverTestRun
13
- controller: Blueprint = driver_matrix_api_bp
14
- all_models = [
15
- DriverTestRun,
16
- ]
17
- all_types = [
18
- TestCollection,
19
- TestSuite,
20
- TestCase,
21
- EnvironmentInfo
22
- ]
@@ -1,62 +0,0 @@
1
- from dataclasses import dataclass
2
- from typing import TypedDict
3
- from uuid import UUID
4
-
5
-
6
- class RawMatrixTestCase(TypedDict):
7
- name: str
8
- status: str
9
- time: float
10
- classname: str
11
- message: str
12
-
13
-
14
- class RawMatrixTestSuite(TypedDict):
15
- name: str
16
- tests: int
17
- failures: int
18
- disabled: int
19
- skipped: int
20
- passed: int
21
- errors: int
22
- time: float
23
- cases: list[RawMatrixTestCase]
24
-
25
-
26
- class RawMatrixTestResult(TypedDict):
27
- name: str
28
- driver_name: str
29
- tests: int
30
- failures: int
31
- errors: int
32
- disabled: int
33
- skipped: int
34
- passed: int
35
- time: float
36
- timestamp: str
37
- 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
@@ -1,60 +0,0 @@
1
- import base64
2
- import logging
3
- from uuid import UUID
4
- from argus.backend.db import ScyllaCluster
5
- from argus.backend.models.web import ArgusRelease, ArgusTest
6
- from argus.backend.plugins.driver_matrix_tests.model import DriverTestRun
7
-
8
-
9
- LOGGER = logging.getLogger(__name__)
10
-
11
- class DriverMatrixService:
12
- def tested_versions_report(self, build_id: str) -> dict:
13
- db = ScyllaCluster.get()
14
- all_runs_for_test_query = db.prepare(f"SELECT * FROM {DriverTestRun.table_name()} WHERE build_id = ?")
15
-
16
- rows = list(db.session.execute(all_runs_for_test_query, parameters=(build_id,)).all())
17
-
18
- if len(rows) == 0:
19
- raise Exception(f"No results for build_id {build_id}", build_id)
20
-
21
- latest = rows[0]
22
- try:
23
- test: ArgusTest = ArgusTest.get(id=latest["test_id"])
24
- release: ArgusRelease = ArgusRelease.get(id=latest["release_id"])
25
- except (ArgusTest.DoesNotExist, ArgusRelease.DoesNotExist):
26
- raise Exception(f"Unable to find release and test information for build_id {build_id} and run_id {latest['id']}", build_id, latest["id"])
27
-
28
-
29
- version_map = {}
30
-
31
- for row in rows:
32
- driver_versions = [(col["name"], col["driver"]) for col in row["test_collection"]]
33
- for version, driver_type in driver_versions:
34
- driver_type = driver_type if driver_type else "Unknown"
35
- versions: list = version_map.get(driver_type, [])
36
- if version not in versions:
37
- versions.append(version)
38
- versions.sort()
39
- version_map[driver_type] = versions
40
-
41
- response = {
42
- "release": release.name,
43
- "test": test.name,
44
- "build_id": build_id,
45
- "versions": version_map,
46
- }
47
- 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
@@ -1,42 +0,0 @@
1
- from cassandra.cqlengine.usertype import UserType
2
- from cassandra.cqlengine import columns
3
-
4
-
5
- class TestCase(UserType):
6
- name = columns.Text()
7
- status = columns.Text()
8
- time = columns.Float()
9
- classname = columns.Text()
10
- message = columns.Text()
11
-
12
-
13
- class TestSuite(UserType):
14
- name = columns.Text()
15
- tests_total = columns.Integer(default=lambda: 0)
16
- failures = columns.Integer(default=lambda: 0)
17
- disabled = columns.Integer(default=lambda: 0)
18
- skipped = columns.Integer(default=lambda: 0)
19
- passed = columns.Integer(default=lambda: 0)
20
- errors = columns.Integer(default=lambda: 0)
21
- time = columns.Float()
22
- cases = columns.List(value_type=columns.UserDefinedType(user_type=TestCase))
23
-
24
-
25
- class TestCollection(UserType):
26
- name = columns.Text()
27
- driver = columns.Text()
28
- tests_total = columns.Integer(default=lambda: 0)
29
- failure_message = columns.Text()
30
- failures = columns.Integer(default=lambda: 0)
31
- disabled = columns.Integer(default=lambda: 0)
32
- skipped = columns.Integer(default=lambda: 0)
33
- passed = columns.Integer(default=lambda: 0)
34
- errors = columns.Integer(default=lambda: 0)
35
- timestamp = columns.DateTime()
36
- time = columns.Float(default=lambda: 0.0)
37
- suites = columns.List(value_type=columns.UserDefinedType(user_type=TestSuite))
38
-
39
-
40
- class EnvironmentInfo(UserType):
41
- key = columns.Text()
42
- value = columns.Text()
@@ -1,79 +0,0 @@
1
- from datetime import datetime
2
- import re
3
- from uuid import UUID
4
- from cassandra.cqlengine import columns
5
- from cassandra.cqlengine.models import Model
6
- from argus.backend.db import ScyllaCluster
7
- from argus.backend.models.web import ArgusRelease
8
- from argus.backend.plugins.core import PluginModelBase
9
- from argus.backend.plugins.generic.types import GenericRunFinishRequest, GenericRunSubmitRequest
10
- from argus.backend.util.enums import TestStatus
11
-
12
-
13
- class GenericPluginException(Exception):
14
- pass
15
-
16
-
17
- class GenericRun(PluginModelBase):
18
- _plugin_name = "generic"
19
- __table_name__ = "generic_run"
20
- logs = columns.Map(key_type=columns.Text(), value_type=columns.Text())
21
- started_by = columns.Text()
22
- # TODO: Legacy field name, should be renamed to product_version and abstracted
23
- scylla_version = columns.Text()
24
-
25
- @classmethod
26
- def _stats_query(cls) -> str:
27
- return ("SELECT id, test_id, group_id, release_id, status, start_time, build_job_url, build_id, "
28
- f"assignee, end_time, investigation_status, heartbeat, scylla_version FROM {cls.table_name()} WHERE build_id IN ? PER PARTITION LIMIT 15")
29
-
30
- @classmethod
31
- def get_distinct_product_versions(cls, release: ArgusRelease, cluster: ScyllaCluster = None) -> list[str]:
32
- if not cluster:
33
- cluster = ScyllaCluster.get()
34
- statement = cluster.prepare(f"SELECT scylla_version FROM {cls.table_name()} WHERE release_id = ?")
35
- rows = cluster.session.execute(query=statement, parameters=(release.id,))
36
- unique_versions = {r["scylla_version"] for r in rows if r["scylla_version"]}
37
-
38
- return sorted(list(unique_versions), reverse=True)
39
-
40
- def submit_product_version(self, version: str):
41
- pattern = re.compile(r"((?P<short>[\w.~]+)-(?P<build>(0\.)?(?P<date>[0-9]{8,8})\.(?P<commit>\w+).*))")
42
- if match := pattern.search(version):
43
- self.scylla_version = match.group("short")
44
- self.set_full_version(version)
45
-
46
- @classmethod
47
- def load_test_run(cls, run_id: UUID) -> 'GenericRun':
48
- return cls.get(id=run_id)
49
-
50
- @classmethod
51
- def submit_run(cls, request_data: GenericRunSubmitRequest) -> 'GenericRun':
52
- try:
53
- run = cls.get(id=request_data["run_id"])
54
- raise GenericPluginException(f"Run with UUID {request_data['run_id']} already exists.", request_data["run_id"])
55
- except cls.DoesNotExist:
56
- pass
57
- run = cls()
58
- run.start_time = datetime.utcnow()
59
- run.build_id = request_data["build_id"]
60
- run.started_by = request_data["started_by"]
61
- run.id = request_data["run_id"]
62
- run.build_job_url = request_data["build_url"]
63
- run.assign_categories()
64
- try:
65
- run.assignee = run.get_scheduled_assignee()
66
- except Model.DoesNotExist:
67
- run.assignee = None
68
- if version := request_data.get("scylla_version"):
69
- run.submit_product_version(version)
70
- run.status = TestStatus.RUNNING.value
71
- run.save()
72
-
73
- return run
74
-
75
- def finish_run(self, payload: GenericRunFinishRequest = None):
76
- self.end_time = datetime.utcnow()
77
- self.status = TestStatus(payload["status"]).value
78
- if version := payload.get("scylla_version"):
79
- self.submit_product_version(version)