test(sync): cover FullSync's phase transitions end-to-end

TestFillPendingDetails_ReportsPhaseAwareProgressThroughActivitiesAndWorkoutsPhases
only ever called FillPendingDetails directly, never exercising
FullSync's own setProgress(PhaseDiscovering, ...) / deferred
setProgress(PhaseIdle, ...) wiring around backfillCore/
incrementalSyncCore -- what handleSyncRun actually runs in production
and what SyncModal's "Discovering activities..." spinner depends on.

Add a mock.Client.Delay field (slept, ctx-cancellable, at the start of
GetActivities) so a test can give the discovering phase real
wall-clock duration, then add
TestFullSync_ReportsPhaseTransitionsThroughDiscoveringToIdle, which
runs FullSync in a goroutine and polls Progress() to confirm it
observes PhaseDiscovering mid-flight and PhaseIdle after completion.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-27 09:01:30 +02:00
parent 3a7f305221
commit f7e7b68078
2 changed files with 90 additions and 1 deletions

View File

@@ -4,6 +4,7 @@ package mock
import (
"context"
"time"
"geniusrun/backend/internal/garmin"
)
@@ -20,7 +21,13 @@ type Client struct {
// all-calls-fail Err field below -- so a test can simulate one
// activity's workout fetch failing while others in the same batch
// succeed.
WorkoutErrByID map[int64]error
WorkoutErrByID map[int64]error
// Delay, if set, is slept (ctx-cancellable) at the start of every
// GetActivities call -- lets a test give sync.Service's discovering
// phase (backfillCore/incrementalSyncCore) real wall-clock duration, so
// a concurrent goroutine can observe Progress() mid-flight instead of
// the call returning instantly.
Delay time.Duration
Err error // if set, every call returns this error
authResultCursor int
ClosedCalled bool
@@ -58,6 +65,13 @@ func (c *Client) CompleteMFA(ctx context.Context, code string) (garmin.AuthResul
func (c *Client) GetActivities(ctx context.Context, startDate, endDate string, limit int) ([]garmin.Activity, error) {
c.GetActivitiesCalls++
if c.Delay > 0 {
select {
case <-ctx.Done():
return nil, ctx.Err()
case <-time.After(c.Delay):
}
}
if c.Err != nil {
return nil, c.Err
}