Fix flaky CI: default SyncOptions, pause test race, job timeout - #119
Merged
Merged
Conversation
- SyncEngine: fall back to a default SyncOptions when none is passed, so documented defaults (PreserveTimestamps, PreservePermissions) apply. Without it, files copied by an options-less sync kept fresh write timestamps; on slow runners a later sync saw the remote side as modified and turned a skipped update into a conflict upload (SynchronizeAsync_UpdateExistingFalse_SkipsModifications on macOS). - Add a regression test for the options-less timestamp default. - SyncEngineTests: PauseAsync_CalledMultipleTimes_IsIdempotent now issues all pause calls before resuming. A late PauseAsync from a queued Task.Run could land after the single ResumeAsync and hang the ubuntu job until GitHub's 6-hour timeout. - CI: add timeout-minutes: 30 to the build job. Claude-Session: https://claude.ai/code/session_01XugGo6npZqDT15B3EcMkDk
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #119 +/- ##
==========================================
- Coverage 78.99% 78.82% -0.17%
==========================================
Files 44 44
Lines 4874 4874
Branches 723 726 +3
==========================================
- Hits 3850 3842 -8
- Misses 774 775 +1
- Partials 250 257 +7 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes the two intermittent CI failures seen on the recent dependency PRs (#115, #117). Neither was caused by the dependency bumps.
1. Options-less sync ignored
SyncOptionsdefaults (library bug)SyncEnginestored theoptionsargument as-is, so callingSynchronizeAsync()/SyncFolderAsync()/SyncFilesAsync()without options left_currentOptionsnull. Every_currentOptions?.Xcheck then fell back to "off", which silently disabled the documented defaultsPreserveTimestamps = trueandPreservePermissions = true.This is what made
SynchronizeAsync_UpdateExistingFalse_SkipsModificationsflaky on macOS: the options-less initial sync left copied files with fresh write timestamps, while the database recorded the scanned timestamps. When the runner took more than the 2-second change-detection window, the next sync saw the remote side as modified too, raised aBothModifiedconflict, and theUseLocalresolver uploaded, bypassingUpdateExisting = false.Fix:
_currentOptions = options ?? new SyncOptions();at all three entry points. All other option checks keep their current behaviour, because their defaults match the old null fallback. A regression test (SynchronizeAsync_NoOptions_PreservesTimestampsByDefault) fails without the fix and passes with it.2. Race in
PauseAsync_CalledMultipleTimes_IsIdempotent(test bug, hung ubuntu jobs)The test spawned a
Task.Runper progress event, each callingPauseAsync(), then calledResumeAsync()once. A queued pause could land after that resume, leaving the engine paused with nobody to resume it. All three 6-hour hangs (runs 32477251497, 32477889169, 33693463535) stopped at exactly this test.Fix: all pause calls now happen synchronously in the first non-scanning progress event, so they always precede the resume. The test waits for either the pause point or sync completion, and caps the final wait at 30 s so a regression fails instead of hanging.
3. CI safety net
timeout-minutes: 30on the build job, so any future hang fails in 30 minutes instead of 6 hours.Testing
dotnet format --verify-no-changes: cleandotnet test: 819 passed, 130 skipped (integration), 0 failedFollow-up (not in this PR)
A file that exists on both sides with no sync state produces a concurrent Upload and Download of the same path during the first sync. Content is identical so it's harmless today, but it's a read/write race and should become a single compare-then-record step.
https://claude.ai/code/session_01XugGo6npZqDT15B3EcMkDk