api: scope activities, sync, review-queue, and reclassify handlers to userID
Completes the internal/api scoping pass -- the whole package now compiles against the per-user store/sync/garmin signatures from Tasks 4-13. Also fixes the test helpers (newTestServer now returns the provisioned userID) and a latent bug in TestResolveUser_LeavesContextEmptyWhenNotProvisioned, which relied on doJSON's hardcoded "test-user" session sub being unprovisioned -- never caught before since internal/api couldn't compile since Task 12. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -30,7 +30,7 @@ var testSessionConfig = SessionConfig{
|
||||
PublicBaseURL: "https://geniusrun.example.com",
|
||||
}
|
||||
|
||||
func newTestServer(t *testing.T) (*Server, *store.DB) {
|
||||
func newTestServer(t *testing.T) (*Server, *store.DB, int64) {
|
||||
t.Helper()
|
||||
db, err := store.Open(filepath.Join(t.TempDir(), "geniusrun_test.db"))
|
||||
if err != nil {
|
||||
@@ -38,14 +38,15 @@ func newTestServer(t *testing.T) (*Server, *store.DB) {
|
||||
}
|
||||
t.Cleanup(func() { db.Close() })
|
||||
|
||||
if _, err := db.ProvisionUser(context.Background(), "test-user", "Test User"); err != nil {
|
||||
userID, err := db.ProvisionUser(context.Background(), "test-user", "Test User")
|
||||
if err != nil {
|
||||
t.Fatalf("ProvisionUser: %v", err)
|
||||
}
|
||||
|
||||
m := &mock.Client{}
|
||||
garminFactory := func(garmin.Config) garmin.Client { return m }
|
||||
s := NewServer(db, garminFactory, garmin.Config{}, appsync.Config{}, &authmock.Verifier{}, testSessionConfig)
|
||||
return s, db
|
||||
return s, db, userID
|
||||
}
|
||||
|
||||
func doJSON(t *testing.T, handler http.Handler, method, path string, body any) *httptest.ResponseRecorder {
|
||||
@@ -73,7 +74,7 @@ func doJSON(t *testing.T, handler http.Handler, method, path string, body any) *
|
||||
}
|
||||
|
||||
func TestHealth(t *testing.T) {
|
||||
s, _ := newTestServer(t)
|
||||
s, _, _ := newTestServer(t)
|
||||
rec := doJSON(t, s.Router(), http.MethodGet, "/api/health", nil)
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("status = %d, want 200", rec.Code)
|
||||
@@ -81,7 +82,7 @@ func TestHealth(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestWorkoutKindList_ReturnsEightSeededTypesWithPaceFields(t *testing.T) {
|
||||
s, _ := newTestServer(t)
|
||||
s, _, _ := newTestServer(t)
|
||||
rec := doJSON(t, s.Router(), http.MethodGet, "/api/workout-kinds/", nil)
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("status = %d", rec.Code)
|
||||
@@ -101,7 +102,7 @@ func TestWorkoutKindList_ReturnsEightSeededTypesWithPaceFields(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestWorkoutKindUpdate_SetsRuleAndPace(t *testing.T) {
|
||||
s, _ := newTestServer(t)
|
||||
s, _, _ := newTestServer(t)
|
||||
router := s.Router()
|
||||
|
||||
rec := doJSON(t, router, http.MethodGet, "/api/workout-kinds/", nil)
|
||||
@@ -138,7 +139,7 @@ func TestWorkoutKindUpdate_SetsRuleAndPace(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestWorkoutKindUpdate_RejectsInvalidRule(t *testing.T) {
|
||||
s, _ := newTestServer(t)
|
||||
s, _, _ := newTestServer(t)
|
||||
router := s.Router()
|
||||
|
||||
rec := doJSON(t, router, http.MethodGet, "/api/workout-kinds/", nil)
|
||||
@@ -155,7 +156,7 @@ func TestWorkoutKindUpdate_RejectsInvalidRule(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestWorkoutKindUpdate_RejectsInvertedHRRange(t *testing.T) {
|
||||
s, _ := newTestServer(t)
|
||||
s, _, _ := newTestServer(t)
|
||||
router := s.Router()
|
||||
|
||||
rec := doJSON(t, router, http.MethodGet, "/api/workout-kinds/", nil)
|
||||
@@ -174,7 +175,7 @@ func TestWorkoutKindUpdate_RejectsInvertedHRRange(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestWorkoutKindUpdate_RejectsInvertedPaceRange(t *testing.T) {
|
||||
s, _ := newTestServer(t)
|
||||
s, _, _ := newTestServer(t)
|
||||
router := s.Router()
|
||||
|
||||
rec := doJSON(t, router, http.MethodGet, "/api/workout-kinds/", nil)
|
||||
@@ -193,31 +194,31 @@ func TestWorkoutKindUpdate_RejectsInvertedPaceRange(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestReviewQueueResolve(t *testing.T) {
|
||||
s, db := newTestServer(t)
|
||||
s, db, userID := newTestServer(t)
|
||||
ctx := newCtx()
|
||||
|
||||
activityID, err := db.UpsertActivity(ctx, store.Activity{GarminActivityID: 1, StartTimeUTC: "2026-07-11 06:00:00", RawJSON: "{}"})
|
||||
activityID, err := db.UpsertActivity(ctx, userID, store.Activity{GarminActivityID: 1, StartTimeUTC: "2026-07-11 06:00:00", RawJSON: "{}"})
|
||||
if err != nil {
|
||||
t.Fatalf("UpsertActivity: %v", err)
|
||||
}
|
||||
kindID, err := db.CreateWorkoutKind(ctx, store.WorkoutKind{Name: "Test Kind", RuleJSON: `{"match":"all","conditions":[]}`, IsActive: true})
|
||||
kindID, err := db.CreateWorkoutKind(ctx, userID, store.WorkoutKind{Name: "Test Kind", RuleJSON: `{"match":"all","conditions":[]}`, IsActive: true})
|
||||
if err != nil {
|
||||
t.Fatalf("CreateWorkoutKind: %v", err)
|
||||
}
|
||||
if _, err := db.InsertKindAssignment(ctx, store.KindAssignment{
|
||||
if _, err := db.InsertKindAssignment(ctx, userID, store.KindAssignment{
|
||||
ActivityID: activityID, AssignmentSource: store.AssignmentSourceRuleEngine, Status: store.AssignmentStatusNeedsReview,
|
||||
CandidateKindsJSON: "[]",
|
||||
}); err != nil {
|
||||
t.Fatalf("InsertKindAssignment: %v", err)
|
||||
}
|
||||
targetLow, targetHigh := 3.0, 3.5
|
||||
if err := db.ReplaceLaps(ctx, activityID, []store.Lap{
|
||||
if err := db.ReplaceLaps(ctx, userID, activityID, []store.Lap{
|
||||
{LapIndex: 1, TargetPaceLowMps: &targetLow, TargetPaceHighMps: &targetHigh},
|
||||
}); err != nil {
|
||||
t.Fatalf("ReplaceLaps: %v", err)
|
||||
}
|
||||
hr := 150.0
|
||||
if err := db.ReplaceActivitySamples(ctx, activityID, []store.Sample{
|
||||
if err := db.ReplaceActivitySamples(ctx, userID, activityID, []store.Sample{
|
||||
{ElapsedSeconds: 0, HeartRate: &hr},
|
||||
}); err != nil {
|
||||
t.Fatalf("ReplaceActivitySamples: %v", err)
|
||||
@@ -322,19 +323,19 @@ func TestReviewQueueResolve(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestReviewQueue_PaginatesByCursor(t *testing.T) {
|
||||
s, db := newTestServer(t)
|
||||
s, db, userID := newTestServer(t)
|
||||
ctx := newCtx()
|
||||
|
||||
// 5 activities, newest first once sorted: 2026-07-05 .. 2026-07-01.
|
||||
for i := 1; i <= 5; i++ {
|
||||
activityID, err := db.UpsertActivity(ctx, store.Activity{
|
||||
activityID, err := db.UpsertActivity(ctx, userID, store.Activity{
|
||||
GarminActivityID: int64(i),
|
||||
StartTimeUTC: fmt.Sprintf("2026-07-0%d 06:00:00", i), RawJSON: "{}",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("UpsertActivity: %v", err)
|
||||
}
|
||||
if _, err := db.InsertKindAssignment(ctx, store.KindAssignment{
|
||||
if _, err := db.InsertKindAssignment(ctx, userID, store.KindAssignment{
|
||||
ActivityID: activityID, AssignmentSource: store.AssignmentSourceRuleEngine, Status: store.AssignmentStatusNeedsReview,
|
||||
CandidateKindsJSON: "[]",
|
||||
}); err != nil {
|
||||
@@ -400,10 +401,10 @@ func TestReviewQueue_PaginatesByCursor(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestReviewQueue_FiltersByKindAndUnclassifiedStayPaginated(t *testing.T) {
|
||||
s, db := newTestServer(t)
|
||||
s, db, userID := newTestServer(t)
|
||||
ctx := newCtx()
|
||||
|
||||
kinds, err := db.ListWorkoutKinds(ctx, true)
|
||||
kinds, err := db.ListWorkoutKinds(ctx, userID, true)
|
||||
if err != nil || len(kinds) < 2 {
|
||||
t.Fatalf("ListWorkoutKinds: %v (len=%d)", err, len(kinds))
|
||||
}
|
||||
@@ -411,7 +412,7 @@ func TestReviewQueue_FiltersByKindAndUnclassifiedStayPaginated(t *testing.T) {
|
||||
|
||||
// 2 activities assigned to kindA, 1 to kindB, 1 unclassified.
|
||||
makeActivity := func(n int64, kindID *int64) {
|
||||
activityID, err := db.UpsertActivity(ctx, store.Activity{
|
||||
activityID, err := db.UpsertActivity(ctx, userID, store.Activity{
|
||||
GarminActivityID: n,
|
||||
StartTimeUTC: fmt.Sprintf("2026-07-0%d 06:00:00", n), RawJSON: "{}",
|
||||
})
|
||||
@@ -422,7 +423,7 @@ func TestReviewQueue_FiltersByKindAndUnclassifiedStayPaginated(t *testing.T) {
|
||||
if kindID == nil {
|
||||
status = store.AssignmentStatusNeedsReview
|
||||
}
|
||||
if _, err := db.InsertKindAssignment(ctx, store.KindAssignment{
|
||||
if _, err := db.InsertKindAssignment(ctx, userID, store.KindAssignment{
|
||||
ActivityID: activityID, WorkoutKindID: kindID, AssignmentSource: store.AssignmentSourceRuleEngine,
|
||||
Status: status, CandidateKindsJSON: "[]",
|
||||
}); err != nil {
|
||||
@@ -487,14 +488,14 @@ func TestReviewQueue_FiltersByKindAndUnclassifiedStayPaginated(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestResolveReview_RejectsRaceKind(t *testing.T) {
|
||||
s, db := newTestServer(t)
|
||||
s, db, userID := newTestServer(t)
|
||||
ctx := newCtx()
|
||||
|
||||
activityID, err := db.UpsertActivity(ctx, store.Activity{GarminActivityID: 1, StartTimeUTC: "2026-07-11 06:00:00", RawJSON: "{}"})
|
||||
activityID, err := db.UpsertActivity(ctx, userID, store.Activity{GarminActivityID: 1, StartTimeUTC: "2026-07-11 06:00:00", RawJSON: "{}"})
|
||||
if err != nil {
|
||||
t.Fatalf("UpsertActivity: %v", err)
|
||||
}
|
||||
raceKind, ok, err := db.GetWorkoutKindByName(ctx, "Race")
|
||||
raceKind, ok, err := db.GetWorkoutKindByName(ctx, userID, "Race")
|
||||
if err != nil || !ok {
|
||||
t.Fatalf("GetWorkoutKindByName(Race): ok=%v err=%v", ok, err)
|
||||
}
|
||||
@@ -506,35 +507,35 @@ func TestResolveReview_RejectsRaceKind(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestReclassifyAll_SkipsManualAndRaceAssignments(t *testing.T) {
|
||||
s, db := newTestServer(t)
|
||||
s, db, userID := newTestServer(t)
|
||||
ctx := newCtx()
|
||||
|
||||
easyID, err := db.CreateWorkoutKind(ctx, store.WorkoutKind{Name: "Test Easy", RuleJSON: `{"match":"all","conditions":[{"metric":"distance_meters","op":">=","value":0}]}`, IsActive: true})
|
||||
easyID, err := db.CreateWorkoutKind(ctx, userID, store.WorkoutKind{Name: "Test Easy", RuleJSON: `{"match":"all","conditions":[{"metric":"distance_meters","op":">=","value":0}]}`, IsActive: true})
|
||||
if err != nil {
|
||||
t.Fatalf("CreateWorkoutKind: %v", err)
|
||||
}
|
||||
raceKind, ok, err := db.GetWorkoutKindByName(ctx, "Race")
|
||||
raceKind, ok, err := db.GetWorkoutKindByName(ctx, userID, "Race")
|
||||
if err != nil || !ok {
|
||||
t.Fatalf("GetWorkoutKindByName(Race): ok=%v err=%v", ok, err)
|
||||
}
|
||||
|
||||
ruleEngineActivity, _ := db.UpsertActivity(ctx, store.Activity{GarminActivityID: 1, StartTimeUTC: "2026-07-01 06:00:00", RawJSON: "{}"})
|
||||
manualActivity, _ := db.UpsertActivity(ctx, store.Activity{GarminActivityID: 2, StartTimeUTC: "2026-07-02 06:00:00", RawJSON: "{}"})
|
||||
raceActivity, _ := db.UpsertActivity(ctx, store.Activity{GarminActivityID: 3, EventTypeKey: "race", StartTimeUTC: "2026-07-03 06:00:00", RawJSON: "{}"})
|
||||
ruleEngineActivity, _ := db.UpsertActivity(ctx, userID, store.Activity{GarminActivityID: 1, StartTimeUTC: "2026-07-01 06:00:00", RawJSON: "{}"})
|
||||
manualActivity, _ := db.UpsertActivity(ctx, userID, store.Activity{GarminActivityID: 2, StartTimeUTC: "2026-07-02 06:00:00", RawJSON: "{}"})
|
||||
raceActivity, _ := db.UpsertActivity(ctx, userID, store.Activity{GarminActivityID: 3, EventTypeKey: "race", StartTimeUTC: "2026-07-03 06:00:00", RawJSON: "{}"})
|
||||
|
||||
if _, err := db.InsertKindAssignment(ctx, store.KindAssignment{
|
||||
if _, err := db.InsertKindAssignment(ctx, userID, store.KindAssignment{
|
||||
ActivityID: ruleEngineActivity, WorkoutKindID: &easyID, AssignmentSource: store.AssignmentSourceRuleEngine,
|
||||
Status: store.AssignmentStatusAssigned, CandidateKindsJSON: "[]",
|
||||
}); err != nil {
|
||||
t.Fatalf("InsertKindAssignment (rule engine): %v", err)
|
||||
}
|
||||
if _, err := db.InsertKindAssignment(ctx, store.KindAssignment{
|
||||
if _, err := db.InsertKindAssignment(ctx, userID, store.KindAssignment{
|
||||
ActivityID: manualActivity, WorkoutKindID: &easyID, AssignmentSource: store.AssignmentSourceManual,
|
||||
Status: store.AssignmentStatusAssigned, CandidateKindsJSON: "[]",
|
||||
}); err != nil {
|
||||
t.Fatalf("InsertKindAssignment (manual): %v", err)
|
||||
}
|
||||
if _, err := db.InsertKindAssignment(ctx, store.KindAssignment{
|
||||
if _, err := db.InsertKindAssignment(ctx, userID, store.KindAssignment{
|
||||
ActivityID: raceActivity, WorkoutKindID: &raceKind.ID, AssignmentSource: store.AssignmentSourceRuleEngine,
|
||||
Status: store.AssignmentStatusAssigned, CandidateKindsJSON: "[]",
|
||||
}); err != nil {
|
||||
@@ -555,7 +556,7 @@ func TestReclassifyAll_SkipsManualAndRaceAssignments(t *testing.T) {
|
||||
t.Fatalf("reclassified = %d, want 1 (only the non-locked rule-engine activity)", body.Reclassified)
|
||||
}
|
||||
|
||||
manualAssignment, ok, err := db.CurrentAssignment(ctx, manualActivity)
|
||||
manualAssignment, ok, err := db.CurrentAssignment(ctx, userID, manualActivity)
|
||||
if err != nil || !ok {
|
||||
t.Fatalf("CurrentAssignment(manual): ok=%v err=%v", ok, err)
|
||||
}
|
||||
@@ -563,7 +564,7 @@ func TestReclassifyAll_SkipsManualAndRaceAssignments(t *testing.T) {
|
||||
t.Errorf("manual assignment was overwritten: %+v", manualAssignment)
|
||||
}
|
||||
|
||||
raceAssignment, ok, err := db.CurrentAssignment(ctx, raceActivity)
|
||||
raceAssignment, ok, err := db.CurrentAssignment(ctx, userID, raceActivity)
|
||||
if err != nil || !ok {
|
||||
t.Fatalf("CurrentAssignment(race): ok=%v err=%v", ok, err)
|
||||
}
|
||||
@@ -573,25 +574,25 @@ func TestReclassifyAll_SkipsManualAndRaceAssignments(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestListActivities_ReportsLockedForManualAndRaceAssignments(t *testing.T) {
|
||||
s, db := newTestServer(t)
|
||||
s, db, userID := newTestServer(t)
|
||||
ctx := newCtx()
|
||||
|
||||
easyID, err := db.CreateWorkoutKind(ctx, store.WorkoutKind{Name: "Test Easy Locked", RuleJSON: `{"match":"all","conditions":[]}`, IsActive: true})
|
||||
easyID, err := db.CreateWorkoutKind(ctx, userID, store.WorkoutKind{Name: "Test Easy Locked", RuleJSON: `{"match":"all","conditions":[]}`, IsActive: true})
|
||||
if err != nil {
|
||||
t.Fatalf("CreateWorkoutKind: %v", err)
|
||||
}
|
||||
raceKind, ok, err := db.GetWorkoutKindByName(ctx, "Race")
|
||||
raceKind, ok, err := db.GetWorkoutKindByName(ctx, userID, "Race")
|
||||
if err != nil || !ok {
|
||||
t.Fatalf("GetWorkoutKindByName(Race): ok=%v err=%v", ok, err)
|
||||
}
|
||||
|
||||
ruleEngineActivity, _ := db.UpsertActivity(ctx, store.Activity{GarminActivityID: 1, StartTimeUTC: "2026-07-01 06:00:00", RawJSON: "{}"})
|
||||
manualActivity, _ := db.UpsertActivity(ctx, store.Activity{GarminActivityID: 2, StartTimeUTC: "2026-07-02 06:00:00", RawJSON: "{}"})
|
||||
raceActivity, _ := db.UpsertActivity(ctx, store.Activity{GarminActivityID: 3, EventTypeKey: "race", StartTimeUTC: "2026-07-03 06:00:00", RawJSON: "{}"})
|
||||
ruleEngineActivity, _ := db.UpsertActivity(ctx, userID, store.Activity{GarminActivityID: 1, StartTimeUTC: "2026-07-01 06:00:00", RawJSON: "{}"})
|
||||
manualActivity, _ := db.UpsertActivity(ctx, userID, store.Activity{GarminActivityID: 2, StartTimeUTC: "2026-07-02 06:00:00", RawJSON: "{}"})
|
||||
raceActivity, _ := db.UpsertActivity(ctx, userID, store.Activity{GarminActivityID: 3, EventTypeKey: "race", StartTimeUTC: "2026-07-03 06:00:00", RawJSON: "{}"})
|
||||
|
||||
db.InsertKindAssignment(ctx, store.KindAssignment{ActivityID: ruleEngineActivity, WorkoutKindID: &easyID, AssignmentSource: store.AssignmentSourceRuleEngine, Status: store.AssignmentStatusAssigned, CandidateKindsJSON: "[]"})
|
||||
db.InsertKindAssignment(ctx, store.KindAssignment{ActivityID: manualActivity, WorkoutKindID: &easyID, AssignmentSource: store.AssignmentSourceManual, Status: store.AssignmentStatusAssigned, CandidateKindsJSON: "[]"})
|
||||
db.InsertKindAssignment(ctx, store.KindAssignment{ActivityID: raceActivity, WorkoutKindID: &raceKind.ID, AssignmentSource: store.AssignmentSourceRuleEngine, Status: store.AssignmentStatusAssigned, CandidateKindsJSON: "[]"})
|
||||
db.InsertKindAssignment(ctx, userID, store.KindAssignment{ActivityID: ruleEngineActivity, WorkoutKindID: &easyID, AssignmentSource: store.AssignmentSourceRuleEngine, Status: store.AssignmentStatusAssigned, CandidateKindsJSON: "[]"})
|
||||
db.InsertKindAssignment(ctx, userID, store.KindAssignment{ActivityID: manualActivity, WorkoutKindID: &easyID, AssignmentSource: store.AssignmentSourceManual, Status: store.AssignmentStatusAssigned, CandidateKindsJSON: "[]"})
|
||||
db.InsertKindAssignment(ctx, userID, store.KindAssignment{ActivityID: raceActivity, WorkoutKindID: &raceKind.ID, AssignmentSource: store.AssignmentSourceRuleEngine, Status: store.AssignmentStatusAssigned, CandidateKindsJSON: "[]"})
|
||||
|
||||
rec := doJSON(t, s.Router(), http.MethodGet, "/api/activities/", nil)
|
||||
if rec.Code != http.StatusOK {
|
||||
@@ -624,10 +625,10 @@ func TestListActivities_ReportsLockedForManualAndRaceAssignments(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSyncReset_DeletesActivitiesAndBackfillEndpointIsGone(t *testing.T) {
|
||||
s, db := newTestServer(t)
|
||||
s, db, userID := newTestServer(t)
|
||||
ctx := newCtx()
|
||||
|
||||
if _, err := db.UpsertActivity(ctx, store.Activity{GarminActivityID: 1, StartTimeUTC: "2026-07-11 06:00:00", RawJSON: "{}"}); err != nil {
|
||||
if _, err := db.UpsertActivity(ctx, userID, store.Activity{GarminActivityID: 1, StartTimeUTC: "2026-07-11 06:00:00", RawJSON: "{}"}); err != nil {
|
||||
t.Fatalf("UpsertActivity: %v", err)
|
||||
}
|
||||
|
||||
@@ -639,7 +640,7 @@ func TestSyncReset_DeletesActivitiesAndBackfillEndpointIsGone(t *testing.T) {
|
||||
|
||||
deadline := time.Now().Add(2 * time.Second)
|
||||
for {
|
||||
activities, err := db.ListActivities(ctx, store.ActivityFilter{})
|
||||
activities, err := db.ListActivities(ctx, userID, store.ActivityFilter{})
|
||||
if err != nil {
|
||||
t.Fatalf("ListActivities: %v", err)
|
||||
}
|
||||
@@ -660,17 +661,17 @@ func TestSyncReset_DeletesActivitiesAndBackfillEndpointIsGone(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestProgression_ReturnsSortedTimeSeries(t *testing.T) {
|
||||
s, db := newTestServer(t)
|
||||
s, db, userID := newTestServer(t)
|
||||
ctx := newCtx()
|
||||
|
||||
kindID, _ := db.CreateWorkoutKind(ctx, store.WorkoutKind{Name: "Test Kind", RuleJSON: `{}`, IsActive: true})
|
||||
kindID, _ := db.CreateWorkoutKind(ctx, userID, store.WorkoutKind{Name: "Test Kind", RuleJSON: `{}`, IsActive: true})
|
||||
|
||||
speed := 3.0
|
||||
a1, _ := db.UpsertActivity(ctx, store.Activity{GarminActivityID: 1, StartTimeUTC: "2026-07-01 06:00:00", AvgSpeedMps: &speed, RawJSON: "{}"})
|
||||
a2, _ := db.UpsertActivity(ctx, store.Activity{GarminActivityID: 2, StartTimeUTC: "2026-07-05 06:00:00", AvgSpeedMps: &speed, RawJSON: "{}"})
|
||||
a1, _ := db.UpsertActivity(ctx, userID, store.Activity{GarminActivityID: 1, StartTimeUTC: "2026-07-01 06:00:00", AvgSpeedMps: &speed, RawJSON: "{}"})
|
||||
a2, _ := db.UpsertActivity(ctx, userID, store.Activity{GarminActivityID: 2, StartTimeUTC: "2026-07-05 06:00:00", AvgSpeedMps: &speed, RawJSON: "{}"})
|
||||
|
||||
for _, id := range []int64{a2, a1} { // insert out of order on purpose
|
||||
db.InsertKindAssignment(ctx, store.KindAssignment{ActivityID: id, WorkoutKindID: &kindID, AssignmentSource: store.AssignmentSourceManual, Status: store.AssignmentStatusAssigned, CandidateKindsJSON: "[]"})
|
||||
db.InsertKindAssignment(ctx, userID, store.KindAssignment{ActivityID: id, WorkoutKindID: &kindID, AssignmentSource: store.AssignmentSourceManual, Status: store.AssignmentStatusAssigned, CandidateKindsJSON: "[]"})
|
||||
}
|
||||
|
||||
rec := doJSON(t, s.Router(), http.MethodGet, "/api/progression/"+itoa(kindID)+"?metric=pace", nil)
|
||||
@@ -713,7 +714,7 @@ func itoa(v int64) string {
|
||||
}
|
||||
|
||||
func TestProfile_GetDefaultsThenUpdate(t *testing.T) {
|
||||
s, _ := newTestServer(t)
|
||||
s, _, _ := newTestServer(t)
|
||||
router := s.Router()
|
||||
|
||||
rec := doJSON(t, router, http.MethodGet, "/api/profile", nil)
|
||||
@@ -745,7 +746,7 @@ func TestProfile_GetDefaultsThenUpdate(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestProfile_RejectsInvalidHRZones(t *testing.T) {
|
||||
s, _ := newTestServer(t)
|
||||
s, _, _ := newTestServer(t)
|
||||
router := s.Router()
|
||||
|
||||
rec := doJSON(t, router, http.MethodGet, "/api/profile", nil)
|
||||
@@ -764,13 +765,13 @@ func TestProfile_RejectsInvalidHRZones(t *testing.T) {
|
||||
|
||||
func newTestServerWithAuth(t *testing.T, verifier auth.Verifier) (*Server, *store.DB) {
|
||||
t.Helper()
|
||||
s, db := newTestServer(t)
|
||||
s, db, _ := newTestServer(t)
|
||||
s.Auth = verifier
|
||||
return s, db
|
||||
}
|
||||
|
||||
func TestHealth_NoSessionRequired(t *testing.T) {
|
||||
s, _ := newTestServer(t)
|
||||
s, _, _ := newTestServer(t)
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/health", nil)
|
||||
rec := httptest.NewRecorder()
|
||||
s.Router().ServeHTTP(rec, req)
|
||||
@@ -780,7 +781,7 @@ func TestHealth_NoSessionRequired(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestProtectedRoute_RejectsMissingSession(t *testing.T) {
|
||||
s, _ := newTestServer(t)
|
||||
s, _, _ := newTestServer(t)
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/profile/", nil)
|
||||
rec := httptest.NewRecorder()
|
||||
s.Router().ServeHTTP(rec, req)
|
||||
@@ -899,7 +900,7 @@ func TestSessionMe_ReturnsAuthenticatedUser(t *testing.T) {
|
||||
|
||||
func mustServerRouter(t *testing.T) http.Handler {
|
||||
t.Helper()
|
||||
s, _ := newTestServer(t)
|
||||
s, _, _ := newTestServer(t)
|
||||
return s.Router()
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user