df58bc25a3
---ci--- project: orca phase: 3 milestone: v0.3 status: complete requirements: covered: [REQ-022, REQ-030, REQ-032] partial: [] ---/ci--- v0.3 milestone merged to main. Includes all v0.2 work (P08-P10) that was previously on the milestone branch but not yet merged to main, plus the v0.3 completion work (iter.Seq streaming + doctor network/db). v0.2 phases included: P08 (mTLS), P09 (scheduling), P10 (security scan). v0.3 phases: P0 (pre-execution), P1 (iter.Seq streaming), P2 (doctor), P3 (final review+ship). Total: 40 requirements, all complete. No new go.mod dependencies. Full test suite passes under -race. gofmt + go vet clean.
67 lines
2.0 KiB
Go
67 lines
2.0 KiB
Go
package engine
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"git.cloudinit.dev/coreci/orca/internal/store"
|
|
)
|
|
|
|
func TestPickNodeBestFit(t *testing.T) {
|
|
caps := []*store.NodeCapacity{
|
|
{NodeID: "node-b", CPUMillicores: 1000, MemoryMiB: 1024, DiskMiB: 1024},
|
|
{NodeID: "node-a", CPUMillicores: 4000, MemoryMiB: 4096, DiskMiB: 4096},
|
|
{NodeID: "node-c", CPUMillicores: 500, MemoryMiB: 512, DiskMiB: 512},
|
|
}
|
|
spec := JobSpec{CPUMillicores: 1000, MemoryMiB: 1024, DiskMiB: 1024}
|
|
got, idx, err := PickNode(spec, caps)
|
|
if err != nil {
|
|
t.Fatalf("PickNode: %v", err)
|
|
}
|
|
if got.NodeID != "node-a" {
|
|
t.Errorf("PickNode: got %s, want node-a (most free capacity)", got.NodeID)
|
|
}
|
|
if idx != 1 {
|
|
t.Errorf("PickNode: got idx %d, want 1", idx)
|
|
}
|
|
}
|
|
|
|
func TestPickNodeNoFit(t *testing.T) {
|
|
caps := []*store.NodeCapacity{
|
|
{NodeID: "node-a", CPUMillicores: 100, MemoryMiB: 100, DiskMiB: 100},
|
|
}
|
|
spec := JobSpec{CPUMillicores: 1000, MemoryMiB: 1024, DiskMiB: 1024}
|
|
_, _, err := PickNode(spec, caps)
|
|
if err == nil {
|
|
t.Fatal("expected PickNode to fail when no node can fit")
|
|
}
|
|
}
|
|
|
|
func TestPickNodeTieDeterministic(t *testing.T) {
|
|
// Two nodes with identical free capacity. Tie broken by NodeID
|
|
// (lexicographic) for determinism.
|
|
caps := []*store.NodeCapacity{
|
|
{NodeID: "node-z", CPUMillicores: 4000, MemoryMiB: 4096, DiskMiB: 4096},
|
|
{NodeID: "node-a", CPUMillicores: 4000, MemoryMiB: 4096, DiskMiB: 4096},
|
|
}
|
|
spec := JobSpec{CPUMillicores: 1000, MemoryMiB: 1024, DiskMiB: 1024}
|
|
got, _, err := PickNode(spec, caps)
|
|
if err != nil {
|
|
t.Fatalf("PickNode: %v", err)
|
|
}
|
|
if got.NodeID != "node-a" {
|
|
t.Errorf("PickNode tie-break: got %s, want node-a (lexicographic)", got.NodeID)
|
|
}
|
|
}
|
|
|
|
func TestJobSpecFits(t *testing.T) {
|
|
spec := JobSpec{CPUMillicores: 1000, MemoryMiB: 1024, DiskMiB: 1024}
|
|
c := &store.NodeCapacity{CPUMillicores: 2000, MemoryMiB: 2048, DiskMiB: 2048}
|
|
if !spec.Fits(c) {
|
|
t.Error("Fits: should fit")
|
|
}
|
|
c.CPUMillicores = 500
|
|
if spec.Fits(c) {
|
|
t.Error("Fits: should not fit (CPU too low)")
|
|
}
|
|
}
|