()
| 316 | |
| 317 | |
| 318 | def run_tests() -> bool: |
| 319 | current_dir = Path(__file__).resolve().parent |
| 320 | project_root = current_dir.parent |
| 321 | backend_source = project_root / "backend" |
| 322 | sdk_source = project_root / "sdk" |
| 323 | |
| 324 | os.chdir(project_root) |
| 325 | check_required_packages() |
| 326 | |
| 327 | test_files = _collect_test_files(project_root) |
| 328 | if not test_files: |
| 329 | logger.error("No test files found") |
| 330 | return False |
| 331 | |
| 332 | for coverage_artifact in [current_dir / ".coverage", *current_dir.glob(".coverage.*")]: |
| 333 | if coverage_artifact.exists(): |
| 334 | coverage_artifact.unlink() |
| 335 | coverage_xml = current_dir / "coverage.xml" |
| 336 | if coverage_xml.exists(): |
| 337 | coverage_xml.unlink() |
| 338 | |
| 339 | workers = _worker_count(len(test_files)) |
| 340 | timeout_seconds = _file_timeout_seconds() |
| 341 | logger.info("Found %s test files", len(test_files)) |
| 342 | logger.info("Running with %s file worker(s)", workers) |
| 343 | if timeout_seconds: |
| 344 | logger.info("Per-file timeout: %s seconds", timeout_seconds) |
| 345 | |
| 346 | results: list[dict] = [] |
| 347 | with ThreadPoolExecutor(max_workers=workers) as executor: |
| 348 | futures = [ |
| 349 | executor.submit( |
| 350 | _run_test_file, |
| 351 | index=index, |
| 352 | test_file=test_file, |
| 353 | project_root=project_root, |
| 354 | backend_source=backend_source, |
| 355 | sdk_source=sdk_source, |
| 356 | coverage_dir=current_dir, |
| 357 | timeout_seconds=timeout_seconds, |
| 358 | ) |
| 359 | for index, test_file in enumerate(test_files) |
| 360 | ] |
| 361 | for future in as_completed(futures): |
| 362 | result = future.result() |
| 363 | results.append(result) |
| 364 | _print_file_result(result) |
| 365 | |
| 366 | _print_test_summary(results) |
| 367 | failed = [result for result in results if result["returncode"] != 0] |
| 368 | if failed: |
| 369 | logger.error("\nFailed test files: %s", len(failed)) |
| 370 | for result in failed[:10]: |
| 371 | logger.error("\n%s\n%s\n%s", result["file"], result["stdout"][-4000:], result["stderr"][-2000:]) |
| 372 | generate_error_report(results) |
| 373 | |
| 374 | coverage_ok = _combine_coverage(current_dir, project_root) |
| 375 | if coverage_ok: |
no test coverage detected