@@ -109,6 +109,62 @@ public async Task ExecuteSync_PostSendReceiveFailure_ReturnsExpectedStatus(strin
109109 PostSendReceive ) ;
110110 }
111111
112+ [ Theory ]
113+ [ InlineData ( false , true , SyncJobStatusEnum . SendReceiveFailed ) ]
114+ [ InlineData ( true , true , SyncJobStatusEnum . Success ) ]
115+ // Currently (2026-03) Chorus doesn't set ErrorEncountered to true if the only error is during a push,
116+ // so we also need to test that the second S/R will be triggered on HTTP 500 errors even if IProgress.ErrorEncountered is false.
117+ // Once Chorus fixes that bug and errors on push are detected, the second bool param can be removed and this test can be simplified
118+ [ InlineData ( false , false , SyncJobStatusEnum . SendReceiveFailed ) ]
119+ [ InlineData ( true , false , SyncJobStatusEnum . Success ) ]
120+ public async Task ExecuteSync_PostSendReceiveHttp500_RetriesOneTime ( bool retrySucceeds , bool progressReportsErrorOnHttp500 , SyncJobStatusEnum expectedStatus )
121+ {
122+ using var h = new SyncWorkerTestHarness ( ) ;
123+ const string error500 = SendReceiveHelpers . LfMergeBridgeResult . Http500Indicator ;
124+ var srResults = new List < SendReceiveHelpers . LfMergeBridgeResult > ( ) ;
125+ // First S/R succeeds
126+ srResults . Add ( new SendReceiveHelpers . LfMergeBridgeResult ( "success" ) ) ;
127+ // Second S/R gets HTTP 500, but Chorus may or may not record that fact
128+ srResults . Add ( progressReportsErrorOnHttp500
129+ ? new SendReceiveHelpers . LfMergeBridgeResult ( error500 , ProgressHelper . CreateErrorProgress ( ) )
130+ : new SendReceiveHelpers . LfMergeBridgeResult ( error500 ) ) ;
131+ if ( retrySucceeds )
132+ {
133+ // "Third" S/R (first and only retry of second S/R) succeeds
134+ srResults . Add ( new SendReceiveHelpers . LfMergeBridgeResult ( "success" ) ) ;
135+ }
136+ else
137+ {
138+ // "Third" S/R (first and only retry of second S/R) also gets HTTP 500, but Chorus may or may not record that fact
139+ srResults . Add ( progressReportsErrorOnHttp500
140+ ? new SendReceiveHelpers . LfMergeBridgeResult ( error500 , ProgressHelper . CreateErrorProgress ( ) )
141+ : new SendReceiveHelpers . LfMergeBridgeResult ( error500 ) ) ;
142+ }
143+ h . SetSendReceiveResults ( srResults . ToArray ( ) ) ;
144+
145+ var syncResult = new SyncResult ( CrdtChanges : 5 , FwdataChanges : 3 ) ;
146+ var result = await h . RunAsync ( syncResult ) ;
147+
148+ result . Status . Should ( ) . Be ( expectedStatus ) ;
149+ var expectedSteps = new List < SyncStep > ( [
150+ TestAuth ,
151+ CheckBlocked ,
152+ PreSendReceive ,
153+ MediaSyncFwData ,
154+ MediaSyncCrdt ,
155+ GetSnapshot ,
156+ Sync ,
157+ PostSendReceive ,
158+ PostSendReceive
159+ ] ) ;
160+ if ( retrySucceeds )
161+ {
162+ expectedSteps . Add ( RegenerateSnapshot ) ;
163+ expectedSteps . Add ( HarmonySync ) ;
164+ }
165+ h . Steps . Should ( ) . Equal ( expectedSteps ) ;
166+ }
167+
112168 [ Theory ]
113169 [ InlineData ( "Rolling back... validation error" , true , SyncJobStatusEnum . SyncBlocked ) ]
114170 [ InlineData ( "network error" , false , SyncJobStatusEnum . SendReceiveFailed ) ]
0 commit comments