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

@@ -16,6 +16,7 @@ from .constants import (
16
16
  KEY_XDIST_N,
17
17
  KEY_RERUNS,
18
18
  KEY_COUNT,
19
+ KEY_TIMEOUT,
19
20
  KEY_AUTH_SERVER_URL,
20
21
  KEY_AUTH_CLIENT_ID,
21
22
  KEY_AUTH_CLIENT_SECRET,
@@ -26,6 +27,7 @@ from .constants import (
26
27
  DEFAULT_MARKS,
27
28
  DEFAULT_XDIST_N,
28
29
  DEFAULT_RERUNS,
30
+ DEFAULT_TIMEOUT,
29
31
  )
30
32
  from .utils import get_config_value, ensure_env_from_config
31
33
  from .runner import run_pytest
@@ -54,6 +56,12 @@ from .commands.marks_cmd import marks_cmd
54
56
  type=int,
55
57
  help="Number of times to repeat each test (requires pytest-repeat)",
56
58
  )
59
+ @click.option(
60
+ "--timeout",
61
+ envvar=KEY_TIMEOUT,
62
+ type=int,
63
+ help="Per-test timeout in seconds (default: 300)",
64
+ )
57
65
  @click.option("--auth-server-url", envvar=KEY_AUTH_SERVER_URL, help="Auth server url")
58
66
  @click.option("--auth-client-id", envvar=KEY_AUTH_CLIENT_ID, help="Auth client id")
