@@ -32,9 +32,19 @@ fn create_test_repo_with_files() -> (TempDir, PathBuf) {
3232 . success ( ) ;
3333
3434 // Create files of different sizes
35- fs:: write ( repo_path. join ( "small.txt" ) , "small file" ) . expect ( "Failed to write file" ) ;
36- fs:: write ( repo_path. join ( "medium.txt" ) , "x" . repeat ( 1024 ) ) . expect ( "Failed to write file" ) ;
37- fs:: write ( repo_path. join ( "large.txt" ) , "x" . repeat ( 1024 * 1024 ) ) . expect ( "Failed to write file" ) ;
35+ for ( name, content) in [
36+ ( "small.txt" , "small file" . as_bytes ( ) ) ,
37+ ( "medium.txt" , & vec ! [ b'x' ; 1024 ] ) ,
38+ ( "large.txt" , & vec ! [ b'x' ; 1024 * 1024 ] ) ,
39+ ] {
40+ let mut file = fs:: File :: create ( repo_path. join ( name) ) . expect ( "Failed to create file" ) ;
41+ use std:: io:: Write ;
42+ file. write_all ( content) . expect ( "Failed to write" ) ;
43+ file. sync_all ( ) . expect ( "Failed to sync" ) ;
44+ }
45+
46+ // Give it time to persist the files to disk
47+ sleep ( Duration :: from_millis ( 1000 ) ) ;
3848
3949 // Add and commit files
4050 Command :: new ( "git" )
@@ -49,6 +59,30 @@ fn create_test_repo_with_files() -> (TempDir, PathBuf) {
4959 . assert ( )
5060 . success ( ) ;
5161
62+ // Wait until Git repo is fully ready
63+ Command :: new ( "git" )
64+ . arg ( "status" )
65+ . current_dir ( & repo_path)
66+ . assert ( )
67+ . success ( ) ;
68+
69+ // Remove potential stale .git/index.lock file
70+ let lock_file = repo_path. join ( ".git/index.lock" ) ;
71+ if lock_file. exists ( ) {
72+ fs:: remove_file ( & lock_file) . expect ( "Failed to remove stale index.lock" ) ;
73+ }
74+
75+ let output = Command :: new ( "git" )
76+ . args ( [ "ls-files" ] )
77+ . current_dir ( & repo_path)
78+ . output ( )
79+ . expect ( "Failed to run git ls-files" ) ;
80+
81+ let stdout = String :: from_utf8_lossy ( & output. stdout ) ;
82+ assert ! ( stdout. contains( "small.txt" ) , "small.txt not committed" ) ;
83+ assert ! ( stdout. contains( "medium.txt" ) , "medium.txt not committed" ) ;
84+ assert ! ( stdout. contains( "large.txt" ) , "large.txt not committed" ) ;
85+
5286 ( temp_dir, repo_path)
5387}
5488
@@ -257,21 +291,50 @@ fn test_large_files_run_function_with_files() {
257291 . success ( )
258292 . stdout ( predicate:: str:: contains ( "Scanning repository" ) ) ;
259293
260- // Test direct function call (for coverage)
261- match execute_command_in_dir ( & repo_path, large_files_command ( 10 , None ) ) {
262- Ok ( result) => {
263- assert ! ( result. is_success( ) ) ;
264- assert ! (
265- result. stdout. contains( "📦 Files larger than" )
266- || result. stdout. contains( "No files larger than" )
267- ) ;
294+ // Retry loop for flaky CI environments
295+ let retries = 3 ;
296+ let mut result = None ;
297+
298+ for _ in 0 ..retries {
299+ match execute_command_in_dir ( & repo_path, large_files_command ( 10 , None ) ) {
300+ Ok ( r) if r. is_success ( ) => {
301+ result = Some ( r) ;
302+ break ;
303+ }
304+ Ok ( r) => {
305+ eprintln ! (
306+ "Retrying after failure.\n STDOUT:\n {}\n STDERR:\n {}" ,
307+ r. stdout, r. stderr
308+ ) ;
309+ std:: thread:: sleep ( std:: time:: Duration :: from_millis ( 500 ) ) ;
310+ }
311+ Err ( _) => {
312+ eprintln ! ( "Warning: Directory test failed, skipping test" ) ;
313+ return ;
314+ }
268315 }
269- Err ( _) => {
270- eprintln ! ( "Warning: Directory test failed, skipping test" ) ;
271- return ;
316+ }
317+
318+ if result. is_none ( ) {
319+ // Final log if all retries failed
320+ if let Ok ( r) = execute_command_in_dir ( & repo_path, large_files_command ( 10 , None ) ) {
321+ eprintln ! (
322+ "Final failure.\n STDOUT:\n {}\n STDERR:\n {}" ,
323+ r. stdout, r. stderr
324+ ) ;
272325 }
273326 }
274327
328+ let result = result. expect ( "Large files command failed after retries" ) ;
329+ assert ! ( result. is_success( ) ) ;
330+ assert ! (
331+ result. stdout. contains( "📦 Files larger than" )
332+ || result. stdout. contains( "No files larger than" )
333+ ) ;
334+
335+ // Ensure temp_dir is kept alive for the test duration
336+ assert ! ( std:: path:: Path :: new( temp_dir. path( ) ) . exists( ) ) ;
337+
275338 // Keep temp_dir alive
276339 drop ( temp_dir) ;
277340}
@@ -288,18 +351,46 @@ fn test_large_files_with_high_threshold() {
288351 . success ( )
289352 . stdout ( predicate:: str:: contains ( "No files found larger than" ) ) ;
290353
291- // Test direct function call with high threshold (for coverage)
292- match execute_command_in_dir ( & repo_path, large_files_command ( 10 , Some ( 100.0 ) ) ) {
293- Ok ( result) => {
294- assert ! ( result. is_success( ) ) ;
295- assert ! ( result. stdout. contains( "No files larger than 100.0MB found" ) ) ;
354+ // Retry loop for flaky CI environments
355+ let retries = 3 ;
356+ let mut result = None ;
357+
358+ for _ in 0 ..retries {
359+ match execute_command_in_dir ( & repo_path, large_files_command ( 10 , Some ( 100.0 ) ) ) {
360+ Ok ( r) if r. is_success ( ) => {
361+ result = Some ( r) ;
362+ break ;
363+ }
364+ Ok ( r) => {
365+ eprintln ! (
366+ "Retrying after failure.\n STDOUT:\n {}\n STDERR:\n {}" ,
367+ r. stdout, r. stderr
368+ ) ;
369+ std:: thread:: sleep ( std:: time:: Duration :: from_millis ( 500 ) ) ;
370+ }
371+ Err ( _) => {
372+ eprintln ! ( "Warning: Directory test failed, skipping test" ) ;
373+ return ;
374+ }
296375 }
297- Err ( _) => {
298- eprintln ! ( "Warning: Directory test failed, skipping test" ) ;
299- return ;
376+ }
377+
378+ if result. is_none ( ) {
379+ // Final log if all retries failed
380+ if let Ok ( r) = execute_command_in_dir ( & repo_path, large_files_command ( 10 , Some ( 100.0 ) ) ) {
381+ eprintln ! (
382+ "Final failure.\n STDOUT:\n {}\n STDERR:\n {}" ,
383+ r. stdout, r. stderr
384+ ) ;
300385 }
301386 }
302387
388+ let result = result. expect ( "Large files command failed after retries" ) ;
389+ assert ! ( result. is_success( ) ) ;
390+ assert ! ( result. stdout. contains( "No files larger than 100.0MB found" ) ) ;
391+
392+ assert ! ( std:: path:: Path :: new( temp_dir. path( ) ) . exists( ) ) ;
393+
303394 // Keep temp_dir alive
304395 drop ( temp_dir) ;
305396}
@@ -323,6 +414,8 @@ fn test_large_files_default_limit() {
323414// Integration tests for large_files.rs run() function testing all code paths
324415
325416use std:: process:: Command as StdCommand ;
417+ use std:: thread:: sleep;
418+ use std:: time:: Duration ;
326419
327420mod common;
328421
0 commit comments