212 lines
6.3 KiB
Go
212 lines
6.3 KiB
Go
package lidarrquarantine
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"io"
|
|
"log/slog"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/jackc/pgx/v5/pgxpool"
|
|
|
|
"git.fabledsword.com/bvandeusen/minstrel/internal/db"
|
|
"git.fabledsword.com/bvandeusen/minstrel/internal/db/dbq"
|
|
"git.fabledsword.com/bvandeusen/minstrel/internal/dbtest"
|
|
"git.fabledsword.com/bvandeusen/minstrel/internal/lidarrconfig"
|
|
)
|
|
|
|
func newPool(t *testing.T) *pgxpool.Pool {
|
|
t.Helper()
|
|
if testing.Short() {
|
|
t.Skip("skipping integration test in -short mode")
|
|
}
|
|
dsn := os.Getenv("MINSTREL_TEST_DATABASE_URL")
|
|
if dsn == "" {
|
|
t.Skip("MINSTREL_TEST_DATABASE_URL not set")
|
|
}
|
|
if err := db.Migrate(dsn, slog.New(slog.NewTextHandler(io.Discard, nil))); err != nil {
|
|
t.Fatalf("migrate: %v", err)
|
|
}
|
|
pool, err := pgxpool.New(context.Background(), dsn)
|
|
if err != nil {
|
|
t.Fatalf("pool: %v", err)
|
|
}
|
|
t.Cleanup(pool.Close)
|
|
dbtest.ResetDB(t, pool)
|
|
return pool
|
|
}
|
|
|
|
func seedUser(t *testing.T, pool *pgxpool.Pool, name string) dbq.User {
|
|
t.Helper()
|
|
u, err := dbq.New(pool).CreateUser(context.Background(), dbq.CreateUserParams{
|
|
Username: dbtest.TestUserPrefix + name, PasswordHash: "x",
|
|
ApiToken: name + "-token", IsAdmin: false,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("seed user %s: %v", name, err)
|
|
}
|
|
return u
|
|
}
|
|
|
|
func seedTrack(t *testing.T, pool *pgxpool.Pool, title, mbid string) (dbq.Track, dbq.Album, dbq.Artist) {
|
|
t.Helper()
|
|
q := dbq.New(pool)
|
|
artist, err := q.UpsertArtist(context.Background(), dbq.UpsertArtistParams{
|
|
Name: "Test Artist", SortName: "Test Artist",
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("artist: %v", err)
|
|
}
|
|
albumMBID := mbid + "-album"
|
|
album, err := q.UpsertAlbum(context.Background(), dbq.UpsertAlbumParams{
|
|
Title: "Test Album", SortTitle: "Test Album",
|
|
ArtistID: artist.ID, Mbid: &albumMBID,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("album: %v", err)
|
|
}
|
|
track, err := q.UpsertTrack(context.Background(), dbq.UpsertTrackParams{
|
|
Title: title, AlbumID: album.ID, ArtistID: artist.ID,
|
|
DurationMs: 1000, FilePath: filepath.Join(t.TempDir(), title+".mp3"),
|
|
FileSize: 100, FileFormat: "mp3",
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("track: %v", err)
|
|
}
|
|
return track, album, artist
|
|
}
|
|
|
|
func TestFlag_HappyPath(t *testing.T) {
|
|
pool := newPool(t)
|
|
user := seedUser(t, pool, "alice")
|
|
track, _, _ := seedTrack(t, pool, "Bad Track", "abc")
|
|
|
|
svc := NewService(pool, lidarrconfig.New(pool), nil)
|
|
row, err := svc.Flag(context.Background(), user.ID, track.ID, "bad_rip", "crackly")
|
|
if err != nil {
|
|
t.Fatalf("Flag: %v", err)
|
|
}
|
|
if string(row.Reason) != "bad_rip" {
|
|
t.Errorf("reason = %v", row.Reason)
|
|
}
|
|
if row.Notes == nil || *row.Notes != "crackly" {
|
|
t.Errorf("notes = %v", row.Notes)
|
|
}
|
|
}
|
|
|
|
func TestFlag_UpsertOnSecondFlag(t *testing.T) {
|
|
pool := newPool(t)
|
|
user := seedUser(t, pool, "alice")
|
|
track, _, _ := seedTrack(t, pool, "T", "x")
|
|
|
|
svc := NewService(pool, lidarrconfig.New(pool), nil)
|
|
if _, err := svc.Flag(context.Background(), user.ID, track.ID, "bad_rip", "first"); err != nil {
|
|
t.Fatalf("first flag: %v", err)
|
|
}
|
|
row, err := svc.Flag(context.Background(), user.ID, track.ID, "wrong_tags", "")
|
|
if err != nil {
|
|
t.Fatalf("second flag: %v", err)
|
|
}
|
|
if string(row.Reason) != "wrong_tags" {
|
|
t.Errorf("reason = %v", row.Reason)
|
|
}
|
|
if row.Notes != nil {
|
|
t.Errorf("notes = %v, want nil after empty notes upsert", row.Notes)
|
|
}
|
|
}
|
|
|
|
func TestFlag_BadReasonRejected(t *testing.T) {
|
|
pool := newPool(t)
|
|
user := seedUser(t, pool, "alice")
|
|
track, _, _ := seedTrack(t, pool, "T", "x")
|
|
|
|
svc := NewService(pool, lidarrconfig.New(pool), nil)
|
|
_, err := svc.Flag(context.Background(), user.ID, track.ID, "garbage", "")
|
|
if !errors.Is(err, ErrBadReason) {
|
|
t.Errorf("err = %v, want ErrBadReason", err)
|
|
}
|
|
}
|
|
|
|
func TestUnflag_DeletesRow(t *testing.T) {
|
|
pool := newPool(t)
|
|
user := seedUser(t, pool, "alice")
|
|
track, _, _ := seedTrack(t, pool, "T", "x")
|
|
|
|
svc := NewService(pool, lidarrconfig.New(pool), nil)
|
|
if _, err := svc.Flag(context.Background(), user.ID, track.ID, "bad_rip", ""); err != nil {
|
|
t.Fatalf("Flag: %v", err)
|
|
}
|
|
if err := svc.Unflag(context.Background(), user.ID, track.ID); err != nil {
|
|
t.Fatalf("Unflag: %v", err)
|
|
}
|
|
if err := svc.Unflag(context.Background(), user.ID, track.ID); !errors.Is(err, ErrQuarantineNotFound) {
|
|
t.Errorf("second Unflag err = %v, want ErrQuarantineNotFound", err)
|
|
}
|
|
}
|
|
|
|
func TestListMine_OrderedNewestFirst(t *testing.T) {
|
|
pool := newPool(t)
|
|
user := seedUser(t, pool, "alice")
|
|
t1, _, _ := seedTrack(t, pool, "T1", "x")
|
|
t2, _, _ := seedTrack(t, pool, "T2", "y")
|
|
|
|
svc := NewService(pool, lidarrconfig.New(pool), nil)
|
|
if _, err := svc.Flag(context.Background(), user.ID, t1.ID, "bad_rip", ""); err != nil {
|
|
t.Fatalf("Flag t1: %v", err)
|
|
}
|
|
if _, err := svc.Flag(context.Background(), user.ID, t2.ID, "duplicate", ""); err != nil {
|
|
t.Fatalf("Flag t2: %v", err)
|
|
}
|
|
|
|
rows, err := svc.ListMine(context.Background(), user.ID)
|
|
if err != nil {
|
|
t.Fatalf("ListMine: %v", err)
|
|
}
|
|
if len(rows) != 2 {
|
|
t.Fatalf("len = %d, want 2", len(rows))
|
|
}
|
|
// T2 was flagged second — newest first.
|
|
if rows[0].LidarrQuarantine.TrackID != t2.ID {
|
|
t.Errorf("first row track = %v, want T2 (%v)", rows[0].LidarrQuarantine.TrackID, t2.ID)
|
|
}
|
|
}
|
|
|
|
func TestListAdminQueue_AggregatesByTrackWithReasonCounts(t *testing.T) {
|
|
pool := newPool(t)
|
|
alice := seedUser(t, pool, "alice")
|
|
bob := seedUser(t, pool, "bob")
|
|
carol := seedUser(t, pool, "carol")
|
|
track, _, _ := seedTrack(t, pool, "Hot Mess", "abc")
|
|
|
|
svc := NewService(pool, lidarrconfig.New(pool), nil)
|
|
if _, err := svc.Flag(context.Background(), alice.ID, track.ID, "bad_rip", ""); err != nil {
|
|
t.Fatalf("alice flag: %v", err)
|
|
}
|
|
if _, err := svc.Flag(context.Background(), bob.ID, track.ID, "bad_rip", ""); err != nil {
|
|
t.Fatalf("bob flag: %v", err)
|
|
}
|
|
if _, err := svc.Flag(context.Background(), carol.ID, track.ID, "wrong_tags", ""); err != nil {
|
|
t.Fatalf("carol flag: %v", err)
|
|
}
|
|
|
|
rows, err := svc.ListAdminQueue(context.Background())
|
|
if err != nil {
|
|
t.Fatalf("ListAdminQueue: %v", err)
|
|
}
|
|
if len(rows) != 1 {
|
|
t.Fatalf("len = %d, want 1 aggregated row", len(rows))
|
|
}
|
|
r := rows[0]
|
|
if r.ReportCount != 3 {
|
|
t.Errorf("report_count = %d, want 3", r.ReportCount)
|
|
}
|
|
if r.ReasonCounts["bad_rip"] != 2 || r.ReasonCounts["wrong_tags"] != 1 {
|
|
t.Errorf("reason_counts = %+v, want bad_rip=2 wrong_tags=1", r.ReasonCounts)
|
|
}
|
|
if len(r.Reports) != 3 {
|
|
t.Errorf("reports len = %d, want 3", len(r.Reports))
|
|
}
|
|
}
|