From abbbf17bcfe6dfa663b7019c4892db09e27b3808 Mon Sep 17 00:00:00 2001 From: Martin Kagamino Lehoux Date: Thu, 27 Aug 2026 13:37:26 +0200 Subject: Resync Strava title from list payload via Save Context / Problem: Strava titles can be corrected after import. The sync path only handled new rides; existing rides were marked skipped without checking the cheap list metadata, so corrections like ride #789 stayed stale. What: In syncRides reuse the existing Save write path for rare title resyncs (pay GPX parse cost) when existing.Name != list.Name; track progress.Updated and surface it in SSE/TS UI; add tests for resync without stream fetch. Remove the now-obsolete TODO. QA: go test/ vet, tsc, biome/stylelint pass. --- web/server_test.go | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 76 insertions(+), 2 deletions(-) (limited to 'web/server_test.go') diff --git a/web/server_test.go b/web/server_test.go index a60d742..7137031 100644 --- a/web/server_test.go +++ b/web/server_test.go @@ -615,6 +615,80 @@ func TestSyncRidesSavesActivityWithoutRoute(t *testing.T) { assert.True(t, found) } +func TestSyncRidesResyncsTitleFromList(t *testing.T) { + server, db := newWebTestServer(t) + startDate := time.Date(2026, 8, 1, 7, 0, 0, 0, time.UTC) + gpxPath := testGPXPath(t, "existing.gpx") + require.NoError(t, ride.Save(db, ride.StoredRide{ + ExternalID: "strava:789", + GPXPath: gpxPath, + Name: "Old Title", + Type: "Ride", + StartDate: startDate, + DistanceM: 20_000, + })) + // Verify the title was corrected on Strava (ride #789). + client := fakeSyncClient{ + activities: []strava.Activity{ + {ID: 789, Name: "Corrected Title", Type: "Ride", StartDate: startDate}, + }, + results: map[int64]fakeSyncResult{}, + } + gpxDir := t.TempDir() + var getCalled bool + wrapped := countingSyncClient{inner: client, getCalled: &getCalled} + progress, err := server.syncRides(wrapped, gpxDir, startDate, startDate.AddDate(0, 0, 1), nil) + require.NoError(t, err) + assert.Equal(t, SyncProgress{Total: 1, Completed: 1, Imported: 0, Skipped: 0, Updated: 1}, progress) + assert.False(t, getCalled, "sync should not fetch streams for metadata resync") + updated, found, err := ride.GetByExternalID(db, "strava:789") + require.NoError(t, err) + require.True(t, found) + assert.Equal(t, "Corrected Title", updated.Name) + assert.Equal(t, gpxPath, updated.GPXPath, "GPX path should be preserved on metadata resync") +} + +func TestSyncRidesSkipsWhenTitleUnchanged(t *testing.T) { + server, db := newWebTestServer(t) + startDate := time.Date(2026, 8, 1, 7, 0, 0, 0, time.UTC) + require.NoError(t, ride.Save(db, ride.StoredRide{ + ExternalID: "strava:789", + GPXPath: testGPXPath(t, "existing2.gpx"), + Name: "Same Title", + Type: "Ride", + StartDate: startDate, + DistanceM: 20_000, + })) + client := fakeSyncClient{ + activities: []strava.Activity{ + {ID: 789, Name: "Same Title", Type: "Ride", StartDate: startDate}, + }, + results: map[int64]fakeSyncResult{}, + } + gpxDir := t.TempDir() + progress, err := server.syncRides(client, gpxDir, startDate, startDate.AddDate(0, 0, 1), nil) + require.NoError(t, err) + assert.Equal(t, SyncProgress{Total: 1, Completed: 1, Imported: 0, Skipped: 1, Updated: 0}, progress) + stored, found, err := ride.GetByExternalID(db, "strava:789") + require.NoError(t, err) + require.True(t, found) + assert.Equal(t, "Same Title", stored.Name) +} + +type countingSyncClient struct { + inner fakeSyncClient + getCalled *bool +} + +func (c countingSyncClient) List(from, to time.Time) ([]strava.Activity, error) { + return c.inner.List(from, to) +} + +func (c countingSyncClient) Get(id int64) (strava.Activity, []byte, error) { + *c.getCalled = true + return c.inner.Get(id) +} + func TestSyncRejectsConcurrentImport(t *testing.T) { server, _ := newWebTestServer(t) appConfig, err := config.Load(server.configPath) @@ -645,8 +719,8 @@ func TestWriteSyncEvent(t *testing.T) { require.NoError(t, writeSyncEvent(response, response, "complete", progress)) body := response.Body.String() - assert.Contains(t, body, "event: progress\ndata: {\"total\":2,\"completed\":1,\"imported\":1,\"skipped\":0}\n\n") - assert.Contains(t, body, "event: complete\ndata: {\"total\":2,\"completed\":1,\"imported\":1,\"skipped\":0}\n\n") + assert.Contains(t, body, "event: progress\ndata: {\"total\":2,\"completed\":1,\"imported\":1,\"skipped\":0,\"updated\":0}\n\n") + assert.Contains(t, body, "event: complete\ndata: {\"total\":2,\"completed\":1,\"imported\":1,\"skipped\":0,\"updated\":0}\n\n") assert.Less(t, strings.Index(body, "event: progress"), strings.Index(body, "event: complete")) } -- cgit v1.3