fix(library): expose scan activity and failed analysis file details
ci / api / api (push) Successful in 55s
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 1m6s
ci / db / db (push) Successful in 52s
ci / mobile / mobile (Metro-бандл Android) (push) Successful in 1m38s
release / android (APK в релиз) (push) Successful in 3m50s
ci / ts / ts (packages + web) (push) Successful in 3m20s
release / release (версия и заметки) (push) Successful in 5s
release / desktop (Linux и Windows в релиз) (push) Successful in 44m45s
release / prune (старые файлы и прогоны) (push) Successful in 7s
ci / api / api (push) Successful in 55s
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 1m6s
ci / db / db (push) Successful in 52s
ci / mobile / mobile (Metro-бандл Android) (push) Successful in 1m38s
release / android (APK в релиз) (push) Successful in 3m50s
ci / ts / ts (packages + web) (push) Successful in 3m20s
release / release (версия и заметки) (push) Successful in 5s
release / desktop (Linux и Windows в релиз) (push) Successful in 44m45s
release / prune (старые файлы и прогоны) (push) Successful in 7s
This commit is contained in:
1 parent
17b6dd2041
commit
0dc0384c78
20 files changed
+1114
-326
No files matched your search
@@ -0,0 +1,90 @@
|
||||
//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 TestLibraryDiagnostics(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: "diagnostics", 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))
|
||||
})
|
||||
before, err := store.Counts(ctx)
|
||||
require.NoError(t, err)
|
||||
badID, err := store.SaveFile(ctx, src.ID, uuid.Nil, library.FileData{RelPath: "broken.mp3", Mtime: time.Now(), ScanError: "invalid audio"}, nil)
|
||||
require.NoError(t, err)
|
||||
counts, err := store.Counts(ctx)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, before.Errors+1, counts.Errors)
|
||||
require.NoError(t, store.MarkMissing(ctx, []uuid.UUID{badID}, time.Now()))
|
||||
counts, err = store.Counts(ctx)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, before.Errors, counts.Errors)
|
||||
fileErrors, err := store.FileErrors(ctx, "", 200)
|
||||
require.NoError(t, err)
|
||||
for _, item := range fileErrors {
|
||||
require.NotEqual(t, badID, item.ID, "absent files must not remain in read errors")
|
||||
}
|
||||
// Failed analysis jobs retain their place in diagnostics even without a file.
|
||||
root := t.TempDir()
|
||||
scanner := library.NewScanner(store, fakeProber{}, library.NewProgressBoard(), slog.New(slog.DiscardHandler))
|
||||
tracks := map[uuid.UUID]bool{}
|
||||
for _, name := range []string{"Artist - First.flac", "Artist - Second.flac"} {
|
||||
require.NoError(t, os.WriteFile(filepath.Join(root, name), []byte(name), 0o644))
|
||||
fileID, err := scanner.ScanFile(ctx, src, root, name)
|
||||
require.NoError(t, err)
|
||||
var trackID uuid.UUID
|
||||
require.NoError(t, pool.QueryRow(ctx, `SELECT track_id FROM media_files WHERE id = $1`, fileID).Scan(&trackID))
|
||||
tracks[trackID] = true
|
||||
_, err = pool.Exec(ctx, `UPDATE analysis_jobs SET status = 'failed', error = 'audio is shorter than 1 s' WHERE track_id = $1`, trackID)
|
||||
require.NoError(t, err)
|
||||
if name == "Artist - Second.flac" {
|
||||
_, err = pool.Exec(ctx, `DELETE FROM media_files WHERE id = $1`, fileID)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
}
|
||||
var paths, missing int
|
||||
after := uuid.Nil
|
||||
for {
|
||||
page, err := store.AnalysisErrors(ctx, after, 1)
|
||||
require.NoError(t, err)
|
||||
if len(page) == 0 {
|
||||
break
|
||||
}
|
||||
item := page[0]
|
||||
require.NotEqual(t, after, item.TrackID, "pagination must advance")
|
||||
after = item.TrackID
|
||||
if !tracks[item.TrackID] {
|
||||
continue
|
||||
}
|
||||
require.Equal(t, "audio is shorter than 1 s", item.Error)
|
||||
if item.RelPath == nil {
|
||||
missing++
|
||||
} else {
|
||||
paths++
|
||||
require.Equal(t, "Artist - First.flac", *item.RelPath)
|
||||
require.Equal(t, src.ID, *item.SourceID)
|
||||
}
|
||||
}
|
||||
require.Equal(t, 1, paths)
|
||||
require.Equal(t, 1, missing)
|
||||
}
|
||||
Reference in new issue
Block a user