1+ #!/usr/bin/env python3
2+ from __future__ import annotations
3+
4+ import json
5+ import sys
6+ import traceback
7+ from pathlib import Path
8+
9+ from framework .context import E2EContext
10+ from framework .result import TestResult
11+ from framework .utils import ensure_directory , write_text_file
12+ from testcases .tc0001_basic_resync import TestCase0001BasicResync
13+
14+
15+ def build_test_suite () -> list :
16+ """
17+ Return the ordered list of E2E test cases to execute.
18+
19+ Add future test cases here in the required execution order.
20+ """
21+ return [
22+ TestCase0001BasicResync (),
23+ ]
24+
25+
26+ def result_to_actions_case (result : TestResult ) -> dict :
27+ """
28+ Convert the internal TestResult into the JSON structure expected by the
29+ GitHub Actions workflow summary/reporting logic.
30+ """
31+ output = {
32+ "id" : result .case_id ,
33+ "name" : result .name ,
34+ "status" : result .status ,
35+ }
36+
37+ if result .reason :
38+ output ["reason" ] = result .reason
39+
40+ if result .artifacts :
41+ output ["artifacts" ] = result .artifacts
42+
43+ if result .details :
44+ output ["details" ] = result .details
45+
46+ return output
47+
48+
49+ def main () -> int :
50+ context = E2EContext .from_environment ()
51+ ensure_directory (context .out_dir )
52+ ensure_directory (context .logs_dir )
53+ ensure_directory (context .state_dir )
54+ ensure_directory (context .work_root )
55+
56+ context .log (
57+ f"Initialising E2E framework for target='{ context .e2e_target } ', "
58+ f"run_id='{ context .run_id } '"
59+ )
60+
61+ cases = []
62+ failed = False
63+
64+ for testcase in build_test_suite ():
65+ context .log (f"Starting test case { testcase .case_id } : { testcase .name } " )
66+
67+ try :
68+ result = testcase .run (context )
69+
70+ if result .case_id != testcase .case_id :
71+ raise RuntimeError (
72+ f"Test case returned mismatched case_id: "
73+ f"expected '{ testcase .case_id } ', got '{ result .case_id } '"
74+ )
75+
76+ cases .append (result_to_actions_case (result ))
77+
78+ if result .status != "pass" :
79+ failed = True
80+ context .log (
81+ f"Test case { testcase .case_id } FAILED: { result .reason or 'no reason provided' } "
82+ )
83+ else :
84+ context .log (f"Test case { testcase .case_id } PASSED" )
85+
86+ except Exception as exc :
87+ failed = True
88+ tb = traceback .format_exc ()
89+
90+ context .log (f"Unhandled exception in test case { testcase .case_id } : { exc } " )
91+ context .log (tb )
92+
93+ error_log = context .logs_dir / f"{ testcase .case_id } _exception.log"
94+ write_text_file (error_log , tb )
95+
96+ failure_result = TestResult (
97+ case_id = testcase .case_id ,
98+ name = testcase .name ,
99+ status = "fail" ,
100+ reason = f"Unhandled exception: { exc } " ,
101+ artifacts = [str (error_log )],
102+ details = {
103+ "exception_type" : type (exc ).__name__ ,
104+ },
105+ )
106+ cases .append (result_to_actions_case (failure_result ))
107+
108+ results = {
109+ "target" : context .e2e_target ,
110+ "run_id" : context .run_id ,
111+ "cases" : cases ,
112+ }
113+
114+ results_file = context .out_dir / "results.json"
115+ results_json = json .dumps (results , indent = 2 , sort_keys = False )
116+ write_text_file (results_file , results_json )
117+
118+ context .log (f"Wrote results to { results_file } " )
119+
120+ return 1 if failed else 0
121+
122+
123+ if __name__ == "__main__" :
124+ sys .exit (main ())
0 commit comments