codemie-test-harness 0.1.222__py3-none-any.whl → 0.1.223__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.

@@ -951,11 +951,21 @@ def integration(integration_utils):
951
951
 
952
952
 
953
953
  @pytest.fixture(scope="session")
954
- def vendor_utils():
954
+ def vendor_assistant_utils():
955
955
  """Create VendorUtils instance for managing vendor assistants"""
956
- from codemie_test_harness.tests.utils.vendor_utils import VendorUtils
956
+ from codemie_test_harness.tests.utils.vendor_utils import VendorAssistantUtils
957
957
 
958
- return VendorUtils()
958
+ return VendorAssistantUtils()
959
+
960
+
961
+ @pytest.fixture(scope="session")
962
+ def vendor_workflow_utils():
963
+ """Create VendorWorkflowUtils instance for managing vendor workflows"""
964
+ from codemie_test_harness.tests.utils.vendor_workflow_utils import (
965
+ VendorWorkflowUtils,
966
+ )
967
+
968
+ return VendorWorkflowUtils()
959
969
 
960
970
 
961
971
  def pytest_sessionfinish(session):
@@ -0,0 +1,50 @@
1
+ """Test data for vendor workflow e2e tests."""
2
+
3
+ import json
4
+ import pytest
5
+ from codemie_sdk.models.vendor_assistant import VendorType
6
+ from codemie_sdk.models.integration import CredentialTypes
7
+
8
+ from codemie_test_harness.tests.utils.credentials_manager import CredentialsManager
9
+
10
+
11
+ vendor_workflow_test_data = [
12
+ pytest.param(
13
+ VendorType.AWS,
14
+ CredentialTypes.AWS,
15
+ CredentialsManager.aws_credentials(),
16
+ "codemie-autotests-flow-object-input",
17
+ json.dumps({"genre": "pop", "number": 3}),
18
+ """
19
+ # Pop Playlist: Just Three Hits
20
+
21
+ 1. "As It Was" by Harry Styles
22
+ 2. "Blinding Lights" by The Weeknd
23
+ 3. "Levitating" by Dua Lipa
24
+
25
+ These three modern pop classics offer a perfect mini-playlist with upbeat tempos and catchy hooks. Enjoy!
26
+ """,
27
+ marks=[pytest.mark.aws, pytest.mark.bedrock],
28
+ id="AWS_Bedrock_Object_Input",
29
+ ),
30
+ # pytest.param(
31
+ # VendorType.AZURE,
32
+ # CredentialTypes.AZURE,
33
+ # CredentialsManager.azure_credentials(),
34
+ # "workflow-name",
35
+ # json.dumps({"genre": "rock", "number": 5}),
36
+ # "Rock Playlist",
37
+ # marks=[pytest.mark.azure],
38
+ # id="Azure_AI_Object_Input",
39
+ # ),
40
+ # pytest.param(
41
+ # VendorType.GCP,
42
+ # CredentialTypes.GCP,
43
+ # CredentialsManager.gcp_credentials(),
44
+ # "workflow-name",
45
+ # json.dumps({"genre": "jazz", "number": 4}),
46
+ # "Jazz Playlist",
47
+ # marks=[pytest.mark.gcp],
48
+ # id="GCP_Vertex_AI_Object_Input",
49
+ # ),
50
+ ]
@@ -20,13 +20,13 @@ logger = setup_logger(__name__)
20
20
  DRAFT_VERSION = "DRAFT"
21
21
 
22
22
 
23
- class VendorUtils:
23
+ class VendorAssistantUtils:
24
24
  """Utility class for vendor assistant operations."""
25
25
 
26
26
  def __init__(self):
27
27
  """Initialize VendorUtils with CodeMie client."""
28
28
  self.client = get_client()
29
- self.vendor_service = self.client.vendors
29
+ self.vendor_assistant_service = self.client.vendor_assistants
30
30
 
