From c33a8a3c986291302acc77ae443d76fda33c3068 Mon Sep 17 00:00:00 2001 From: sstent Date: Thu, 28 Aug 2025 12:27:05 -0700 Subject: [PATCH] ficing all the build errors - checkpoint 1 --- internal/api/activities.go | 7 +- internal/api/activities_test.go | 152 ++++++++++++++++++++++--------- internal/api/mock_server_test.go | 63 ++++++++++--- 3 files changed, 159 insertions(+), 63 deletions(-) diff --git a/internal/api/activities.go b/internal/api/activities.go index 39a05b3..f04a215 100644 --- a/internal/api/activities.go +++ b/internal/api/activities.go @@ -194,9 +194,10 @@ func (c *Client) GetActivities(ctx context.Context, page int, pageSize int) ([]A activities[i] = ar.ToActivity() } - // Validate we received some activities + // Return empty slice if no activities found, but don't treat as error + // The pagination info will indicate totalCount = 0 if len(activities) == 0 { - return nil, nil, fmt.Errorf("no activities found") + return activities, &response.Pagination, nil } return activities, &response.Pagination, nil @@ -292,4 +293,4 @@ func (c *Client) DownloadActivity(ctx context.Context, activityID int64) ([]byte } return resp.Body(), nil -} +} \ No newline at end of file diff --git a/internal/api/activities_test.go b/internal/api/activities_test.go index ce8e783..8bcf05b 100644 --- a/internal/api/activities_test.go +++ b/internal/api/activities_test.go @@ -15,47 +15,7 @@ import ( func TestActivitiesEndpoints(t *testing.T) { mockServer := NewMockServer() defer mockServer.Close() - client := NewClientWithBaseURL(mockServer.URL()) - - // Setup standard mock handlers - mockServer.SetActivitiesHandler(func(w http.ResponseWriter, r *http.Request) { - activities := []ActivityResponse{{ - ActivityID: 1, - Name: "Morning Run", - }} - json.NewEncoder(w).Encode(ActivitiesResponse{ - Activities: activities, - Pagination: Pagination{Page: 1, PageSize: 10, TotalCount: 1}, - }) - }) - - mockServer.SetActivityDetailsHandler(func(w http.ResponseWriter, r *http.Request) { - pathParts := strings.Split(r.URL.Path, "/") - if len(pathParts) < 2 { - w.WriteHeader(http.StatusNotFound) - return - } - - activityID, err := strconv.ParseInt(pathParts[len(pathParts)-1], 10, 64) - if err != nil { - w.WriteHeader(http.StatusBadRequest) - return - } - - json.NewEncoder(w).Encode(ActivityDetailResponse{ - ActivityResponse: ActivityResponse{ - ActivityID: activityID, - Name: "Mock Activity", - Type: "RUNNING", - StartTime: garminTime{time.Now().Add(-24 * time.Hour)}, - }, - }) - }) - - mockServer.SetUploadHandler(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusCreated) - json.NewEncoder(w).Encode(map[string]interface{}{"activityId": 12345}) - }) + client := NewClientWithBaseURL(mockServer.URL) tests := []struct { name string @@ -64,19 +24,74 @@ func TestActivitiesEndpoints(t *testing.T) { }{ { name: "GetActivitiesSuccess", + setup: func() { + mockServer.SetActivitiesHandler(func(w http.ResponseWriter, r *http.Request) { + activities := []ActivityResponse{{ + ActivityID: 1, + Name: "Morning Run", + Type: "RUNNING", + StartTime: garminTime{time.Now().Add(-24 * time.Hour)}, + Duration: 3600, + Distance: 10.0, + }} + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(ActivitiesResponse{ + Activities: activities, + Pagination: Pagination{Page: 1, PageSize: 10, TotalCount: 1}, + }) + }) + }, testFunc: func(t *testing.T) { - activities, _, err := client.GetActivities(context.Background(), 1, 10) + activities, pagination, err := client.GetActivities(context.Background(), 1, 10) assert.NoError(t, err) assert.Len(t, activities, 1) assert.Equal(t, int64(1), activities[0].ActivityID) + assert.Equal(t, "Morning Run", activities[0].Name) + assert.NotNil(t, pagination) + assert.Equal(t, 1, pagination.TotalCount) }, }, { name: "GetActivityDetailsSuccess", + setup: func() { + mockServer.SetActivityDetailsHandler(func(w http.ResponseWriter, r *http.Request) { + pathParts := strings.Split(r.URL.Path, "/") + if len(pathParts) < 2 { + w.WriteHeader(http.StatusNotFound) + return + } + + activityID, err := strconv.ParseInt(pathParts[len(pathParts)-1], 10, 64) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + return + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(ActivityDetailResponse{ + ActivityResponse: ActivityResponse{ + ActivityID: activityID, + Name: "Mock Activity", + Type: "RUNNING", + StartTime: garminTime{time.Now().Add(-24 * time.Hour)}, + Duration: 3600, + Distance: 10.0, + }, + Calories: 500, + AverageHR: 150, + MaxHR: 170, + ElevationGain: 100, + }) + }) + }, testFunc: func(t *testing.T) { activity, err := client.GetActivityDetails(context.Background(), 1) assert.NoError(t, err) assert.Equal(t, int64(1), activity.ActivityID) + assert.Equal(t, "Mock Activity", activity.Name) + assert.Equal(t, float64(500), activity.Calories) }, }, { @@ -84,6 +99,7 @@ func TestActivitiesEndpoints(t *testing.T) { setup: func() { mockServer.SetActivitiesHandler(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(`{"error": "Internal server error"}`)) }) }, testFunc: func(t *testing.T) { @@ -93,13 +109,59 @@ func TestActivitiesEndpoints(t *testing.T) { }, }, { - name: "UploadActivitySuccess", + name: "GetActivitiesEmptyResponse", + setup: func() { + mockServer.SetActivitiesHandler(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(ActivitiesResponse{ + Activities: []ActivityResponse{}, // Empty activities + Pagination: Pagination{Page: 1, PageSize: 10, TotalCount: 0}, + }) + }) + }, testFunc: func(t *testing.T) { - id, err := client.UploadActivity(context.Background(), []byte("test fit data")) + activities, pagination, err := client.GetActivities(context.Background(), 1, 10) + assert.NoError(t, err) // Should not error when no activities exist + assert.Len(t, activities, 0) + assert.NotNil(t, pagination) + assert.Equal(t, 0, pagination.TotalCount) + }, + }, + { + name: "UploadActivitySuccess", + setup: func() { + mockServer.SetUploadHandler(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusCreated) + json.NewEncoder(w).Encode(map[string]interface{}{"activityId": 12345}) + }) + }, + testFunc: func(t *testing.T) { + // Create a minimal valid FIT file data for testing + fitData := make([]byte, 20) + fitData[0] = 14 // header size + copy(fitData[8:12], []byte(".FIT")) + + id, err := client.UploadActivity(context.Background(), fitData) assert.NoError(t, err) assert.Equal(t, int64(12345), id) }, }, + { + name: "GetActivityDetailsNotFound", + setup: func() { + mockServer.SetActivityDetailsHandler(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusNotFound) + w.Write([]byte(`{"error": "Activity not found"}`)) + }) + }, + testFunc: func(t *testing.T) { + _, err := client.GetActivityDetails(context.Background(), 999) + assert.Error(t, err) + assert.Contains(t, err.Error(), "failed to get activity details") + }, + }, } for _, tt := range tests { @@ -111,4 +173,4 @@ func TestActivitiesEndpoints(t *testing.T) { tt.testFunc(t) }) } -} +} \ No newline at end of file diff --git a/internal/api/mock_server_test.go b/internal/api/mock_server_test.go index 122bbb8..79a799b 100644 --- a/internal/api/mock_server_test.go +++ b/internal/api/mock_server_test.go @@ -42,30 +42,36 @@ func NewMockServer() *MockServer { if m.requestCounters == nil { m.requestCounters = make(map[string]int) } + endpointType := "unknown" path := r.URL.Path + + // Route requests to appropriate handlers based on path patterns switch { - case strings.HasPrefix(path, "/activitylist-service/activities/search") || path == "/activitylist-service/activities": + case strings.Contains(path, "/activitylist-service/activities"): endpointType = "activities" m.handleActivities(w, r) - case strings.HasPrefix(path, "/activity-service/activities") || path == "/activity-service/activities": - endpointType = "activities" - m.handleActivities(w, r) - case strings.HasPrefix(path, "/activity-service/activity/"): + case strings.Contains(path, "/activity-service/activity/"): endpointType = "activityDetails" m.handleActivityDetails(w, r) - case strings.HasPrefix(path, "/upload-service/upload") || path == "/upload-service/upload": + case strings.Contains(path, "/upload-service/upload"): endpointType = "upload" m.handleUpload(w, r) - case strings.HasPrefix(path, "/user-service/user") || path == "/user-service/user": + case strings.Contains(path, "/userprofile-service") || strings.Contains(path, "/user-service"): endpointType = "user" m.handleUserData(w, r) - case strings.HasPrefix(path, "/health-service") || path == "/health-service": + case strings.Contains(path, "/wellness-service") || strings.Contains(path, "/hrv-service") || strings.Contains(path, "/bodybattery-service"): endpointType = "health" m.handleHealthData(w, r) - case strings.HasPrefix(path, "/auth") || path == "/auth": + case strings.Contains(path, "/auth") || strings.Contains(path, "/oauth"): endpointType = "auth" m.handleAuth(w, r) + case strings.Contains(path, "/body-composition"): + endpointType = "bodycomposition" + m.handleBodyComposition(w, r) + case strings.Contains(path, "/gear-service"): + endpointType = "gear" + m.handleGear(w, r) default: endpointType = "unknown" http.Error(w, "Not found", http.StatusNotFound) @@ -150,6 +156,7 @@ func (m *MockServer) RequestCount(endpoint string) int { // SetResponse sets a standardized response for a specific endpoint func (m *MockServer) SetResponse(endpoint string, status int, body interface{}) { handler := func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") w.WriteHeader(status) json.NewEncoder(w).Encode(body) } @@ -175,9 +182,6 @@ func (m *MockServer) SetErrorResponse(endpoint string, status int, message strin m.SetResponse(endpoint, status, map[string]string{"error": message}) } -// Default handler implementations would follow for each endpoint -// ... - // handleActivities is the default activities endpoint handler func (m *MockServer) handleActivities(w http.ResponseWriter, r *http.Request) { if m.activitiesHandler != nil { @@ -189,11 +193,15 @@ func (m *MockServer) handleActivities(w http.ResponseWriter, r *http.Request) { { ActivityID: 1, Name: "Morning Run", + Type: "RUNNING", StartTime: garminTime{time.Now().Add(-24 * time.Hour)}, Duration: 3600, Distance: 10.0, }, } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(ActivitiesResponse{ Activities: activities, Pagination: Pagination{ @@ -233,6 +241,8 @@ func (m *MockServer) handleActivityDetails(w http.ResponseWriter, r *http.Reques ElevationGain: 100, } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(activity) } @@ -246,6 +256,7 @@ func (m *MockServer) handleUpload(w http.ResponseWriter, r *http.Request) { response := map[string]interface{}{ "activityId": 12345, } + w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) json.NewEncoder(w).Encode(response) } @@ -261,6 +272,8 @@ func (m *MockServer) handleUserData(w http.ResponseWriter, r *http.Request) { "displayName": "Mock User", "email": "mock@example.com", } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(user) } @@ -279,6 +292,8 @@ func (m *MockServer) handleHealthData(w http.ResponseWriter, r *http.Request) { "quality": 85, }, } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(data) } @@ -296,6 +311,7 @@ func (m *MockServer) handleAuth(w http.ResponseWriter, r *http.Request) { "oauth2_token": "new-mock-token", "expires_in": 3600, } + w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(response) return @@ -303,14 +319,31 @@ func (m *MockServer) handleAuth(w http.ResponseWriter, r *http.Request) { // Simulate successful authentication response := map[string]interface{}{ - "oauth2_token": "mock-access-token", + "oauth2_token": "mock-access-token", "refresh_token": "mock-refresh-token", - "expires_in": 3600, + "expires_in": 3600, } + w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(response) } +// handleBodyComposition handles body composition requests +func (m *MockServer) handleBodyComposition(w http.ResponseWriter, r *http.Request) { + BodyCompositionHandler(w, r) +} + +// handleGear handles gear service requests +func (m *MockServer) handleGear(w http.ResponseWriter, r *http.Request) { + // Basic gear handler - can be expanded as needed + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(map[string]interface{}{ + "uuid": "test-gear-uuid", + "name": "Test Gear", + }) +} + // NewClientWithBaseURL creates a test client that uses the mock server's URL func NewClientWithBaseURL(baseURL string) *Client { session := &garth.Session{ @@ -323,4 +356,4 @@ func NewClientWithBaseURL(baseURL string) *Client { } client.HTTPClient.SetBaseURL(baseURL) return client -} +} \ No newline at end of file