package worker import ( "context" "path/filepath" "sync/atomic" "testing" "time" "git.pengzhan.dev/haopengzhan/rsspipe/internal/db" "git.pengzhan.dev/haopengzhan/rsspipe/internal/events" "git.pengzhan.dev/haopengzhan/rsspipe/internal/models" ) type mockPatcher struct { patchedCount int32 } func (m *mockPatcher) PatchEntry(ctx context.Context, entryID string, patch models.PatchEntryRequest) (*models.FeedEntry, *models.EntryDiff, error) { atomic.AddInt32(&m.patchedCount, 1) return &models.FeedEntry{ID: entryID}, &models.EntryDiff{}, nil } func (m *mockPatcher) GetEntry(ctx context.Context, id string) (*models.FeedEntry, error) { return &models.FeedEntry{ID: id}, nil } func TestJobEngineExecution(t *testing.T) { tempDBPath := filepath.Join(t.TempDir(), "job_test.db") database, err := db.InitDB(tempDBPath) if err != nil { t.Fatalf("failed to init db: %v", err) } defer func() { _ = database.Close() }() bus := events.NewEventBus() patcher := &mockPatcher{} engine := NewJobEngine(database, bus, patcher, 5) var executedCount int32 engine.RegisterHandler("test_task", func(ctx context.Context, job models.Job) (*models.PatchEntryRequest, map[string]interface{}, error) { atomic.AddInt32(&executedCount, 1) read := true return &models.PatchEntryRequest{IsRead: &read}, map[string]interface{}{"done": true}, nil }) ctx, cancel := context.WithCancel(context.Background()) defer cancel() engine.Start(ctx) // Enqueue test job job := models.Job{ Type: "test_task", Payload: map[string]interface{}{"entry_id": "e_100"}, Status: "pending", IdempotencyKey: "test_key_1", RunAt: time.Now().UTC(), } created, err := database.CreateJob(job) if err != nil { t.Fatalf("failed to create job: %v", err) } // Wait for engine to claim and execute time.Sleep(1 * time.Second) finalJob, err := database.GetJob(created.ID) if err != nil { t.Fatalf("failed to get job: %v", err) } if finalJob.Status != "completed" { t.Errorf("expected job status 'completed', got '%s'", finalJob.Status) } if atomic.LoadInt32(&executedCount) != 1 { t.Errorf("expected executedCount 1, got %d", atomic.LoadInt32(&executedCount)) } if atomic.LoadInt32(&patcher.patchedCount) != 1 { t.Errorf("expected patcher to be called once, got %d", atomic.LoadInt32(&patcher.patchedCount)) } engine.Stop() _ = database.Close() }