59
67
  @click.option(
@@ -73,6 +81,7 @@ def cli(
73
81
  workers: Optional[int],
74
82
  reruns: Optional[int],
75
83
  count: Optional[int],
84
+ timeout: Optional[int],
76
85
  auth_server_url: Optional[str],
77
86
  auth_client_id: Optional[str],
78
87
  auth_client_secret: Optional[str],
@@ -109,6 +118,11 @@ def cli(
109
118
  if count is not None
110
119
  else (int(get_config_value(KEY_COUNT)) if get_config_value(KEY_COUNT) else None)
111
120
  )
121
+ resolved_timeout = (
122
+ timeout
123
+ if timeout is not None
124
+ else int(get_config_value(KEY_TIMEOUT, str(DEFAULT_TIMEOUT)))
125
+ )
112
126
 
113
127
  # Ensure env vars. CLI args override env/config.
114
128
  provided = {
@@ -133,12 +147,19 @@ def cli(
133
147
  workers=resolved_workers,
134
148
  reruns=resolved_reruns,
135
149
  count=resolved_count,
150
+ timeout=resolved_timeout,
136
151
  )
137
152
  )
138
153
 
139
154
  # default behavior
140
155
  if ctx.invoked_subcommand is None and not ctx.resilient_parsing:
141
- run_pytest(resolved_workers, resolved_marks, resolved_reruns, resolved_count)
156
+ run_pytest(
157
+ resolved_workers,
158
+ resolved_marks,
159
+ resolved_reruns,
160
+ resolved_count,
161
+ resolved_timeout,
162
+ )
142
163
 
143
164
 
144
165
  # Register subcommands
@@ -5,9 +5,9 @@ from typing import Dict, List
5
5
  from ..constants import (
6
6
  CONSOLE,
7
7
  CREDENTIAL_CATEGORIES,
8
- INTEGRATION_KEYS,
9
8
  mask_sensitive_value,
10
9
  is_sensitive_key,
10
+ INTEGRATION_KEYS,
11
11
  )
12
12
  from ..utils import (
13
13
  load_config,
@@ -15,6 +15,11 @@ from ..runner import run_pytest
15
15
  type=int,
16
16
  help="Number of times to repeat each test (requires pytest-repeat)",
17
17
  )
18
+ @click.option(
19
+ "--timeout",
20
+ type=int,
21
+ help="Per-test timeout in seconds (overrides config/default)",
22
+ )
18
23
  @click.argument("extra", nargs=-1)
19
24
  @click.pass_context
20
25
  def run_cmd(
@@ -23,22 +28,26 @@ def run_cmd(
23
28
  workers: Optional[int],
24
29
  reruns: Optional[int],
25
30
  count: Optional[int],
31
+ timeout: Optional[int],
26
32
  extra: Tuple[str, ...],
27
33
  ):
28
34
  """Run pytest with configured options.
29
35
 
30
36
  Example: codemie-test-harness run --marks "smoke and not ui" -n 8 --reruns 2 -k keyword
31
37
  Example with repeat: codemie-test-harness run --marks excel_generation --count 50 -n 10
38
+ Example with timeout: codemie-test-harness run --marks slow --timeout 600 -n 4
32
39
  """
33
40
  resolved_marks = marks or ctx.obj.get("marks")
34
41
  resolved_workers = workers if workers is not None else ctx.obj.get("workers")
35
42
  resolved_reruns = reruns if reruns is not None else ctx.obj.get("reruns")
36
43
  resolved_count = count if count is not None else ctx.obj.get("count")
44
+ resolved_timeout = timeout if timeout is not None else ctx.obj.get("timeout")
37
45
 
38
46
  run_pytest(
39
47
  int(resolved_workers),
40
48
  str(resolved_marks),
41
49
  int(resolved_reruns),
42
50
  resolved_count,
51
+ resolved_timeout,
43
52
  extra,
44
53
  )
@@ -147,6 +147,16 @@ DEFAULT_MARKS = "smoke"
147
147
  DEFAULT_XDIST_N = 8
148
148
  DEFAULT_RERUNS = 2
149
149
 
150
+ AUTH_KEYS = [
151
+ KEY_AUTH_SERVER_URL,
152
+ KEY_AUTH_CLIENT_ID,
153
+ KEY_AUTH_CLIENT_SECRET,
154
+ KEY_AUTH_USERNAME,
155
+ KEY_AUTH_PASSWORD,
156
+ KEY_AUTH_REALM_NAME,
157
+ KEY_CODEMIE_API_DOMAIN,
158
+ ]
159
+
150
160
  # === CREDENTIAL CATEGORIES ===
151
161
  VERSION_CONTROL_KEYS = [
152
162
  KEY_GIT_ENV,
@@ -274,6 +284,17 @@ DATA_MANAGEMENT_KEYS = [
274
284
  KEY_MSSQL_PASSWORD,
275
285
  ]
276
286
 
287
+ # Combined lists for backwards compatibility
288
+ INTEGRATION_KEYS = (
289
+ VERSION_CONTROL_KEYS
290
+ + PROJECT_MANAGEMENT_KEYS
291
+ + CLOUD_PROVIDERS_KEYS
292
+ + DEVELOPMENT_TOOLS_KEYS
293
+ + NOTIFICATIONS_KEYS
294
+ + RESEARCH_TOOLS_KEYS
295
+ + DATA_MANAGEMENT_KEYS
296
+ )
297
+
277
298
  # Category mapping for CLI
278
299
  CREDENTIAL_CATEGORIES = {
279
300
  "version-control": {
@@ -53,6 +53,7 @@ def build_pytest_cmd(
53
53
  marks: str,
54
54
  reruns: int,
55
55
  count: int | None = None,
56
+ timeout: int | None = None,
56
57
  extra: Iterable[str] | None = None,
57
58
  ) -> tuple[List[str], str]:
58
59
  tests_path, root_dir = resolve_tests_path_and_root()
@@ -65,6 +66,8 @@ def build_pytest_cmd(
65
66
  cmd += ["--reruns", str(reruns)]
66
67
  if count and int(count) > 0:
67
68
  cmd += ["--count", str(count)]
69
+ if timeout and int(timeout) > 0:
70
+ cmd += ["--timeout", str(timeout)]
68
71
  if extra:
69
72
  cmd += list(extra)
70
73
  return cmd, root_dir
@@ -107,11 +110,12 @@ def run_pytest(
107
110
  marks: str,
108
111
  reruns: int,
109
112
  count: int | None = None,
113
+ timeout: int | None = None,
110
114
  extra: Iterable[str] | None = None,
111
115
  ) -> None:
112
116
  # Validate marks before running pytest
113
117
  validate_marks_expression(marks)
114
118
 
115
- cmd, root_dir = build_pytest_cmd(workers, marks, reruns, count, extra)
119
+ cmd, root_dir = build_pytest_cmd(workers, marks, reruns, count, timeout, extra)
116
120
  CONSOLE.print(f"[cyan]Running:[/] {' '.join(cmd)} (cwd={root_dir})")
117
121
  raise SystemExit(subprocess.call(cmd, cwd=root_dir))
@@ -1,5 +1,8 @@
1
1
  [pytest]
2
2
  addopts = -v
3
+ timeout = 300
4
+ timeout_method = signal
5
+ timeout_func_only = true
3
6
  filterwarnings =
4
7
  ignore::pytest.PytestUnknownMarkWarning
5
8
  ignore::urllib3.exceptions.InsecureRequestWarning
@@ -25,6 +25,7 @@ from codemie_sdk.models.integration import (
25
25
  from codemie_sdk.models.workflow import WorkflowCreateRequest, WorkflowMode, Workflow
26
26
 
27
27
  from codemie_test_harness.tests import PROJECT, autotest_entity_prefix
28
+ from codemie_test_harness.tests.test_data.file_test_data import file_test_data
28
29
  from codemie_test_harness.tests.test_data.google_datasource_test_data import (
29
30
  GOOGLE_DOC_URL,
30
31
  )
@@ -32,7 +33,7 @@ from codemie_test_harness.tests.utils.assistant_utils import AssistantUtils
32
33
  from codemie_test_harness.tests.utils.credentials_manager import CredentialsManager
33
34
  from codemie_test_harness.tests.utils.base_utils import get_random_name, wait_for_entity
34
35
  from codemie_test_harness.tests.utils.client_factory import get_client
35
- from codemie_test_harness.tests.utils.constants import TESTS_PATH
36
+ from codemie_test_harness.tests.utils.constants import TESTS_PATH, FILES_PATH
36
37
  from codemie_test_harness.tests.utils.conversation_utils import ConversationUtils
37
38
  from codemie_test_harness.tests.utils.datasource_utils import DataSourceUtils
38
39
  from codemie_test_harness.tests.utils.gitbud_utils import GitBudUtils
@@ -458,6 +459,21 @@ def code_datasource(
458
459
  datasource_utils.delete_datasource(datasource)
459
460
 
460
461
 
462
+ @pytest.fixture(scope="session")
463
+ def file_datasource(datasource_utils, default_embedding_llm):
464
+ file_name = file_test_data[2][0]
465
+
466
+ datasource = datasource_utils.create_file_datasource(
467
+ name=get_random_name(),
468
+ description=f"[Autotest] {file_name} with {default_embedding_llm.base_name} embedding model",
469
+ files=[str(FILES_PATH / file_name)],
470
+ embeddings_model=default_embedding_llm.base_name,
471
+ )
472
+ yield datasource
473
+ if datasource:
474
+ datasource_utils.delete_datasource(datasource)
475
+
476
+
461
477
  @pytest.fixture(scope="session")
462
478
  def gitlab_datasource(datasource_utils, gitlab_integration, default_embedding_llm):
463
479
  datasource = datasource_utils.create_gitlab_datasource(
@@ -37,6 +37,7 @@ from codemie_test_harness.tests.test_data.pm_tools_test_data import (
37
37
  from codemie_test_harness.tests.test_data.report_portal_tools_test_data import (
38
38
  rp_test_data,
39
39
  )
40
+ from codemie_test_harness.tests.utils.base_utils import assert_tool_triggered
40
41
  from codemie_test_harness.tests.utils.credentials_manager import CredentialsManager
41
42
  from codemie_test_harness.tests.utils.constants import test_project_name
42
43
 
@@ -80,7 +81,11 @@ def test_assistant_with_default_integration_cloud(
80
81
  # create an assistant
81
82
  cloud_assistant = assistant(toolkit, tool_name, project_name=test_project_name)
82
83
 
83
- response = assistant_utils.ask_assistant(cloud_assistant, prompt)
84
+ response, triggered_tools = assistant_utils.ask_assistant(
85
+ cloud_assistant, prompt, minimal_response=False
86
+ )
87
+
88
+ assert_tool_triggered(tool_name, triggered_tools)
84
89
 
85
90
  similarity_check.check_similarity(response, expected_response)
86
91
 
@@ -119,7 +124,11 @@ def test_assistant_with_default_integration_ado(
119
124
  # create an assistant
120
125
  ado_assistant = assistant(toolkit, tool_name, project_name=test_project_name)
121
126
 
122
- response = assistant_utils.ask_assistant(ado_assistant, prompt)
127
+ response, triggered_tools = assistant_utils.ask_assistant(
128
+ ado_assistant, prompt, minimal_response=False
129
+ )
130
+
131
+ assert_tool_triggered(tool_name, triggered_tools)
123
132
 
124
133
  similarity_check.check_similarity(response, expected_response)
125
134
 
@@ -163,7 +172,11 @@ def test_assistant_with_default_integration_codebase(
163
172
  toolkit, CodeBaseTool.SONAR, project_name=test_project_name
164
173
  )
165
174
 
166
- response = assistant_utils.ask_assistant(sonar_assistant, prompt)
175
+ response, triggered_tools = assistant_utils.ask_assistant(
176
+ sonar_assistant, prompt, minimal_response=False
177
+ )
178
+
179
+ assert_tool_triggered(CodeBaseTool.SONAR, triggered_tools)
167
180
 
168
181
  similarity_check.check_similarity(response, expected_response)
169
182
 
@@ -216,7 +229,11 @@ def test_assistant_with_default_integration_git(
216
229
  project_name=test_project_name,
217
230
  )
218
231
 
219
- response = assistant_utils.ask_assistant(git_assistant, prompt)
232
+ response, triggered_tools = assistant_utils.ask_assistant(
233
+ git_assistant, prompt, minimal_response=False
234
+ )
235
+
236
+ assert_tool_triggered(tool_name, triggered_tools)
220
237
 
221
238
  similarity_check.check_similarity(response, expected_response)
222
239
 
@@ -255,7 +272,11 @@ def test_assistant_with_default_integration_jira(
255
272
  project_name=test_project_name,
256
273
  )
257
274
 
258
- response = assistant_utils.ask_assistant(jira_assistant, JIRA_TOOL_PROMPT)
275
+ response, triggered_tools = assistant_utils.ask_assistant(
276
+ jira_assistant, JIRA_TOOL_PROMPT, minimal_response=False
277
+ )
278
+
279
+ assert_tool_triggered(ProjectManagementTool.JIRA, triggered_tools)
259
280
 
260
281
  similarity_check.check_similarity(response, RESPONSE_FOR_JIRA_TOOL)
261
282
 
@@ -292,7 +313,11 @@ def test_assistant_with_default_integration_email(
292
313
  Toolkit.NOTIFICATION, NotificationTool.EMAIL, project_name=test_project_name
293
314
  )
294
315
 
295
- response = assistant_utils.ask_assistant(email_assistant, EMAIL_TOOL_PROMPT)
316
+ response, triggered_tools = assistant_utils.ask_assistant(
317
+ email_assistant, EMAIL_TOOL_PROMPT, minimal_response=False
318
+ )
319
+
320
+ assert_tool_triggered(NotificationTool.EMAIL, triggered_tools)
296
321
 
297
322
  similarity_check.check_similarity(response, EMAIL_RESPONSE)
298
323
 
@@ -329,7 +354,11 @@ def test_assistant_with_default_integration_keycloak(
329
354
  project_name=test_project_name,
330
355
  )
331
356
 
332
- response = assistant_utils.ask_assistant(keycloak_assistant, KEYCLOAK_TOOL_PROMPT)
357
+ response, triggered_tools = assistant_utils.ask_assistant(
358
+ keycloak_assistant, KEYCLOAK_TOOL_PROMPT, minimal_response=False
359
+ )
360
+
361
+ assert_tool_triggered(AccessManagementTool.KEYCLOAK, triggered_tools)
333
362
 
334
363
  similarity_check.check_similarity(response, KEYCLOAK_TOOL_RESPONSE)
335
364
 
@@ -369,6 +398,10 @@ def test_assistant_with_default_integration_report_portal(
369
398
  project_name=test_project_name,
370
399
  )
371
400
 
372
- response = assistant_utils.ask_assistant(report_portal_assistant, prompt)
401
+ response, triggered_tools = assistant_utils.ask_assistant(
402
+ report_portal_assistant, prompt, minimal_response=False
403
+ )
404
+
405
+ assert_tool_triggered(ReportPortalTool.GET_DASHBOARD_DATA, triggered_tools)
373
406
 
374
407
  similarity_check.check_similarity(response, expected_response)
@@ -3,11 +3,8 @@ from codemie_sdk.models.assistant import ToolKitDetails, ToolDetails
3
3
  from hamcrest import assert_that, has_item
4
4
  from codemie_test_harness.tests.enums.model_types import ModelTypes
5
5
  from codemie_test_harness.tests.enums.tools import Toolkit, FileManagementTool
6
- from codemie_test_harness.tests.test_data.file_test_data import file_test_data
7
6
  from codemie_test_harness.tests.test_data.llm_test_data import MODEL_RESPONSES
8
- from codemie_test_harness.tests.utils.base_utils import get_random_name
9
7
  from codemie_test_harness.tests.utils.client_factory import get_client
10
- from codemie_test_harness.tests.utils.constants import FILES_PATH
11
8
  from codemie_test_harness.tests.utils.env_resolver import get_environment
12
9
  from codemie_test_harness.tests.utils.pytest_utils import check_mark
13
10
 
@@ -121,6 +118,7 @@ def test_assistant_with_different_models_with_datasource_attached(
121
118
  datasource_utils,
122
119
  default_embedding_llm,
123
120
  kb_context,
121
+ file_datasource,
124
122
  ):
125
123
  assert_that(
126
124
  [row.base_name for row in llm_utils.list_llm_models()],
@@ -128,17 +126,8 @@ def test_assistant_with_different_models_with_datasource_attached(
128
126
  f"{model_type} is missing in backend response",
129
127
  )
130
128
 
131
- file_name = file_test_data[2][0]
132
-
133
- datasource = datasource_utils.create_file_datasource(
134
- name=get_random_name(),
135
- description=f"[Autotest] {file_name} with {default_embedding_llm.base_name} embedding model",
136
- files=[str(FILES_PATH / file_name)],
137
- embeddings_model=default_embedding_llm.base_name,
138
- )
139
-
140
129
  assistant = assistant_utils.create_assistant(
141
- model_type, context=[kb_context(datasource)]
130
+ model_type, context=[kb_context(file_datasource)]
142
131
  )
143
132
  response = assistant_utils.ask_assistant(assistant, "Just say one word: 'Hello'")
144
133