codemie-test-harness 0.1.205__py3-none-any.whl → 0.1.207__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/tests/assistant/datasource/test_code_datasource.py +2 -2
- codemie_test_harness/tests/assistant/tools/git/test_assistant_with_git_tools.py +14 -14
- codemie_test_harness/tests/conftest.py +34 -12
- codemie_test_harness/tests/e2e/test_e2e.py +2 -2
- codemie_test_harness/tests/ui/assistants/test_create_assistant.py +13 -13
- codemie_test_harness/tests/ui/assistants/test_edit_assistant.py +200 -0
- codemie_test_harness/tests/ui/datasource/test_create_datasource.py +2 -2
- codemie_test_harness/tests/ui/datasource/test_edit_datasource.py +2 -2
- codemie_test_harness/tests/ui/datasource/test_view_datasource.py +2 -2
- codemie_test_harness/tests/ui/pageobject/assistants/assistant_mcp_server.py +171 -0
- codemie_test_harness/tests/ui/pageobject/assistants/assistant_sidebar.py +140 -0
- codemie_test_harness/tests/ui/pageobject/assistants/assistant_view_page.py +256 -0
- codemie_test_harness/tests/ui/pageobject/assistants/assistants_page.py +63 -0
- codemie_test_harness/tests/ui/pageobject/assistants/{create_assistant_page.py → create_edit_assistant_page.py} +379 -95
- codemie_test_harness/tests/ui/test_data/assistant_test_data.py +347 -18
- codemie_test_harness/tests/utils/constants.py +1 -1
- codemie_test_harness/tests/utils/webhook_utils.py +10 -0
- codemie_test_harness/tests/webhook/__init__.py +0 -0
- codemie_test_harness/tests/webhook/test_webhook_service.py +225 -0
- codemie_test_harness/tests/workflow/assistant_tools/git/test_workflow_with_assistant_git_tools.py +14 -14
- codemie_test_harness/tests/workflow/virtual_assistant_tools/git/test_workflow_with_git_tools.py +14 -14
- {codemie_test_harness-0.1.205.dist-info → codemie_test_harness-0.1.207.dist-info}/METADATA +2 -2
- {codemie_test_harness-0.1.205.dist-info → codemie_test_harness-0.1.207.dist-info}/RECORD +25 -18
- {codemie_test_harness-0.1.205.dist-info → codemie_test_harness-0.1.207.dist-info}/WHEEL +0 -0
- {codemie_test_harness-0.1.205.dist-info → codemie_test_harness-0.1.207.dist-info}/entry_points.txt +0 -0
|
@@ -8,6 +8,7 @@ reusable data factories for consistent testing.
|
|
|
8
8
|
|
|
9
9
|
from dataclasses import dataclass
|
|
10
10
|
from typing import Optional, List
|
|
11
|
+
from enum import Enum
|
|
11
12
|
|
|
12
13
|
from codemie_test_harness.tests.utils.base_utils import get_random_name
|
|
13
14
|
|
|
@@ -28,6 +29,24 @@ class AssistantTestData:
|
|
|
28
29
|
shared: bool = False
|
|
29
30
|
|
|
30
31
|
|
|
32
|
+
@dataclass
|
|
33
|
+
class AssistantMCPConfigTestData:
|
|
34
|
+
"""
|
|
35
|
+
Data class for assistant MCP config test data.
|
|
36
|
+
|
|
37
|
+
This class encapsulates all the data needed for assistant creation tests,
|
|
38
|
+
providing a clean and type-safe way to manage test data.
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
name: str
|
|
42
|
+
description: str
|
|
43
|
+
configuration: str
|
|
44
|
+
token_size_limit: Optional[str] = None
|
|
45
|
+
configuration_type: Optional[bool] = False
|
|
46
|
+
env_var: Optional[str] = None
|
|
47
|
+
mcp_url: Optional[str] = None
|
|
48
|
+
|
|
49
|
+
|
|
31
50
|
class AssistantTestDataFactory:
|
|
32
51
|
"""
|
|
33
52
|
Factory class for generating assistant test data.
|
|
@@ -117,7 +136,33 @@ class AssistantTestDataFactory:
|
|
|
117
136
|
]
|
|
118
137
|
|
|
119
138
|
|
|
120
|
-
class
|
|
139
|
+
class AssistantMCPTestDataFactory:
|
|
140
|
+
"""
|
|
141
|
+
Factory class for generating assistant test data for creating new MCP server..
|
|
142
|
+
|
|
143
|
+
This factory provides various methods to create different types of
|
|
144
|
+
assistant test data for different testing scenarios.
|
|
145
|
+
"""
|
|
146
|
+
|
|
147
|
+
@staticmethod
|
|
148
|
+
def create_minimal_assistant_mcp_data() -> AssistantMCPConfigTestData:
|
|
149
|
+
"""
|
|
150
|
+
Create minimal assistant data with only required fields.
|
|
151
|
+
|
|
152
|
+
This represents the most basic assistant creation scenario
|
|
153
|
+
with minimal required information.
|
|
154
|
+
|
|
155
|
+
Returns:
|
|
156
|
+
AssistantMCPTestDataFactory: Minimal assistant mcp config test data
|
|
157
|
+
"""
|
|
158
|
+
return AssistantMCPConfigTestData(
|
|
159
|
+
name="MCP Test",
|
|
160
|
+
description="MCP for test purposes",
|
|
161
|
+
configuration='{"command": "test"}',
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
class AssistantValidationErrors(Enum):
|
|
121
166
|
"""
|
|
122
167
|
Validation rules and constraints for assistant data.
|
|
123
168
|
|
|
@@ -125,24 +170,30 @@ class AssistantValidationRules:
|
|
|
125
170
|
to assistant data during testing.
|
|
126
171
|
"""
|
|
127
172
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
173
|
+
NAME_REQUIRED = "Name is required"
|
|
174
|
+
ICON_URL_NOT_VALID = "Icon URL must be a valid URL"
|
|
175
|
+
DESCRIPTION_REQUIRED = "Description is required"
|
|
176
|
+
SYSTEM_PROMPT_REQUIRED = "System instructions are required"
|
|
177
|
+
TEMPERATURE_NOT_VALID = "Temperature must be at most 2"
|
|
178
|
+
TOP_P_NOT_VALID = "Top P must be at most 1"
|
|
132
179
|
|
|
133
|
-
# Required fields
|
|
134
|
-
REQUIRED_FIELDS = ["name", "description", "system_prompt"]
|
|
135
180
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
181
|
+
class AssistantPopUpMessages(Enum):
|
|
182
|
+
"""
|
|
183
|
+
Enumerates expected popup notification and toast messages for assistant actions in UI tests.
|
|
184
|
+
|
|
185
|
+
This enum class should include all standardized popup/toast messages
|
|
186
|
+
that are expected to appear as a result of user workflow, such as
|
|
187
|
+
success/error messages after saving or updating an assistant,
|
|
188
|
+
deletion confirmations, or integration test results.
|
|
189
|
+
|
|
190
|
+
Using this enum in UI tests ensures message checks are maintainable,
|
|
191
|
+
consistent, and robust against typo errors or message changes.
|
|
192
|
+
"""
|
|
193
|
+
|
|
194
|
+
ASSISTANT_UPDATED_SUCCESS = "Assistant has been updated successfully!"
|
|
195
|
+
ASSISTANT_CREATED_SUCCESS = "Assistant has been created successfully!"
|
|
196
|
+
ASSISTANT_DELETED_SUCCESS = "Assistant has been deleted successfully!"
|
|
146
197
|
|
|
147
198
|
|
|
148
199
|
# ==================== CONVENIENCE FUNCTIONS ====================
|
|
@@ -163,6 +214,11 @@ def get_validation_test_data() -> List[AssistantTestData]:
|
|
|
163
214
|
return AssistantTestDataFactory.create_validation_test_data()
|
|
164
215
|
|
|
165
216
|
|
|
217
|
+
def get_minimal_assistant_mcp_config_data() -> AssistantMCPConfigTestData:
|
|
218
|
+
"""Convenience function to get minimal assistant mcp config test data."""
|
|
219
|
+
return AssistantMCPTestDataFactory.create_minimal_assistant_mcp_data()
|
|
220
|
+
|
|
221
|
+
|
|
166
222
|
# ==================== TEST DATA CONSTANTS ====================
|
|
167
223
|
|
|
168
224
|
# Common test values for reuse
|
|
@@ -196,4 +252,277 @@ COMMON_ICON_URLS = {
|
|
|
196
252
|
|
|
197
253
|
ICON_URL = "https://raw.githubusercontent.com/epam-gen-ai-run/ai-run-install/main/docs/assets/ai/AQAUiTestGenerator.png"
|
|
198
254
|
|
|
199
|
-
|
|
255
|
+
|
|
256
|
+
# ==================== ASSISTANT TOOLS CONSTANTS ====================
|
|
257
|
+
class Section(Enum):
|
|
258
|
+
AVAILABLE_TOOLS = "Available Tools"
|
|
259
|
+
EXTERNAL_TOOLS = "External Tools"
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
class Toolkit(Enum):
|
|
263
|
+
GIT = "Git"
|
|
264
|
+
VCS = "VCS"
|
|
265
|
+
CODEBASE_TOOLS = "Codebase Tools"
|
|
266
|
+
RESEARCH = "Research"
|
|
267
|
+
CLOUD = "Cloud"
|
|
268
|
+
AZURE_DEVOPS_WIKI = "Azure DevOps Wiki"
|
|
269
|
+
AZURE_DEVOPS_WORK_ITEM = "Azure DevOps Work Item"
|
|
270
|
+
AZURE_DEVOPS_TEST_PLAN = "Azure DevOps Test Plan"
|
|
271
|
+
ACCESS_MANAGEMENT = "Access Management"
|
|
272
|
+
PROJECT_MANAGEMENT = "Project Management"
|
|
273
|
+
PLUGIN = "Plugin"
|
|
274
|
+
OPEN_API = "OpenAPI"
|
|
275
|
+
NOTIFICATION = "Notification"
|
|
276
|
+
DATA_MANAGEMENT = "Data Management"
|
|
277
|
+
FILE_MANAGEMENT = "File Management"
|
|
278
|
+
QUALITY_ASSURANCE = "Quality Assurance"
|
|
279
|
+
REPORT_PORTAL = "Report Portal"
|
|
280
|
+
IT_SERVICE_MANAGEMENT = "IT Service Management"
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
class ExternalToolKit(Enum):
|
|
284
|
+
MCP_SERVERS = "MCP Servers"
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
class GitTool(Enum):
|
|
288
|
+
CREATE_BRANCH = "Create Branch"
|
|
289
|
+
SET_ACTIVE_BRANCH = "Set Active Branch"
|
|
290
|
+
LIST_BRANCHES_IN_REPO = "List Branches In Repo"
|
|
291
|
+
CREATE_FILE = "Create File"
|
|
292
|
+
UPDATE_FILE = "Update File"
|
|
293
|
+
UPDATE_FILE_DIFF = "Update File Diff"
|
|
294
|
+
DELETE_FILE = "Delete File"
|
|
295
|
+
CREATE_PULL_REQUEST = "Create Pull/Merge request"
|
|
296
|
+
GET_PR_CHANGES = "Get Pull/Merge Request Changes"
|
|
297
|
+
CREATE_PR_CHANGE_COMMENT = "Create Pull/Merge Request Change Comment"
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
class VcsTool(Enum):
|
|
301
|
+
GITHUB = "Github"
|
|
302
|
+
GITLAB = "Gitlab"
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
class CodebaseTool(Enum):
|
|
306
|
+
GET_REPOSITORY_FILE_TREE_V2 = "Get Repo Tree with filtering (Experimental)"
|
|
307
|
+
SEARCH_CODE_REPO_V2 = "Search Code with filtering (Experimental)"
|
|
308
|
+
READ_FILES_CONTENT = "Read Files Content"
|
|
309
|
+
READ_FILES_CONTENT_SUMMARY = "Read Files Content With Summary For Large"
|
|
310
|
+
SEARCH_CODE_REPO_BY_PATH = "Search Code Repo By Path"
|
|
311
|
+
SONAR = "Sonar"
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
class ResearchTool(Enum):
|
|
315
|
+
GOOGLE_SEARCH = "Google Search"
|
|
316
|
+
GOOGLE_PLACES = "Google Places"
|
|
317
|
+
GOOGLE_PLACES_FIND_NEAR = "Google Places Find Near"
|
|
318
|
+
WIKIPEDIA = "Wikipedia"
|
|
319
|
+
TAVILY_SEARCH = "Tavily Search"
|
|
320
|
+
WEB_SCRAPPER = "Web Scraper"
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
class CloudTool(Enum):
|
|
324
|
+
KUBERNETES = "Kubernetes"
|
|
325
|
+
AWS = "AWS"
|
|
326
|
+
GCP = "GCP"
|
|
327
|
+
AZURE = "Azure"
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
class AzureDevOpsWikiTool(Enum):
|
|
331
|
+
GET_WIKI = "Get Wiki"
|
|
332
|
+
GET_WIKI_PAGE_BY_PATH = "Get Wiki Page By Path"
|
|
333
|
+
GET_WIKI_PAGE_BY_ID = "Get Wiki Page By ID"
|
|
334
|
+
DELETE_PAGE_BY_PATH = "Delete Wiki Page By Path"
|
|
335
|
+
DELETE_PAGE_BY_ID = "Delete Wiki Page By ID"
|
|
336
|
+
MODIFY_WIKI_PAGE = "Modify Wiki Page"
|
|
337
|
+
RENAME_WIKI_PAGE = "Rename Wiki Page"
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
class AzureDevOpsWorkItemTool(Enum):
|
|
341
|
+
SEARCH_WORK_ITEMS = "Search Work Items"
|
|
342
|
+
CREATE_WORK_ITEM = "Create Work Item"
|
|
343
|
+
UPDATE_WORK_ITEM = "Update Work Item"
|
|
344
|
+
GET_WORK_ITEM = "Get Work Item"
|
|
345
|
+
LINK_WORK_ITEMS = "Link Work Items"
|
|
346
|
+
GET_RELATION_TYPES = "Get Relation Types"
|
|
347
|
+
GET_COMMENTS = "Get Comments"
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
class AzureDevOpsTestPlanTool(Enum):
|
|
351
|
+
CREATE_TEST_PLAN = "Create Test Plan"
|
|
352
|
+
DELETE_TEST_PLAN = "Delete Test Plan"
|
|
353
|
+
GET_TEST_PLAN = "Get Test Plan"
|
|
354
|
+
CREATE_TEST_SUITE = "Create Test Suite"
|
|
355
|
+
DELETE_TEST_SUITE = "Delete Test Suite"
|
|
356
|
+
GET_TEST_SUITE = "Get Test Suite"
|
|
357
|
+
ADD_TEST_CASE = "Add Test Case"
|
|
358
|
+
GET_TEST_CASE = "Get Test Case"
|
|
359
|
+
GET_TEST_CASES = "Get Test Cases"
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
class AccessManagementTool(Enum):
|
|
363
|
+
KEYCLOAK = "Keycloak"
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
class ProjectManagementTool(Enum):
|
|
367
|
+
GENERIC_JIRA = "Generic Jira"
|
|
368
|
+
GENERIC_CONFLUENCE = "Generic Confluence"
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
class PluginTool(Enum):
|
|
372
|
+
PLUGIN = "Plugin"
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
class OpenAPITool(Enum):
|
|
376
|
+
INVOKE_EXTERNAL_API = "Invoke external API"
|
|
377
|
+
GET_OPEN_API_SPEC = "Get Open API spec"
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
class NotificationTool(Enum):
|
|
381
|
+
EMAIL = "Email"
|
|
382
|
+
TELEGRAM = "Telegram"
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
class DataManagementTool(Enum):
|
|
386
|
+
ELASTIC = "Search Elastic index"
|
|
387
|
+
SQL = "SQL"
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
class FileManagementTool(Enum):
|
|
391
|
+
READ_FILE = "Read file"
|
|
392
|
+
WRITE_FILE = "Write file"
|
|
393
|
+
LIST_DIRECTORY = "List directory"
|
|
394
|
+
RUN_COMMAND_LINE = "Run command line"
|
|
395
|
+
CODE_INTERPRETER = "Code Interpreter"
|
|
396
|
+
GENERATE_IMAGE_TOOL = "Generate image"
|
|
397
|
+
DIFF_UPDATE_FILE_TOOL = "Read Generate Update File (diff)"
|
|
398
|
+
STR_REPLACE_EDITOR = "Filesystem Editor Tool"
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
class QualityAssuranceTool(Enum):
|
|
402
|
+
ZEPHYR_SCALE = "Zephyr Scale"
|
|
403
|
+
ZEPHYR_SQUAD = "Zephyr Squad"
|
|
404
|
+
|
|
405
|
+
|
|
406
|
+
class ITServiceManagementTool(Enum):
|
|
407
|
+
SERVICENOW_TABLE_API = "ServiceNow Table API"
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
class MCPServersTool(Enum):
|
|
411
|
+
ADD_MCP_SERVER = " Add MCP Server "
|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
TOOLKIT_TOOLS = {
|
|
415
|
+
Section.AVAILABLE_TOOLS: {
|
|
416
|
+
Toolkit.GIT: [
|
|
417
|
+
GitTool.CREATE_BRANCH,
|
|
418
|
+
GitTool.SET_ACTIVE_BRANCH,
|
|
419
|
+
GitTool.LIST_BRANCHES_IN_REPO,
|
|
420
|
+
GitTool.CREATE_FILE,
|
|
421
|
+
GitTool.UPDATE_FILE,
|
|
422
|
+
GitTool.UPDATE_FILE_DIFF,
|
|
423
|
+
GitTool.DELETE_FILE,
|
|
424
|
+
GitTool.CREATE_PULL_REQUEST,
|
|
425
|
+
GitTool.GET_PR_CHANGES,
|
|
426
|
+
GitTool.CREATE_PR_CHANGE_COMMENT,
|
|
427
|
+
],
|
|
428
|
+
Toolkit.VCS: [
|
|
429
|
+
VcsTool.GITHUB,
|
|
430
|
+
VcsTool.GITLAB,
|
|
431
|
+
],
|
|
432
|
+
Toolkit.CODEBASE_TOOLS: [
|
|
433
|
+
CodebaseTool.GET_REPOSITORY_FILE_TREE_V2,
|
|
434
|
+
CodebaseTool.SEARCH_CODE_REPO_V2,
|
|
435
|
+
CodebaseTool.READ_FILES_CONTENT,
|
|
436
|
+
CodebaseTool.READ_FILES_CONTENT_SUMMARY,
|
|
437
|
+
CodebaseTool.SEARCH_CODE_REPO_BY_PATH,
|
|
438
|
+
CodebaseTool.SONAR,
|
|
439
|
+
],
|
|
440
|
+
Toolkit.RESEARCH: [
|
|
441
|
+
ResearchTool.GOOGLE_SEARCH,
|
|
442
|
+
ResearchTool.GOOGLE_PLACES,
|
|
443
|
+
ResearchTool.GOOGLE_PLACES_FIND_NEAR,
|
|
444
|
+
ResearchTool.WIKIPEDIA,
|
|
445
|
+
ResearchTool.TAVILY_SEARCH,
|
|
446
|
+
ResearchTool.WEB_SCRAPPER,
|
|
447
|
+
],
|
|
448
|
+
Toolkit.CLOUD: [
|
|
449
|
+
CloudTool.KUBERNETES,
|
|
450
|
+
CloudTool.AWS,
|
|
451
|
+
CloudTool.GCP,
|
|
452
|
+
CloudTool.AZURE,
|
|
453
|
+
],
|
|
454
|
+
Toolkit.AZURE_DEVOPS_WIKI: [
|
|
455
|
+
AzureDevOpsWikiTool.GET_WIKI,
|
|
456
|
+
AzureDevOpsWikiTool.GET_WIKI_PAGE_BY_PATH,
|
|
457
|
+
AzureDevOpsWikiTool.GET_WIKI_PAGE_BY_ID,
|
|
458
|
+
AzureDevOpsWikiTool.DELETE_PAGE_BY_PATH,
|
|
459
|
+
AzureDevOpsWikiTool.DELETE_PAGE_BY_ID,
|
|
460
|
+
AzureDevOpsWikiTool.MODIFY_WIKI_PAGE,
|
|
461
|
+
AzureDevOpsWikiTool.RENAME_WIKI_PAGE,
|
|
462
|
+
],
|
|
463
|
+
Toolkit.AZURE_DEVOPS_WORK_ITEM: [
|
|
464
|
+
AzureDevOpsWorkItemTool.SEARCH_WORK_ITEMS,
|
|
465
|
+
AzureDevOpsWorkItemTool.CREATE_WORK_ITEM,
|
|
466
|
+
AzureDevOpsWorkItemTool.UPDATE_WORK_ITEM,
|
|
467
|
+
AzureDevOpsWorkItemTool.GET_WORK_ITEM,
|
|
468
|
+
AzureDevOpsWorkItemTool.LINK_WORK_ITEMS,
|
|
469
|
+
AzureDevOpsWorkItemTool.GET_RELATION_TYPES,
|
|
470
|
+
AzureDevOpsWorkItemTool.GET_COMMENTS,
|
|
471
|
+
],
|
|
472
|
+
Toolkit.AZURE_DEVOPS_TEST_PLAN: [
|
|
473
|
+
AzureDevOpsTestPlanTool.CREATE_TEST_PLAN,
|
|
474
|
+
AzureDevOpsTestPlanTool.DELETE_TEST_PLAN,
|
|
475
|
+
AzureDevOpsTestPlanTool.GET_TEST_PLAN,
|
|
476
|
+
AzureDevOpsTestPlanTool.CREATE_TEST_SUITE,
|
|
477
|
+
AzureDevOpsTestPlanTool.DELETE_TEST_SUITE,
|
|
478
|
+
AzureDevOpsTestPlanTool.GET_TEST_SUITE,
|
|
479
|
+
AzureDevOpsTestPlanTool.ADD_TEST_CASE,
|
|
480
|
+
AzureDevOpsTestPlanTool.GET_TEST_CASE,
|
|
481
|
+
AzureDevOpsTestPlanTool.GET_TEST_CASES,
|
|
482
|
+
],
|
|
483
|
+
Toolkit.ACCESS_MANAGEMENT: [
|
|
484
|
+
AccessManagementTool.KEYCLOAK,
|
|
485
|
+
],
|
|
486
|
+
Toolkit.PROJECT_MANAGEMENT: [
|
|
487
|
+
ProjectManagementTool.GENERIC_JIRA,
|
|
488
|
+
ProjectManagementTool.GENERIC_CONFLUENCE,
|
|
489
|
+
],
|
|
490
|
+
Toolkit.PLUGIN: [
|
|
491
|
+
PluginTool.PLUGIN,
|
|
492
|
+
],
|
|
493
|
+
Toolkit.OPEN_API: [
|
|
494
|
+
OpenAPITool.INVOKE_EXTERNAL_API,
|
|
495
|
+
OpenAPITool.GET_OPEN_API_SPEC,
|
|
496
|
+
],
|
|
497
|
+
Toolkit.NOTIFICATION: [
|
|
498
|
+
NotificationTool.EMAIL,
|
|
499
|
+
NotificationTool.TELEGRAM,
|
|
500
|
+
],
|
|
501
|
+
Toolkit.DATA_MANAGEMENT: [
|
|
502
|
+
DataManagementTool.ELASTIC,
|
|
503
|
+
DataManagementTool.SQL,
|
|
504
|
+
],
|
|
505
|
+
Toolkit.FILE_MANAGEMENT: [
|
|
506
|
+
FileManagementTool.READ_FILE,
|
|
507
|
+
FileManagementTool.WRITE_FILE,
|
|
508
|
+
FileManagementTool.LIST_DIRECTORY,
|
|
509
|
+
FileManagementTool.RUN_COMMAND_LINE,
|
|
510
|
+
FileManagementTool.CODE_INTERPRETER,
|
|
511
|
+
FileManagementTool.GENERATE_IMAGE_TOOL,
|
|
512
|
+
FileManagementTool.DIFF_UPDATE_FILE_TOOL,
|
|
513
|
+
FileManagementTool.STR_REPLACE_EDITOR,
|
|
514
|
+
],
|
|
515
|
+
Toolkit.QUALITY_ASSURANCE: [
|
|
516
|
+
QualityAssuranceTool.ZEPHYR_SCALE,
|
|
517
|
+
QualityAssuranceTool.ZEPHYR_SQUAD,
|
|
518
|
+
],
|
|
519
|
+
Toolkit.IT_SERVICE_MANAGEMENT: [
|
|
520
|
+
ITServiceManagementTool.SERVICENOW_TABLE_API,
|
|
521
|
+
],
|
|
522
|
+
},
|
|
523
|
+
Section.EXTERNAL_TOOLS: {
|
|
524
|
+
ExternalToolKit.MCP_SERVERS: [
|
|
525
|
+
MCPServersTool.ADD_MCP_SERVER,
|
|
526
|
+
]
|
|
527
|
+
},
|
|
528
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from typing import Any, Dict
|
|
2
|
+
|
|
3
|
+
from codemie_test_harness.tests.utils.base_utils import BaseUtils
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class WebhookUtils(BaseUtils):
|
|
7
|
+
"""Utility class for webhook operations in CodeMie test harness."""
|
|
8
|
+
|
|
9
|
+
def trigger_webhook(self, webhook_id: str, data: Dict[str, Any] = None):
|
|
10
|
+
return self.client.webhook.trigger(webhook_id, data)
|
|
File without changes
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
"""Webhook integration tests for CodeMie.
|
|
2
|
+
|
|
3
|
+
This module contains tests for webhook functionality including:
|
|
4
|
+
- Basic webhook operations with different resource types (assistant, workflow, datasource)
|
|
5
|
+
- Error handling and validation
|
|
6
|
+
- Webhook triggering verification
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import pytest
|
|
10
|
+
|
|
11
|
+
from codemie_sdk.models.workflow import ExecutionStatus
|
|
12
|
+
from hamcrest import (
|
|
13
|
+
assert_that,
|
|
14
|
+
equal_to,
|
|
15
|
+
greater_than,
|
|
16
|
+
has_length,
|
|
17
|
+
has_item,
|
|
18
|
+
)
|
|
19
|
+
from codemie_test_harness.tests.utils.base_utils import get_random_name, wait_for_entity
|
|
20
|
+
from codemie_test_harness.tests.ui.test_data.datasource_test_data import (
|
|
21
|
+
DataSourceStatus,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@pytest.mark.webhook
|
|
26
|
+
@pytest.mark.api
|
|
27
|
+
class TestWebhookBasicOperations:
|
|
28
|
+
"""Basic webhook operations tests - verify webhook creation and triggering for different resource types."""
|
|
29
|
+
|
|
30
|
+
def test_webhook_with_assistant(
|
|
31
|
+
self, assistant, webhook_integration, webhook_utils, conversation_utils
|
|
32
|
+
):
|
|
33
|
+
"""Test webhook can be created with assistant and triggers conversation creation."""
|
|
34
|
+
webhook_id = get_random_name()
|
|
35
|
+
message = f"Test message for {webhook_id}"
|
|
36
|
+
|
|
37
|
+
# Create assistant
|
|
38
|
+
assistant = assistant()
|
|
39
|
+
|
|
40
|
+
# Create webhook integration
|
|
41
|
+
webhook_integration(webhook_id, "assistant", assistant.id)
|
|
42
|
+
|
|
43
|
+
# Trigger webhook
|
|
44
|
+
response = webhook_utils.trigger_webhook(webhook_id, data=message)
|
|
45
|
+
assert_that(response.status_code, equal_to(200))
|
|
46
|
+
assert_that(
|
|
47
|
+
response.json()["message"], equal_to("Webhook invoked successfully")
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
# Wait for conversation
|
|
51
|
+
conversation = wait_for_entity(
|
|
52
|
+
lambda: conversation_utils.list_conversations(),
|
|
53
|
+
entity_name=f'"{message}"',
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
# Verify conversation details
|
|
57
|
+
assert_that(conversation.name.strip('"'), equal_to(message))
|
|
58
|
+
assert_that(conversation.initial_assistant_id, equal_to(assistant.id))
|
|
59
|
+
assert_that(conversation.assistant_ids, has_item(assistant.id))
|
|
60
|
+
|
|
61
|
+
def test_webhook_with_workflow(
|
|
62
|
+
self,
|
|
63
|
+
workflow_with_virtual_assistant,
|
|
64
|
+
default_llm,
|
|
65
|
+
webhook_integration,
|
|
66
|
+
webhook_utils,
|
|
67
|
+
workflow_utils,
|
|
68
|
+
):
|
|
69
|
+
"""Test webhook can be created with workflow and triggers workflow execution."""
|
|
70
|
+
webhook_id = get_random_name()
|
|
71
|
+
message = f"Test message for {webhook_id}"
|
|
72
|
+
|
|
73
|
+
# Create a simple workflow
|
|
74
|
+
workflow = workflow_with_virtual_assistant(webhook_id)
|
|
75
|
+
|
|
76
|
+
# Create webhook integration
|
|
77
|
+
webhook_integration(webhook_id, "workflow", workflow.id)
|
|
78
|
+
|
|
79
|
+
# Trigger webhook
|
|
80
|
+
response = webhook_utils.trigger_webhook(webhook_id, data=message)
|
|
81
|
+
assert_that(response.status_code, equal_to(200))
|
|
82
|
+
assert_that(
|
|
83
|
+
response.json()["message"], equal_to("Webhook invoked successfully")
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
# Verify workflow execution was created
|
|
87
|
+
executions = workflow_utils.get_executions(workflow)
|
|
88
|
+
assert_that(
|
|
89
|
+
executions,
|
|
90
|
+
has_length(greater_than(0)),
|
|
91
|
+
"Workflow execution should be created",
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
# Verify execution details
|
|
95
|
+
execution = executions[0]
|
|
96
|
+
|
|
97
|
+
assert_that(execution.prompt.strip('""'), equal_to(message))
|
|
98
|
+
assert_that(execution.workflow_id, equal_to(workflow.id))
|
|
99
|
+
assert_that(execution.status, equal_to(ExecutionStatus.IN_PROGRESS))
|
|
100
|
+
|
|
101
|
+
@pytest.mark.parametrize(
|
|
102
|
+
"datasource_fixture",
|
|
103
|
+
[
|
|
104
|
+
"jira_datasource",
|
|
105
|
+
"confluence_datasource",
|
|
106
|
+
"code_datasource",
|
|
107
|
+
],
|
|
108
|
+
)
|
|
109
|
+
def test_webhook_with_datasource(
|
|
110
|
+
self,
|
|
111
|
+
request,
|
|
112
|
+
datasource_fixture,
|
|
113
|
+
webhook_integration,
|
|
114
|
+
webhook_utils,
|
|
115
|
+
datasource_utils,
|
|
116
|
+
):
|
|
117
|
+
"""Test webhook can be created with datasource and triggers successfully.
|
|
118
|
+
|
|
119
|
+
This test verifies webhook works with datasource as the resource type.
|
|
120
|
+
After triggering the webhook, it verifies that datasource indexing is in progress.
|
|
121
|
+
|
|
122
|
+
Test is parametrized to work with different datasource types:
|
|
123
|
+
- jira_datasource
|
|
124
|
+
- confluence_datasource
|
|
125
|
+
- code_datasource
|
|
126
|
+
"""
|
|
127
|
+
|
|
128
|
+
# Get the datasource from the fixture
|
|
129
|
+
datasource = request.getfixturevalue(datasource_fixture)
|
|
130
|
+
|
|
131
|
+
# Create webhook integration with datasource
|
|
132
|
+
webhook_id = get_random_name()
|
|
133
|
+
webhook_integration(webhook_id, "datasource", datasource.id)
|
|
134
|
+
|
|
135
|
+
# Trigger webhook
|
|
136
|
+
response = webhook_utils.trigger_webhook(webhook_id)
|
|
137
|
+
assert_that(response.status_code, equal_to(200))
|
|
138
|
+
assert_that(
|
|
139
|
+
response.json()["message"], equal_to("Webhook invoked successfully")
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
# Verify datasource exists and check its status (indexing should be in progress)
|
|
143
|
+
triggered_datasource = datasource_utils.get_datasource(datasource.id)
|
|
144
|
+
|
|
145
|
+
assert_that(triggered_datasource.id, equal_to(datasource.id))
|
|
146
|
+
assert_that(triggered_datasource.name, equal_to(datasource.name))
|
|
147
|
+
assert_that(triggered_datasource.status, DataSourceStatus.FETCHING)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
@pytest.mark.webhook
|
|
151
|
+
@pytest.mark.api
|
|
152
|
+
class TestWebhookErrorHandling:
|
|
153
|
+
"""Tests for webhook error handling - invalid IDs and disabled webhooks."""
|
|
154
|
+
|
|
155
|
+
def test_webhook_trigger_with_invalid_id(self, webhook_utils):
|
|
156
|
+
"""Test that triggering webhook with invalid ID returns error."""
|
|
157
|
+
invalid_webhook_id = "non_existent_webhook_" + get_random_name()
|
|
158
|
+
|
|
159
|
+
response = webhook_utils.trigger_webhook(invalid_webhook_id)
|
|
160
|
+
|
|
161
|
+
# Should return error status code
|
|
162
|
+
assert_that(response.status_code, equal_to(500))
|
|
163
|
+
assert_that(response.json()["detail"], equal_to("Webhook processing failed"))
|
|
164
|
+
|
|
165
|
+
def test_webhook_trigger_with_disabled_webhook(
|
|
166
|
+
self, assistant, webhook_integration, webhook_utils, conversation_utils
|
|
167
|
+
):
|
|
168
|
+
"""Test that disabled webhook cannot be triggered."""
|
|
169
|
+
assistant = assistant()
|
|
170
|
+
webhook_id = get_random_name()
|
|
171
|
+
message = f"Test message for {webhook_id}"
|
|
172
|
+
|
|
173
|
+
# Create webhook in disabled state
|
|
174
|
+
webhook_integration(webhook_id, "assistant", assistant.id, is_enabled=False)
|
|
175
|
+
|
|
176
|
+
# Try to trigger disabled webhook
|
|
177
|
+
response = webhook_utils.trigger_webhook(webhook_id, data=message)
|
|
178
|
+
|
|
179
|
+
# Should return error status code (not 200) for disabled webhook
|
|
180
|
+
assert_that(response.status_code, equal_to(500))
|
|
181
|
+
assert_that(response.json()["detail"], equal_to("Webhook processing failed"))
|
|
182
|
+
|
|
183
|
+
conversations = conversation_utils.get_conversation_by_assistant_id(
|
|
184
|
+
assistant.id
|
|
185
|
+
)
|
|
186
|
+
assert_that(len(conversations), equal_to(0))
|
|
187
|
+
|
|
188
|
+
def test_webhook_invalid_resource_id(self, webhook_integration, webhook_utils):
|
|
189
|
+
"""Test webhook with invalid resource ID."""
|
|
190
|
+
webhook_id = get_random_name()
|
|
191
|
+
message = f"Test message for {webhook_id}"
|
|
192
|
+
invalid_resource_id = "invalid_resource_" + get_random_name()
|
|
193
|
+
|
|
194
|
+
# Create webhook with invalid resource ID
|
|
195
|
+
webhook_integration(webhook_id, "assistant", invalid_resource_id)
|
|
196
|
+
|
|
197
|
+
# Trigger webhook - should handle gracefully
|
|
198
|
+
response = webhook_utils.trigger_webhook(webhook_id, data=message)
|
|
199
|
+
|
|
200
|
+
assert_that(response.status_code, equal_to(500))
|
|
201
|
+
assert_that(response.json()["detail"], equal_to("Webhook processing failed"))
|
|
202
|
+
|
|
203
|
+
def test_webhook_with_file_datasource(
|
|
204
|
+
self,
|
|
205
|
+
request,
|
|
206
|
+
file_datasource,
|
|
207
|
+
webhook_integration,
|
|
208
|
+
webhook_utils,
|
|
209
|
+
datasource_utils,
|
|
210
|
+
):
|
|
211
|
+
"""Test webhook with unsupported datasource type."""
|
|
212
|
+
|
|
213
|
+
# Create webhook integration with datasource
|
|
214
|
+
webhook_id = get_random_name()
|
|
215
|
+
webhook_integration(webhook_id, "datasource", file_datasource.id)
|
|
216
|
+
|
|
217
|
+
# Trigger webhook
|
|
218
|
+
response = webhook_utils.trigger_webhook(webhook_id)
|
|
219
|
+
assert_that(response.status_code, equal_to(403))
|
|
220
|
+
assert_that(
|
|
221
|
+
response.json()["detail"],
|
|
222
|
+
equal_to(
|
|
223
|
+
"Datasource type 'knowledge_base_file' is not supported via webhook."
|
|
224
|
+
),
|
|
225
|
+
)
|