feat: complete remaining Go backend modules
This commit is contained in:
1 parent
cea2751dc5
commit
aef5a97165
145 files changed
+18376
-199
No files matched your search
@@ -78,6 +78,135 @@ func TestJobsAdapterUpdateClearsLeaseAndProviderTask(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestJobsAdapterUpdateClearsStaleProviderError(t *testing.T) {
|
||||
now := time.Date(2026, 8, 13, 8, 0, 0, 0, time.UTC)
|
||||
querier := &jobQuerier{rows: &jobRows{rows: [][]any{jobRow(now)}}}
|
||||
database := NewDatabase(Config{Backend: BackendPostgres}, querier)
|
||||
status := jobs.StatusSucceeded
|
||||
|
||||
if _, err := database.UpdateJob(context.Background(), "job-1", jobs.Patch{Status: &status, ClearError: true}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !strings.Contains(querier.query, "error = NULL") {
|
||||
t.Fatalf("update query does not clear stale error: %s", querier.query)
|
||||
}
|
||||
}
|
||||
|
||||
func TestJobsAdapterFencesWorkerUpdateByExpectedStateAndLeaseOwner(t *testing.T) {
|
||||
now := time.Date(2026, 8, 13, 8, 0, 0, 0, time.UTC)
|
||||
querier := &jobQuerier{rows: &jobRows{rows: [][]any{jobRow(now)}}}
|
||||
database := NewDatabase(Config{Backend: BackendPostgres}, querier)
|
||||
status := jobs.StatusSucceeded
|
||||
worker := "worker-1"
|
||||
_, err := database.UpdateJob(context.Background(), "job-1", jobs.Patch{Status: &status, ExpectedStatuses: []jobs.Status{jobs.StatusRunning}, ExpectedLockedBy: &worker})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !strings.Contains(querier.query, "status = ANY(") || !strings.Contains(querier.query, "locked_by =") {
|
||||
t.Fatalf("fenced update query = %s", querier.query)
|
||||
}
|
||||
|
||||
querier.rows = &jobRows{}
|
||||
_, err = database.UpdateJob(context.Background(), "job-1", jobs.Patch{Status: &status, ExpectedStatuses: []jobs.Status{jobs.StatusRunning}, ExpectedLockedBy: &worker})
|
||||
if !errors.Is(err, jobs.ErrTransitionConflict) {
|
||||
t.Fatalf("lost lease error = %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestJobsAdapterActivatesChargedCreationAtomically(t *testing.T) {
|
||||
querier := &jobQuerier{rows: &jobRows{rows: [][]any{{"job-1"}}}}
|
||||
database := NewDatabase(Config{Backend: BackendPostgres}, querier)
|
||||
if err := database.ActivateCreation(context.Background(), "job-1", json.RawMessage(`{"status":"charged"}`)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if querier.query != ActivateJobCreationSQL || !strings.Contains(querier.query, "dispatch_ready_at") {
|
||||
t.Fatalf("activation query = %s", querier.query)
|
||||
}
|
||||
}
|
||||
|
||||
func TestJobsAdapterActivationReplayIsIdempotentForSameBilling(t *testing.T) {
|
||||
querier := &jobQuerier{rows: &jobRows{rows: [][]any{{"job-1"}}}}
|
||||
database := NewDatabase(Config{Backend: BackendPostgres}, querier)
|
||||
billingState := json.RawMessage(`{"status":"charged","ledgerEntryId":"ledger-1"}`)
|
||||
if err := database.ActivateCreation(context.Background(), "job-1", billingState); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
querier.rows = &jobRows{rows: [][]any{{"job-1"}}}
|
||||
if err := database.ActivateCreation(context.Background(), "job-1", billingState); err != nil {
|
||||
t.Fatalf("replay: %v", err)
|
||||
}
|
||||
if !strings.Contains(querier.query, "dispatch_ready_at IS NULL OR billing = $2::jsonb") {
|
||||
t.Fatalf("activation is not idempotent for matching billing: %s", querier.query)
|
||||
}
|
||||
}
|
||||
|
||||
func TestJobsAdapterWritesBillingAndOutputAssetsThroughNarrowStateSeam(t *testing.T) {
|
||||
querier := &jobQuerier{rows: &jobRows{rows: [][]any{{"job-1"}}}}
|
||||
database := NewDatabase(Config{Backend: BackendPostgres}, querier)
|
||||
|
||||
if err := database.WriteBilling(context.Background(), "job-1", json.RawMessage(`{"status":"refunded"}`)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if querier.query != WriteJobBillingSQL || !reflect.DeepEqual(querier.args, []any{"job-1", json.RawMessage(`{"status":"refunded"}`)}) {
|
||||
t.Fatalf("billing query=%q args=%#v", querier.query, querier.args)
|
||||
}
|
||||
|
||||
querier.rows = &jobRows{rows: [][]any{{"job-1"}}}
|
||||
if err := database.WriteOutputAssetIDs(context.Background(), "job-1", []string{"asset-1", "asset-2"}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if querier.query != WriteJobOutputAssetIDsSQL || !reflect.DeepEqual(querier.args, []any{"job-1", []string{"asset-1", "asset-2"}}) {
|
||||
t.Fatalf("outputs query=%q args=%#v", querier.query, querier.args)
|
||||
}
|
||||
}
|
||||
|
||||
func TestJobsAdapterFencesOrchestrationStateWrites(t *testing.T) {
|
||||
querier := &jobQuerier{rows: &jobRows{rows: [][]any{{"job-1"}}}}
|
||||
database := NewDatabase(Config{Backend: BackendPostgres}, querier)
|
||||
if err := database.WriteBillingFenced(context.Background(), "job-1", json.RawMessage(`{"status":"settled"}`), jobs.StatusSucceeded, "worker-1"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if querier.query != WriteJobBillingFencedSQL || !reflect.DeepEqual(querier.args, []any{"job-1", json.RawMessage(`{"status":"settled"}`), "succeeded", "worker-1"}) {
|
||||
t.Fatalf("query=%q args=%#v", querier.query, querier.args)
|
||||
}
|
||||
querier.rows = &jobRows{}
|
||||
if err := database.WriteOutputAssetIDsFenced(context.Background(), "job-1", []string{"asset"}, jobs.StatusSucceeded, "worker-1"); !errors.Is(err, jobs.ErrTransitionConflict) {
|
||||
t.Fatalf("lost lease error=%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestJobsAdapterPersistsFailedCreationAtomically(t *testing.T) {
|
||||
querier := &jobQuerier{rows: &jobRows{rows: [][]any{{"job-1"}}}}
|
||||
database := NewDatabase(Config{Backend: BackendPostgres}, querier)
|
||||
job := jobs.Job{
|
||||
ID: "job-1", Status: jobs.StatusFailed,
|
||||
Error: &jobs.JobError{Message: "generation charge failed"},
|
||||
Billing: json.RawMessage(`{"status":"not_charged"}`),
|
||||
}
|
||||
|
||||
if err := database.FailCreation(context.Background(), job); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if querier.query != FailJobCreationSQL {
|
||||
t.Fatalf("query=%q", querier.query)
|
||||
}
|
||||
if len(querier.args) != 4 || querier.args[0] != "job-1" || querier.args[1] != string(jobs.StatusFailed) ||
|
||||
!reflect.DeepEqual(querier.args[2], json.RawMessage(`{"message":"generation charge failed"}`)) ||
|
||||
!reflect.DeepEqual(querier.args[3], job.Billing) {
|
||||
t.Fatalf("args=%#v", querier.args)
|
||||
}
|
||||
}
|
||||
|
||||
func TestJobsAdapterStateWritesFailWhenJobIsMissing(t *testing.T) {
|
||||
database := NewDatabase(Config{Backend: BackendPostgres}, &jobQuerier{rows: &jobRows{}})
|
||||
if err := database.WriteBilling(context.Background(), "missing", json.RawMessage(`{}`)); err == nil {
|
||||
t.Fatal("WriteBilling error=nil")
|
||||
}
|
||||
if err := database.WriteOutputAssetIDs(context.Background(), "missing", []string{}); err == nil {
|
||||
t.Fatal("WriteOutputAssetIDs error=nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestJobsAdapterFailsClosedWithoutPostgres(t *testing.T) {
|
||||
database := NewDatabase(Config{Backend: BackendLocal}, nil)
|
||||
if _, err := database.ClaimJobs(context.Background(), "worker", 1, 300); err == nil {
|
||||
@@ -91,9 +220,9 @@ func TestJobsAdapterFailsClosedWithoutPostgres(t *testing.T) {
|
||||
func jobRow(now time.Time) []any {
|
||||
return []any{
|
||||
"job-1", "api:client", "client", "image.generate", "mock", "fixture", "queued", "prompt",
|
||||
[]string{}, []string{}, []string{}, nil, []byte(`{"input":true}`), nil, nil, nil,
|
||||
[]string{}, []string{}, []string{}, nil, nil, []byte(`{"input":true}`), nil, nil, nil,
|
||||
"idem-1", "fingerprint", 5, 0, 3, now, nil, nil, nil, nil, "https://hooks.example.test", 0,
|
||||
nil, []byte(`{"source":"api","accountId":"client","displayName":"client"}`), nil, now, now,
|
||||
nil, []byte(`{"source":"api","accountId":"client","displayName":"client"}`), nil, now, nil, now, now,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,8 +264,12 @@ func (rows *jobRows) Scan(dest ...any) error {
|
||||
}
|
||||
case *int:
|
||||
*target = value.(int)
|
||||
case *int64:
|
||||
*target = value.(int64)
|
||||
case *time.Time:
|
||||
*target = value.(time.Time)
|
||||
if value != nil {
|
||||
*target = value.(time.Time)
|
||||
}
|
||||
case *sql.NullString:
|
||||
if value != nil {
|
||||
*target = sql.NullString{String: value.(string), Valid: true}
|
||||
@@ -151,6 +284,8 @@ func (rows *jobRows) Scan(dest ...any) error {
|
||||
if value != nil {
|
||||
*target = append([]byte(nil), value.([]byte)...)
|
||||
}
|
||||
case *any:
|
||||
*target = value
|
||||
default:
|
||||
return errors.New("unsupported scan target")
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user