@@ -233,53 +233,63 @@ public void Remote_stale_2week_re_download_refreshes_mtime_immediate_followup_do
233233 var remoteRef = "gist.github.com/kzu/0ac826dc7de666546aaedd38e5965381" ;
234234 var logPath = Path . Combine ( scratch , "stale-download.log" ) ;
235235
236- // Ensure clean-ish start for this ref's cache dir (best effort)
237- try { RunGo ( "clean" , remoteRef ) ; } catch { }
238-
239- // Warm-up download
240- var warm = RunGo ( remoteRef , "--" , "-v:q" ) ;
241- Assert . Equal ( 0 , warm . ExitCode ) ;
242- Assert . Contains ( "run.cs" , warm . Output ) ;
243-
244- // Locate the downloaded source cs for this ref (uses the same base as production)
245- var goRoot = GetTempRoot ( ) ;
246- var gistRoot = Directory . GetDirectories ( goRoot , "*" , SearchOption . AllDirectories )
247- . FirstOrDefault ( d => d . Replace ( '\\ ' , '/' ) . Contains ( "gist.github.com/kzu/0ac826dc7de666546aaedd38e5965381" ) ) ;
248- Assert . False ( string . IsNullOrEmpty ( gistRoot ) , "expected download dir for gist ref" ) ;
249- var sourceCs = Directory . GetFiles ( gistRoot , "run.cs" , SearchOption . AllDirectories ) . FirstOrDefault ( )
250- ?? Directory . GetFiles ( gistRoot , "*.cs" , SearchOption . AllDirectories ) . FirstOrDefault ( ) ;
251- Assert . False ( string . IsNullOrEmpty ( sourceCs ) , "expected source .cs under download" ) ;
252- var srcInfo = new FileInfo ( sourceCs ) ;
253-
254- // Artificially age it >14 days
255- var staleTime = DateTime . UtcNow . AddDays ( - 20 ) ;
256- srcInfo . LastWriteTimeUtc = staleTime ;
257- Assert . True ( ( DateTime . UtcNow - srcInfo . LastWriteTimeUtc ) . TotalDays > 14 ) ;
258-
259- // Re-invoke: should detect stale, (re)download/touch mtime to recent, succeed with marker
260- var ( exitStale , outStale ) = RunGo ( remoteRef , "--" , "-v:q" ) ;
261- File . WriteAllText ( logPath , "STALE-RE-INVOKE:\n " + outStale ) ;
262- Assert . Equal ( 0 , exitStale ) ;
263- Assert . Contains ( "run.cs" , outStale ) ;
264-
265- srcInfo . Refresh ( ) ;
266- var afterStaleMtime = srcInfo . LastWriteTimeUtc ;
267- File . AppendAllText ( logPath , $ "\n SOURCE-MTIME-AFTER-STALE: { afterStaleMtime : O} \n ") ;
268- Assert . True ( ( DateTime . UtcNow - afterStaleMtime ) . TotalMinutes < 5 , "source mtime should be refreshed to recent by re-dl" ) ;
269-
270- // Immediate follow-up: must NOT update the source mtime (plan requirement)
271- var mtimeBeforeImmediate = srcInfo . LastWriteTimeUtc ;
272- var ( exitImm , outImm ) = RunGo ( remoteRef , "--" , "-v:q" ) ;
273- File . AppendAllText ( logPath , "IMMEDIATE-FOLLOWUP:\n " + outImm ) ;
274- Assert . Equal ( 0 , exitImm ) ;
275- Assert . Contains ( "run.cs" , outImm ) ;
276-
277- srcInfo . Refresh ( ) ;
278- var mtimeAfterImmediate = srcInfo . LastWriteTimeUtc ;
279- File . AppendAllText ( logPath , $ "SOURCE-MTIME-AFTER-IMMEDIATE: { mtimeAfterImmediate : O} \n ") ;
280-
281- var deltaSeconds = ( mtimeAfterImmediate - mtimeBeforeImmediate ) . TotalSeconds ;
282- // The immediate run (cache hit, no dl) must not have updated the source mtime via our logic or observable change.
283- Assert . True ( deltaSeconds < 2.0 , $ "immediate follow-up must not update source mtime (delta={ deltaSeconds } s)") ;
236+ try
237+ {
238+ // Ensure clean-ish start for this ref's cache dir (best effort)
239+ try { RunGo ( "clean" , remoteRef ) ; } catch { }
240+
241+ // Warm-up download
242+ var warm = RunGo ( remoteRef , "--" , "-v:q" ) ;
243+ Assert . Equal ( 0 , warm . ExitCode ) ;
244+ Assert . Contains ( "run.cs" , warm . Output ) ;
245+
246+ // Locate the downloaded source cs for this ref (robust search, not brittle FirstOrDefault + loose contains)
247+ var goRoot = GetTempRoot ( ) ;
248+ var gistCandidates = Directory . GetDirectories ( goRoot , "*0ac826dc7de666546aaedd38e5965381*" , SearchOption . AllDirectories )
249+ . OrderByDescending ( d => d . Length )
250+ . ToArray ( ) ;
251+ var gistRoot = gistCandidates . FirstOrDefault ( d => Directory . GetFiles ( d , "*.cs" , SearchOption . AllDirectories ) . Any ( ) )
252+ ?? gistCandidates . FirstOrDefault ( ) ;
253+ Assert . False ( string . IsNullOrEmpty ( gistRoot ) , "expected download dir for gist ref" ) ;
254+ var sourceCs = Directory . GetFiles ( gistRoot , "run.cs" , SearchOption . AllDirectories ) . FirstOrDefault ( )
255+ ?? Directory . GetFiles ( gistRoot , "*.cs" , SearchOption . AllDirectories ) . OrderBy ( f => f ) . FirstOrDefault ( ) ;
256+ Assert . False ( string . IsNullOrEmpty ( sourceCs ) , "expected source .cs under download" ) ;
257+ var srcInfo = new FileInfo ( sourceCs ) ;
258+
259+ // Artificially age it >14 days
260+ var staleTime = DateTime . UtcNow . AddDays ( - 20 ) ;
261+ srcInfo . LastWriteTimeUtc = staleTime ;
262+ Assert . True ( ( DateTime . UtcNow - srcInfo . LastWriteTimeUtc ) . TotalDays > 14 ) ;
263+
264+ // Re-invoke: should detect stale, (re)download/touch mtime to recent, succeed with marker
265+ var ( exitStale , outStale ) = RunGo ( remoteRef , "--" , "-v:q" ) ;
266+ File . WriteAllText ( logPath , "STALE-RE-INVOKE:\n " + outStale ) ;
267+ Assert . Equal ( 0 , exitStale ) ;
268+ Assert . Contains ( "run.cs" , outStale ) ;
269+
270+ srcInfo . Refresh ( ) ;
271+ var afterStaleMtime = srcInfo . LastWriteTimeUtc ;
272+ File . AppendAllText ( logPath , $ "\n SOURCE-MTIME-AFTER-STALE: { afterStaleMtime : O} \n ") ;
273+ Assert . True ( ( DateTime . UtcNow - afterStaleMtime ) . TotalMinutes < 5 , "source mtime should be refreshed to recent by re-dl" ) ;
274+
275+ // Immediate follow-up: must NOT update the source mtime (plan requirement)
276+ var mtimeBeforeImmediate = srcInfo . LastWriteTimeUtc ;
277+ var ( exitImm , outImm ) = RunGo ( remoteRef , "--" , "-v:q" ) ;
278+ File . AppendAllText ( logPath , "IMMEDIATE-FOLLOWUP:\n " + outImm ) ;
279+ Assert . Equal ( 0 , exitImm ) ;
280+ Assert . Contains ( "run.cs" , outImm ) ;
281+
282+ srcInfo . Refresh ( ) ;
283+ var mtimeAfterImmediate = srcInfo . LastWriteTimeUtc ;
284+ File . AppendAllText ( logPath , $ "SOURCE-MTIME-AFTER-IMMEDIATE: { mtimeAfterImmediate : O} \n ") ;
285+
286+ var deltaSeconds = ( mtimeAfterImmediate - mtimeBeforeImmediate ) . TotalSeconds ;
287+ // The immediate run (cache hit, no dl) must not have updated the source mtime via our logic or observable change.
288+ Assert . True ( deltaSeconds < 2.0 , $ "immediate follow-up must not update source mtime (delta={ deltaSeconds } s)") ;
289+ }
290+ finally
291+ {
292+ try { RunGo ( "clean" , remoteRef ) ; } catch { }
293+ }
284294 }
285295}
0 commit comments