d9d0beda3b
94 new tests across 4 packages. Coverage: engine 8.3%→65.1%, transport
26.3%→84.6%, proxmox 5.1%→82.7%, audit 0%→100%. Bug fix: dispatch.go
bytesReadCloser.Read returned fmt.Errorf("EOF") instead of io.EOF —
broke HTTP request body transmission (latent since v0.2 P02).
---ci---
project: orca
phase: 3
milestone: v0.7
status: verify
requirements:
covered: [REQ-055]
partial: []
---/ci---
146 lines
3.7 KiB
Go
146 lines
3.7 KiB
Go
package engine
|
|
|
|
import (
|
|
"context"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
|
|
"git.cloudinit.dev/coreci/orca/internal/model"
|
|
"git.cloudinit.dev/coreci/orca/internal/store"
|
|
)
|
|
|
|
func newTestExecutor(t *testing.T) (*Executor, func()) {
|
|
t.Helper()
|
|
path := filepath.Join(t.TempDir(), "test.db")
|
|
db, err := store.Open(path)
|
|
if err != nil {
|
|
t.Fatalf("open db: %v", err)
|
|
}
|
|
ex := NewExecutor(store.NewJobRepo(db), store.NewTaskRepo(db), nil)
|
|
return ex, func() { _ = db.Close() }
|
|
}
|
|
|
|
func TestExecutor_Submit_Success(t *testing.T) {
|
|
ex, cleanup := newTestExecutor(t)
|
|
defer cleanup()
|
|
ctx := context.Background()
|
|
spec := []byte(`{"command":"/bin/echo","args":["hello"]}`)
|
|
jobID, err := ex.Submit(ctx, spec)
|
|
if err != nil {
|
|
t.Fatalf("Submit: %v", err)
|
|
}
|
|
if jobID == "" {
|
|
t.Fatal("Submit: empty jobID")
|
|
}
|
|
status, err := ex.Status(ctx, jobID)
|
|
if err != nil {
|
|
t.Fatalf("Status: %v", err)
|
|
}
|
|
if status != string(model.JobStatusComplete) {
|
|
t.Errorf("Status: got %q, want %q", status, model.JobStatusComplete)
|
|
}
|
|
}
|
|
|
|
func TestExecutor_Submit_MissingCommand(t *testing.T) {
|
|
ex, cleanup := newTestExecutor(t)
|
|
defer cleanup()
|
|
_, err := ex.Submit(context.Background(), []byte(`{"name":"x"}`))
|
|
if err == nil {
|
|
t.Fatal("Submit: expected error for missing command, got nil")
|
|
}
|
|
}
|
|
|
|
func TestExecutor_Submit_MalformedJSON(t *testing.T) {
|
|
ex, cleanup := newTestExecutor(t)
|
|
defer cleanup()
|
|
_, err := ex.Submit(context.Background(), []byte(`{bad json`))
|
|
if err == nil {
|
|
t.Fatal("Submit: expected error for malformed JSON, got nil")
|
|
}
|
|
}
|
|
|
|
func TestExecutor_Submit_FailingCommand(t *testing.T) {
|
|
ex, cleanup := newTestExecutor(t)
|
|
defer cleanup()
|
|
ctx := context.Background()
|
|
jobID, err := ex.Submit(ctx, []byte(`{"command":"/bin/false"}`))
|
|
if err == nil {
|
|
t.Fatal("Submit failing command: expected error, got nil")
|
|
}
|
|
if jobID == "" {
|
|
t.Fatal("Submit failing command: empty jobID")
|
|
}
|
|
status, err := ex.Status(ctx, jobID)
|
|
if err != nil {
|
|
t.Fatalf("Status: %v", err)
|
|
}
|
|
if status != string(model.JobStatusFailed) {
|
|
t.Errorf("Status: got %q, want %q", status, model.JobStatusFailed)
|
|
}
|
|
}
|
|
|
|
func TestExecutor_Status_NotFound(t *testing.T) {
|
|
ex, cleanup := newTestExecutor(t)
|
|
defer cleanup()
|
|
_, err := ex.Status(context.Background(), "nonexistent-job-id")
|
|
if err == nil {
|
|
t.Fatal("Status: expected error for missing job, got nil")
|
|
}
|
|
}
|
|
|
|
func TestExecutor_Run_Success(t *testing.T) {
|
|
ex, cleanup := newTestExecutor(t)
|
|
defer cleanup()
|
|
ctx := context.Background()
|
|
job := &model.Job{
|
|
ID: uuid.NewString(),
|
|
Name: "run-success",
|
|
Spec: "{}",
|
|
Status: model.JobStatusPending,
|
|
}
|
|
specs := []TaskSpec{{Name: "echo", Command: "/bin/echo", Args: []string{"hi"}}}
|
|
if err := ex.Run(ctx, job, specs); err != nil {
|
|
t.Fatalf("Run: %v", err)
|
|
}
|
|
got, err := ex.Status(ctx, job.ID)
|
|
if err != nil {
|
|
t.Fatalf("Status: %v", err)
|
|
}
|
|
if got != string(model.JobStatusComplete) {
|
|
t.Errorf("Status: got %q, want %q", got, model.JobStatusComplete)
|
|
}
|
|
}
|
|
|
|
func TestExecutor_Run_ContextCancel(t *testing.T) {
|
|
ex, cleanup := newTestExecutor(t)
|
|
defer cleanup()
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
job := &model.Job{
|
|
ID: uuid.NewString(),
|
|
Name: "run-cancel",
|
|
Spec: "{}",
|
|
Status: model.JobStatusPending,
|
|
}
|
|
specs := []TaskSpec{{Name: "sleep", Command: "/bin/sleep", Args: []string{"10"}}}
|
|
|
|
go func() {
|
|
time.Sleep(100 * time.Millisecond)
|
|
cancel()
|
|
}()
|
|
|
|
err := ex.Run(ctx, job, specs)
|
|
if err == nil {
|
|
t.Fatal("Run: expected error after context cancel, got nil")
|
|
}
|
|
status, sErr := ex.Status(context.Background(), job.ID)
|
|
if sErr != nil {
|
|
t.Fatalf("Status after cancel: %v", sErr)
|
|
}
|
|
if status == string(model.JobStatusComplete) {
|
|
t.Errorf("Status: got %q, want not complete (task should have been killed)", status)
|
|
}
|
|
}
|