codemie-test-harness 0.1.135__py3-none-any.whl → 0.1.137__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/__init__.py +1 -0
- codemie_test_harness/tests/conftest.py +17 -0
- codemie_test_harness/tests/service/test_assistant_service.py +349 -379
- codemie_test_harness/tests/service/test_datasource_service.py +276 -292
- codemie_test_harness/tests/service/test_integration_service.py +133 -122
- codemie_test_harness/tests/service/test_llm_service.py +16 -17
- codemie_test_harness/tests/service/test_task_service.py +108 -120
- codemie_test_harness/tests/service/test_user_service.py +36 -19
- codemie_test_harness/tests/service/test_workflow_execution_service.py +142 -169
- codemie_test_harness/tests/service/test_workflow_service.py +145 -144
- codemie_test_harness/tests/utils/assistant_utils.py +39 -4
- codemie_test_harness/tests/utils/llm_utils.py +9 -0
- codemie_test_harness/tests/utils/search_utils.py +11 -5
- codemie_test_harness/tests/utils/user_utils.py +9 -0
- codemie_test_harness/tests/utils/workflow_utils.py +34 -6
- {codemie_test_harness-0.1.135.dist-info → codemie_test_harness-0.1.137.dist-info}/METADATA +2 -2
- {codemie_test_harness-0.1.135.dist-info → codemie_test_harness-0.1.137.dist-info}/RECORD +19 -17
- {codemie_test_harness-0.1.135.dist-info → codemie_test_harness-0.1.137.dist-info}/WHEEL +0 -0
- {codemie_test_harness-0.1.135.dist-info → codemie_test_harness-0.1.137.dist-info}/entry_points.txt +0 -0
|
@@ -1,24 +1,41 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
from codemie_sdk import CodeMieClient
|
|
1
|
+
import os
|
|
4
2
|
from codemie_sdk.models.user import User, UserData
|
|
3
|
+
from hamcrest import (
|
|
4
|
+
assert_that,
|
|
5
|
+
instance_of,
|
|
6
|
+
is_not,
|
|
7
|
+
all_of,
|
|
8
|
+
has_property,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def test_about_me(user_utils):
|
|
13
|
+
user = user_utils.get_about_me()
|
|
5
14
|
|
|
15
|
+
assert_that(
|
|
16
|
+
user,
|
|
17
|
+
all_of(
|
|
18
|
+
instance_of(User),
|
|
19
|
+
has_property("user_id", is_not(None)),
|
|
20
|
+
has_property("name", os.getenv("AUTH_USERNAME")),
|
|
21
|
+
has_property("username", os.getenv("AUTH_USERNAME")),
|
|
22
|
+
has_property("is_admin", is_not(None)),
|
|
23
|
+
has_property("applications", instance_of(list)),
|
|
24
|
+
has_property("applications_admin", instance_of(list)),
|
|
25
|
+
has_property("knowledge_bases", instance_of(list)),
|
|
26
|
+
),
|
|
27
|
+
"User profile should have all required properties with correct types",
|
|
28
|
+
)
|
|
6
29
|
|
|
7
|
-
def test_about_me(client: CodeMieClient):
|
|
8
|
-
"""Test successful retrieval of user profile."""
|
|
9
|
-
user = client.users.about_me()
|
|
10
|
-
assert isinstance(user, User)
|
|
11
|
-
assert user.user_id is not None
|
|
12
|
-
assert user.name is not None
|
|
13
|
-
assert user.username is not None
|
|
14
|
-
assert isinstance(user.is_admin, bool)
|
|
15
|
-
assert isinstance(user.applications, list)
|
|
16
|
-
assert isinstance(user.applications_admin, list)
|
|
17
|
-
assert isinstance(user.knowledge_bases, list)
|
|
18
30
|
|
|
31
|
+
def test_get_user_data(user_utils):
|
|
32
|
+
user_data = user_utils.get_user_data()
|
|
19
33
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
34
|
+
assert_that(
|
|
35
|
+
user_data,
|
|
36
|
+
all_of(
|
|
37
|
+
instance_of(UserData),
|
|
38
|
+
has_property("user_id", is_not(None)),
|
|
39
|
+
),
|
|
40
|
+
"User data should be valid UserData instance with user_id",
|
|
41
|
+
)
|
|
@@ -1,183 +1,156 @@
|
|
|
1
|
-
"""Integration tests for WorkflowExecutionService."""
|
|
2
|
-
|
|
3
1
|
from time import sleep
|
|
4
2
|
|
|
5
3
|
import pytest
|
|
6
|
-
import
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
4
|
+
from hamcrest import (
|
|
5
|
+
assert_that,
|
|
6
|
+
equal_to,
|
|
7
|
+
has_length,
|
|
8
|
+
contains_string,
|
|
9
|
+
all_of,
|
|
10
|
+
less_than_or_equal_to,
|
|
11
|
+
has_property,
|
|
12
|
+
is_not,
|
|
13
13
|
)
|
|
14
|
+
|
|
15
|
+
from codemie_sdk.models.workflow import ExecutionStatus, WorkflowMode
|
|
14
16
|
from codemie_test_harness.tests import PROJECT
|
|
15
17
|
from codemie_test_harness.tests.utils.base_utils import get_random_name
|
|
16
18
|
|
|
19
|
+
from codemie_test_harness.tests.utils.yaml_utils import (
|
|
20
|
+
AssistantModel,
|
|
21
|
+
StateModel,
|
|
22
|
+
WorkflowYamlModel,
|
|
23
|
+
prepare_yaml_content,
|
|
24
|
+
)
|
|
17
25
|
|
|
18
|
-
@pytest.fixture
|
|
19
|
-
def valid_workflow_yaml(default_llm) -> str:
|
|
20
|
-
"""Return a valid workflow YAML configuration for testing."""
|
|
21
|
-
return f"""
|
|
22
|
-
assistants:
|
|
23
|
-
- id: asst
|
|
24
|
-
name: Simple assistant
|
|
25
|
-
model: {default_llm.base_name}
|
|
26
|
-
system_prompt: |
|
|
27
|
-
You are simple chatbot.
|
|
28
|
-
Generate a simple response.
|
|
29
|
-
|
|
30
|
-
states:
|
|
31
|
-
- id: simple
|
|
32
|
-
assistant_id: asst
|
|
33
|
-
task: |
|
|
34
|
-
Say "Hello, World!"
|
|
35
|
-
next:
|
|
36
|
-
state_id: end
|
|
37
|
-
"""
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
@pytest.fixture
|
|
41
|
-
def test_workflow(client: CodeMieClient, valid_workflow_yaml: str):
|
|
42
|
-
"""Create a test workflow and clean it up after the test."""
|
|
43
|
-
workflow_name = get_random_name()
|
|
44
|
-
workflow_id = None
|
|
45
|
-
|
|
46
|
-
try:
|
|
47
|
-
# Create workflow
|
|
48
|
-
create_request = WorkflowCreateRequest(
|
|
49
|
-
name=workflow_name,
|
|
50
|
-
description="Test workflow for executions",
|
|
51
|
-
project=PROJECT,
|
|
52
|
-
yaml_config=valid_workflow_yaml,
|
|
53
|
-
mode=WorkflowMode.SEQUENTIAL,
|
|
54
|
-
shared=False,
|
|
55
|
-
)
|
|
56
26
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
f"Workflow execution did not complete within {attempts * 2} seconds"
|
|
27
|
+
@pytest.fixture(scope="session")
|
|
28
|
+
def test_workflow(default_llm, search_utils, workflow_utils):
|
|
29
|
+
assistant_and_state_name = get_random_name()
|
|
30
|
+
|
|
31
|
+
assistant = AssistantModel(
|
|
32
|
+
id=assistant_and_state_name,
|
|
33
|
+
model=default_llm.base_name,
|
|
34
|
+
system_prompt="You are simple chatbot. Generate a simple response.",
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
state = StateModel(
|
|
38
|
+
id=assistant_and_state_name,
|
|
39
|
+
assistant_id=assistant_and_state_name,
|
|
40
|
+
task='Say "Hello, World!"',
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
workflow_yaml = WorkflowYamlModel(
|
|
44
|
+
enable_summarization_node=True,
|
|
45
|
+
assistants=[assistant],
|
|
46
|
+
states=[state],
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
yaml_content = prepare_yaml_content(workflow_yaml.model_dump(exclude_none=True))
|
|
50
|
+
created = workflow_utils.create_workflow(
|
|
51
|
+
workflow_yaml=yaml_content,
|
|
52
|
+
workflow_type=WorkflowMode.SEQUENTIAL,
|
|
53
|
+
project_name=PROJECT,
|
|
54
|
+
description="Test workflow for executions",
|
|
55
|
+
)
|
|
56
|
+
assert_that(created, is_not(None))
|
|
57
|
+
|
|
58
|
+
workflows = search_utils.list_workflows(projects=PROJECT, per_page=10)
|
|
59
|
+
workflow = next((wf for wf in workflows if wf.name == created.name), None)
|
|
60
|
+
assert_that(workflow, is_not(None))
|
|
61
|
+
|
|
62
|
+
return workflow.id
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def test_run_workflow(workflow_utils, search_utils, test_workflow: str):
|
|
66
|
+
execution = workflow_utils.run_workflow(test_workflow, "Test")
|
|
67
|
+
|
|
68
|
+
assert_that(execution, is_not(None))
|
|
69
|
+
|
|
70
|
+
# Test listing all executions
|
|
71
|
+
executions = search_utils.list_workflow_executions(test_workflow_id=test_workflow)
|
|
72
|
+
assert_that(executions, has_length(equal_to(1)))
|
|
73
|
+
found_execution = executions[0]
|
|
74
|
+
execution_id = executions[0].execution_id
|
|
75
|
+
assert_that(
|
|
76
|
+
found_execution,
|
|
77
|
+
all_of(
|
|
78
|
+
has_property("workflow_id", equal_to(test_workflow)),
|
|
79
|
+
has_property("status", is_not(None)),
|
|
80
|
+
has_property("created_date", is_not(None)),
|
|
81
|
+
has_property("created_by", is_not(None)),
|
|
82
|
+
),
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
# Test pagination
|
|
86
|
+
paginated = search_utils.list_workflow_executions(
|
|
87
|
+
test_workflow_id=test_workflow,
|
|
88
|
+
page=0,
|
|
89
|
+
per_page=1,
|
|
90
|
+
)
|
|
91
|
+
assert_that(paginated, has_length(less_than_or_equal_to(1)))
|
|
92
|
+
|
|
93
|
+
max_attempts = 30 # 30 * 2 seconds = 60 seconds total wait time
|
|
94
|
+
attempts = 0
|
|
95
|
+
while attempts < max_attempts:
|
|
96
|
+
execution = workflow_utils.get_workflow_execution(
|
|
97
|
+
test_workflow_id=test_workflow, execution_id=execution_id
|
|
98
|
+
)
|
|
99
|
+
if execution.status == ExecutionStatus.SUCCEEDED:
|
|
100
|
+
# Only verify states and outputs on successful execution
|
|
101
|
+
# Verify execution states
|
|
102
|
+
states = workflow_utils.get_workflow_executions_states(
|
|
103
|
+
test_workflow, execution_id
|
|
104
|
+
).list()
|
|
105
|
+
assert_that(states, has_length(equal_to(2)))
|
|
106
|
+
|
|
107
|
+
first_state = states[0]
|
|
108
|
+
second_state = states[1]
|
|
109
|
+
assert_that(first_state.completed_at, is_not(None))
|
|
110
|
+
assert_that(second_state.completed_at, is_not(None))
|
|
111
|
+
assert_that(
|
|
112
|
+
first_state.completed_at,
|
|
113
|
+
less_than_or_equal_to(second_state.completed_at),
|
|
145
114
|
)
|
|
146
115
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
print(workflows)
|
|
170
|
-
assert len(workflows) == 0
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
def test_list_executions_invalid_parameters(client: CodeMieClient, test_workflow: str):
|
|
174
|
-
"""Test listing executions with invalid parameters."""
|
|
175
|
-
# Test invalid page number
|
|
116
|
+
# Verify the state outputs
|
|
117
|
+
for state in states:
|
|
118
|
+
state_output = workflow_utils.get_workflow_executions_states(
|
|
119
|
+
test_workflow, execution_id
|
|
120
|
+
).get_output(state.id)
|
|
121
|
+
# For our test workflow, the first state should contain "Hello, World!"
|
|
122
|
+
if state.id == "simple":
|
|
123
|
+
assert_that(state_output.output, contains_string("Hello, World!"))
|
|
124
|
+
break
|
|
125
|
+
elif execution.status == ExecutionStatus.FAILED:
|
|
126
|
+
pytest.fail(f"Workflow execution failed: {execution.error_message}")
|
|
127
|
+
|
|
128
|
+
sleep(2)
|
|
129
|
+
attempts += 1
|
|
130
|
+
else:
|
|
131
|
+
raise TimeoutError(
|
|
132
|
+
f"Workflow execution did not complete within {attempts * 2} seconds"
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
@pytest.mark.skip(reason="Bug: https://jiraeu.epam.com/browse/EPMCDME-7883")
|
|
137
|
+
def test_list_executions_nonexistent_workflow(search_utils):
|
|
176
138
|
with pytest.raises(Exception) as exc_info:
|
|
177
|
-
|
|
178
|
-
|
|
139
|
+
search_utils.list_workflow_executions("non-existent-id")
|
|
140
|
+
|
|
141
|
+
assert_that(
|
|
142
|
+
str(exc_info.value).lower(),
|
|
143
|
+
contains_string("No workflows found with id non-existent-id"),
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def test_list_executions_with_invalid_page_number(search_utils):
|
|
148
|
+
with pytest.raises(Exception) as exc_info:
|
|
149
|
+
search_utils.list_workflow_executions(test_workflow_id=None, page=-1)
|
|
150
|
+
assert_that(str(exc_info.value).lower(), contains_string("page"))
|
|
151
|
+
|
|
179
152
|
|
|
180
|
-
|
|
153
|
+
def test_list_executions_with_invalid_per_page_value(search_utils):
|
|
181
154
|
with pytest.raises(Exception) as exc_info:
|
|
182
|
-
|
|
183
|
-
|
|
155
|
+
search_utils.list_workflow_executions(test_workflow_id=None, per_page=0)
|
|
156
|
+
assert_that(str(exc_info.value).lower(), contains_string("per_page"))
|