110 lines
2.9 KiB
Go
110 lines
2.9 KiB
Go
package eval
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"testing"
|
|
"time"
|
|
|
|
_ "modernc.org/sqlite"
|
|
)
|
|
|
|
func TestBatch_EmptyInputClosesChannel(t *testing.T) {
|
|
b := &Batch{Concurrency: 3}
|
|
ch := b.Run(context.Background(), nil)
|
|
select {
|
|
case _, ok := <-ch:
|
|
if ok {
|
|
t.Fatal("expected closed channel for empty input")
|
|
}
|
|
case <-time.After(100 * time.Millisecond):
|
|
t.Fatal("channel did not close")
|
|
}
|
|
}
|
|
|
|
func TestBatch_NilClientErrorsEveryJob(t *testing.T) {
|
|
b := &Batch{Concurrency: 2}
|
|
jobs := []JobContext{
|
|
{URL: "https://a", Company: "A", Title: "T"},
|
|
{URL: "https://b", Company: "B", Title: "T"},
|
|
}
|
|
ch := b.Run(context.Background(), jobs)
|
|
var starts, errors int
|
|
for ev := range ch {
|
|
switch ev.Kind {
|
|
case EventStart:
|
|
starts++
|
|
case EventError:
|
|
errors++
|
|
case EventDone:
|
|
t.Fatalf("unexpected EventDone with nil client")
|
|
}
|
|
}
|
|
if starts != 2 || errors != 2 {
|
|
t.Errorf("starts=%d errors=%d, want 2/2", starts, errors)
|
|
}
|
|
}
|
|
|
|
func TestBatch_DemoteBelowMinScore(t *testing.T) {
|
|
db := setupReportDB(t)
|
|
defer db.Close()
|
|
// Seed a job + application row (Evaluated, score=3.0).
|
|
if _, err := db.Exec(`INSERT INTO jobs (url, company, title, source) VALUES (?, ?, ?, ?)`,
|
|
"https://x/1", "Acme", "Engineer", "test"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var jobID int64
|
|
if err := db.QueryRow(`SELECT id FROM jobs WHERE url = ?`, "https://x/1").Scan(&jobID); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
res, err := db.Exec(`INSERT INTO applications (job_id, status, score) VALUES (?, 'Evaluated', 3.0)`, jobID)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
appID, _ := res.LastInsertId()
|
|
|
|
b := &Batch{DB: db, MinScore: 4.0}
|
|
if err := b.demoteBelowScore(context.Background(), appID); err != nil {
|
|
t.Fatalf("demote: %v", err)
|
|
}
|
|
var status string
|
|
if err := db.QueryRow(`SELECT status FROM applications WHERE id = ?`, appID).Scan(&status); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if status != "Discarded" {
|
|
t.Errorf("status = %q, want Discarded", status)
|
|
}
|
|
|
|
// Now set the row to Applied and re-run demote — it must NOT regress.
|
|
if _, err := db.Exec(`UPDATE applications SET status = 'Applied' WHERE id = ?`, appID); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := b.demoteBelowScore(context.Background(), appID); err != nil {
|
|
t.Fatalf("demote#2: %v", err)
|
|
}
|
|
_ = db.QueryRow(`SELECT status FROM applications WHERE id = ?`, appID).Scan(&status)
|
|
if status != "Applied" {
|
|
t.Errorf("user-advanced status must be preserved, got %q", status)
|
|
}
|
|
}
|
|
|
|
// silence unused-import warning when the only test using sql is compiled out.
|
|
var _ = (*sql.DB)(nil)
|
|
|
|
func TestBatch_ContextCanceledBeforeStart(t *testing.T) {
|
|
b := &Batch{Concurrency: 1}
|
|
jobs := []JobContext{{URL: "https://x", Company: "X", Title: "T"}}
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
cancel()
|
|
ch := b.Run(ctx, jobs)
|
|
var errs int
|
|
for ev := range ch {
|
|
if ev.Kind == EventError {
|
|
errs++
|
|
}
|
|
}
|
|
if errs != 1 {
|
|
t.Errorf("expected 1 error from canceled batch, got %d", errs)
|
|
}
|
|
}
|