mirror of
https://github.com/mulgadc/spinifex.git
synced 2026-10-15 17:11:30 +00:00
98fc01764b
* feat(ecs): thread resourceRequirements GPU count through conv, ContainerDef, AssignContainer and RunSpec * feat(ecs): add GPU placement dimension — InstanceRecord capacity, fits/reserve/release, STRINGSET resource reporting * feat(ecs): agent GPU discovery via nvidia-smi, pinning ledger, device-UUID report-back and DescribeTasks gpuIds * feat(ecs): inject assigned GPU devices into containerd OCI spec via CDI (oci.WithCDIDevices) * test(ecs): add GPU task e2e (nvidia-smi container, gpuIds assertion) to gpu e2e suite * test(gpu): decouple base-AMI requirement from GPU fixture so ECS e2e runs without the ubuntu EC2 image * test(gpu): pick smallest advertised GPU instance type to fit a single host * fix(ecs): preserve pinned GPU UUIDs across STOPPED state change so DescribeTasks reports gpuIds for one-shot tasks
67 lines
1.7 KiB
Go
67 lines
1.7 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
ctrruntime "github.com/mulgadc/spinifex/cmd/ecs-agent/runtime"
|
|
)
|
|
|
|
func TestAgent_RunRegistersThenStopsOnContext(t *testing.T) {
|
|
cp := &fakeCP{}
|
|
cfg := config{Heartbeat: 5 * time.Millisecond, PollInterval: 5 * time.Millisecond}
|
|
puller := &ctrruntime.FakePuller{}
|
|
a := newAgent(cfg, testIdentity(), cp, puller, puller, nil)
|
|
a.closers = append(a.closers, puller.Close)
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
done := make(chan error, 1)
|
|
go func() { done <- a.Run(ctx) }()
|
|
|
|
// Give it time to register + re-register (heartbeat) a few times.
|
|
time.Sleep(30 * time.Millisecond)
|
|
cancel()
|
|
|
|
select {
|
|
case err := <-done:
|
|
if err != nil {
|
|
t.Fatalf("Run returned error: %v", err)
|
|
}
|
|
case <-time.After(time.Second):
|
|
t.Fatal("Run did not return after cancel")
|
|
}
|
|
|
|
// One boot register + at least one heartbeat re-register.
|
|
if cp.registerCount() < 2 {
|
|
t.Errorf("registers = %d, want >= 2 (boot + heartbeat)", cp.registerCount())
|
|
}
|
|
if !puller.Closed {
|
|
t.Error("Stop did not close the puller")
|
|
}
|
|
}
|
|
|
|
func TestDetectCapacity_Positive(t *testing.T) {
|
|
c := detectCapacity(nil)
|
|
if c.CPU <= 0 {
|
|
t.Errorf("CPU = %d, want > 0", c.CPU)
|
|
}
|
|
// MemoryMiB may be 0 on platforms without /proc/meminfo; just assert non-negative.
|
|
if c.MemoryMiB < 0 {
|
|
t.Errorf("MemoryMiB = %d, want >= 0", c.MemoryMiB)
|
|
}
|
|
if c.GPU != 0 || c.GPUIDs != nil {
|
|
t.Errorf("no GPU UUIDs given: want GPU=0/GPUIDs=nil, got %d/%v", c.GPU, c.GPUIDs)
|
|
}
|
|
}
|
|
|
|
func TestDetectCapacity_WithGPUUUIDs(t *testing.T) {
|
|
c := detectCapacity([]string{"GPU-aaa", "GPU-bbb"})
|
|
if c.GPU != 2 {
|
|
t.Errorf("GPU = %d, want 2", c.GPU)
|
|
}
|
|
if len(c.GPUIDs) != 2 {
|
|
t.Errorf("GPUIDs = %v, want 2 entries", c.GPUIDs)
|
|
}
|
|
}
|