summaryrefslogtreecommitdiff
path: root/internal/service/progress_test.go
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-04-29 17:27:53 +0300
committerPaul Buetow <paul@buetow.org>2026-04-29 17:27:53 +0300
commit916d92b94a1ef0f7482914e210d421cf5e3f02cd (patch)
treeb5a6c3c916a7f2c69594fcfb757ab7f2dec09c50 /internal/service/progress_test.go
parent4d71aabf4feb1dcb9c940926fbcc4285525b1c05 (diff)
feat(n9): Implement MediaService, AdminService, ProgressService, GCWorker
Diffstat (limited to 'internal/service/progress_test.go')
-rw-r--r--internal/service/progress_test.go187
1 files changed, 187 insertions, 0 deletions
diff --git a/internal/service/progress_test.go b/internal/service/progress_test.go
new file mode 100644
index 0000000..4baf03f
--- /dev/null
+++ b/internal/service/progress_test.go
@@ -0,0 +1,187 @@
+package service
+
+import (
+ "context"
+ "errors"
+ "testing"
+
+ "github.com/paul/kiss-media-player/internal/model"
+ "github.com/paul/kiss-media-player/internal/repository"
+)
+
+func TestProgressService_UpdateProgress(t *testing.T) {
+ ctx := context.Background()
+
+ tests := []struct {
+ name string
+ sessionID string
+ userID int64
+ mediaID int64
+ position float64
+ accLastPosition float64
+ accAccumulated float64
+ accCounted bool
+ accErr error
+ upsertProgressErr error
+ upsertAccErr error
+ incrementErr error
+ wantErr bool
+ wantCounted bool
+ }{
+ {
+ name: "fresh accumulator does not reach 60 due to clamp",
+ sessionID: "sess1",
+ userID: 1,
+ mediaID: 10,
+ position: 65,
+ accLastPosition: 0,
+ accAccumulated: 0,
+ accCounted: false,
+ wantCounted: false,
+ },
+ {
+ name: "accumulator reaches 60",
+ sessionID: "sess1",
+ userID: 1,
+ mediaID: 10,
+ position: 12,
+ accLastPosition: 0,
+ accAccumulated: 48,
+ accCounted: false,
+ wantCounted: true,
+ },
+ {
+ name: "delta clamped to 12",
+ sessionID: "sess1",
+ userID: 1,
+ mediaID: 10,
+ position: 20,
+ accLastPosition: 0,
+ accAccumulated: 0,
+ accCounted: false,
+ wantCounted: false,
+ },
+ {
+ name: "negative delta clamped",
+ sessionID: "sess1",
+ userID: 1,
+ mediaID: 10,
+ position: 5,
+ accLastPosition: 10,
+ accAccumulated: 50,
+ accCounted: false,
+ wantCounted: false,
+ },
+ {
+ name: "already counted",
+ sessionID: "sess1",
+ userID: 1,
+ mediaID: 10,
+ position: 10,
+ accLastPosition: 0,
+ accAccumulated: 65,
+ accCounted: true,
+ wantCounted: true,
+ },
+ {
+ name: "upsert progress error",
+ sessionID: "sess1",
+ userID: 1,
+ mediaID: 10,
+ position: 12,
+ accAccumulated: 48,
+ upsertProgressErr: errors.New("boom"),
+ wantErr: true,
+ },
+ {
+ name: "get accumulator error",
+ sessionID: "sess1",
+ userID: 1,
+ mediaID: 10,
+ position: 12,
+ accAccumulated: 48,
+ accErr: errors.New("boom"),
+ wantErr: true,
+ },
+ {
+ name: "upsert accumulator error",
+ sessionID: "sess1",
+ userID: 1,
+ mediaID: 10,
+ position: 12,
+ accAccumulated: 48,
+ upsertAccErr: errors.New("boom"),
+ wantErr: true,
+ },
+ {
+ name: "increment error",
+ sessionID: "sess1",
+ userID: 1,
+ mediaID: 10,
+ position: 12,
+ accAccumulated: 48,
+ incrementErr: errors.New("boom"),
+ wantErr: true,
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ var savedAcc *model.PlaybackAccumulator
+ var incremented int64
+
+ store := &repository.MockStore{
+ PlaybackProgressRepo: repository.MockPlaybackProgressRepo{
+ UpsertProgressFunc: func(ctx context.Context, progress *model.PlaybackProgress) error {
+ return tt.upsertProgressErr
+ },
+ },
+ PlaybackAccumulatorRepo: repository.MockPlaybackAccumulatorRepo{
+ GetAccumulatorFunc: func(ctx context.Context, sessionID string, mediaID int64) (*model.PlaybackAccumulator, error) {
+ if tt.accErr != nil {
+ return nil, tt.accErr
+ }
+ return &model.PlaybackAccumulator{
+ SessionID: sessionID,
+ MediaID: mediaID,
+ LastPosition: tt.accLastPosition,
+ AccumulatedSeconds: tt.accAccumulated,
+ Counted: tt.accCounted,
+ }, nil
+ },
+ UpsertAccumulatorFunc: func(ctx context.Context, acc *model.PlaybackAccumulator) error {
+ savedAcc = acc
+ return tt.upsertAccErr
+ },
+ },
+ MediaRepo: repository.MockMediaRepo{
+ IncrementPlayCountFunc: func(ctx context.Context, id int64) error {
+ incremented = id
+ return tt.incrementErr
+ },
+ },
+ }
+
+ svc := NewProgressService(store, newMockClock())
+ err := svc.UpdateProgress(ctx, tt.sessionID, tt.userID, tt.mediaID, tt.position)
+ if tt.wantErr {
+ if err == nil {
+ t.Fatal("expected error")
+ }
+ return
+ }
+ if err != nil {
+ t.Fatalf("unexpected error: %v", err)
+ }
+ if savedAcc == nil {
+ t.Fatal("expected accumulator saved")
+ }
+ if savedAcc.Counted != tt.wantCounted {
+ t.Fatalf("expected Counted=%v, got %v", tt.wantCounted, savedAcc.Counted)
+ }
+ if tt.wantCounted && !tt.accCounted && incremented != tt.mediaID {
+ t.Fatalf("expected IncrementPlayCount called with %d", tt.mediaID)
+ }
+ })
+ }
+}