//go:build integration package dbtest import ( "context" "log/slog" "os" "path/filepath" "testing" "time" "github.com/google/uuid" "github.com/stretchr/testify/require" "pipu/api/internal/library" "pipu/api/internal/platform/db" ) func TestSourceCoverStats(t *testing.T) { pool := connect(t) ctx := context.Background() require.NoError(t, db.Migrate(ctx, pool)) store := library.NewStore(pool) src, err := store.SaveSource(ctx, library.Source{ID: uuid.New(), Name: "cover stats", Type: library.SourceLocal, Status: "mounted", TagsFirst: true, NFSOptions: "ro"}) require.NoError(t, err) t.Cleanup(func() { require.NoError(t, store.DeleteSource(ctx, src.ID)) require.NoError(t, store.CleanupOrphans(ctx)) }) root := t.TempDir() scanner := library.NewScanner(store, fakeProber{}, library.NewProgressBoard(), slog.New(slog.DiscardHandler)) for _, rel := range []string{"covered/StatsArtist - First.flac", "covered/StatsArtist - Second.flac", "external/StatsArtist - Third.flac", "pending/StatsArtist - Fourth.flac"} { file := filepath.Join(root, filepath.FromSlash(rel)) require.NoError(t, os.MkdirAll(filepath.Dir(file), 0o755)) require.NoError(t, os.WriteFile(file, []byte(rel), 0o644)) _, err := scanner.ScanFile(ctx, src, root, rel) require.NoError(t, err) } _, err = pool.Exec(ctx, `UPDATE albums SET cover_path = 'test-key', cover_checked_at = now() WHERE id IN ( SELECT t.album_id FROM tracks t JOIN media_files f ON f.track_id=t.id WHERE f.source_id=$1 AND f.rel_path LIKE 'covered/%')`, src.ID) require.NoError(t, err) _, err = pool.Exec(ctx, `UPDATE albums SET genius_cover_url = 'https://example.org/cover.jpg', cover_checked_at = now() WHERE id IN ( SELECT t.album_id FROM tracks t JOIN media_files f ON f.track_id=t.id WHERE f.source_id=$1 AND f.rel_path LIKE 'external/%')`, src.ID) require.NoError(t, err) stats, err := store.SourceCoverStats(ctx, src.ID) require.NoError(t, err) require.Equal(t, library.CoverStats{FilesTotal: 4, FilesWithCover: 2, AlbumsPending: 1}, stats) // Removed and excluded files leave the denominator as well as the numerator. _, err = pool.Exec(ctx, `UPDATE media_files SET missing_since=$2 WHERE source_id=$1 AND rel_path LIKE '%Second.flac'`, src.ID, time.Now()) require.NoError(t, err) src.ExcludedDirs = []string{"external"} _, err = store.SaveSource(ctx, src) require.NoError(t, err) stats, err = store.SourceCoverStats(ctx, src.ID) require.NoError(t, err) require.Equal(t, library.CoverStats{FilesTotal: 2, FilesWithCover: 1, AlbumsPending: 1}, stats) }