utf-queue-client 1.16.0__tar.gz → 1.17.2__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.
- utf-queue-client-1.17.2/PKG-INFO +11 -0
- {utf-queue-client-1.16.0 → utf-queue-client-1.17.2}/setup.py +2 -3
- {utf-queue-client-1.16.0 → utf-queue-client-1.17.2}/test/test_amqp_connections.py +1 -1
- utf-queue-client-1.17.2/test/test_publish_release_info.py +145 -0
- utf-queue-client-1.17.2/test/test_rail_data_producer_tests.py +64 -0
- utf-queue-client-1.17.2/utf_queue_client/clients/test_rail_data_producer.py +95 -0
- {utf-queue-client-1.16.0 → utf-queue-client-1.17.2}/utf_queue_client/models/base_model.py +8 -4
- utf-queue-client-1.17.2/utf_queue_client/models/schemas/utf_queue_models/models/python/__init__.py +0 -0
- utf-queue-client-1.17.2/utf_queue_client/models/schemas/utf_queue_models/models/python/generated_models.py +291 -0
- utf-queue-client-1.17.2/utf_queue_client/models/schemas/utf_queue_models/schema/queue_message.json +662 -0
- {utf-queue-client-1.16.0 → utf-queue-client-1.17.2}/utf_queue_client/scripts/publish_release_info_cli.py +40 -21
- utf-queue-client-1.17.2/utf_queue_client.egg-info/PKG-INFO +11 -0
- {utf-queue-client-1.16.0 → utf-queue-client-1.17.2}/utf_queue_client.egg-info/SOURCES.txt +5 -0
- {utf-queue-client-1.16.0 → utf-queue-client-1.17.2}/utf_queue_client.egg-info/entry_points.txt +0 -1
- utf-queue-client-1.16.0/PKG-INFO +0 -13
- utf-queue-client-1.16.0/test/test_publish_release_info.py +0 -72
- utf-queue-client-1.16.0/utf_queue_client.egg-info/PKG-INFO +0 -13
- {utf-queue-client-1.16.0 → utf-queue-client-1.17.2}/README.md +0 -0
- {utf-queue-client-1.16.0 → utf-queue-client-1.17.2}/setup.cfg +0 -0
- {utf-queue-client-1.16.0 → utf-queue-client-1.17.2}/test/test_async_consumer.py +0 -0
- {utf-queue-client-1.16.0 → utf-queue-client-1.17.2}/test/test_connection_retry.py +0 -0
- {utf-queue-client-1.16.0 → utf-queue-client-1.17.2}/test/test_data_lake_data_producer.py +0 -0
- {utf-queue-client-1.16.0 → utf-queue-client-1.17.2}/test/test_http_producer.py +0 -0
- {utf-queue-client-1.16.0 → utf-queue-client-1.17.2}/test/test_legacy_base_model.py +0 -0
- {utf-queue-client-1.16.0 → utf-queue-client-1.17.2}/test/test_models.py +0 -0
- {utf-queue-client-1.16.0 → utf-queue-client-1.17.2}/test/test_opentelemetry_data_producer.py +0 -0
- {utf-queue-client-1.16.0 → utf-queue-client-1.17.2}/test/test_publish_test_results.py +0 -0
- {utf-queue-client-1.16.0 → utf-queue-client-1.17.2}/test/test_sqa_test_result_producer.py +0 -0
- {utf-queue-client-1.16.0 → utf-queue-client-1.17.2}/test/test_ubai_copy.py +0 -0
- {utf-queue-client-1.16.0 → utf-queue-client-1.17.2}/test/test_ubai_search.py +0 -0
- {utf-queue-client-1.16.0 → utf-queue-client-1.17.2}/test/test_ubai_update_retention.py +0 -0
- {utf-queue-client-1.16.0 → utf-queue-client-1.17.2}/test/test_ubai_upload.py +0 -0
- {utf-queue-client-1.16.0 → utf-queue-client-1.17.2}/test/test_utils.py +0 -0
- {utf-queue-client-1.16.0 → utf-queue-client-1.17.2}/utf_queue_client/__init__.py +0 -0
- {utf-queue-client-1.16.0 → utf-queue-client-1.17.2}/utf_queue_client/clients/__init__.py +0 -0
- {utf-queue-client-1.16.0 → utf-queue-client-1.17.2}/utf_queue_client/clients/async_consumer.py +0 -0
- {utf-queue-client-1.16.0 → utf-queue-client-1.17.2}/utf_queue_client/clients/base_producer.py +0 -0
- {utf-queue-client-1.16.0 → utf-queue-client-1.17.2}/utf_queue_client/clients/data_lake_data_producer.py +0 -0
- {utf-queue-client-1.16.0 → utf-queue-client-1.17.2}/utf_queue_client/clients/http_producer.py +0 -0
- {utf-queue-client-1.16.0 → utf-queue-client-1.17.2}/utf_queue_client/clients/opentelemetry_data_producer.py +0 -0
- {utf-queue-client-1.16.0 → utf-queue-client-1.17.2}/utf_queue_client/clients/sqa_test_result_producer.py +0 -0
- {utf-queue-client-1.16.0 → utf-queue-client-1.17.2}/utf_queue_client/clients/ubai_artifact_upload_request_producer.py +0 -0
- {utf-queue-client-1.16.0 → utf-queue-client-1.17.2}/utf_queue_client/exceptions/__init__.py +0 -0
- {utf-queue-client-1.16.0 → utf-queue-client-1.17.2}/utf_queue_client/models/__init__.py +0 -0
- {utf-queue-client-1.16.0 → utf-queue-client-1.17.2}/utf_queue_client/models/model_factory.py +0 -0
- {utf-queue-client-1.16.0 → utf-queue-client-1.17.2}/utf_queue_client/models/schemas/__init__.py +0 -0
- {utf-queue-client-1.16.0 → utf-queue-client-1.17.2}/utf_queue_client/scripts/__init__.py +0 -0
- {utf-queue-client-1.16.0 → utf-queue-client-1.17.2}/utf_queue_client/scripts/publish_test_results_cli.py +0 -0
- {utf-queue-client-1.16.0 → utf-queue-client-1.17.2}/utf_queue_client/scripts/ubai_copy_cli.py +0 -0
- {utf-queue-client-1.16.0 → utf-queue-client-1.17.2}/utf_queue_client/scripts/ubai_search_cli.py +0 -0
- {utf-queue-client-1.16.0 → utf-queue-client-1.17.2}/utf_queue_client/scripts/ubai_update_retention_cli.py +0 -0
- {utf-queue-client-1.16.0 → utf-queue-client-1.17.2}/utf_queue_client/scripts/ubai_upload_cli.py +0 -0
- {utf-queue-client-1.16.0 → utf-queue-client-1.17.2}/utf_queue_client/utils/__init__.py +0 -0
- {utf-queue-client-1.16.0 → utf-queue-client-1.17.2}/utf_queue_client/utils/queue_metrics_exporter.py +0 -0
- {utf-queue-client-1.16.0 → utf-queue-client-1.17.2}/utf_queue_client/utils/queue_span_exporter.py +0 -0
- {utf-queue-client-1.16.0 → utf-queue-client-1.17.2}/utf_queue_client.egg-info/dependency_links.txt +0 -0
- {utf-queue-client-1.16.0 → utf-queue-client-1.17.2}/utf_queue_client.egg-info/requires.txt +0 -0
- {utf-queue-client-1.16.0 → utf-queue-client-1.17.2}/utf_queue_client.egg-info/top_level.txt +0 -0
|
@@ -2,11 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
|
|
6
5
|
from setuptools import setup, find_packages # noqa: H301
|
|
7
6
|
|
|
8
7
|
NAME = "utf-queue-client"
|
|
9
|
-
VERSION = "1.
|
|
8
|
+
VERSION = "1.17.2"
|
|
10
9
|
# To install the library, run the following
|
|
11
10
|
#
|
|
12
11
|
# python setup.py install
|
|
@@ -54,7 +53,7 @@ setup(
|
|
|
54
53
|
"publish_test_results_cli = utf_queue_client.scripts.publish_test_results_cli:cli_entrypoint",
|
|
55
54
|
"ubai_update_retention_cli = utf_queue_client.scripts.ubai_update_retention_cli:cli_entrypoint",
|
|
56
55
|
"publish_release_info_cli = utf_queue_client.scripts.publish_release_info_cli:cli_entrypoint",
|
|
57
|
-
"ubai_copy_cli = utf_queue_client.scripts.ubai_copy_cli:cli_entrypoint"
|
|
56
|
+
"ubai_copy_cli = utf_queue_client.scripts.ubai_copy_cli:cli_entrypoint",
|
|
58
57
|
],
|
|
59
58
|
},
|
|
60
59
|
include_package_data=True,
|
|
@@ -25,7 +25,7 @@ def queue_server(request):
|
|
|
25
25
|
],
|
|
26
26
|
)
|
|
27
27
|
def test_producer(queue_server, username, password):
|
|
28
|
-
suffix = ".
|
|
28
|
+
suffix = ".silabs.net"
|
|
29
29
|
queue_server = f"{queue_server}{suffix}"
|
|
30
30
|
l = logging.getLogger("test_producer")
|
|
31
31
|
l.info("Creating producer...")
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from otel_extensions import inject_context_to_env, instrumented
|
|
3
|
+
import os
|
|
4
|
+
import subprocess
|
|
5
|
+
import sys
|
|
6
|
+
from utf_queue_client.scripts.publish_release_info_cli import publish_release_information, \
|
|
7
|
+
update_artifacts_retention_days_to_keep_forever, cli
|
|
8
|
+
import requests
|
|
9
|
+
from unittest import mock
|
|
10
|
+
from unittest.mock import MagicMock, patch
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@pytest.fixture
|
|
14
|
+
def publish_release_info():
|
|
15
|
+
yield [
|
|
16
|
+
("releaseDate", "2023-06-16"),
|
|
17
|
+
("branchName", "release/gecko_sdk_3.2"),
|
|
18
|
+
("releaseType", "GA"),
|
|
19
|
+
("releaseName", "23Q2-GA"),
|
|
20
|
+
("SDKBuildNum", "407"),
|
|
21
|
+
("installerURLSDK", "https://jenkins-cbs-gecko-sdk.silabs.net/job/Gecko_SDK_Suite_super/job/release%252F21q4/284/"),
|
|
22
|
+
("IARVersionNum", "9.20.4"),
|
|
23
|
+
("GCCVersionNum", "10.3.1"),
|
|
24
|
+
("CommanderVersionNum", "v1.8.1"),
|
|
25
|
+
("SEVersionNum", "1.2.4"),
|
|
26
|
+
("WSTKFirmwareVersionNum", "v1.4.4")
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@instrumented
|
|
31
|
+
def test_publish_release_info(request, publish_release_info):
|
|
32
|
+
args = ["--username", "svc_sqabot", "--password", "password"]
|
|
33
|
+
for k, v in publish_release_info:
|
|
34
|
+
args += ["--data", k, v]
|
|
35
|
+
|
|
36
|
+
base_dir = os.path.dirname(os.path.dirname(__file__))
|
|
37
|
+
@inject_context_to_env
|
|
38
|
+
def call_cli_script():
|
|
39
|
+
assert "TRACEPARENT" in os.environ
|
|
40
|
+
process = subprocess.Popen(
|
|
41
|
+
[
|
|
42
|
+
sys.executable,
|
|
43
|
+
os.path.join(
|
|
44
|
+
base_dir, "utf_queue_client", "scripts", "publish_release_info_cli.py"
|
|
45
|
+
),
|
|
46
|
+
]
|
|
47
|
+
+ args,
|
|
48
|
+
)
|
|
49
|
+
process.communicate()
|
|
50
|
+
assert process.poll() == 0
|
|
51
|
+
|
|
52
|
+
call_cli_script()
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def test_publish_release_information():
|
|
56
|
+
requests_post = requests.post
|
|
57
|
+
requests.post = MagicMock()
|
|
58
|
+
publish_release_information("", "", {})
|
|
59
|
+
assert requests.post.call_count == 2
|
|
60
|
+
requests.post = requests_post
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def test_publish_release_cli_insufficient_params():
|
|
64
|
+
requests_post = requests.post
|
|
65
|
+
requests_post_mock = MagicMock()
|
|
66
|
+
requests.post = requests_post_mock
|
|
67
|
+
cli("", "", {})
|
|
68
|
+
assert requests.post.call_count == 0
|
|
69
|
+
requests.post = requests_post
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def test_publish_release_cli():
|
|
73
|
+
requests_post = requests.post
|
|
74
|
+
requests_post_mock = MagicMock()
|
|
75
|
+
requests.post = requests_post_mock
|
|
76
|
+
cli("", "", {("branchName", "test"), ("releaseData", "")})
|
|
77
|
+
assert requests_post_mock.call_count == 2
|
|
78
|
+
post_params = requests_post_mock.call_args.kwargs.get('json')
|
|
79
|
+
assert post_params.get("branchName") == "test"
|
|
80
|
+
assert post_params.get("releaseData") is None
|
|
81
|
+
requests.post = requests_post
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def test_update_artifacts_retention_days_to_keep_forever():
|
|
85
|
+
requests_patch = requests.patch
|
|
86
|
+
requests.patch = MagicMock()
|
|
87
|
+
data_dict = {"branchName": "release/gec", "SDKBuildNum": "407"}
|
|
88
|
+
update_artifacts_retention_days_to_keep_forever(data_dict)
|
|
89
|
+
assert requests.patch.call_count == 1
|
|
90
|
+
requests.patch = requests_patch
|
|
91
|
+
patch_response = MagicMock()
|
|
92
|
+
mocked_patch =mock.patch.object(requests, "patch", return_value=patch_response)
|
|
93
|
+
patch_response.status_code = 200
|
|
94
|
+
update_artifacts_retention_days_to_keep_forever(data_dict)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
@patch('requests.post')
|
|
98
|
+
def test_publish_release_information_success(mock_post):
|
|
99
|
+
mock_response_auth = MagicMock()
|
|
100
|
+
mock_response_auth.json.return_value = {"access_token": "test_token"}
|
|
101
|
+
mock_response_auth.raise_for_status.return_value = None
|
|
102
|
+
|
|
103
|
+
mock_response_release = MagicMock()
|
|
104
|
+
mock_response_release.status_code = 201
|
|
105
|
+
mock_response_release.json.return_value = {"message": "success"}
|
|
106
|
+
|
|
107
|
+
mock_post.side_effect = [mock_response_auth, mock_response_release]
|
|
108
|
+
|
|
109
|
+
result = publish_release_information("test_username", "test_password", {"test_key": "test_value"})
|
|
110
|
+
assert mock_response_release.json.called
|
|
111
|
+
assert result
|
|
112
|
+
|
|
113
|
+
@patch('requests.post')
|
|
114
|
+
def test_publish_release_information_release_fail(mock_post):
|
|
115
|
+
# Mock the responses
|
|
116
|
+
mock_response_auth = MagicMock()
|
|
117
|
+
mock_response_auth.json.return_value = {"access_token": "test_token"}
|
|
118
|
+
mock_response_auth.raise_for_status.return_value = None
|
|
119
|
+
|
|
120
|
+
mock_response_release = MagicMock()
|
|
121
|
+
mock_response_release.status_code = 400
|
|
122
|
+
mock_response_release.text = "Release failed"
|
|
123
|
+
|
|
124
|
+
mock_post.side_effect = [mock_response_auth, mock_response_release]
|
|
125
|
+
|
|
126
|
+
result = publish_release_information("test_username", "test_password", {"test_key": "test_value"})
|
|
127
|
+
assert result is None
|
|
128
|
+
|
|
129
|
+
@patch('requests.post')
|
|
130
|
+
def test_publish_release_information_release_fail_422(mock_post):
|
|
131
|
+
# Mock the responses
|
|
132
|
+
mock_response_auth = MagicMock()
|
|
133
|
+
mock_response_auth.json.return_value = {"access_token": "test_token"}
|
|
134
|
+
mock_response_auth.raise_for_status.return_value = None
|
|
135
|
+
|
|
136
|
+
mock_response_release = MagicMock()
|
|
137
|
+
mock_response_release.status_code = 422
|
|
138
|
+
mock_response_release.json.return_value = {"detail": [{"loc": ["", "test_field"], "msg": "test_error"}]}
|
|
139
|
+
|
|
140
|
+
mock_post.side_effect = [mock_response_auth, mock_response_release]
|
|
141
|
+
|
|
142
|
+
# Call the function
|
|
143
|
+
result = publish_release_information("test_username", "test_password", {"test_key": "test_value"})
|
|
144
|
+
assert mock_response_release.json.called
|
|
145
|
+
assert result is None
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
from unittest.mock import MagicMock
|
|
2
|
+
|
|
3
|
+
from utf_queue_client.clients.test_rail_data_producer import (
|
|
4
|
+
TestRailDataProducer,
|
|
5
|
+
TestRailDataProducerFactory,
|
|
6
|
+
DummyTestRailDataProducer,
|
|
7
|
+
LocalTestRailDataProducer,
|
|
8
|
+
)
|
|
9
|
+
import pytest
|
|
10
|
+
import os
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def test_result_producer_empty_url():
|
|
14
|
+
with pytest.raises(RuntimeError):
|
|
15
|
+
_ = TestRailDataProducer()
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@pytest.mark.parametrize("queue_consumer", [60, 120], indirect=True)
|
|
19
|
+
def test_result_producer_central_queue(
|
|
20
|
+
request,
|
|
21
|
+
test_rail_add_test_result,
|
|
22
|
+
amqp_url,
|
|
23
|
+
queue_consumer,
|
|
24
|
+
):
|
|
25
|
+
os.environ["UTF_PRODUCER_APP_ID"] = request.node.name
|
|
26
|
+
producer = TestRailDataProducerFactory.create_producer()
|
|
27
|
+
producer.publish_add_test_result(test_rail_add_test_result)
|
|
28
|
+
queue_consumer.expect_messages(1)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def test_dummy_producer(test_rail_add_test_result):
|
|
32
|
+
producer = DummyTestRailDataProducer()
|
|
33
|
+
producer.publish_add_test_result(test_rail_add_test_result)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def test_local_test_rail_producer(test_rail_add_test_result, mocker):
|
|
37
|
+
mocker.patch(
|
|
38
|
+
"utf_queue_client.clients.base_producer.BlockingProducer.__init__",
|
|
39
|
+
return_value=None,
|
|
40
|
+
)
|
|
41
|
+
mocker.patch(
|
|
42
|
+
"utf_queue_client.clients.base_producer.BlockingProducer.queue_declare"
|
|
43
|
+
)
|
|
44
|
+
mock_producer_publish = mocker.patch(
|
|
45
|
+
"utf_queue_client.clients.base_producer.BlockingProducer.publish"
|
|
46
|
+
)
|
|
47
|
+
producer = LocalTestRailDataProducer()
|
|
48
|
+
producer.producer_app_id = "DUMMY"
|
|
49
|
+
producer.publish_add_test_result(test_rail_add_test_result)
|
|
50
|
+
assert mock_producer_publish.called
|
|
51
|
+
kwargs = mock_producer_publish.call_args.kwargs
|
|
52
|
+
payload = kwargs.get("payload")
|
|
53
|
+
assert payload.get("recordType") == "TEST_RAIL_EVENT"
|
|
54
|
+
assert payload.get("recordSubType") == "TEST_RESULT"
|
|
55
|
+
assert payload.get("tenantKey") == "DUMMY"
|
|
56
|
+
payload_data = payload.get("payload")
|
|
57
|
+
assert payload_data.get("version") == "v1"
|
|
58
|
+
assert payload_data.get("comment") == "testing"
|
|
59
|
+
assert payload_data.get("status") == "pass"
|
|
60
|
+
assert payload_data.get("run_id") == 1234
|
|
61
|
+
assert payload_data.get("id") == "C123"
|
|
62
|
+
custom_props = payload_data.get("custom_props")
|
|
63
|
+
assert custom_props.get("custom_interface_type") == "gcc"
|
|
64
|
+
assert custom_props.get("custom_evk_version") == "v2"
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from .base_producer import BlockingProducer as AMQPBlockingProducer, ConnectionError
|
|
3
|
+
from .http_producer import CompositeHTTPProducer
|
|
4
|
+
from ..models import TestRailResult
|
|
5
|
+
from ..models import QueueMessage
|
|
6
|
+
from . import Loggable
|
|
7
|
+
from socket import gethostname
|
|
8
|
+
from datetime import datetime
|
|
9
|
+
from abc import ABC, abstractmethod
|
|
10
|
+
from otel_extensions import instrumented
|
|
11
|
+
from typing import Optional
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
__all__ = [
|
|
15
|
+
"TestRailDataProducer",
|
|
16
|
+
"DummyTestRailDataProducer",
|
|
17
|
+
"ConnectionError",
|
|
18
|
+
"TestRailDataProducerFactory",
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class BaseTestRailDataProducer(ABC):
|
|
23
|
+
@abstractmethod
|
|
24
|
+
def publish_add_test_result(self, test_result: TestRailResult):
|
|
25
|
+
"""publish a test result object"""
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class TestRailDataProducer(BaseTestRailDataProducer):
|
|
29
|
+
RECORD_TYPE = "TEST_RAIL_EVENT"
|
|
30
|
+
|
|
31
|
+
def __init__(
|
|
32
|
+
self,
|
|
33
|
+
url=None,
|
|
34
|
+
producer_app_id: str = None,
|
|
35
|
+
producer_class: Optional[type] = None,
|
|
36
|
+
):
|
|
37
|
+
if producer_class is None:
|
|
38
|
+
producer_class = AMQPBlockingProducer
|
|
39
|
+
self.queue_name = "default"
|
|
40
|
+
self.__producer_client = producer_class(url, producer_app_id)
|
|
41
|
+
self.__producer_client.queue_declare(queue=self.queue_name, durable=True)
|
|
42
|
+
self.producer_app_id = producer_app_id
|
|
43
|
+
|
|
44
|
+
@instrumented
|
|
45
|
+
def publish_add_test_result(self, test_result: TestRailResult):
|
|
46
|
+
queue_message = QueueMessage(
|
|
47
|
+
payload=test_result,
|
|
48
|
+
recordType=self.RECORD_TYPE,
|
|
49
|
+
recordSubType="TEST_RESULT",
|
|
50
|
+
tenantKey=self.producer_app_id,
|
|
51
|
+
recordTimestamp=datetime.now().isoformat(),
|
|
52
|
+
)
|
|
53
|
+
queue_message.validate_schema()
|
|
54
|
+
self.__producer_client.publish(
|
|
55
|
+
exchange="",
|
|
56
|
+
routing_key=self.queue_name,
|
|
57
|
+
payload=queue_message.as_dict(),
|
|
58
|
+
persistent=True,
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class LocalTestRailDataProducer(TestRailDataProducer):
|
|
63
|
+
def __init__(self):
|
|
64
|
+
super().__init__(
|
|
65
|
+
"amqp://guest:guest@localhost:5672/%2f",
|
|
66
|
+
os.environ.get(
|
|
67
|
+
"UTF_PRODUCER_APP_ID", f"LocalTestRailDataProducer at {gethostname()}"
|
|
68
|
+
),
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class DummyTestRailDataProducer(BaseTestRailDataProducer):
|
|
73
|
+
def publish_add_test_result(self, test_result: TestRailResult):
|
|
74
|
+
# noqa
|
|
75
|
+
pass
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class TestRailDataProducerFactory(Loggable):
|
|
79
|
+
@classmethod
|
|
80
|
+
def create_producer(cls, raise_on_connection_error=False):
|
|
81
|
+
try:
|
|
82
|
+
queue_server_url = os.environ.get("UTF_QUEUE_SERVER_URL")
|
|
83
|
+
if queue_server_url is not None:
|
|
84
|
+
return TestRailDataProducer(
|
|
85
|
+
url=queue_server_url,
|
|
86
|
+
producer_app_id=os.environ.get("UTF_PRODUCER_APP_ID"),
|
|
87
|
+
producer_class=CompositeHTTPProducer,
|
|
88
|
+
)
|
|
89
|
+
else:
|
|
90
|
+
return LocalTestRailDataProducer()
|
|
91
|
+
except ConnectionError as e:
|
|
92
|
+
cls.logger.warning(f"Unable to connect to queue server: {repr(e)}")
|
|
93
|
+
if raise_on_connection_error:
|
|
94
|
+
raise
|
|
95
|
+
return DummyTestRailDataProducer()
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
from typing import Optional, List, Any
|
|
2
|
+
from warnings import catch_warnings, filterwarnings
|
|
3
|
+
|
|
2
4
|
import jsonschema
|
|
3
5
|
from ..exceptions import SchemaValidationError, ValidationError
|
|
4
6
|
from pydantic import (
|
|
@@ -26,10 +28,12 @@ class BaseModelWithValidation(PydanticBaseModel):
|
|
|
26
28
|
def _set_schema(self, schema: dict, class_name: str):
|
|
27
29
|
validator_class = jsonschema.validators.validator_for(schema)
|
|
28
30
|
validator_class.check_schema(schema)
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
with catch_warnings():
|
|
32
|
+
filterwarnings("ignore", category=DeprecationWarning)
|
|
33
|
+
self.__validator = validator_class(
|
|
34
|
+
schema["definitions"][class_name],
|
|
35
|
+
resolver=jsonschema.RefResolver.from_schema(schema),
|
|
36
|
+
)
|
|
33
37
|
|
|
34
38
|
def as_dict(self) -> dict:
|
|
35
39
|
return self.dict()
|
utf-queue-client-1.17.2/utf_queue_client/models/schemas/utf_queue_models/models/python/__init__.py
ADDED
|
File without changes
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
# generated by datamodel-codegen:
|
|
2
|
+
# filename: queue_message.json
|
|
3
|
+
# timestamp: 2024-03-25T08:36:22+00:00
|
|
4
|
+
|
|
5
|
+
from typing import Any, Dict, List, Optional, Union
|
|
6
|
+
|
|
7
|
+
from pydantic import Extra, Field, constr
|
|
8
|
+
from typing_extensions import Literal
|
|
9
|
+
from utf_queue_client.models.base_model import BaseModelWithValidation
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Model(BaseModelWithValidation):
|
|
13
|
+
__root__: Any
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class QueueRecord(BaseModelWithValidation):
|
|
17
|
+
pass
|
|
18
|
+
|
|
19
|
+
class Config:
|
|
20
|
+
extra = Extra.allow
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class DataLakeData(BaseModelWithValidation):
|
|
24
|
+
dataFormat: Literal['CSV', 'JSON', 'JSONSTR', 'NDJSON', 'PARQUET']
|
|
25
|
+
object_id: Optional[str] = None
|
|
26
|
+
data: Union[Dict[str, Any], List[Dict[str, Any]], str]
|
|
27
|
+
compression: Optional[Literal['GZIP', 'NONE', 'SNAPPY']] = None
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class TelemetryData(BaseModelWithValidation):
|
|
31
|
+
dataType: Literal['LOGS', 'METRICS', 'TRACES']
|
|
32
|
+
base64ProtobufData: str
|
|
33
|
+
compression: Optional[str] = None
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class ArtifactMetadata(BaseModelWithValidation):
|
|
37
|
+
pass
|
|
38
|
+
|
|
39
|
+
class Config:
|
|
40
|
+
extra = Extra.allow
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class ArtifactBuildMetadata(BaseModelWithValidation):
|
|
44
|
+
branch: Optional[str] = None
|
|
45
|
+
stack: Optional[str] = None
|
|
46
|
+
build_number: Optional[str] = None
|
|
47
|
+
target: Optional[str] = None
|
|
48
|
+
studio: Optional[str] = None
|
|
49
|
+
compiler: Optional[str] = None
|
|
50
|
+
app_name: Optional[str] = None
|
|
51
|
+
test_suite: Optional[str] = None
|
|
52
|
+
chip_id: Optional[str] = None
|
|
53
|
+
studio_build_version: Optional[str] = None
|
|
54
|
+
compiler_build_version: Optional[str] = None
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class SqaAppBuildResult(BaseModelWithValidation):
|
|
58
|
+
session_pk_id: str = Field(
|
|
59
|
+
...,
|
|
60
|
+
description='Logical FK to dbo.jobStatusTable.\nNot creating the constraint in case this comes in before the session record.',
|
|
61
|
+
)
|
|
62
|
+
app_name: constr(max_length=512) = Field(..., description='Name of the application')
|
|
63
|
+
app_description: Optional[constr(max_length=1024)] = Field(
|
|
64
|
+
None, description='Description of what the application does'
|
|
65
|
+
)
|
|
66
|
+
test_suite_name: Optional[constr(max_length=512)] = Field(
|
|
67
|
+
None, description='Description of the grouping of applications'
|
|
68
|
+
)
|
|
69
|
+
test_result_type: constr(max_length=256) = Field(
|
|
70
|
+
..., description='Need table for validation created from the existing java enum'
|
|
71
|
+
)
|
|
72
|
+
executor_name: Optional[constr(max_length=256)] = Field(
|
|
73
|
+
None, description='Where the application was built'
|
|
74
|
+
)
|
|
75
|
+
feature_name: Optional[constr(max_length=256)] = Field(
|
|
76
|
+
None, description='Feature being tested by this test'
|
|
77
|
+
)
|
|
78
|
+
module_name: Optional[constr(max_length=256)] = Field(
|
|
79
|
+
None, description='Description of the device type that the application runs on'
|
|
80
|
+
)
|
|
81
|
+
phy_name: Optional[constr(max_length=256)] = Field(
|
|
82
|
+
None, description='Radio configuration used by the device'
|
|
83
|
+
)
|
|
84
|
+
test_result: Literal['FAIL', 'PASS', 'block', 'fail', 'pass', 'skip'] = Field(
|
|
85
|
+
..., description='Did the application build'
|
|
86
|
+
)
|
|
87
|
+
engineer_name: Optional[constr(max_length=256)] = Field(
|
|
88
|
+
None, description='Name of the engineer who created the test'
|
|
89
|
+
)
|
|
90
|
+
exception_msg: Optional[str] = Field(
|
|
91
|
+
None, description='Stack dump exception message from build'
|
|
92
|
+
)
|
|
93
|
+
iot_req_id: Optional[constr(max_length=256)] = Field(
|
|
94
|
+
None, description='JIRA IOT Req Number'
|
|
95
|
+
)
|
|
96
|
+
tool_chain: Optional[constr(max_length=256)] = Field(
|
|
97
|
+
None,
|
|
98
|
+
description='Need table for validation.\nThis is the tool and version used to build the application with colon separation\niar:7.80.1',
|
|
99
|
+
)
|
|
100
|
+
notes: Optional[constr(max_length=256)] = None
|
|
101
|
+
test_duration_sec: float = Field(
|
|
102
|
+
..., description='Length of time to build the application'
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
class SqaTestResult(BaseModelWithValidation):
|
|
107
|
+
session_pk_id: str = Field(
|
|
108
|
+
...,
|
|
109
|
+
description='Logical FK to dbo.jobStatusTable.\nNot creating the constraint in case this comes in before the session record.',
|
|
110
|
+
)
|
|
111
|
+
test_case_id: constr(max_length=512) = Field(
|
|
112
|
+
...,
|
|
113
|
+
description='Passed in from the test executor.\nFrom the test management system or git.',
|
|
114
|
+
)
|
|
115
|
+
test_case_version_num: int
|
|
116
|
+
test_suite_name: Optional[constr(max_length=512)] = Field(
|
|
117
|
+
None, description='Named group of tests'
|
|
118
|
+
)
|
|
119
|
+
test_description: Optional[constr(max_length=1024)] = Field(
|
|
120
|
+
None, description='What does the test case actually do'
|
|
121
|
+
)
|
|
122
|
+
test_result_type: constr(max_length=256) = Field(
|
|
123
|
+
..., description='Need to create a table for verification of this field'
|
|
124
|
+
)
|
|
125
|
+
test_parametric_data: Optional[str] = Field(
|
|
126
|
+
None, description='Test Parametric Data'
|
|
127
|
+
)
|
|
128
|
+
test_case_name: constr(max_length=512) = Field(
|
|
129
|
+
...,
|
|
130
|
+
description='Human readable version of the test case ID\nShort summary/description',
|
|
131
|
+
)
|
|
132
|
+
executor_name: constr(max_length=256) = Field(
|
|
133
|
+
..., description='Where the test actually ran'
|
|
134
|
+
)
|
|
135
|
+
feature_name: constr(max_length=256) = Field(
|
|
136
|
+
..., description='Feature being tested by this test'
|
|
137
|
+
)
|
|
138
|
+
test_creation_date: str = Field(
|
|
139
|
+
..., description='Date the test was created\nISO-8601 format'
|
|
140
|
+
)
|
|
141
|
+
testbed_name: constr(max_length=256) = Field(
|
|
142
|
+
..., description='Grouping of all of the hardware used to execute the test'
|
|
143
|
+
)
|
|
144
|
+
module_name: constr(max_length=256) = Field(
|
|
145
|
+
..., description='Testbed component list'
|
|
146
|
+
)
|
|
147
|
+
phy_name: Optional[constr(max_length=256)] = Field(
|
|
148
|
+
None, description='Radio configuration used by the device'
|
|
149
|
+
)
|
|
150
|
+
test_result: Literal['block', 'fail', 'metrics', 'pass', 'skip']
|
|
151
|
+
engineer_name: Optional[constr(max_length=256)] = Field(
|
|
152
|
+
None, description='Name of the engineer who created the test'
|
|
153
|
+
)
|
|
154
|
+
exception_msg: Optional[str] = Field(
|
|
155
|
+
None, description='If an error occurs, this is the message returned.'
|
|
156
|
+
)
|
|
157
|
+
iot_req_id: constr(max_length=256)
|
|
158
|
+
tool_chain: constr(max_length=256) = Field(
|
|
159
|
+
...,
|
|
160
|
+
description='Need table for validation.\nThis is the tool and version used to build the application with colon separation\niar:7.80.1',
|
|
161
|
+
)
|
|
162
|
+
vendor_name: Optional[constr(max_length=256)] = None
|
|
163
|
+
vendor_build: Optional[constr(max_length=256)] = None
|
|
164
|
+
vendor_result: Optional[constr(max_length=256)] = None
|
|
165
|
+
notes: Optional[constr(max_length=1024)] = None
|
|
166
|
+
portal_watch: Optional[str] = Field(
|
|
167
|
+
None, description='Change this to boolean - default false'
|
|
168
|
+
)
|
|
169
|
+
test_duration_sec: float = Field(..., description='Test duration in seconds')
|
|
170
|
+
test_bed_label: Optional[constr(max_length=256)] = None
|
|
171
|
+
req_id: Optional[constr(max_length=256)] = None
|
|
172
|
+
product_line: Optional[constr(max_length=256)] = None
|
|
173
|
+
product_type: Optional[constr(max_length=256)] = None
|
|
174
|
+
customer_type: Optional[constr(max_length=256)] = None
|
|
175
|
+
jenkins_test_case_results_url: Optional[constr(max_length=1500)] = None
|
|
176
|
+
test_case_uuid: Optional[str] = Field(
|
|
177
|
+
None, description='UUID generated by the client software'
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
class SqaTestSession(BaseModelWithValidation):
|
|
182
|
+
PK_ID: str = Field(..., description='UUID generated by the Jenkins client software')
|
|
183
|
+
startTime: str = Field(..., description='ISO-8601 Datetime')
|
|
184
|
+
stopTime: Optional[str] = Field(None, description='ISO-8601 datetime')
|
|
185
|
+
jenkinsJobStatus: Literal['COMPLETE', 'FAIL', 'IN PROGRESS'] = Field(
|
|
186
|
+
..., description='Status of the Jenkins job'
|
|
187
|
+
)
|
|
188
|
+
duration: Optional[int] = Field(
|
|
189
|
+
None,
|
|
190
|
+
description='Elapsed number of seconds for the Jenkins job.\nShould be close to stop time - start time.\nChange the data type in the DB to integer.',
|
|
191
|
+
)
|
|
192
|
+
jobType: Optional[constr(max_length=256)] = Field(
|
|
193
|
+
None, description='Type of Jenkins job'
|
|
194
|
+
)
|
|
195
|
+
releaseName: constr(max_length=256)
|
|
196
|
+
branchName: constr(max_length=256)
|
|
197
|
+
stackName: constr(max_length=256)
|
|
198
|
+
SDKBuildNum: int
|
|
199
|
+
SDKUrl: Optional[constr(max_length=1500)] = None
|
|
200
|
+
studioUrl: Optional[constr(max_length=1500)] = None
|
|
201
|
+
totalTests: Optional[int] = None
|
|
202
|
+
PASS_cnt: Optional[int] = None
|
|
203
|
+
FAIL_cnt: Optional[int] = None
|
|
204
|
+
SKIP_cnt: Optional[int] = None
|
|
205
|
+
BLOCK_cnt: Optional[int] = None
|
|
206
|
+
jenkinsServerName: constr(max_length=256)
|
|
207
|
+
jenkinRunNum: int
|
|
208
|
+
jenkinsJobName: constr(max_length=1500)
|
|
209
|
+
jenkinsTestResultsUrl: constr(max_length=1500)
|
|
210
|
+
traceId: Optional[constr(max_length=500)] = None
|
|
211
|
+
testFramework: Optional[constr(max_length=256)] = None
|
|
212
|
+
SDKVersion: Optional[constr(max_length=256)] = None
|
|
213
|
+
test_run_by: Optional[constr(max_length=256)] = None
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
class LogEvent(BaseModelWithValidation):
|
|
217
|
+
pass
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
class ExceptionEvent(BaseModelWithValidation):
|
|
221
|
+
pass
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
class TestResultCustomProps(BaseModelWithValidation):
|
|
225
|
+
pass
|
|
226
|
+
|
|
227
|
+
class Config:
|
|
228
|
+
extra = Extra.allow
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
class QueueMessage(BaseModelWithValidation):
|
|
232
|
+
recordType: Literal[
|
|
233
|
+
'ARTIFACT_UPLOAD_REQUEST',
|
|
234
|
+
'DATALAKE_DATA',
|
|
235
|
+
'EXCEPTION_EVENT',
|
|
236
|
+
'LOG_EVENT',
|
|
237
|
+
'OPENTELEMETRY_DATA',
|
|
238
|
+
'TEST_RAIL_EVENT',
|
|
239
|
+
'UTF_TEST_EVENT',
|
|
240
|
+
] = Field(..., description='Type of record')
|
|
241
|
+
recordSubType: Optional[
|
|
242
|
+
Literal['BUILD_RESULT', 'SESSION_START', 'SESSION_STOP', 'TEST_RESULT']
|
|
243
|
+
] = Field(
|
|
244
|
+
None,
|
|
245
|
+
description='Subtype of record. Not all types have a subtype, but it is required when they have one.',
|
|
246
|
+
)
|
|
247
|
+
tenantKey: str = Field(
|
|
248
|
+
...,
|
|
249
|
+
description='Unique string that identifies the app/group sending the message.\nForward looking to match the data lake infrastructure.',
|
|
250
|
+
)
|
|
251
|
+
recordTimestamp: str = Field(
|
|
252
|
+
...,
|
|
253
|
+
description='UTC datetime.\nUse ISO-8601 format with time zone\n2022-03-10T18:50:05Z',
|
|
254
|
+
)
|
|
255
|
+
payload: 'QueueRecord' = Field(
|
|
256
|
+
...,
|
|
257
|
+
description='Record Payload.\nThis is flexible to allow different fields for different record types and DB tables',
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
class QueueMessageV1(BaseModelWithValidation):
|
|
262
|
+
recordType: Literal[
|
|
263
|
+
'ARTIFACT_UPLOAD_REQUEST',
|
|
264
|
+
'EXCEPTION_EVENT',
|
|
265
|
+
'LOG_EVENT',
|
|
266
|
+
'TEST_EVENT',
|
|
267
|
+
'UTF_TEST_EVENT',
|
|
268
|
+
] = Field(..., description='Type of record')
|
|
269
|
+
payload: 'QueueRecord' = Field(..., description='Record Payload')
|
|
270
|
+
timestamp: float = Field(
|
|
271
|
+
..., description='UTC Timestamp\nGiven in seconds since epoch (unix time)'
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
class ArtifactUploadRequest(BaseModelWithValidation):
|
|
276
|
+
name: str
|
|
277
|
+
extension: str
|
|
278
|
+
metadata: Union['ArtifactMetadata', 'ArtifactBuildMetadata']
|
|
279
|
+
base64Content: str
|
|
280
|
+
validateMetadata: bool
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
class TestRailResult(BaseModelWithValidation):
|
|
284
|
+
id: str
|
|
285
|
+
run_id: int
|
|
286
|
+
status: str
|
|
287
|
+
comment: Optional[str] = None
|
|
288
|
+
version: Optional[str] = None
|
|
289
|
+
defects: Optional[str] = None
|
|
290
|
+
assigned_to_id: Optional[int] = None
|
|
291
|
+
custom_props: Optional['TestResultCustomProps'] = None
|