Files

115 lines
3.2 KiB
Go
Raw Permalink Normal View History

// MockClient support: a fake Client for tests and frontend/dev
// work without a live Garmin account or the wrapper subprocess.
package garmin
import (
"context"
"time"
)
// MockClient is a fake Client returning data supplied by the test/caller.
type MockClient struct {
AuthResults []AuthResult // consumed in order by Authenticate/CompleteMFA calls
Activities []Activity
Splits map[int64]ActivitySplits
Details map[int64]ActivityDetails
Workouts map[int64]Workout
// WorkoutErrByID, if set for a given workout ID, makes GetWorkoutByID
// return that error for that ID specifically -- independent of the
// all-calls-fail Err field below -- so a test can simulate one
// activity's workout fetch failing while others in the same batch
// succeed.
WorkoutErrByID map[int64]error
// Delay, if set, is slept (ctx-cancellable) at the start of every
// GetActivities call -- lets a test give sync.Service's discovering
// phase (backfillCore/incrementalSyncCore) real wall-clock duration, so
// a concurrent goroutine can observe Progress() mid-flight instead of
// the call returning instantly.
Delay time.Duration
Err error // if set, every call returns this error
authResultCursor int
ClosedCalled bool
GetActivitiesCalls int
AuthenticateCalls int
LastEmail string
LastPassword string
}
var _ Client = (*MockClient)(nil)
func (c *MockClient) nextAuthResult() AuthResult {
if c.authResultCursor >= len(c.AuthResults) {
return AuthResult{Status: AuthSuccess, Message: "Authenticated successfully."}
}
r := c.AuthResults[c.authResultCursor]
c.authResultCursor++
return r
}
func (c *MockClient) Authenticate(ctx context.Context) (AuthResult, error) {
c.AuthenticateCalls++
if c.Err != nil {
return AuthResult{}, c.Err
}
return c.nextAuthResult(), nil
}
func (c *MockClient) CompleteMFA(ctx context.Context, code string) (AuthResult, error) {
if c.Err != nil {
return AuthResult{}, c.Err
}
return c.nextAuthResult(), nil
}
func (c *MockClient) GetActivities(ctx context.Context, startDate, endDate string, limit int) ([]Activity, error) {
c.GetActivitiesCalls++
if c.Delay > 0 {
select {
case <-ctx.Done():
return nil, ctx.Err()
case <-time.After(c.Delay):
}
}
if c.Err != nil {
return nil, c.Err
}
if limit > 0 && limit < len(c.Activities) {
return c.Activities[:limit], nil
}
return c.Activities, nil
}
func (c *MockClient) GetActivitySplits(ctx context.Context, activityID int64) (ActivitySplits, error) {
if c.Err != nil {
return ActivitySplits{}, c.Err
}
return c.Splits[activityID], nil
}
func (c *MockClient) GetActivityDetails(ctx context.Context, activityID int64) (ActivityDetails, error) {
if c.Err != nil {
return ActivityDetails{}, c.Err
}
return c.Details[activityID], nil
}
func (c *MockClient) GetWorkoutByID(ctx context.Context, workoutID int64) (Workout, error) {
if c.Err != nil {
return Workout{}, c.Err
}
if err, ok := c.WorkoutErrByID[workoutID]; ok {
return Workout{}, err
}
return c.Workouts[workoutID], nil
}
func (c *MockClient) UpdateCredentials(email, password string) {
c.LastEmail = email
c.LastPassword = password
}
func (c *MockClient) Close() error {
c.ClosedCalled = true
return nil
}