mirror of
https://github.com/sstent/go-garminconnect.git
synced 2026-02-14 19:32:08 +00:00
ficing all the build errors - checkpoint 1
This commit is contained in:
@@ -194,9 +194,10 @@ func (c *Client) GetActivities(ctx context.Context, page int, pageSize int) ([]A
|
|||||||
activities[i] = ar.ToActivity()
|
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 {
|
if len(activities) == 0 {
|
||||||
return nil, nil, fmt.Errorf("no activities found")
|
return activities, &response.Pagination, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
return resp.Body(), nil
|
||||||
}
|
}
|
||||||
@@ -15,47 +15,7 @@ import (
|
|||||||
func TestActivitiesEndpoints(t *testing.T) {
|
func TestActivitiesEndpoints(t *testing.T) {
|
||||||
mockServer := NewMockServer()
|
mockServer := NewMockServer()
|
||||||
defer mockServer.Close()
|
defer mockServer.Close()
|
||||||
client := NewClientWithBaseURL(mockServer.URL())
|
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})
|
|
||||||
})
|
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
@@ -64,19 +24,74 @@ func TestActivitiesEndpoints(t *testing.T) {
|
|||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "GetActivitiesSuccess",
|
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) {
|
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.NoError(t, err)
|
||||||
assert.Len(t, activities, 1)
|
assert.Len(t, activities, 1)
|
||||||
assert.Equal(t, int64(1), activities[0].ActivityID)
|
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",
|
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) {
|
testFunc: func(t *testing.T) {
|
||||||
activity, err := client.GetActivityDetails(context.Background(), 1)
|
activity, err := client.GetActivityDetails(context.Background(), 1)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, int64(1), activity.ActivityID)
|
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() {
|
setup: func() {
|
||||||
mockServer.SetActivitiesHandler(func(w http.ResponseWriter, r *http.Request) {
|
mockServer.SetActivitiesHandler(func(w http.ResponseWriter, r *http.Request) {
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
w.Write([]byte(`{"error": "Internal server error"}`))
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
testFunc: func(t *testing.T) {
|
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) {
|
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.NoError(t, err)
|
||||||
assert.Equal(t, int64(12345), id)
|
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 {
|
for _, tt := range tests {
|
||||||
@@ -111,4 +173,4 @@ func TestActivitiesEndpoints(t *testing.T) {
|
|||||||
tt.testFunc(t)
|
tt.testFunc(t)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -42,30 +42,36 @@ func NewMockServer() *MockServer {
|
|||||||
if m.requestCounters == nil {
|
if m.requestCounters == nil {
|
||||||
m.requestCounters = make(map[string]int)
|
m.requestCounters = make(map[string]int)
|
||||||
}
|
}
|
||||||
|
|
||||||
endpointType := "unknown"
|
endpointType := "unknown"
|
||||||
path := r.URL.Path
|
path := r.URL.Path
|
||||||
|
|
||||||
|
// Route requests to appropriate handlers based on path patterns
|
||||||
switch {
|
switch {
|
||||||
case strings.HasPrefix(path, "/activitylist-service/activities/search") || path == "/activitylist-service/activities":
|
case strings.Contains(path, "/activitylist-service/activities"):
|
||||||
endpointType = "activities"
|
endpointType = "activities"
|
||||||
m.handleActivities(w, r)
|
m.handleActivities(w, r)
|
||||||
case strings.HasPrefix(path, "/activity-service/activities") || path == "/activity-service/activities":
|
case strings.Contains(path, "/activity-service/activity/"):
|
||||||
endpointType = "activities"
|
|
||||||
m.handleActivities(w, r)
|
|
||||||
case strings.HasPrefix(path, "/activity-service/activity/"):
|
|
||||||
endpointType = "activityDetails"
|
endpointType = "activityDetails"
|
||||||
m.handleActivityDetails(w, r)
|
m.handleActivityDetails(w, r)
|
||||||
case strings.HasPrefix(path, "/upload-service/upload") || path == "/upload-service/upload":
|
case strings.Contains(path, "/upload-service/upload"):
|
||||||
endpointType = "upload"
|
endpointType = "upload"
|
||||||
m.handleUpload(w, r)
|
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"
|
endpointType = "user"
|
||||||
m.handleUserData(w, r)
|
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"
|
endpointType = "health"
|
||||||
m.handleHealthData(w, r)
|
m.handleHealthData(w, r)
|
||||||
case strings.HasPrefix(path, "/auth") || path == "/auth":
|
case strings.Contains(path, "/auth") || strings.Contains(path, "/oauth"):
|
||||||
endpointType = "auth"
|
endpointType = "auth"
|
||||||
m.handleAuth(w, r)
|
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:
|
default:
|
||||||
endpointType = "unknown"
|
endpointType = "unknown"
|
||||||
http.Error(w, "Not found", http.StatusNotFound)
|
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
|
// SetResponse sets a standardized response for a specific endpoint
|
||||||
func (m *MockServer) SetResponse(endpoint string, status int, body interface{}) {
|
func (m *MockServer) SetResponse(endpoint string, status int, body interface{}) {
|
||||||
handler := func(w http.ResponseWriter, r *http.Request) {
|
handler := func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.WriteHeader(status)
|
w.WriteHeader(status)
|
||||||
json.NewEncoder(w).Encode(body)
|
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})
|
m.SetResponse(endpoint, status, map[string]string{"error": message})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default handler implementations would follow for each endpoint
|
|
||||||
// ...
|
|
||||||
|
|
||||||
// handleActivities is the default activities endpoint handler
|
// handleActivities is the default activities endpoint handler
|
||||||
func (m *MockServer) handleActivities(w http.ResponseWriter, r *http.Request) {
|
func (m *MockServer) handleActivities(w http.ResponseWriter, r *http.Request) {
|
||||||
if m.activitiesHandler != nil {
|
if m.activitiesHandler != nil {
|
||||||
@@ -189,11 +193,15 @@ func (m *MockServer) handleActivities(w http.ResponseWriter, r *http.Request) {
|
|||||||
{
|
{
|
||||||
ActivityID: 1,
|
ActivityID: 1,
|
||||||
Name: "Morning Run",
|
Name: "Morning Run",
|
||||||
|
Type: "RUNNING",
|
||||||
StartTime: garminTime{time.Now().Add(-24 * time.Hour)},
|
StartTime: garminTime{time.Now().Add(-24 * time.Hour)},
|
||||||
Duration: 3600,
|
Duration: 3600,
|
||||||
Distance: 10.0,
|
Distance: 10.0,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
json.NewEncoder(w).Encode(ActivitiesResponse{
|
json.NewEncoder(w).Encode(ActivitiesResponse{
|
||||||
Activities: activities,
|
Activities: activities,
|
||||||
Pagination: Pagination{
|
Pagination: Pagination{
|
||||||
@@ -233,6 +241,8 @@ func (m *MockServer) handleActivityDetails(w http.ResponseWriter, r *http.Reques
|
|||||||
ElevationGain: 100,
|
ElevationGain: 100,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
json.NewEncoder(w).Encode(activity)
|
json.NewEncoder(w).Encode(activity)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -246,6 +256,7 @@ func (m *MockServer) handleUpload(w http.ResponseWriter, r *http.Request) {
|
|||||||
response := map[string]interface{}{
|
response := map[string]interface{}{
|
||||||
"activityId": 12345,
|
"activityId": 12345,
|
||||||
}
|
}
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.WriteHeader(http.StatusCreated)
|
w.WriteHeader(http.StatusCreated)
|
||||||
json.NewEncoder(w).Encode(response)
|
json.NewEncoder(w).Encode(response)
|
||||||
}
|
}
|
||||||
@@ -261,6 +272,8 @@ func (m *MockServer) handleUserData(w http.ResponseWriter, r *http.Request) {
|
|||||||
"displayName": "Mock User",
|
"displayName": "Mock User",
|
||||||
"email": "mock@example.com",
|
"email": "mock@example.com",
|
||||||
}
|
}
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
json.NewEncoder(w).Encode(user)
|
json.NewEncoder(w).Encode(user)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,6 +292,8 @@ func (m *MockServer) handleHealthData(w http.ResponseWriter, r *http.Request) {
|
|||||||
"quality": 85,
|
"quality": 85,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
json.NewEncoder(w).Encode(data)
|
json.NewEncoder(w).Encode(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -296,6 +311,7 @@ func (m *MockServer) handleAuth(w http.ResponseWriter, r *http.Request) {
|
|||||||
"oauth2_token": "new-mock-token",
|
"oauth2_token": "new-mock-token",
|
||||||
"expires_in": 3600,
|
"expires_in": 3600,
|
||||||
}
|
}
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
json.NewEncoder(w).Encode(response)
|
json.NewEncoder(w).Encode(response)
|
||||||
return
|
return
|
||||||
@@ -303,14 +319,31 @@ func (m *MockServer) handleAuth(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
// Simulate successful authentication
|
// Simulate successful authentication
|
||||||
response := map[string]interface{}{
|
response := map[string]interface{}{
|
||||||
"oauth2_token": "mock-access-token",
|
"oauth2_token": "mock-access-token",
|
||||||
"refresh_token": "mock-refresh-token",
|
"refresh_token": "mock-refresh-token",
|
||||||
"expires_in": 3600,
|
"expires_in": 3600,
|
||||||
}
|
}
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
json.NewEncoder(w).Encode(response)
|
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
|
// NewClientWithBaseURL creates a test client that uses the mock server's URL
|
||||||
func NewClientWithBaseURL(baseURL string) *Client {
|
func NewClientWithBaseURL(baseURL string) *Client {
|
||||||
session := &garth.Session{
|
session := &garth.Session{
|
||||||
@@ -323,4 +356,4 @@ func NewClientWithBaseURL(baseURL string) *Client {
|
|||||||
}
|
}
|
||||||
client.HTTPClient.SetBaseURL(baseURL)
|
client.HTTPClient.SetBaseURL(baseURL)
|
||||||
return client
|
return client
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user