@@ -2,13 +2,20 @@ use anyhow::Context;
22use clap:: Parser ;
33use nix:: sys:: resource:: { getrlimit, setrlimit, Resource } ;
44use std:: fs:: { self , File } ;
5+ use std:: io:: Write ;
56use std:: panic:: catch_unwind;
67use std:: path:: { Path , PathBuf } ;
78use std:: process:: { Command , Stdio } ;
89use std:: env;
910use tempdir:: TempDir ;
1011use test_cases:: { test_cases, Test , TestCase , TestSetup } ;
1112
13+ struct TestResult {
14+ name : String ,
15+ passed : bool ,
16+ log_path : PathBuf ,
17+ }
18+
1219fn get_test ( name : & str ) -> anyhow:: Result < Box < dyn Test > > {
1320 let tests = test_cases ( ) ;
1421 tests
@@ -133,7 +140,7 @@ fn setup_namespace_and_run(test_setup: TestSetup) -> anyhow::Result<()> {
133140 }
134141}
135142
136- fn run_single_test ( test_case : & str , base_dir : & Path , keep_all : bool , max_name_len : usize ) -> anyhow:: Result < bool > {
143+ fn run_single_test ( test_case : & str , base_dir : & Path , keep_all : bool , max_name_len : usize ) -> anyhow:: Result < TestResult > {
137144 let executable = env:: current_exe ( ) . context ( "Failed to detect current executable" ) ?;
138145 let test_dir = base_dir. join ( test_case) ;
139146 fs:: create_dir ( & test_dir) . context ( "Failed to create test directory" ) ?;
@@ -162,22 +169,61 @@ fn run_single_test(test_case: &str, base_dir: &Path, keep_all: bool, max_name_le
162169 test. check ( child) ;
163170 } ) ;
164171
165- match result {
166- Ok ( ( ) ) => {
167- eprintln ! ( " OK" ) ;
168- if !keep_all {
169- let _ = fs:: remove_dir_all ( & test_dir) ;
170- }
171- Ok ( true )
172- }
173- Err ( _e) => {
174- eprintln ! ( " FAIL" ) ;
175- Ok ( false )
172+ let passed = result. is_ok ( ) ;
173+ if passed {
174+ eprintln ! ( "OK" ) ;
175+ if !keep_all {
176+ let _ = fs:: remove_dir_all ( & test_dir) ;
176177 }
178+ } else {
179+ eprintln ! ( "FAIL" ) ;
180+ }
181+
182+ Ok ( TestResult {
183+ name : test_case. to_string ( ) ,
184+ passed,
185+ log_path,
186+ } )
187+ }
188+
189+ fn write_github_summary ( results : & [ TestResult ] , num_ok : usize , num_tests : usize ) -> anyhow:: Result < ( ) > {
190+ let summary_path = env:: var ( "GITHUB_STEP_SUMMARY" )
191+ . context ( "GITHUB_STEP_SUMMARY environment variable not set" ) ?;
192+
193+ let mut file = fs:: OpenOptions :: new ( )
194+ . create ( true )
195+ . append ( true )
196+ . open ( & summary_path)
197+ . context ( "Failed to open GITHUB_STEP_SUMMARY" ) ?;
198+
199+ let all_passed = num_ok == num_tests;
200+ let status = if all_passed { "✅" } else { "❌" } ;
201+
202+ writeln ! ( file, "## {status} Integration Tests ({num_ok}/{num_tests} passed)\n " ) ?;
203+
204+ for result in results {
205+ let icon = if result. passed { "✅" } else { "❌" } ;
206+ let log_content = fs:: read_to_string ( & result. log_path ) . unwrap_or_default ( ) ;
207+
208+ writeln ! ( file, "<details>" ) ?;
209+ writeln ! ( file, "<summary>{icon} {}</summary>\n " , result. name) ?;
210+ writeln ! ( file, "```" ) ?;
211+ // Limit log size to avoid huge summaries (1 MiB limit)
212+ const MAX_LOG_SIZE : usize = 1024 * 1024 ;
213+ let truncated = if log_content. len ( ) > MAX_LOG_SIZE {
214+ format ! ( "... (truncated, showing last 1 MiB) ...\n {}" , & log_content[ log_content. len( ) - MAX_LOG_SIZE ..] )
215+ } else {
216+ log_content
217+ } ;
218+ writeln ! ( file, "{truncated}" ) ?;
219+ writeln ! ( file, "```" ) ?;
220+ writeln ! ( file, "</details>\n " ) ?;
177221 }
222+
223+ Ok ( ( ) )
178224}
179225
180- fn run_tests ( test_case : & str , base_dir : Option < PathBuf > , keep_all : bool ) -> anyhow:: Result < ( ) > {
226+ fn run_tests ( test_case : & str , base_dir : Option < PathBuf > , keep_all : bool , github_summary : bool ) -> anyhow:: Result < ( ) > {
181227 // Create the base directory - either use provided path or create a temp one
182228 let base_dir = match base_dir {
183229 Some ( path) => {
@@ -191,12 +237,10 @@ fn run_tests(test_case: &str, base_dir: Option<PathBuf>, keep_all: bool) -> anyh
191237 }
192238 } ;
193239
194- let mut num_tests = 1 ;
195- let mut num_ok: usize = 0 ;
240+ let mut results: Vec < TestResult > = Vec :: new ( ) ;
196241
197242 if test_case == "all" {
198243 let all_tests = test_cases ( ) ;
199- num_tests = all_tests. len ( ) ;
200244 let max_name_len = all_tests. iter ( ) . map ( |t| t. name . len ( ) ) . max ( ) . unwrap_or ( 0 ) ;
201245
202246 for TestCase {
@@ -205,11 +249,19 @@ fn run_tests(test_case: &str, base_dir: Option<PathBuf>, keep_all: bool) -> anyh
205249 requires_namespace : _,
206250 } in all_tests
207251 {
208- num_ok += run_single_test ( name, & base_dir, keep_all, max_name_len) . context ( name) ? as usize ;
252+ results . push ( run_single_test ( name, & base_dir, keep_all, max_name_len) . context ( name) ?) ;
209253 }
210254 } else {
211255 let max_name_len = test_case. len ( ) ;
212- num_ok += run_single_test ( test_case, & base_dir, keep_all, max_name_len) . context ( test_case. to_string ( ) ) ? as usize ;
256+ results. push ( run_single_test ( test_case, & base_dir, keep_all, max_name_len) . context ( test_case. to_string ( ) ) ?) ;
257+ }
258+
259+ let num_tests = results. len ( ) ;
260+ let num_ok = results. iter ( ) . filter ( |r| r. passed ) . count ( ) ;
261+
262+ // Write GitHub Actions summary if requested
263+ if github_summary {
264+ write_github_summary ( & results, num_ok, num_tests) ?;
213265 }
214266
215267 let num_failures = num_tests - num_ok;
@@ -244,6 +296,9 @@ enum CliCommand {
244296 /// Keep test artifacts even for passing tests (by default only failing tests are kept)
245297 #[ arg( long) ]
246298 keep_all : bool ,
299+ /// Write test results to GitHub Actions job summary ($GITHUB_STEP_SUMMARY)
300+ #[ arg( long) ]
301+ github_summary : bool ,
247302 } ,
248303 StartVm {
249304 #[ arg( long) ]
@@ -259,6 +314,7 @@ impl Default for CliCommand {
259314 test_case : "all" . to_string ( ) ,
260315 base_dir : None ,
261316 keep_all : false ,
317+ github_summary : false ,
262318 }
263319 }
264320}
@@ -279,6 +335,6 @@ fn main() -> anyhow::Result<()> {
279335 tmp_dir,
280336 requires_namespace : false , // Will be set by start_vm based on test case
281337 } ) ,
282- CliCommand :: Test { test_case, base_dir, keep_all } => run_tests ( & test_case, base_dir, keep_all) ,
338+ CliCommand :: Test { test_case, base_dir, keep_all, github_summary } => run_tests ( & test_case, base_dir, keep_all, github_summary ) ,
283339 }
284340}
0 commit comments