package store import ( "context" "errors" "testing" "github.com/jackc/pgx/v5" ) func completeTestJob(t *testing.T, s *Store, id string) Job { t.Helper() ctx := context.Background() job, _, err := s.Enqueue(ctx, sampleEpisode(id), "manual") if err != nil { t.Fatal(err) } claimed, err := s.ClaimNext(ctx) if err != nil || claimed.ID != job.ID { t.Fatalf("claim: %+v %v", claimed, err) } if err := s.Complete(ctx, job.ID, "番組/video.mp4", 1234); err != nil { t.Fatal(err) } result, err := s.GetSucceededJob(ctx, job.ID) if err != nil { t.Fatal(err) } return result } func TestLibraryStoreOperations(t *testing.T) { s := New(testPool(t, true)) ctx := context.Background() first := completeTestJob(t, s, "library-1") second := completeTestJob(t, s, "library-2") jobs, err := s.ListSucceededJobs(ctx, 1) if err != nil || len(jobs) != 1 || jobs[0].ID != second.ID { t.Fatalf("完了一覧: %+v %v", jobs, err) } if first.FilePath == nil || *first.FilePath != "番組/video.mp4" || first.FileSizeBytes == nil || *first.FileSizeBytes != 1234 || first.FinishedAt == nil { t.Fatalf("完了情報: %+v", first) } queued, _, err := s.Enqueue(ctx, sampleEpisode("not-finished"), "manual") if err != nil { t.Fatal(err) } if _, err := s.GetSucceededJob(ctx, queued.ID); !errors.Is(err, pgx.ErrNoRows) { t.Fatalf("未完了の取得: %v", err) } if err := s.DeleteSucceededJob(ctx, queued.ID); !errors.Is(err, ErrInvalidTransition) { t.Fatalf("未完了の削除: %v", err) } if err := s.DeleteSucceededJob(ctx, first.ID); err != nil { t.Fatal(err) } if _, err := s.GetJob(ctx, first.ID); !errors.Is(err, pgx.ErrNoRows) { t.Fatalf("削除後の取得: %v", err) } if err := s.DeleteSucceededJob(ctx, first.ID); !errors.Is(err, ErrInvalidTransition) { t.Fatalf("再削除: %v", err) } if _, err := s.ListSucceededJobs(ctx, 0); err == nil { t.Fatal("0件の上限を許した") } } func TestDeleteSucceededJobKeepsKnownEpisodeAndAllowsManualRequeue(t *testing.T) { s := New(testPool(t, true)) ctx := context.Background() ep := seriesEpisode("known-library", "known-series") created, err := s.RegisterSubscription(ctx, "known-series", "番組", []Episode{ep}, false) if err != nil || !created { t.Fatalf("番組登録: %t %v", created, err) } job, created, err := s.Enqueue(ctx, ep, "manual") if err != nil || !created { t.Fatalf("手動投入: %+v %t %v", job, created, err) } claimed, err := s.ClaimNext(ctx) if err != nil || claimed.ID != job.ID { t.Fatalf("取得: %+v %v", claimed, err) } if err := s.Complete(ctx, job.ID, "番組/video.mp4", 10); err != nil { t.Fatal(err) } if err := s.DeleteSucceededJob(ctx, job.ID); err != nil { t.Fatal(err) } unknown, err := s.UnknownEpisodeIDs(ctx, "known-series", []string{ep.ID}) if err != nil || len(unknown) != 0 { t.Fatalf("削除後の既知記録: %v %v", unknown, err) } requeued, created, err := s.Enqueue(ctx, ep, "manual") if err != nil || !created || requeued.Status != "queued" || requeued.Source != "manual" { t.Fatalf("削除後の手動再投入: %+v %t %v", requeued, created, err) } }