Coverage for src / ocarina / opinionated / plugins / reports / results_to_json.py: 0.00%
35 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-06-04 15:56 +0200
« prev ^ index » next coverage.py v7.13.5, created at 2026-06-04 15:56 +0200
1"""Generate JSON test reports.
3Serializes test results into structured, machine-readable JSON files.
4Designed for integration with CI/CD pipelines, monitoring tools,
5or automated reporting systems.
7Output format:
8 {
9 "Campaign": {
10 "Suite": {
11 "test_case": [
12 {"status": "success" | "fail", "error"?: "..."},
13 counter,
14 metadata
15 ]
16 }
17 }
18 }
20Example:
21 >>> results_dir = Path(tempfile.mkdtemp(prefix=".json_results_", dir=Path.cwd()))
22 >>> generate_json_results(results, results_dir=results_dir, logger=logger)
23 # Creates: results_dir/abcd1234.json
25"""
27import json
28import uuid
29from typing import TYPE_CHECKING, Any
31from ocarina.railway.result import is_fail, is_ok
33if TYPE_CHECKING:
34 from pathlib import Path
36 from ocarina.custom_types.oc_test_layers import TestCycleResults
37 from ocarina.ports.ilogger import ILogger
40def _result_to_serializable(v: Any) -> dict[str, str]: # noqa: ANN401
41 if is_ok(v):
42 return {"status": "success"}
43 if is_fail(v):
44 return {"status": "fail", "error": str(v.error)}
46 msg = f"Expected Ok or Fail instances, but got: {type(v)}"
47 raise TypeError(msg)
50def generate_json_results(
51 *,
52 results: TestCycleResults,
53 output_dir: Path,
54 logger: ILogger,
55) -> None:
56 """Write test results to a JSON file in results_dir.
58 Args:
59 results: Hierarchical test results structure.
60 output_dir: Directory where the JSON file will be written.
61 logger: Logger for progress and error reporting.
63 Raises:
64 RuntimeError: If a unique filename cannot be generated.
66 """
67 output_dir.mkdir(parents=True, exist_ok=True)
69 max_stem_length = 8
70 max_attempts = 500
71 for _ in range(max_attempts):
72 filename = f"{uuid.uuid4().hex[:max_stem_length]}.json"
73 file_path = output_dir / filename
75 if not file_path.exists():
76 break
77 else:
78 msg = f"Can't generate unique JSON filename in: {output_dir}."
79 raise RuntimeError(msg)
81 payload = {
82 campaign_name: {
83 suite_name: tests for suite_name, tests in suites.items() if tests
84 }
85 for campaign_name, suites in results.items()
86 if any(tests for tests in suites.values())
87 }
89 if not payload:
90 logger.warning("No test results to write.")
91 return
93 try:
94 with file_path.open("w", encoding="utf-8") as f:
95 json.dump(payload, f, indent=2, default=_result_to_serializable)
96 except Exception as exc:
97 msg = f"Can't write JSON file: {file_path}"
98 logger.exception(msg, exc=exc)
99 return
101 msg = f"Plugin execution done. Output: {file_path}"
102 logger.info(msg)