codemie-test-harness 0.1.129__py3-none-any.whl → 0.1.130__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.
Potentially problematic release.
This version of codemie-test-harness might be problematic. Click here for more details.
- {codemie_test_harness-0.1.129.dist-info → codemie_test_harness-0.1.130.dist-info}/METADATA +2 -2
- {codemie_test_harness-0.1.129.dist-info → codemie_test_harness-0.1.130.dist-info}/RECORD +10 -6
- tests/conftest.py +4 -0
- tests/providers/__init__.py +0 -0
- tests/providers/test_providers_endpoints.py +239 -0
- tests/test_data/files/provider_payload.json +382 -0
- tests/utils/http_utils.py +91 -3
- tests/utils/provider_utils.py +178 -0
- {codemie_test_harness-0.1.129.dist-info → codemie_test_harness-0.1.130.dist-info}/WHEEL +0 -0
- {codemie_test_harness-0.1.129.dist-info → codemie_test_harness-0.1.130.dist-info}/entry_points.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: codemie-test-harness
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.130
|
|
4
4
|
Summary: Autotest for CodeMie backend and UI
|
|
5
5
|
Author: Anton Yeromin
|
|
6
6
|
Author-email: anton_yeromin@epam.com
|
|
@@ -13,7 +13,7 @@ Requires-Dist: aws-assume-role-lib (>=2.10.0,<3.0.0)
|
|
|
13
13
|
Requires-Dist: boto3 (>=1.39.8,<2.0.0)
|
|
14
14
|
Requires-Dist: click (>=8.1.7,<9.0.0)
|
|
15
15
|
Requires-Dist: codemie-plugins (>=0.1.123,<0.2.0)
|
|
16
|
-
Requires-Dist: codemie-sdk-python (==0.1.
|
|
16
|
+
Requires-Dist: codemie-sdk-python (==0.1.130)
|
|
17
17
|
Requires-Dist: pytest (>=8.4.1,<9.0.0)
|
|
18
18
|
Requires-Dist: pytest-playwright (>=0.7.0,<0.8.0)
|
|
19
19
|
Requires-Dist: pytest-reportportal (>=5.5.2,<6.0.0)
|
|
@@ -52,7 +52,7 @@ tests/assistant/tools/servicenow/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRk
|
|
|
52
52
|
tests/assistant/tools/servicenow/test_servicenow_tools.py,sha256=x3m5CW65la_FVwL5inJwl35KU_bhMVJfNsqTnyYnFkc,589
|
|
53
53
|
tests/assistant/tools/vcs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
54
54
|
tests/assistant/tools/vcs/test_assistant_with_vcs_tools.py,sha256=j9lWYbQ5BjU-4L74tBm4gxQqfb3TCc0T9SEFluTDytc,859
|
|
55
|
-
tests/conftest.py,sha256=
|
|
55
|
+
tests/conftest.py,sha256=PdhMQMvYlhklKW4KuEda20HnzfO2eBoIsQ5AafCYd0Q,25719
|
|
56
56
|
tests/e2e/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
57
57
|
tests/e2e/test_e2e.py,sha256=_jWiDgUhOpO2p2VH987RXepS3PKvd1pSd3IFxKtK_z4,6215
|
|
58
58
|
tests/enums/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -69,6 +69,8 @@ tests/integrations/user/test_user_integrations.py,sha256=wmTYEK55y5aKU-DjOMyJnI_
|
|
|
69
69
|
tests/llm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
70
70
|
tests/llm/assistants/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
71
71
|
tests/llm/assistants/test_llm.py,sha256=XjWZH7Pg8-cva64OlkZYWPMGZJ3MeCLJXsxlVnYXqWs,3162
|
|
72
|
+
tests/providers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
73
|
+
tests/providers/test_providers_endpoints.py,sha256=5A2JJvqsetcAP3IoqK4eoiebsdUC5rxr4gJ-sSFRq6M,7836
|
|
72
74
|
tests/search/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
73
75
|
tests/search/test_search_assistant.py,sha256=Pqbv9ysVy-IN4v05orBq0akpuHkzHDAtVa6eLorD5GE,3170
|
|
74
76
|
tests/search/test_search_datasource.py,sha256=b_Q7zjCjw_9qjUQEblUnoZeDxXOMZLsXmWQnxuj2GQk,6618
|
|
@@ -108,6 +110,7 @@ tests/test_data/direct_tools/vcs_tools_test_data.py,sha256=ioMJ-eQfa2S1NPmXHyb9U
|
|
|
108
110
|
tests/test_data/file_management_tools_test_data.py,sha256=TP9D2CtrZ_N6BFLcqErW6ggHlN9hUkSKGGGwo4Gt55c,3727
|
|
109
111
|
tests/test_data/file_test_data.py,sha256=lhMJBbejENthkDNcg5vvUB-nWFU4zidnPaplQJBU1CM,11712
|
|
110
112
|
tests/test_data/files/large-files/large_file.txt,sha256=uLjvYxR0RpLPrXstAfhvfWhMwiWrhsaCl_WV-Lh6GKA,110100480
|
|
113
|
+
tests/test_data/files/provider_payload.json,sha256=TkRb0GucodIXg3TgjxRD_mJOJRsQw_oFKv3pyTSYlZ0,17371
|
|
111
114
|
tests/test_data/files/test.csv,sha256=M1FdTVc3LM74A2g6dQxRfOmJEvyJXRKBzWVzD4lFSno,52
|
|
112
115
|
tests/test_data/files/test.docx,sha256=COrp_ujSoOVcG88in3t3w2oGckbd7xovk-ArsOrAq1w,26643
|
|
113
116
|
tests/test_data/files/test.gif,sha256=y8UgoZSskETNHFBx5l7dQuoMXhbsPKpYX65kCAWRYI0,3442386
|
|
@@ -210,11 +213,12 @@ tests/utils/constants.py,sha256=pQB9dC2MgT8X1wPA0rWmGJn4HSWCpUZvvLuI42kw2nY,1090
|
|
|
210
213
|
tests/utils/datasource_utils.py,sha256=Dwos1XAZefm1wjB_EkJ2S9Ax4a74MIDKaOxctGAdaH8,12443
|
|
211
214
|
tests/utils/file_utils.py,sha256=hY-kwnyzvtd1BQif8r5NhvRTGfpKLmQKyRsq1Tuflhg,585
|
|
212
215
|
tests/utils/gitbud_utils.py,sha256=UJ3RbhPSjHQSdos6S6zTR9iZULrBDJXoXq9cbjFH7bo,7829
|
|
213
|
-
tests/utils/http_utils.py,sha256=
|
|
216
|
+
tests/utils/http_utils.py,sha256=wjhttibzzNhleKzWgWC01Q0Y5sV9scu-Ski-qgJPd-Q,4179
|
|
214
217
|
tests/utils/integration_utils.py,sha256=nP7pqDklkp_xPp4hUjSjZ_MBgeRucjYz1CrDq5Zuw58,4358
|
|
215
218
|
tests/utils/json_utils.py,sha256=PWO4Ixxgta_zkdq-8umcP9qwDSi9JFxMuaT2NW3v1eI,226
|
|
216
219
|
tests/utils/logger_util.py,sha256=6Kca4pLxyTYnUgm2i3j19DdZSH6XUSGXPjHtExx33QU,828
|
|
217
220
|
tests/utils/notification_utils.py,sha256=0x0-yEIH7Azn5Cs2KRXHfQVBJwiwo1F8xSnfaynvQ8Q,3459
|
|
221
|
+
tests/utils/provider_utils.py,sha256=jxyDxiC1TKqnev1xtmsXLKNJbDqAG12kGDB1tuK_O1g,5077
|
|
218
222
|
tests/utils/pytest_utils.py,sha256=k-mEjX2qpnh37sqKpJqYhZT6BV9974y_KaAhv8Xj9GI,284
|
|
219
223
|
tests/utils/search_utils.py,sha256=O8uYyczObhTYtmdL6TVmH5F9xPuppICiGVbixSmRhzo,1108
|
|
220
224
|
tests/utils/similarity_check.py,sha256=vUp1ksz80hZwTsykCc027bR3tCXwd3ZdRLmMtYnEjjg,1447
|
|
@@ -314,7 +318,7 @@ tests/workflow/virtual_assistant_tools/servicenow/__init__.py,sha256=47DEQpj8HBS
|
|
|
314
318
|
tests/workflow/virtual_assistant_tools/servicenow/test_workflow_with_servicenow_tools.py,sha256=ecTfkwxPMbyyEKS-dArAQkluZURO1nThwDdD66mgC3E,814
|
|
315
319
|
tests/workflow/virtual_assistant_tools/vcs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
316
320
|
tests/workflow/virtual_assistant_tools/vcs/test_workflow_with_vcs_tools.py,sha256=G0iI3X7SGEEy1Z2Hc7j917saY3lpzgfil_GtALCFilE,1043
|
|
317
|
-
codemie_test_harness-0.1.
|
|
318
|
-
codemie_test_harness-0.1.
|
|
319
|
-
codemie_test_harness-0.1.
|
|
320
|
-
codemie_test_harness-0.1.
|
|
321
|
+
codemie_test_harness-0.1.130.dist-info/METADATA,sha256=NO40P2WjyBMPyafu0tTS80UtDcwCIKDj9rmK69SMR9M,8998
|
|
322
|
+
codemie_test_harness-0.1.130.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
|
|
323
|
+
codemie_test_harness-0.1.130.dist-info/entry_points.txt,sha256=n98t-EOM5M1mnMl_j2X4siyeO9zr0WD9a5LF7JyElIM,73
|
|
324
|
+
codemie_test_harness-0.1.130.dist-info/RECORD,,
|
tests/conftest.py
CHANGED
|
@@ -34,6 +34,7 @@ from tests.utils.gitbud_utils import GitBudUtils
|
|
|
34
34
|
from tests.utils.integration_utils import IntegrationUtils
|
|
35
35
|
from tests.utils.logger_util import setup_logger
|
|
36
36
|
from tests.utils.notification_utils import GmailUtils
|
|
37
|
+
from tests.utils.provider_utils import ProviderUtils
|
|
37
38
|
from tests.utils.search_utils import SearchUtils
|
|
38
39
|
from tests.utils.similarity_check import SimilarityCheck
|
|
39
40
|
from tests.utils.workflow_utils import WorkflowUtils
|
|
@@ -818,3 +819,6 @@ def pytest_sessionfinish(session):
|
|
|
818
819
|
if prefix in workflow.name:
|
|
819
820
|
client.workflows.delete(workflow_id=workflow.id)
|
|
820
821
|
sleep(clean_up_timeout)
|
|
822
|
+
|
|
823
|
+
providers_utils = ProviderUtils(client)
|
|
824
|
+
providers_utils.cleanup_test_providers()
|
|
File without changes
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from hamcrest import (
|
|
3
|
+
assert_that,
|
|
4
|
+
is_,
|
|
5
|
+
equal_to,
|
|
6
|
+
has_key,
|
|
7
|
+
all_of,
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
from tests.utils.base_utils import get_random_name
|
|
11
|
+
from tests.utils.provider_utils import ProviderUtils
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@pytest.fixture(scope="session")
|
|
15
|
+
def providers_utils(client):
|
|
16
|
+
return ProviderUtils(client)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
nonexistent_id = "nonexistent-provider-id-12345"
|
|
20
|
+
|
|
21
|
+
# =============================================================================
|
|
22
|
+
# GET /v1/providers - List all providers
|
|
23
|
+
# =============================================================================
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@pytest.mark.regression
|
|
27
|
+
def test_get_providers_endpoint(providers_utils):
|
|
28
|
+
response = providers_utils.send_get_request_to_providers_endpoint()
|
|
29
|
+
|
|
30
|
+
assert_that(response.status_code, equal_to(200))
|
|
31
|
+
|
|
32
|
+
response_data = response.json()
|
|
33
|
+
|
|
34
|
+
# Validate response structure
|
|
35
|
+
assert_that(isinstance(response_data, list), is_(True))
|
|
36
|
+
for provider in response_data:
|
|
37
|
+
assert_that(
|
|
38
|
+
provider,
|
|
39
|
+
all_of(has_key("provided_toolkits"), has_key("service_location_url")),
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
# =============================================================================
|
|
44
|
+
# POST /v1/providers - Create new provider
|
|
45
|
+
# =============================================================================
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@pytest.mark.regression
|
|
49
|
+
def test_post_providers_endpoint(providers_utils):
|
|
50
|
+
request_json = providers_utils.provider_request_json()
|
|
51
|
+
# Ensure unique provider name to avoid conflicts
|
|
52
|
+
provider_name = get_random_name()
|
|
53
|
+
request_json["name"] = provider_name
|
|
54
|
+
|
|
55
|
+
create_response = providers_utils.send_post_request_to_providers_endpoint(
|
|
56
|
+
request_json
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
assert_that(create_response.status_code, equal_to(200))
|
|
60
|
+
|
|
61
|
+
# get provider to verify it was created
|
|
62
|
+
get_response = providers_utils.send_get_request_to_providers_endpoint()
|
|
63
|
+
|
|
64
|
+
providers = get_response.json()
|
|
65
|
+
created_provider = next((p for p in providers if p["name"] == provider_name), None)
|
|
66
|
+
|
|
67
|
+
assert_that(
|
|
68
|
+
created_provider is not None,
|
|
69
|
+
is_(True),
|
|
70
|
+
"Created provider should be in the list",
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@pytest.mark.regression
|
|
75
|
+
def test_post_providers_endpoint_validation_error(providers_utils):
|
|
76
|
+
"""Test POST /v1/providers with invalid provided_toolkits node"""
|
|
77
|
+
request_json = providers_utils.provider_request_json()
|
|
78
|
+
request_json["provided_toolkits"] = "invalid_value"
|
|
79
|
+
|
|
80
|
+
response = providers_utils.send_post_request_to_providers_endpoint(request_json)
|
|
81
|
+
|
|
82
|
+
assert_that(response.status_code, equal_to(422))
|
|
83
|
+
assert_that(
|
|
84
|
+
response.json()["error"]["details"][0]["msg"],
|
|
85
|
+
equal_to("Input should be a valid list"),
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
@pytest.mark.regression
|
|
90
|
+
def test_post_providers_endpoint_with_existing_name(providers_utils):
|
|
91
|
+
provider_id = providers_utils.create_provider()
|
|
92
|
+
|
|
93
|
+
provider = providers_utils.get_provider_by_id(provider_id).json()
|
|
94
|
+
|
|
95
|
+
existing_name = provider["name"]
|
|
96
|
+
request_json = providers_utils.provider_request_json()
|
|
97
|
+
request_json["name"] = existing_name
|
|
98
|
+
|
|
99
|
+
create_response = providers_utils.send_post_request_to_providers_endpoint(
|
|
100
|
+
request_json
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
assert_that(create_response.status_code, equal_to(409))
|
|
104
|
+
assert_that(
|
|
105
|
+
create_response.json()["error"]["details"],
|
|
106
|
+
equal_to(f"A provider with the name [{existing_name}] already exists."),
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
# =============================================================================
|
|
111
|
+
# GET /v1/providers/datasource_schemas - Get datasource schemas
|
|
112
|
+
# =============================================================================
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
@pytest.mark.regression
|
|
116
|
+
def test_get_providers_datasource_schema_endpoint(providers_utils):
|
|
117
|
+
response = providers_utils.send_get_request_datasource_schemas_endpoint()
|
|
118
|
+
|
|
119
|
+
assert_that(response.status_code, equal_to(200))
|
|
120
|
+
|
|
121
|
+
response_data = response.json()
|
|
122
|
+
|
|
123
|
+
# Validate response structure
|
|
124
|
+
assert_that(isinstance(response_data, list), is_(True))
|
|
125
|
+
for provider in response_data:
|
|
126
|
+
assert_that(
|
|
127
|
+
provider,
|
|
128
|
+
all_of(
|
|
129
|
+
has_key("id"),
|
|
130
|
+
has_key("provider_name"),
|
|
131
|
+
has_key("name"),
|
|
132
|
+
has_key("base_schema"),
|
|
133
|
+
has_key("create_schema"),
|
|
134
|
+
),
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
# =============================================================================
|
|
139
|
+
# GET /v1/providers/{provider_id} - Get specific provider
|
|
140
|
+
# =============================================================================
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
@pytest.mark.regression
|
|
144
|
+
def test_get_provider_by_id_endpoint(providers_utils):
|
|
145
|
+
provider_id = providers_utils.create_provider()
|
|
146
|
+
|
|
147
|
+
provider_response = providers_utils.get_provider_by_id(provider_id)
|
|
148
|
+
|
|
149
|
+
assert_that(provider_response.status_code, equal_to(200))
|
|
150
|
+
assert_that(provider_response.json()["id"], equal_to(provider_id))
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
@pytest.mark.regression
|
|
154
|
+
def test_get_nonexistent_provider(providers_utils):
|
|
155
|
+
"""Test error handling when requesting nonexistent provider."""
|
|
156
|
+
response = providers_utils.get_provider_by_id(nonexistent_id)
|
|
157
|
+
|
|
158
|
+
assert_that(response.status_code, equal_to(404))
|
|
159
|
+
|
|
160
|
+
assert_that(
|
|
161
|
+
response.json()["error"]["details"],
|
|
162
|
+
equal_to(
|
|
163
|
+
f"The provider with ID [{nonexistent_id}] could not be found in the system."
|
|
164
|
+
),
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
# =============================================================================
|
|
169
|
+
# PUT /v1/providers/{provider_id} - Update specific provider
|
|
170
|
+
# =============================================================================
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
@pytest.mark.regression
|
|
174
|
+
def test_put_provider_endpoint(providers_utils):
|
|
175
|
+
provider_id = providers_utils.create_provider()
|
|
176
|
+
provider = providers_utils.get_provider_by_id(provider_id).json()
|
|
177
|
+
|
|
178
|
+
request_json = providers_utils.provider_request_json()
|
|
179
|
+
toolkits = provider["provided_toolkits"]
|
|
180
|
+
toolkits[0]["name"] = "Updated toolkit name"
|
|
181
|
+
toolkits[0]["description"] = "Updated toolkit description"
|
|
182
|
+
request_json["provided_toolkits"] = toolkits
|
|
183
|
+
request_json["name"] = f"{provider['name']} - updated"
|
|
184
|
+
update_response = providers_utils.update_provider(provider_id, request_json)
|
|
185
|
+
|
|
186
|
+
assert_that(update_response.status_code, equal_to(200))
|
|
187
|
+
assert_that(update_response.json()["provided_toolkits"], equal_to(toolkits))
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
@pytest.mark.regression
|
|
191
|
+
def test_put_nonexistent_provider(providers_utils):
|
|
192
|
+
response = providers_utils.update_provider(nonexistent_id, {})
|
|
193
|
+
|
|
194
|
+
assert_that(response.status_code, equal_to(404))
|
|
195
|
+
assert_that(
|
|
196
|
+
response.json()["error"]["details"],
|
|
197
|
+
equal_to(
|
|
198
|
+
f"The provider with ID [{nonexistent_id}] could not be found in the system."
|
|
199
|
+
),
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
# =============================================================================
|
|
204
|
+
# DELETE /v1/providers/{provider_id} - Delete specific provider
|
|
205
|
+
# =============================================================================
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
@pytest.mark.regression
|
|
209
|
+
def test_delete_provider_endpoint(providers_utils):
|
|
210
|
+
provider_id = providers_utils.create_provider()
|
|
211
|
+
delete_response = providers_utils.send_delete_provider_request(provider_id)
|
|
212
|
+
|
|
213
|
+
assert_that(delete_response.status_code, equal_to(204))
|
|
214
|
+
|
|
215
|
+
response = providers_utils.get_provider_by_id(provider_id)
|
|
216
|
+
|
|
217
|
+
assert_that(response.status_code, equal_to(404))
|
|
218
|
+
|
|
219
|
+
assert_that(
|
|
220
|
+
response.json()["error"]["details"],
|
|
221
|
+
equal_to(
|
|
222
|
+
f"The provider with ID [{provider_id}] could not be found in the system."
|
|
223
|
+
),
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
@pytest.mark.regression
|
|
228
|
+
def test_delete_nonexistent_provider(providers_utils):
|
|
229
|
+
"""Test error handling when requesting nonexistent provider."""
|
|
230
|
+
response = providers_utils.send_delete_provider_request(nonexistent_id)
|
|
231
|
+
|
|
232
|
+
assert_that(response.status_code, equal_to(404))
|
|
233
|
+
|
|
234
|
+
assert_that(
|
|
235
|
+
response.json()["error"]["details"],
|
|
236
|
+
equal_to(
|
|
237
|
+
f"The provider with ID [{nonexistent_id}] could not be found in the system."
|
|
238
|
+
),
|
|
239
|
+
)
|
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id":"3928ea28-e9e2-4382-aae0-09d5a24dc2am",
|
|
3
|
+
"date":"2025-04-02T12:54:19.693921",
|
|
4
|
+
"update_date":"2025-04-02T13:50:36.917335",
|
|
5
|
+
"name":"test",
|
|
6
|
+
"service_location_url":"https://codemie-preview.lab.epam.com/codemie-provider-stub-api/",
|
|
7
|
+
"configuration":{
|
|
8
|
+
"auth_type":"Bearer"
|
|
9
|
+
},
|
|
10
|
+
"provided_toolkits":[
|
|
11
|
+
{
|
|
12
|
+
"toolkit_id":"023953e9-b4b2-4264-aa24-7a20ab7cb201",
|
|
13
|
+
"name":"TestAutomationCodeAnalysesToolkit",
|
|
14
|
+
"description":"This ToolKit provides tools for indexing the source code of provided repository and set of methods to get insights of the code and code snippets.",
|
|
15
|
+
"toolkit_config":{
|
|
16
|
+
"type":"Code Analyses Datasource Configuration",
|
|
17
|
+
"description":"Configuration for connecting to GitHub repositories to access code for indexing and analysis.",
|
|
18
|
+
"parameters":{
|
|
19
|
+
"access_token":{
|
|
20
|
+
"description":"Github/Gitlab project access token with appropriate scopes for repository access",
|
|
21
|
+
"type":"Secret",
|
|
22
|
+
"required":true,
|
|
23
|
+
"enum":null
|
|
24
|
+
},
|
|
25
|
+
"datasource_id":{
|
|
26
|
+
"description":"Unique identifier for the datasource",
|
|
27
|
+
"type":"UUID",
|
|
28
|
+
"required":true,
|
|
29
|
+
"enum":null
|
|
30
|
+
},
|
|
31
|
+
"api_url":{
|
|
32
|
+
"description":"Git API URL (use your Git Enterprise API URL)",
|
|
33
|
+
"type":"URL",
|
|
34
|
+
"required":true,
|
|
35
|
+
"enum":null
|
|
36
|
+
},
|
|
37
|
+
"branch":{
|
|
38
|
+
"description":"Branch to index, defaults to master",
|
|
39
|
+
"type":"String",
|
|
40
|
+
"required":false,
|
|
41
|
+
"enum":null
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
"provided_tools":[
|
|
46
|
+
{
|
|
47
|
+
"name":"create_datasource",
|
|
48
|
+
"description":"Creates a new datasource by indexing a Git repository for code analysis. The indexing process extracts code structure, dependencies, and other metadata to enable subsequent queries.",
|
|
49
|
+
"args_schema":{
|
|
50
|
+
"exclude_glob":{
|
|
51
|
+
"type":"String",
|
|
52
|
+
"required":false,
|
|
53
|
+
"description":"Comma separated string of file paths to exclude from indexing",
|
|
54
|
+
"enum":null
|
|
55
|
+
},
|
|
56
|
+
"analyzer":{
|
|
57
|
+
"type":"List",
|
|
58
|
+
"required":false,
|
|
59
|
+
"description":"Type of code analyzer to use for the project. Supported analyzers Java/TS/JS/C#/C++. If not specified best matching analyzer will be chosen automatically.",
|
|
60
|
+
"enum":[
|
|
61
|
+
"Java",
|
|
62
|
+
"TS",
|
|
63
|
+
"JS",
|
|
64
|
+
"C#",
|
|
65
|
+
"C++",
|
|
66
|
+
"Other"
|
|
67
|
+
]
|
|
68
|
+
},
|
|
69
|
+
"datasource_root":{
|
|
70
|
+
"type":"String",
|
|
71
|
+
"required":true,
|
|
72
|
+
"description":"Root directory of the project to be indexed",
|
|
73
|
+
"enum":null
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
"tool_metadata":{
|
|
77
|
+
"tool_type":"stateful",
|
|
78
|
+
"tool_purpose":"life_cycle_management",
|
|
79
|
+
"tool_action_type":"create"
|
|
80
|
+
},
|
|
81
|
+
"tool_result_type":"Json",
|
|
82
|
+
"sync_invocation_supported":false,
|
|
83
|
+
"async_invocation_supported":true
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"name":"reindex_datasource",
|
|
87
|
+
"description":"Updates an existing datasource by re-indexing the associated Git repository to incorporate the latest changes and maintain synchronization with the current codebase.",
|
|
88
|
+
"args_schema":{
|
|
89
|
+
|
|
90
|
+
},
|
|
91
|
+
"tool_metadata":{
|
|
92
|
+
"tool_type":"stateful",
|
|
93
|
+
"tool_purpose":"life_cycle_management",
|
|
94
|
+
"tool_action_type":"modify"
|
|
95
|
+
},
|
|
96
|
+
"tool_result_type":"Json",
|
|
97
|
+
"sync_invocation_supported":false,
|
|
98
|
+
"async_invocation_supported":true
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"name":"delete_datasource",
|
|
102
|
+
"description":"Removes an existing datasource and all its indexed data from the system, freeing up resources and cleaning up stale references.",
|
|
103
|
+
"args_schema":{
|
|
104
|
+
|
|
105
|
+
},
|
|
106
|
+
"tool_metadata":{
|
|
107
|
+
"tool_type":"stateful",
|
|
108
|
+
"tool_purpose":"life_cycle_management",
|
|
109
|
+
"tool_action_type":"remove"
|
|
110
|
+
},
|
|
111
|
+
"tool_result_type":"Json",
|
|
112
|
+
"sync_invocation_supported":false,
|
|
113
|
+
"async_invocation_supported":true
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
"name":"get_files_tree",
|
|
117
|
+
"description":"Retrieves a hierarchical representation of the file system structure of the indexed repository, showing directories and files in a tree format for easy navigation.",
|
|
118
|
+
"args_schema":{
|
|
119
|
+
"path":{
|
|
120
|
+
"type":"String",
|
|
121
|
+
"required":true,
|
|
122
|
+
"description":"Relative path within the repository to start the tree structure from",
|
|
123
|
+
"enum":null
|
|
124
|
+
},
|
|
125
|
+
"level":{
|
|
126
|
+
"type":"Number",
|
|
127
|
+
"required":false,
|
|
128
|
+
"description":"Maximum depth of the tree structure, defaults to full depth",
|
|
129
|
+
"enum":null
|
|
130
|
+
},
|
|
131
|
+
"limit":{
|
|
132
|
+
"type":"Number",
|
|
133
|
+
"required":false,
|
|
134
|
+
"description":"Maximum number of files to include in the tree structure, defaults to all files",
|
|
135
|
+
"enum":null
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
"tool_metadata":{
|
|
139
|
+
"tool_type":"stateful",
|
|
140
|
+
"tool_purpose":"data_retrieval",
|
|
141
|
+
"tool_action_type":null
|
|
142
|
+
},
|
|
143
|
+
"tool_result_type":"String",
|
|
144
|
+
"sync_invocation_supported":true,
|
|
145
|
+
"async_invocation_supported":false
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
"name":"get_files_list",
|
|
149
|
+
"description":"Retrieves a list of files and directories within the specified path in the indexed repository, showing file names and types for easy reference.",
|
|
150
|
+
"args_schema":{
|
|
151
|
+
"path":{
|
|
152
|
+
"type":"String",
|
|
153
|
+
"required":true,
|
|
154
|
+
"description":"Relative path within the repository to list files from",
|
|
155
|
+
"enum":null
|
|
156
|
+
},
|
|
157
|
+
"limit":{
|
|
158
|
+
"type":"Number",
|
|
159
|
+
"required":false,
|
|
160
|
+
"description":"Maximum number of files to include in the list, defaults to all files",
|
|
161
|
+
"enum":null
|
|
162
|
+
},
|
|
163
|
+
"recursive":{
|
|
164
|
+
"type":"Boolean",
|
|
165
|
+
"required":false,
|
|
166
|
+
"description":"Flag to include files from subdirectories recursively, defaults to false",
|
|
167
|
+
"enum":null
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
"tool_metadata":{
|
|
171
|
+
"tool_type":"stateful",
|
|
172
|
+
"tool_purpose":"data_retrieval",
|
|
173
|
+
"tool_action_type":null
|
|
174
|
+
},
|
|
175
|
+
"tool_result_type":"Json",
|
|
176
|
+
"sync_invocation_supported":true,
|
|
177
|
+
"async_invocation_supported":false
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
"name":"get_code_members",
|
|
181
|
+
"description":"Extracts and returns structured information about code components such as classes, methods, functions, and variables within specified file in the indexed repository.",
|
|
182
|
+
"args_schema":{
|
|
183
|
+
"file_path":{
|
|
184
|
+
"type":"String",
|
|
185
|
+
"required":true,
|
|
186
|
+
"description":"Path of the file to extract code members from",
|
|
187
|
+
"enum":null
|
|
188
|
+
},
|
|
189
|
+
"start_line":{
|
|
190
|
+
"type":"Number",
|
|
191
|
+
"required":false,
|
|
192
|
+
"description":"Starting line number to extract code members from, defaults to 1",
|
|
193
|
+
"enum":null
|
|
194
|
+
},
|
|
195
|
+
"end_line":{
|
|
196
|
+
"type":"Number",
|
|
197
|
+
"required":false,
|
|
198
|
+
"description":"Ending line number to extract code members till, defaults to end of file",
|
|
199
|
+
"enum":null
|
|
200
|
+
}
|
|
201
|
+
},
|
|
202
|
+
"tool_metadata":{
|
|
203
|
+
"tool_type":"stateful",
|
|
204
|
+
"tool_purpose":"data_retrieval",
|
|
205
|
+
"tool_action_type":null
|
|
206
|
+
},
|
|
207
|
+
"tool_result_type":"Json",
|
|
208
|
+
"sync_invocation_supported":false,
|
|
209
|
+
"async_invocation_supported":true
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
"name":"get_trimmed_code",
|
|
213
|
+
"description":"Retrieves a simplified version of code from specified files with non-essential elements (like comments and some whitespace) removed to focus on the core functionality.",
|
|
214
|
+
"args_schema":{
|
|
215
|
+
"file_path":{
|
|
216
|
+
"type":"String",
|
|
217
|
+
"required":true,
|
|
218
|
+
"description":"Path of the file to extract trimmed code from",
|
|
219
|
+
"enum":null
|
|
220
|
+
},
|
|
221
|
+
"exclude_private":{
|
|
222
|
+
"type":"Boolean",
|
|
223
|
+
"required":false,
|
|
224
|
+
"description":"Flag to exclude private members from the trimmed code, defaults to false",
|
|
225
|
+
"enum":null
|
|
226
|
+
},
|
|
227
|
+
"show_line_numbers":{
|
|
228
|
+
"type":"Boolean",
|
|
229
|
+
"required":false,
|
|
230
|
+
"description":"Flag to include line numbers in the trimmed code, defaults to false",
|
|
231
|
+
"enum":null
|
|
232
|
+
}
|
|
233
|
+
},
|
|
234
|
+
"tool_metadata":{
|
|
235
|
+
"tool_type":"stateful",
|
|
236
|
+
"tool_purpose":"data_retrieval",
|
|
237
|
+
"tool_action_type":null
|
|
238
|
+
},
|
|
239
|
+
"tool_result_type":"String",
|
|
240
|
+
"sync_invocation_supported":true,
|
|
241
|
+
"async_invocation_supported":false
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
"name":"get_code",
|
|
245
|
+
"description":"Fetches the complete, unmodified source code of specified files or code segments from the indexed repository, preserving all original formatting and comments.",
|
|
246
|
+
"args_schema":{
|
|
247
|
+
"file_path":{
|
|
248
|
+
"type":"String",
|
|
249
|
+
"required":true,
|
|
250
|
+
"description":"Path of the file to extract code from",
|
|
251
|
+
"enum":null
|
|
252
|
+
},
|
|
253
|
+
"start_line":{
|
|
254
|
+
"type":"Number",
|
|
255
|
+
"required":false,
|
|
256
|
+
"description":"Starting line number to extract code from, defaults to 1",
|
|
257
|
+
"enum":null
|
|
258
|
+
},
|
|
259
|
+
"show_line_numbers":{
|
|
260
|
+
"type":"Boolean",
|
|
261
|
+
"required":false,
|
|
262
|
+
"description":"Flag to include line numbers in the code, defaults to false",
|
|
263
|
+
"enum":null
|
|
264
|
+
},
|
|
265
|
+
"end_line":{
|
|
266
|
+
"type":"Number",
|
|
267
|
+
"required":false,
|
|
268
|
+
"description":"Ending line number to extract code till, defaults to end of file",
|
|
269
|
+
"enum":null
|
|
270
|
+
}
|
|
271
|
+
},
|
|
272
|
+
"tool_metadata":{
|
|
273
|
+
"tool_type":"stateful",
|
|
274
|
+
"tool_purpose":"data_retrieval",
|
|
275
|
+
"tool_action_type":null
|
|
276
|
+
},
|
|
277
|
+
"tool_result_type":"String",
|
|
278
|
+
"sync_invocation_supported":true,
|
|
279
|
+
"async_invocation_supported":false
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
"name":"get_metadata",
|
|
283
|
+
"description":"Retrieves metadata information about specified files in the indexed repository, including file size, line count, and other relevant details.",
|
|
284
|
+
"args_schema":{
|
|
285
|
+
"file_path":{
|
|
286
|
+
"type":"String",
|
|
287
|
+
"required":true,
|
|
288
|
+
"description":"Path of the file to extract code from",
|
|
289
|
+
"enum":null
|
|
290
|
+
}
|
|
291
|
+
},
|
|
292
|
+
"tool_metadata":{
|
|
293
|
+
"tool_type":"stateful",
|
|
294
|
+
"tool_purpose":"data_retrieval",
|
|
295
|
+
"tool_action_type":null
|
|
296
|
+
},
|
|
297
|
+
"tool_result_type":"String",
|
|
298
|
+
"sync_invocation_supported":true,
|
|
299
|
+
"async_invocation_supported":false
|
|
300
|
+
},
|
|
301
|
+
{
|
|
302
|
+
"name":"get_outgoing_dependencies",
|
|
303
|
+
"description":"Analyzes and returns information about external dependencies and imports used by specified files or code components, helping to understand code relationships and dependency chains.",
|
|
304
|
+
"args_schema":{
|
|
305
|
+
"file_path":{
|
|
306
|
+
"type":"String",
|
|
307
|
+
"required":true,
|
|
308
|
+
"description":"Path of the file to get outgoing dependencies from",
|
|
309
|
+
"enum":null
|
|
310
|
+
},
|
|
311
|
+
"start_line":{
|
|
312
|
+
"type":"Number",
|
|
313
|
+
"required":false,
|
|
314
|
+
"description":"Starting line number to get outgoing dependencies from, defaults to 1",
|
|
315
|
+
"enum":null
|
|
316
|
+
},
|
|
317
|
+
"end_line":{
|
|
318
|
+
"type":"Number",
|
|
319
|
+
"required":false,
|
|
320
|
+
"description":"Ending line number to get outgoing dependencies till, defaults to end of file",
|
|
321
|
+
"enum":null
|
|
322
|
+
}
|
|
323
|
+
},
|
|
324
|
+
"tool_metadata":{
|
|
325
|
+
"tool_type":"stateful",
|
|
326
|
+
"tool_purpose":"data_retrieval",
|
|
327
|
+
"tool_action_type":null
|
|
328
|
+
},
|
|
329
|
+
"tool_result_type":"Json",
|
|
330
|
+
"sync_invocation_supported":true,
|
|
331
|
+
"async_invocation_supported":false
|
|
332
|
+
}
|
|
333
|
+
]
|
|
334
|
+
},
|
|
335
|
+
{
|
|
336
|
+
"toolkit_id":"98212b72-8b83-4d70-852f-49f0df28a0d4",
|
|
337
|
+
"name":"TestToolkit",
|
|
338
|
+
"description":"Tst toolkit",
|
|
339
|
+
"toolkit_config":{
|
|
340
|
+
"type":"test toolkit",
|
|
341
|
+
"description":"Configuration for connecting to GitHub repositories to access code for indexing and analysis.",
|
|
342
|
+
"parameters":{
|
|
343
|
+
|
|
344
|
+
}
|
|
345
|
+
},
|
|
346
|
+
"provided_tools":[
|
|
347
|
+
{
|
|
348
|
+
"name":"test_tool",
|
|
349
|
+
"description":"Some test tools",
|
|
350
|
+
"args_schema":{
|
|
351
|
+
"service_url":{
|
|
352
|
+
"type":"String",
|
|
353
|
+
"required":true,
|
|
354
|
+
"description":"The url of the service",
|
|
355
|
+
"enum":null
|
|
356
|
+
},
|
|
357
|
+
"exclude_glob":{
|
|
358
|
+
"type":"String",
|
|
359
|
+
"required":false,
|
|
360
|
+
"description":"Comma separated string of file paths to exclude from indexing",
|
|
361
|
+
"enum":null
|
|
362
|
+
},
|
|
363
|
+
"service_method":{
|
|
364
|
+
"type":"String",
|
|
365
|
+
"required":true,
|
|
366
|
+
"description":"The token to access the service",
|
|
367
|
+
"enum":null
|
|
368
|
+
}
|
|
369
|
+
},
|
|
370
|
+
"tool_metadata":{
|
|
371
|
+
"tool_type":null,
|
|
372
|
+
"tool_purpose":null,
|
|
373
|
+
"tool_action_type":null
|
|
374
|
+
},
|
|
375
|
+
"tool_result_type":"Json",
|
|
376
|
+
"sync_invocation_supported":false,
|
|
377
|
+
"async_invocation_supported":true
|
|
378
|
+
}
|
|
379
|
+
]
|
|
380
|
+
}
|
|
381
|
+
]
|
|
382
|
+
}
|
tests/utils/http_utils.py
CHANGED
|
@@ -2,10 +2,9 @@ import logging
|
|
|
2
2
|
from typing import TypeVar, Type, Optional, Any, Union, Dict, List
|
|
3
3
|
|
|
4
4
|
import requests
|
|
5
|
-
from pydantic import BaseModel
|
|
6
|
-
|
|
7
5
|
from codemie_sdk.utils.http import ApiRequestHandler
|
|
8
6
|
from codemie_sdk.utils.http import log_request
|
|
7
|
+
from pydantic import BaseModel
|
|
9
8
|
|
|
10
9
|
T = TypeVar("T", bound=Union[BaseModel, List[BaseModel], dict])
|
|
11
10
|
|
|
@@ -19,7 +18,7 @@ class RequestHandler(ApiRequestHandler):
|
|
|
19
18
|
def post(
|
|
20
19
|
self,
|
|
21
20
|
endpoint: str,
|
|
22
|
-
response_model: Type[T],
|
|
21
|
+
response_model: Type[T] = None,
|
|
23
22
|
json_data: Optional[Dict[str, Any]] = None,
|
|
24
23
|
stream: bool = False,
|
|
25
24
|
wrap_response: bool = True,
|
|
@@ -51,3 +50,92 @@ class RequestHandler(ApiRequestHandler):
|
|
|
51
50
|
return response
|
|
52
51
|
|
|
53
52
|
return self._parse_response(response, response_model, wrap_response)
|
|
53
|
+
|
|
54
|
+
@log_request
|
|
55
|
+
def get(
|
|
56
|
+
self,
|
|
57
|
+
endpoint: str,
|
|
58
|
+
response_model: Type[T] = None,
|
|
59
|
+
params: Optional[Dict[str, Any]] = None,
|
|
60
|
+
wrap_response: bool = True,
|
|
61
|
+
) -> Union[T, requests.Response]:
|
|
62
|
+
"""Makes a GET request and parses the response.
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
endpoint: API endpoint path
|
|
66
|
+
response_model: Pydantic model class or List[Model] for response
|
|
67
|
+
params: Query parameters
|
|
68
|
+
wrap_response: Whether response is wrapped in 'data' field
|
|
69
|
+
|
|
70
|
+
Returns:
|
|
71
|
+
Parsed response object or list of objects
|
|
72
|
+
"""
|
|
73
|
+
if params:
|
|
74
|
+
logger.debug(f"Request params: {params}")
|
|
75
|
+
response = requests.get(
|
|
76
|
+
url=f"{self._base_url}{endpoint}",
|
|
77
|
+
headers=self._get_headers(),
|
|
78
|
+
params=params,
|
|
79
|
+
verify=self._verify_ssl,
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
if response_model:
|
|
83
|
+
return self._parse_response(response, response_model, wrap_response)
|
|
84
|
+
|
|
85
|
+
return response
|
|
86
|
+
|
|
87
|
+
@log_request
|
|
88
|
+
def put(
|
|
89
|
+
self,
|
|
90
|
+
endpoint: str,
|
|
91
|
+
json_data: Dict[str, Any],
|
|
92
|
+
response_model: Type[T] = None,
|
|
93
|
+
params: Optional[Dict[str, Any]] = None,
|
|
94
|
+
wrap_response: bool = True,
|
|
95
|
+
) -> Union[T, requests.Response]:
|
|
96
|
+
"""Makes a PUT request and parses the response.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
endpoint: API endpoint path
|
|
100
|
+
response_model: Pydantic model class or List[Model] for response
|
|
101
|
+
json_data: JSON request body
|
|
102
|
+
params: Query parameters
|
|
103
|
+
wrap_response: Whether response is wrapped in 'data' field
|
|
104
|
+
|
|
105
|
+
Returns:
|
|
106
|
+
Parsed response object or list of objects
|
|
107
|
+
"""
|
|
108
|
+
logger.debug(f"Request body: {json_data}")
|
|
109
|
+
response = requests.put(
|
|
110
|
+
url=f"{self._base_url}{endpoint}",
|
|
111
|
+
headers=self._get_headers(),
|
|
112
|
+
json=json_data,
|
|
113
|
+
params=params,
|
|
114
|
+
verify=self._verify_ssl,
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
if response_model:
|
|
118
|
+
return self._parse_response(response, response_model, wrap_response)
|
|
119
|
+
|
|
120
|
+
return response
|
|
121
|
+
|
|
122
|
+
@log_request
|
|
123
|
+
def delete(
|
|
124
|
+
self,
|
|
125
|
+
endpoint: str,
|
|
126
|
+
) -> requests.Response:
|
|
127
|
+
"""Makes a DELETE request and parses the response.
|
|
128
|
+
|
|
129
|
+
Args:
|
|
130
|
+
endpoint: API endpoint path
|
|
131
|
+
|
|
132
|
+
Returns:
|
|
133
|
+
response object
|
|
134
|
+
"""
|
|
135
|
+
response = requests.delete(
|
|
136
|
+
url=f"{self._base_url}{endpoint}",
|
|
137
|
+
headers=self._get_headers(),
|
|
138
|
+
verify=self._verify_ssl,
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
return response
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import logging
|
|
3
|
+
import os
|
|
4
|
+
from typing import Optional, Dict, Any
|
|
5
|
+
|
|
6
|
+
import requests
|
|
7
|
+
from codemie_sdk import CodeMieClient
|
|
8
|
+
|
|
9
|
+
from tests import autotest_entity_prefix
|
|
10
|
+
from tests.utils import api_domain, verify_ssl
|
|
11
|
+
from tests.utils.base_utils import (
|
|
12
|
+
BaseUtils,
|
|
13
|
+
get_random_name,
|
|
14
|
+
)
|
|
15
|
+
from tests.utils.http_utils import RequestHandler
|
|
16
|
+
|
|
17
|
+
logger = logging.getLogger(__name__)
|
|
18
|
+
|
|
19
|
+
providers_endpoint = "/v1/providers"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class ProviderUtils(BaseUtils):
|
|
23
|
+
def __init__(self, client: CodeMieClient):
|
|
24
|
+
"""Initialize the provides service."""
|
|
25
|
+
|
|
26
|
+
super().__init__(client)
|
|
27
|
+
self._api = RequestHandler(api_domain, self.client.token, verify_ssl)
|
|
28
|
+
|
|
29
|
+
@staticmethod
|
|
30
|
+
def provider_request_json():
|
|
31
|
+
"""Load provider request JSON from file."""
|
|
32
|
+
payload_path = os.path.join(
|
|
33
|
+
os.path.dirname(__file__), "../test_data/files/provider_payload.json"
|
|
34
|
+
)
|
|
35
|
+
with open(payload_path, "r") as pyload_file:
|
|
36
|
+
request_json = json.load(pyload_file)
|
|
37
|
+
|
|
38
|
+
return request_json
|
|
39
|
+
|
|
40
|
+
def send_post_request_to_providers_endpoint(
|
|
41
|
+
self, request: Dict[str, Any]
|
|
42
|
+
) -> requests.Response:
|
|
43
|
+
"""
|
|
44
|
+
Send request to provider creation endpoint without raising error for response status codes.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
request: The provider creation request
|
|
48
|
+
|
|
49
|
+
Returns:
|
|
50
|
+
Raw response from '/v1/providers' endpoint
|
|
51
|
+
"""
|
|
52
|
+
return self._api.post(providers_endpoint, json_data=request, stream=True)
|
|
53
|
+
|
|
54
|
+
def send_get_request_to_providers_endpoint(
|
|
55
|
+
self,
|
|
56
|
+
) -> requests.Response:
|
|
57
|
+
"""
|
|
58
|
+
Send request to get providers endpoint.
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
Raw response from '/v1/providers' endpoint
|
|
62
|
+
"""
|
|
63
|
+
return self._api.get(providers_endpoint)
|
|
64
|
+
|
|
65
|
+
def send_get_request_datasource_schemas_endpoint(
|
|
66
|
+
self,
|
|
67
|
+
) -> requests.Response:
|
|
68
|
+
"""
|
|
69
|
+
Send request to get datasource_schemas endpoint.
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
Raw response from '/v1/providers/datasource_schemas' endpoint
|
|
73
|
+
"""
|
|
74
|
+
return self._api.get(f"{providers_endpoint}/datasource_schemas")
|
|
75
|
+
|
|
76
|
+
def create_provider(
|
|
77
|
+
self,
|
|
78
|
+
) -> str:
|
|
79
|
+
"""
|
|
80
|
+
Creates a provider for test.
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
Created provider id
|
|
84
|
+
"""
|
|
85
|
+
request_json = self.provider_request_json()
|
|
86
|
+
# Ensure unique provider name to avoid conflicts
|
|
87
|
+
request_json["name"] = get_random_name()
|
|
88
|
+
|
|
89
|
+
response = self.send_post_request_to_providers_endpoint(request_json)
|
|
90
|
+
|
|
91
|
+
return response.json()["id"]
|
|
92
|
+
|
|
93
|
+
def list_providers(
|
|
94
|
+
self,
|
|
95
|
+
) -> requests.Response:
|
|
96
|
+
"""
|
|
97
|
+
List all providers.
|
|
98
|
+
|
|
99
|
+
Returns:
|
|
100
|
+
List of provider objects
|
|
101
|
+
"""
|
|
102
|
+
response = self.send_get_request_to_providers_endpoint()
|
|
103
|
+
|
|
104
|
+
return response
|
|
105
|
+
|
|
106
|
+
def get_provider_by_id(self, provider_id: str) -> requests.Response:
|
|
107
|
+
"""
|
|
108
|
+
Get a specific provider by ID.
|
|
109
|
+
|
|
110
|
+
Args:
|
|
111
|
+
provider_id: The provider ID
|
|
112
|
+
|
|
113
|
+
Returns:
|
|
114
|
+
Provider object
|
|
115
|
+
"""
|
|
116
|
+
response = self._api.get(f"{providers_endpoint}/{provider_id}")
|
|
117
|
+
|
|
118
|
+
return response
|
|
119
|
+
|
|
120
|
+
def update_provider(
|
|
121
|
+
self,
|
|
122
|
+
provider_id: str,
|
|
123
|
+
provider_update_payload: dict,
|
|
124
|
+
) -> requests.Response:
|
|
125
|
+
"""
|
|
126
|
+
Update an existing provider.
|
|
127
|
+
|
|
128
|
+
Args:
|
|
129
|
+
provider_id: The provider ID to update
|
|
130
|
+
provider_update_payload: request body
|
|
131
|
+
|
|
132
|
+
Returns:
|
|
133
|
+
Updated provider object
|
|
134
|
+
"""
|
|
135
|
+
endpoint = f"{providers_endpoint}/{provider_id}"
|
|
136
|
+
|
|
137
|
+
return self._api.put(endpoint, json_data=provider_update_payload)
|
|
138
|
+
|
|
139
|
+
def send_delete_provider_request(self, provider_id: str) -> requests.Response:
|
|
140
|
+
"""
|
|
141
|
+
Delete a provider by ID.
|
|
142
|
+
|
|
143
|
+
Args:
|
|
144
|
+
provider_id: The provider ID to delete
|
|
145
|
+
|
|
146
|
+
Returns:
|
|
147
|
+
Response from delete operation
|
|
148
|
+
"""
|
|
149
|
+
return self._api.delete(f"{providers_endpoint}/{provider_id}")
|
|
150
|
+
|
|
151
|
+
def cleanup_test_providers(self, name_prefix: Optional[str] = None):
|
|
152
|
+
"""
|
|
153
|
+
Clean up test providers (those with autotest prefix or specified prefix).
|
|
154
|
+
|
|
155
|
+
Args:
|
|
156
|
+
name_prefix: Prefix to match for cleanup (uses autotest prefix if None)
|
|
157
|
+
"""
|
|
158
|
+
|
|
159
|
+
prefix = name_prefix if name_prefix else autotest_entity_prefix
|
|
160
|
+
|
|
161
|
+
try:
|
|
162
|
+
providers = self.list_providers()
|
|
163
|
+
test_providers = [
|
|
164
|
+
provider
|
|
165
|
+
for provider in providers.json()
|
|
166
|
+
if provider["name"].startswith(prefix)
|
|
167
|
+
]
|
|
168
|
+
|
|
169
|
+
for provider in test_providers:
|
|
170
|
+
try:
|
|
171
|
+
self.send_delete_provider_request(provider["id"])
|
|
172
|
+
except Exception as e:
|
|
173
|
+
# Log but don't fail cleanup for individual provider
|
|
174
|
+
logger.error(f"Failed to delete provider {provider['name']}: {e}")
|
|
175
|
+
|
|
176
|
+
except Exception as e:
|
|
177
|
+
# Log but don't fail if cleanup encounters issues
|
|
178
|
+
logger.error(f"Provider cleanup encountered an error: {e}")
|
|
File without changes
|
{codemie_test_harness-0.1.129.dist-info → codemie_test_harness-0.1.130.dist-info}/entry_points.txt
RENAMED
|
File without changes
|