31
31
  def get_assistant_settings(
32
32
  self,
@@ -47,7 +47,7 @@ class VendorUtils:
47
47
  logger.info(
48
48
  f"Getting assistant settings for {vendor.value} (page={page}, per_page={per_page})"
49
49
  )
50
- settings = self.vendor_service.get_assistant_settings(
50
+ settings = self.vendor_assistant_service.get_assistant_settings(
51
51
  vendor=vendor, page=page, per_page=per_page
52
52
  )
53
53
  logger.info(
@@ -76,7 +76,7 @@ class VendorUtils:
76
76
  logger.info(
77
77
  f"Getting assistants for {vendor.value} setting {setting_id} (per_page={per_page})"
78
78
  )
79
- assistants = self.vendor_service.get_assistants(
79
+ assistants = self.vendor_assistant_service.get_assistants(
80
80
  vendor=vendor,
81
81
  setting_id=setting_id,
82
82
  per_page=per_page,
@@ -106,7 +106,7 @@ class VendorUtils:
106
106
  logger.info(
107
107
  f"Getting assistant {assistant_id} for {vendor.value} setting {setting_id}"
108
108
  )
109
- assistant = self.vendor_service.get_assistant(
109
+ assistant = self.vendor_assistant_service.get_assistant(
110
110
  vendor=vendor, assistant_id=assistant_id, setting_id=setting_id
111
111
  )
112
112
  logger.info(
@@ -137,7 +137,7 @@ class VendorUtils:
137
137
  logger.info(
138
138
  f"Getting aliases for assistant {assistant_id} in {vendor.value} setting {setting_id}"
139
139
  )
140
- aliases = self.vendor_service.get_assistant_aliases(
140
+ aliases = self.vendor_assistant_service.get_assistant_aliases(
141
141
  vendor=vendor,
142
142
  assistant_id=assistant_id,
143
143
  setting_id=setting_id,
@@ -164,7 +164,7 @@ class VendorUtils:
164
164
  VendorAssistantInstallResponse containing installation summary with AI run IDs
165
165
  """
166
166
  logger.info(f"Installing {len(assistants)} assistant(s) for {vendor.value}")
167
- response = self.vendor_service.install_assistants(
167
+ response = self.vendor_assistant_service.install_assistants(
168
168
  vendor=vendor, assistants=assistants
169
169
  )
170
170
  for item in response.summary:
@@ -188,7 +188,7 @@ class VendorUtils:
188
188
  VendorAssistantUninstallResponse with success status
189
189
  """
190
190
  logger.info(f"Uninstalling assistant with CodeMie ID: {codemie_id}")
191
- response = self.vendor_service.uninstall_assistant(
191
+ response = self.vendor_assistant_service.uninstall_assistant(
192
192
  vendor=vendor, ai_run_id=codemie_id
193
193
  )
194
194
  if response.success:
@@ -0,0 +1,418 @@
1
+ """Utility class for managing vendor workflows (AWS Bedrock, Azure, GCP)."""
2
+
3
+ from typing import Optional, List
4
+ from codemie_sdk.models.vendor_assistant import VendorType
5
+ from codemie_sdk.models.vendor_workflow import (
6
+ VendorWorkflowSettingsResponse,
7
+ VendorWorkflowsResponse,
8
+ VendorWorkflow,
9
+ VendorWorkflowAliasesResponse,
10
+ VendorWorkflowInstallRequest,
11
+ VendorWorkflowInstallResponse,
12
+ VendorWorkflowUninstallResponse,
13
+ VendorWorkflowStatus,
14
+ )
15
+ from codemie_test_harness.tests.utils.client_factory import get_client
16
+ from codemie_test_harness.tests.utils.logger_util import setup_logger
17
+
18
+ logger = setup_logger(__name__)
19
+
20
+ DRAFT_VERSION = "DRAFT"
21
+
22
+
23
+ class VendorWorkflowUtils:
24
+ """Utility class for vendor workflow operations."""
25
+
26
+ def __init__(self):
27
+ """Initialize VendorWorkflowUtils with CodeMie client."""
28
+ self.client = get_client()
29
+ self.vendor_workflow_service = self.client.vendor_workflows
30
+
31
+ def get_workflow_settings(
32
+ self,
33
+ vendor: VendorType,
34
+ page: int = 0,
35
+ per_page: int = 10,
36
+ ) -> VendorWorkflowSettingsResponse:
37
+ """Get workflow settings for a specific cloud vendor.
38
+
39
+ Args:
40
+ vendor: Cloud vendor type (AWS, AZURE, GCP)
41
+ page: Page number for pagination
42
+ per_page: Number of items per page
43
+
44
+ Returns:
45
+ VendorWorkflowSettingsResponse containing list of settings
46
+ """
47
+ logger.info(
48
+ f"Getting workflow settings for {vendor.value} (page={page}, per_page={per_page})"
49
+ )
50
+ settings = self.vendor_workflow_service.get_workflow_settings(
51
+ vendor=vendor, page=page, per_page=per_page
52
+ )
53
+ logger.info(
54
+ f"Retrieved {len(settings.data)} settings for {vendor.value} (total: {settings.pagination.total})"
55
+ )
56
+ return settings
57
+
58
+ def get_workflows(
59
+ self,
60
+ vendor: VendorType,
61
+ setting_id: str,
62
+ per_page: int = 10,
63
+ next_token: Optional[str] = None,
64
+ ) -> VendorWorkflowsResponse:
65
+ """Get workflows for a specific vendor setting.
66
+
67
+ Args:
68
+ vendor: Cloud vendor type
69
+ setting_id: ID of the vendor setting
70
+ per_page: Number of items per page
71
+ next_token: Token for pagination
72
+
73
+ Returns:
74
+ VendorWorkflowsResponse containing list of workflows
75
+ """
76
+ logger.info(
77
+ f"Getting workflows for {vendor.value} setting {setting_id} (per_page={per_page})"
78
+ )
79
+ workflows = self.vendor_workflow_service.get_workflows(
80
+ vendor=vendor,
81
+ setting_id=setting_id,
82
+ per_page=per_page,
83
+ next_token=next_token,
84
+ )
85
+ logger.info(
86
+ f"Retrieved {len(workflows.data)} workflows for setting {setting_id}"
87
+ )
88
+ return workflows
89
+
90
+ def get_workflow(
91
+ self,
92
+ vendor: VendorType,
93
+ workflow_id: str,
94
+ setting_id: str,
95
+ ) -> VendorWorkflow:
96
+ """Get a specific workflow by ID.
97
+
98
+ Args:
99
+ vendor: Cloud vendor type
100
+ workflow_id: ID of the workflow
101
+ setting_id: ID of the vendor setting
102
+
103
+ Returns:
104
+ VendorWorkflow with workflow details
105
+ """
106
+ logger.info(
107
+ f"Getting workflow {workflow_id} for {vendor.value} setting {setting_id}"
108
+ )
109
+ workflow = self.vendor_workflow_service.get_workflow(
110
+ vendor=vendor, workflow_id=workflow_id, setting_id=setting_id
111
+ )
112
+ logger.info(f"Retrieved workflow: {workflow.name} (status: {workflow.status})")
113
+ return workflow
114
+
115
+ def get_workflow_aliases(
116
+ self,
117
+ vendor: VendorType,
118
+ workflow_id: str,
119
+ setting_id: str,
120
+ per_page: int = 10,
121
+ next_token: Optional[str] = None,
122
+ ) -> VendorWorkflowAliasesResponse:
123
+ """Get aliases for a specific vendor workflow.
124
+
125
+ Args:
126
+ vendor: Cloud vendor type
127
+ workflow_id: ID of the workflow
128
+ setting_id: ID of the vendor setting
129
+ per_page: Number of items per page
130
+ next_token: Token for pagination
131
+
132
+ Returns:
133
+ VendorWorkflowAliasesResponse containing list of aliases
134
+ """
135
+ logger.info(
136
+ f"Getting aliases for workflow {workflow_id} in {vendor.value} setting {setting_id}"
137
+ )
138
+ aliases = self.vendor_workflow_service.get_workflow_aliases(
139
+ vendor=vendor,
140
+ workflow_id=workflow_id,
141
+ setting_id=setting_id,
142
+ per_page=per_page,
143
+ next_token=next_token,
144
+ )
145
+ logger.info(f"Retrieved {len(aliases.data)} aliases for workflow {workflow_id}")
146
+ return aliases
147
+
148
+ def install_workflows(
149
+ self,
150
+ vendor: VendorType,
151
+ workflows: List[VendorWorkflowInstallRequest],
152
+ ) -> VendorWorkflowInstallResponse:
153
+ """Install/activate vendor workflows.
154
+
155
+ Args:
156
+ vendor: Cloud vendor type
157
+ workflows: List of workflow installation requests
158
+
159
+ Returns:
160
+ VendorWorkflowInstallResponse containing installation summary with AI run IDs
161
+ """
162
+ logger.info(f"Installing {len(workflows)} workflow(s) for {vendor.value}")
163
+ response = self.vendor_workflow_service.install_workflows(
164
+ vendor=vendor, workflows=workflows
165
+ )
166
+ for item in response.summary:
167
+ logger.info(
168
+ f"Installed workflow {item.flowId} (alias: {item.flowAliasId}) -> CodeMie ID: {item.aiRunId}"
169
+ )
170
+ return response
171
+
172
+ def uninstall_workflow(
173
+ self,
174
+ vendor: VendorType,
175
+ codemie_id: str,
176
+ ) -> VendorWorkflowUninstallResponse:
177
+ """Uninstall/deactivate a vendor workflow.
178
+
179
+ Args:
180
+ vendor: Cloud vendor type
181
+ codemie_id: CodeMie workflow ID from installation
182
+
183
+ Returns:
184
+ VendorWorkflowUninstallResponse with success status
185
+ """
186
+ logger.info(f"Uninstalling workflow with CodeMie ID: {codemie_id}")
187
+ response = self.vendor_workflow_service.uninstall_workflow(
188
+ vendor=vendor, ai_run_id=codemie_id
189
+ )
190
+ if response.success:
191
+ logger.info(f"Successfully uninstalled workflow {codemie_id}")
192
+ else:
193
+ logger.warning(f"Failed to uninstall workflow {codemie_id}")
194
+ return response
195
+
196
+ def get_prepared_workflow(
197
+ self,
198
+ workflows: List[VendorWorkflow],
199
+ ) -> Optional[VendorWorkflow]:
200
+ """Get first PREPARED workflow from the list.
201
+
202
+ Args:
203
+ workflows: List of vendor workflows
204
+
205
+ Returns:
206
+ First PREPARED workflow or first workflow if none are PREPARED
207
+ """
208
+ return next(
209
+ (w for w in workflows if w.status == VendorWorkflowStatus.PREPARED),
210
+ workflows[0] if workflows else None,
211
+ )
212
+
213
+ def get_non_draft_alias(
214
+ self,
215
+ aliases: List,
216
+ ) -> Optional:
217
+ """Get first non-DRAFT alias from the list.
218
+
219
+ Args:
220
+ aliases: List of vendor workflow aliases
221
+
222
+ Returns:
223
+ First non-DRAFT alias or first alias if all are DRAFT
224
+ """
225
+ return next(
226
+ (a for a in aliases if a.version != DRAFT_VERSION),
227
+ aliases[0] if aliases else None,
228
+ )
229
+
230
+ def find_workflow_by_name(
231
+ self,
232
+ vendor: VendorType,
233
+ setting_id: str,
234
+ workflow_name: str,
235
+ ) -> Optional[tuple[VendorWorkflow, str]]:
236
+ """Find a workflow by name and return it with an alias.
237
+
238
+ Args:
239
+ vendor: Cloud vendor type
240
+ setting_id: ID of the vendor setting
241
+ workflow_name: Name of the workflow to find
242
+
243
+ Returns:
244
+ Tuple of (VendorWorkflow, alias_id) or None if workflow not found
245
+ """
246
+ logger.info(
247
+ f"Searching for workflow '{workflow_name}' in {vendor.value} setting {setting_id}"
248
+ )
249
+ workflows_response = self.get_workflows(vendor=vendor, setting_id=setting_id)
250
+
251
+ for workflow in workflows_response.data:
252
+ if (
253
+ workflow.name == workflow_name
254
+ and workflow.status == VendorWorkflowStatus.PREPARED
255
+ ):
256
+ aliases_response = self.get_workflow_aliases(
257
+ vendor=vendor, workflow_id=workflow.id, setting_id=setting_id
258
+ )
259
+ if aliases_response.data:
260
+ non_draft_alias = self.get_non_draft_alias(aliases_response.data)
261
+ if non_draft_alias:
262
+ logger.info(
263
+ f"Found workflow: {workflow.name} (ID: {workflow.id}, Alias: {non_draft_alias.id})"
264
+ )
265
+ return workflow, non_draft_alias.id
266
+
267
+ logger.warning(
268
+ f"Workflow '{workflow_name}' not found for {vendor.value} setting {setting_id}"
269
+ )
270
+ return None
271
+
272
+ def find_first_available_workflow(
273
+ self,
274
+ vendor: VendorType,
275
+ setting_id: str,
276
+ ) -> Optional[tuple[VendorWorkflow, str]]:
277
+ """Find the first available (PREPARED) workflow with an alias.
278
+
279
+ Args:
280
+ vendor: Cloud vendor type
281
+ setting_id: ID of the vendor setting
282
+
283
+ Returns:
284
+ Tuple of (VendorWorkflow, alias_id) or None if no available workflow found
285
+ """
286
+ logger.info(
287
+ f"Searching for available workflow in {vendor.value} setting {setting_id}"
288
+ )
289
+ workflows_response = self.get_workflows(vendor=vendor, setting_id=setting_id)
290
+
291
+ for workflow in workflows_response.data:
292
+ if workflow.status == VendorWorkflowStatus.PREPARED:
293
+ aliases_response = self.get_workflow_aliases(
294
+ vendor=vendor, workflow_id=workflow.id, setting_id=setting_id
295
+ )
296
+ if aliases_response.data:
297
+ first_alias = aliases_response.data[0]
298
+ logger.info(
299
+ f"Found available workflow: {workflow.name} (ID: {workflow.id}, Alias: {first_alias.id})"
300
+ )
301
+ return workflow, first_alias.id
302
+
303
+ logger.warning(
304
+ f"No available workflow found for {vendor.value} setting {setting_id}"
305
+ )
306
+ return None
307
+
308
+ def install_workflow_by_name(
309
+ self,
310
+ vendor: VendorType,
311
+ setting_id: str,
312
+ workflow_name: str,
313
+ ) -> Optional[str]:
314
+ """Find and install a workflow by name.
315
+
316
+ Args:
317
+ vendor: Cloud vendor type
318
+ setting_id: ID of the vendor setting
319
+ workflow_name: Name of the workflow to install
320
+
321
+ Returns:
322
+ CodeMie ID of the installed workflow or None if workflow not found
323
+ """
324
+ result = self.find_workflow_by_name(
325
+ vendor=vendor, setting_id=setting_id, workflow_name=workflow_name
326
+ )
327
+ if not result:
328
+ return None
329
+
330
+ workflow, alias_id = result
331
+ install_request = VendorWorkflowInstallRequest(
332
+ id=workflow.id,
333
+ flowAliasId=alias_id,
334
+ setting_id=setting_id,
335
+ )
336
+
337
+ install_response = self.install_workflows(
338
+ vendor=vendor, workflows=[install_request]
339
+ )
340
+
341
+ if install_response.summary:
342
+ return install_response.summary[0].aiRunId
343
+
344
+ return None
345
+
346
+ def install_first_available_workflow(
347
+ self,
348
+ vendor: VendorType,
349
+ setting_id: str,
350
+ ) -> Optional[str]:
351
+ """Find and install the first available workflow.
352
+
353
+ Args:
354
+ vendor: Cloud vendor type
355
+ setting_id: ID of the vendor setting
356
+
357
+ Returns:
358
+ CodeMie ID of the installed workflow or None if no workflow available
359
+ """
360
+ result = self.find_first_available_workflow(
361
+ vendor=vendor, setting_id=setting_id
362
+ )
363
+ if not result:
364
+ return None
365
+
366
+ workflow, alias_id = result
367
+ install_request = VendorWorkflowInstallRequest(
368
+ id=workflow.id,
369
+ flowAliasId=alias_id,
370
+ setting_id=setting_id,
371
+ )
372
+
373
+ install_response = self.install_workflows(
374
+ vendor=vendor, workflows=[install_request]
375
+ )
376
+
377
+ if install_response.summary:
378
+ return install_response.summary[0].aiRunId
379
+
380
+ return None
381
+
382
+ def find_setting_for_integration(
383
+ self,
384
+ vendor: VendorType,
385
+ integration_id: str,
386
+ ):
387
+ """Find setting for an integration by paginating through all settings.
388
+
389
+ Args:
390
+ vendor: Type of vendor (AWS, AZURE, GCP)
391
+ integration_id: ID of the integration to find (searches by setting_id)
392
+
393
+ Returns:
394
+ VendorWorkflowSetting or None if not found
395
+ """
396
+ page = 0
397
+ per_page = 50
398
+
399
+ while True:
400
+ settings_response = self.get_workflow_settings(
401
+ vendor=vendor,
402
+ page=page,
403
+ per_page=per_page,
404
+ )
405
+
406
+ # Find the setting for our integration by setting_id
407
+ for s in settings_response.data:
408
+ if s.setting_id == integration_id:
409
+ return s
410
+
411
+ # Check if there are more pages
412
+ if page >= settings_response.pagination.pages - 1:
413
+ break
414
+
415
+ page += 1
416
+
417
+ logger.warning(f"Setting not found for integration ID '{integration_id}'")
418
+ return None
@@ -12,7 +12,7 @@ from codemie_test_harness.tests.test_data.vendor_test_data import (
12
12
  vendor_assistant_test_data,
13
13
  )
14
14
  def test_vendor_assistant_installation_and_chat(
15
- vendor_utils,
15
+ vendor_assistant_utils,
16
16
  integration,
17
17
  assistant_utils,
18
18
  similarity_check,
@@ -25,21 +25,21 @@ def test_vendor_assistant_installation_and_chat(
25
25
  """Test vendor assistant installation and chat functionality."""
26
26
  _integration = integration(credential_type, credentials)
27
27
 
28
- setting = vendor_utils.find_setting_for_integration(
28
+ setting = vendor_assistant_utils.find_setting_for_integration(
29
29
  vendor=vendor_type,
30
30
  integration_id=_integration.id,
31
31
  )
32
32
  assert_that(setting, is_not(none()))
33
33
  assert_that(setting.invalid or False, is_(False))
34
34
 
35
- assistants_response = vendor_utils.get_assistants(
35
+ assistants_response = vendor_assistant_utils.get_assistants(
36
36
  vendor=vendor_type,
37
37
  setting_id=setting.setting_id,
38
38
  )
39
39
  assert_that(assistants_response, is_not(none()))
40
40
  assert_that(assistants_response.data, is_not(empty()))
41
41
 
42
- codemie_id = vendor_utils.install_first_available_assistant(
42
+ codemie_id = vendor_assistant_utils.install_first_available_assistant(
43
43
  vendor=vendor_type,
44
44
  setting_id=setting.setting_id,
45
45
  )
@@ -58,7 +58,7 @@ def test_vendor_assistant_installation_and_chat(
58
58
 
59
59
  similarity_check.check_similarity(response, expected_response)
60
60
 
61
- uninstall_response = vendor_utils.uninstall_assistant(
61
+ uninstall_response = vendor_assistant_utils.uninstall_assistant(
62
62
  vendor=vendor_type,
63
63
  codemie_id=codemie_id,
64
64
  )