feat: add profile REST endpoints with HR zone validation
Implements GET /api/profile and PUT /api/profile endpoints with validation of HR zones (must be contiguous, non-overlapping, 0-100%). Also updates profile migration to use correct HR zone defaults (0-20, 20-40, etc.) that match validation requirements. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -185,3 +185,53 @@ func TestProgression_ReturnsSortedTimeSeries(t *testing.T) {
|
||||
func itoa(v int64) string {
|
||||
return strconv.FormatInt(v, 10)
|
||||
}
|
||||
|
||||
func TestProfile_GetDefaultsThenUpdate(t *testing.T) {
|
||||
s, _ := newTestServer(t)
|
||||
router := s.Router()
|
||||
|
||||
rec := doJSON(t, router, http.MethodGet, "/api/profile", nil)
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("get status = %d, body = %s", rec.Code, rec.Body.String())
|
||||
}
|
||||
var got store.Profile
|
||||
if err := json.Unmarshal(rec.Body.Bytes(), &got); err != nil {
|
||||
t.Fatalf("unmarshal: %v", err)
|
||||
}
|
||||
if got.RollingWindowDays != 90 {
|
||||
t.Fatalf("RollingWindowDays = %d, want 90", got.RollingWindowDays)
|
||||
}
|
||||
|
||||
got.GarminEmail = "runner@example.com"
|
||||
got.GarminPassword = "hunter2"
|
||||
got.RollingWindowDays = 120
|
||||
rec = doJSON(t, router, http.MethodPut, "/api/profile", got)
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("put status = %d, body = %s", rec.Code, rec.Body.String())
|
||||
}
|
||||
|
||||
rec = doJSON(t, router, http.MethodGet, "/api/profile", nil)
|
||||
var updated store.Profile
|
||||
json.Unmarshal(rec.Body.Bytes(), &updated)
|
||||
if updated.GarminEmail != "runner@example.com" || updated.RollingWindowDays != 120 {
|
||||
t.Fatalf("updated = %+v, want new email/window", updated)
|
||||
}
|
||||
}
|
||||
|
||||
func TestProfile_RejectsInvalidHRZones(t *testing.T) {
|
||||
s, _ := newTestServer(t)
|
||||
router := s.Router()
|
||||
|
||||
rec := doJSON(t, router, http.MethodGet, "/api/profile", nil)
|
||||
var p store.Profile
|
||||
json.Unmarshal(rec.Body.Bytes(), &p)
|
||||
|
||||
maxHR, restingHR := 100.0, 150.0 // resting > max: invalid
|
||||
p.MaxHeartRate = &maxHR
|
||||
p.RestingHeartRate = &restingHR
|
||||
|
||||
rec = doJSON(t, router, http.MethodPut, "/api/profile", p)
|
||||
if rec.Code != http.StatusBadRequest {
|
||||
t.Fatalf("status = %d, want 400, body = %s", rec.Code, rec.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user