package library import ( "context" "errors" "testing" "github.com/google/uuid" "github.com/stretchr/testify/require" "pipu/api/internal/auth" "pipu/api/internal/platform/apperr" ) type scanStoreStub struct{ source Source } func (s scanStoreStub) GetSource(context.Context, uuid.UUID) (Source, error) { return s.source, nil } func (s scanStoreStub) RetryFailedAnalysis(context.Context) (int, error) { return 7, nil } type scanStartFunc func(Source, string, bool) error func (f scanStartFunc) Start(s Source, root string, full bool) error { return f(s, root, full) } func TestScanServiceAuthorizationAndStart(t *testing.T) { id := uuid.New() called := false s := &ScanService{ store: scanStoreStub{Source{ID: id, Status: "mounted"}}, board: NewProgressBoard(), root: func(Source) (string, error) { return "music", nil }, scanner: scanStartFunc(func(src Source, root string, full bool) error { called = true require.Equal(t, id, src.ID) require.Equal(t, "music", root) require.True(t, full) return ErrScanRunning }), } _, err := s.StartScan(context.Background(), id, true) require.Error(t, err) require.False(t, called) ctx := auth.WithPrincipal(context.Background(), auth.Principal{Role: auth.RoleAdmin}) _, err = s.StartScan(ctx, id, true) var problem *apperr.Error require.ErrorAs(t, err, &problem) require.Equal(t, CodeScanRunning, problem.Code) require.True(t, called) } func TestScanServiceDoesNotStartOfflineOrUnresolvedSource(t *testing.T) { s := &ScanService{} // no scanner needed: errors must be returned before IO require.Error(t, s.startScan(Source{Status: "error"}, false)) failure := errors.New("invalid root") s.root = func(Source) (string, error) { return "", failure } require.ErrorIs(t, s.startScan(Source{Status: "mounted"}, false), failure) }