diff options
| author | Paul Buetow <paul@buetow.org> | 2026-05-17 21:21:42 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-05-17 21:21:42 +0300 |
| commit | a7fbe6d5008decde1e2402b422300d83d3a3de0e (patch) | |
| tree | 9e4a23c260e417aa34a894c117f3ff4351b68753 /player-server/internal/repository/api_token_test.go | |
| parent | 27562eaf12a112d46986a4e8ec3dfcc342ae4738 (diff) | |
Add api_tokens table, model, and repository
Diffstat (limited to 'player-server/internal/repository/api_token_test.go')
| -rw-r--r-- | player-server/internal/repository/api_token_test.go | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/player-server/internal/repository/api_token_test.go b/player-server/internal/repository/api_token_test.go new file mode 100644 index 0000000..fe1e923 --- /dev/null +++ b/player-server/internal/repository/api_token_test.go @@ -0,0 +1,139 @@ +package repository + +import ( + "context" + "testing" + "time" + + "codeberg.org/snonux/player/internal/model" +) + +func TestSQLite_APITokenRepo(t *testing.T) { + ctx := context.Background() + s := newTestStore(t) + defer s.Close() + + now := time.Date(2026, 5, 17, 12, 0, 0, 0, time.UTC) + userID := mustCreateAPITokenUser(t, ctx, s, "api-user") + otherUserID := mustCreateAPITokenUser(t, ctx, s, "other-api-user") + + expiresAt := now.Add(24 * time.Hour) + firstID, err := s.Create(ctx, &model.APIToken{ + UserID: userID, + TokenHash: "hash-one", + Name: "first token", + ExpiresAt: &expiresAt, + CreatedAt: now, + }) + if err != nil { + t.Fatalf("create first token: %v", err) + } + + got, err := s.GetByHash(ctx, "hash-one") + if err != nil { + t.Fatalf("get by hash: %v", err) + } + if got == nil { + t.Fatal("expected token, got nil") + } + assertAPIToken(t, got, firstID, userID, "hash-one", "first token", nil, &expiresAt, now) + + lastUsedAt := now.Add(time.Hour) + secondID, err := s.Create(ctx, &model.APIToken{ + UserID: userID, + TokenHash: "hash-two", + Name: "second token", + LastUsedAt: &lastUsedAt, + CreatedAt: now.Add(time.Minute), + }) + if err != nil { + t.Fatalf("create second token: %v", err) + } + if _, err := s.Create(ctx, &model.APIToken{ + UserID: otherUserID, + TokenHash: "hash-other", + Name: "other token", + CreatedAt: now.Add(2 * time.Minute), + }); err != nil { + t.Fatalf("create other user token: %v", err) + } + + tokens, err := s.ListByUser(ctx, userID) + if err != nil { + t.Fatalf("list by user: %v", err) + } + if len(tokens) != 2 { + t.Fatalf("expected 2 tokens, got %d", len(tokens)) + } + if tokens[0].ID != secondID || tokens[1].ID != firstID { + t.Fatalf("unexpected list order: %+v", tokens) + } + + touchedAt := now.Add(2 * time.Hour) + if err := s.TouchLastUsed(ctx, firstID, touchedAt); err != nil { + t.Fatalf("touch last used: %v", err) + } + got, err = s.GetByHash(ctx, "hash-one") + if err != nil { + t.Fatalf("get touched token: %v", err) + } + assertTimePtr(t, got.LastUsedAt, &touchedAt, "last used after touch") + + if err := s.DeleteByID(ctx, firstID); err != nil { + t.Fatalf("delete by id: %v", err) + } + got, err = s.GetByHash(ctx, "hash-one") + if err != nil { + t.Fatalf("get deleted token: %v", err) + } + if got != nil { + t.Fatalf("expected deleted token to be nil, got %+v", got) + } +} + +func mustCreateAPITokenUser(t *testing.T, ctx context.Context, s *SQLite, username string) int64 { + t.Helper() + id, err := s.CreateUser(ctx, &model.User{ + Username: username, + PasswordHash: "hash", + CreatedAt: time.Date(2026, 5, 17, 11, 0, 0, 0, time.UTC), + }) + if err != nil { + t.Fatalf("create user %q: %v", username, err) + } + return id +} + +func assertAPIToken(t *testing.T, token *model.APIToken, id, userID int64, tokenHash, name string, lastUsedAt, expiresAt *time.Time, createdAt time.Time) { + t.Helper() + if token.ID != id { + t.Fatalf("expected id %d, got %d", id, token.ID) + } + if token.UserID != userID { + t.Fatalf("expected user id %d, got %d", userID, token.UserID) + } + if token.TokenHash != tokenHash { + t.Fatalf("expected token hash %q, got %q", tokenHash, token.TokenHash) + } + if token.Name != name { + t.Fatalf("expected name %q, got %q", name, token.Name) + } + assertTimePtr(t, token.LastUsedAt, lastUsedAt, "last used") + assertTimePtr(t, token.ExpiresAt, expiresAt, "expires") + if !token.CreatedAt.Equal(createdAt) { + t.Fatalf("expected created at %s, got %s", createdAt, token.CreatedAt) + } +} + +func assertTimePtr(t *testing.T, got, want *time.Time, field string) { + t.Helper() + if got == nil || want == nil { + if got != want { + t.Fatalf("expected %s %v, got %v", field, want, got) + } + return + } + if !got.Equal(*want) { + t.Fatalf("expected %s %s, got %s", field, *want, *got) + } +} |
