Part of per-user profile isolation: profile rows are no longer a global singleton, so every read/write requires the caller's userID. This also requires scoping ListActivities, ListWorkoutKinds, UpsertActivity, CreateWorkoutKind, GetSyncState, UpdateSyncState, and ResetAllSyncedData to userID, plus updating all related tests in the store package.
76 lines
2.4 KiB
Go
76 lines
2.4 KiB
Go
package store
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
)
|
|
|
|
func TestResetAllSyncedData_DeletesActivitiesCascadesAndRewindsWatermark(t *testing.T) {
|
|
db := openTestDB(t)
|
|
ctx := context.Background()
|
|
userID, err := db.ProvisionUser(ctx, "test-sub", "Test User")
|
|
if err != nil {
|
|
t.Fatalf("ProvisionUser: %v", err)
|
|
}
|
|
|
|
activityID, err := db.UpsertActivity(ctx, userID, Activity{GarminActivityID: 1, StartTimeUTC: "2026-07-11 06:00:00", RawJSON: "{}"})
|
|
if err != nil {
|
|
t.Fatalf("UpsertActivity: %v", err)
|
|
}
|
|
kindID, err := db.CreateWorkoutKind(ctx, userID, WorkoutKind{Name: "Test Reset Kind", RuleJSON: `{"match":"all","conditions":[]}`, IsActive: true})
|
|
if err != nil {
|
|
t.Fatalf("CreateWorkoutKind: %v", err)
|
|
}
|
|
if err := db.ReplaceLaps(ctx, activityID, []Lap{{LapIndex: 1}}); err != nil {
|
|
t.Fatalf("ReplaceLaps: %v", err)
|
|
}
|
|
if _, err := db.InsertKindAssignment(ctx, KindAssignment{
|
|
ActivityID: activityID, WorkoutKindID: &kindID, AssignmentSource: AssignmentSourceRuleEngine,
|
|
Status: AssignmentStatusAssigned, CandidateKindsJSON: "[]",
|
|
}); err != nil {
|
|
t.Fatalf("InsertKindAssignment: %v", err)
|
|
}
|
|
if err := db.UpdateSyncState(ctx, userID, "2020-01-01", true); err != nil {
|
|
t.Fatalf("UpdateSyncState: %v", err)
|
|
}
|
|
|
|
if err := db.ResetAllSyncedData(ctx, userID); err != nil {
|
|
t.Fatalf("ResetAllSyncedData: %v", err)
|
|
}
|
|
|
|
activities, err := db.ListActivities(ctx, userID, ActivityFilter{})
|
|
if err != nil {
|
|
t.Fatalf("ListActivities: %v", err)
|
|
}
|
|
if len(activities) != 0 {
|
|
t.Errorf("expected 0 activities after reset, got %d", len(activities))
|
|
}
|
|
laps, err := db.LapsForActivity(ctx, activityID)
|
|
if err != nil {
|
|
t.Fatalf("LapsForActivity: %v", err)
|
|
}
|
|
if len(laps) != 0 {
|
|
t.Errorf("expected laps to cascade-delete, got %d", len(laps))
|
|
}
|
|
if _, ok, err := db.CurrentAssignment(ctx, activityID); err != nil || ok {
|
|
t.Errorf("expected kind assignment to cascade-delete, ok=%v err=%v", ok, err)
|
|
}
|
|
|
|
state, err := db.GetSyncState(ctx, userID)
|
|
if err != nil {
|
|
t.Fatalf("GetSyncState: %v", err)
|
|
}
|
|
if state.EarliestSyncedDate != nil || state.BackfillComplete {
|
|
t.Errorf("expected watermark rewound to fresh state, got %+v", state)
|
|
}
|
|
|
|
// Workout kinds (the user's taxonomy) must survive a reset.
|
|
kind, ok, err := db.GetWorkoutKind(ctx, kindID)
|
|
if err != nil || !ok {
|
|
t.Fatalf("GetWorkoutKind after reset: ok=%v err=%v", ok, err)
|
|
}
|
|
if kind.Name != "Test Reset Kind" {
|
|
t.Errorf("workout kind was unexpectedly affected by reset: %+v", kind)
|
|
}
|
|
}
|