release / govulncheck (push) Successful in 20s
release / web (push) Successful in 1m20s
release / go (push) Successful in 1m37s
release / integration (push) Successful in 5m15s
release / android (push) Successful in 5m26s
release / Build signed APK (releases and dev) (push) Successful in 5m45s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 16s
release / Verify release artifacts (tag releases only) (push) Skipped
Rewrites the internal/library comment blocks to rule 32. Task, milestone, decision and rule ids are gone; the incidents behind them are restated as the constraint they left (why a file is deleted before its row, why the missing mark is a mark, why duplicates block on duration). Counts and album names from one library are dropped from production comments; test comments keep the names their fixtures use. The tagReadVersion log keeps each version's before and after, without the measurements. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
72 lines
2.4 KiB
Go
72 lines
2.4 KiB
Go
package library
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"log/slog"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"git.fabledsword.com/bvandeusen/minstrel/internal/db/dbq"
|
|
)
|
|
|
|
// The MBID backfills read tags from files, so a track whose file is gone has
|
|
// nothing to give them: they skip it rather than log an "open failed" warning
|
|
// per missing track on every scan.
|
|
func TestMBIDBackfill_SkipsMissingTracks_Integration(t *testing.T) {
|
|
pool := newPool(t)
|
|
ctx := context.Background()
|
|
q := dbq.New(pool)
|
|
dir := t.TempDir()
|
|
|
|
// The album's first track is missing; its second is on disk, untagged.
|
|
gone, album, artist := seedTrack(t, pool, filepath.Join(dir, "gone.mp3"))
|
|
present := filepath.Join(dir, "present.mp3")
|
|
if err := os.WriteFile(present, []byte("not really audio"), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
two := int32(2)
|
|
if _, err := q.UpsertTrack(ctx, dbq.UpsertTrackParams{
|
|
Title: "Present", AlbumID: album.ID, ArtistID: artist.ID, TrackNumber: &two,
|
|
DurationMs: 1000, FilePath: present, FileSize: 100, FileFormat: "mp3",
|
|
}); err != nil {
|
|
t.Fatalf("track: %v", err)
|
|
}
|
|
if _, err := pool.Exec(ctx, "UPDATE tracks SET missing_since = now() WHERE id = $1", gone.ID); err != nil {
|
|
t.Fatalf("mark missing: %v", err)
|
|
}
|
|
|
|
tracks, err := q.ListTracksMissingMbidWithPath(ctx, 100)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(tracks) != 1 || tracks[0].FilePath != present {
|
|
t.Errorf("track backfill lists %+v, want only %s", tracks, present)
|
|
}
|
|
albums, err := q.ListAlbumsMissingMbidWithTrack(ctx, 100)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(albums) != 1 || albums[0].TrackFilePath != present {
|
|
t.Errorf("album backfill reads %+v, want the album via %s", albums, present)
|
|
}
|
|
|
|
// With every track gone, the album has no file to read and is skipped.
|
|
if _, err := pool.Exec(ctx, "UPDATE tracks SET missing_since = now() WHERE album_id = $1", album.ID); err != nil {
|
|
t.Fatalf("mark missing: %v", err)
|
|
}
|
|
var logs bytes.Buffer
|
|
logger := slog.New(slog.NewTextHandler(&logs, nil))
|
|
if res, err := BackfillTrackMBIDs(ctx, pool, logger, -1, nil); err != nil || res.Processed != 0 {
|
|
t.Errorf("track backfill processed %d (err %v), want 0", res.Processed, err)
|
|
}
|
|
if res, err := BackfillMBIDs(ctx, pool, logger, -1, nil); err != nil || res.Processed != 0 {
|
|
t.Errorf("album backfill processed %d (err %v), want 0", res.Processed, err)
|
|
}
|
|
if strings.Contains(logs.String(), "open failed") {
|
|
t.Errorf("a backfill opened a missing file:\n%s", logs.String())
|
|
}
|
|
}
|