iop/apps/edge/internal/service/status_provider_test.go
toki 06f1d36fa3 feat: provider catalog device status - edge dispatch implementation
- Add agent-task archive for 02+01_edge_dispatch
- Remove outdated plan and code review docs
- Update edge bootstrap, input manager, and openai handlers
- Update model queue, run dispatch, and service layer
- Add status provider tests
2026-06-20 16:59:55 +09:00

320 lines
9.2 KiB
Go

package service
import (
"testing"
edgeevents "iop/apps/edge/internal/events"
edgenode "iop/apps/edge/internal/node"
"iop/packages/go/config"
)
func TestListNodeSnapshotsUsesEdgeQueueState(t *testing.T) {
reg := edgenode.NewRegistry()
reg.Register(&edgenode.NodeEntry{NodeID: "node-q-1", Alias: "node-q-1"})
store := edgenode.NewNodeStore()
rec := &edgenode.NodeRecord{
ID: "node-q-1",
Adapters: config.AdaptersConf{
OllamaInstances: []config.OllamaInstanceConf{
{
Name: "ollama-inst",
Enabled: true,
Capacity: 3,
},
},
},
}
store.Add(rec)
bus := edgeevents.NewBus()
svc := New(reg, bus)
svc.SetNodeStore(store)
// Manually inject group state to modelQueueManager
svc.queue.mu.Lock()
svc.queue.groups["test-group"] = &modelQueueGroup{
key: "test-group",
adapter: "ollama-inst",
inflight: map[string]int{"node-q-1": 2},
queue: []*queueItem{
{
candidates: []candidateNode{
{entry: reg.All()[0], capacity: 3},
},
},
},
}
svc.queue.mu.Unlock()
snaps := svc.ListNodeSnapshots()
if len(snaps) != 1 {
t.Fatalf("expected 1 node snapshot, got %d", len(snaps))
}
snap := snaps[0]
if len(snap.ProviderSnapshots) != 1 {
t.Fatalf("expected 1 provider snapshot, got %d", len(snap.ProviderSnapshots))
}
p := snap.ProviderSnapshots[0]
if p.Adapter != "ollama-inst" {
t.Errorf("expected adapter ollama-inst, got %s", p.Adapter)
}
if p.Capacity != 3 {
t.Errorf("expected capacity 3, got %d", p.Capacity)
}
if p.InFlight != 2 {
t.Errorf("expected inflight 2, got %d", p.InFlight)
}
if p.Queued != 1 {
t.Errorf("expected queued 1, got %d", p.Queued)
}
}
func TestListNodeSnapshotsTypeRouteSingleNamedInstance(t *testing.T) {
reg := edgenode.NewRegistry()
reg.Register(&edgenode.NodeEntry{NodeID: "node-q-2", Alias: "node-q-2"})
store := edgenode.NewNodeStore()
rec := &edgenode.NodeRecord{
ID: "node-q-2",
Adapters: config.AdaptersConf{
OllamaInstances: []config.OllamaInstanceConf{
{
Name: "ollama-local",
Enabled: true,
Capacity: 5,
},
},
},
}
store.Add(rec)
bus := edgeevents.NewBus()
svc := New(reg, bus)
svc.SetNodeStore(store)
// Manually inject group state to modelQueueManager with type-name route "ollama"
svc.queue.mu.Lock()
svc.queue.groups["test-group"] = &modelQueueGroup{
key: "test-group",
adapter: "ollama",
inflight: map[string]int{"node-q-2": 3},
queue: []*queueItem{
{
candidates: []candidateNode{
{entry: reg.All()[0], capacity: 5},
},
},
},
}
svc.queue.mu.Unlock()
snaps := svc.ListNodeSnapshots()
if len(snaps) != 1 {
t.Fatalf("expected 1 node snapshot, got %d", len(snaps))
}
snap := snaps[0]
if len(snap.ProviderSnapshots) != 1 {
t.Fatalf("expected 1 provider snapshot, got %d", len(snap.ProviderSnapshots))
}
p := snap.ProviderSnapshots[0]
if p.Adapter != "ollama-local" {
t.Errorf("expected adapter ollama-local, got %s", p.Adapter)
}
if p.Capacity != 5 {
t.Errorf("expected capacity 5, got %d", p.Capacity)
}
if p.InFlight != 3 {
t.Errorf("expected inflight 3, got %d", p.InFlight)
}
if p.Queued != 1 {
t.Errorf("expected queued 1, got %d", p.Queued)
}
}
// REVIEW_API-2: provider id와 adapter key가 다른 경우에도 queue stats가 올바르게 반영되는지 검증.
// provider id는 "provider-vllm-primary"지만, adapter/instance key는 "vllm-gpu"이다.
// queue group에 adapter="vllm-gpu"로 inject하면 provider snapshot이 이 stats를 올바르게 반영해야 한다.
// REVIEW_REVIEW_API-2: adapter가 비어 있을 때 provider id로 fallback하여
// queue stats(InFlight, Queued, LoadRatio)가 올바르게 반영되는지 검증.
func TestListNodeSnapshotsProviderEmptyAdapterFallbackToProviderID(t *testing.T) {
reg := edgenode.NewRegistry()
reg.Register(&edgenode.NodeEntry{NodeID: "node-e-1", Alias: "node-e-1"})
// Node has a provider with empty adapter. Queue state is keyed by provider id.
store := edgenode.NewNodeStore()
rec := &edgenode.NodeRecord{
ID: "node-e-1",
Adapters: config.AdaptersConf{
// No OllamaInstances/vllm_instances matching the provider id.
// This ensures the fallback path is tested.
},
Providers: []config.NodeProviderConf{
{
ID: "standalone-provider",
Type: "cli",
Category: config.CategoryCLI,
Adapter: "", // empty — should fallback to provider id
Models: []string{"test-model"},
Capacity: 2,
},
},
Runtime: config.RuntimeConf{Concurrency: 2},
}
store.Add(rec)
bus := edgeevents.NewBus()
svc := New(reg, bus)
svc.SetNodeStore(store)
// Inject tracking state the way provider-pool dispatch does it:
// inflightByRun keyed by providerID, and queue candidates with providerID set.
svc.queue.mu.Lock()
svc.queue.inflightByRun["run-sp-001"] = inflightRec{
groupKey: "test-group",
nodeID: "node-e-1",
providerID: "standalone-provider",
}
svc.queue.groups["test-group"] = &modelQueueGroup{
key: "test-group",
adapter: "standalone-provider",
inflight: map[string]int{"node-e-1": 1},
queue: []*queueItem{
{
candidates: []candidateNode{
{entry: reg.All()[0], capacity: 2, providerID: "standalone-provider"},
},
},
},
}
svc.queue.mu.Unlock()
snaps := svc.ListNodeSnapshots()
if len(snaps) != 1 {
t.Fatalf("expected 1 node snapshot, got %d", len(snaps))
}
snap := snaps[0]
// Find the provider snapshot by its provider id.
found := false
for i, ps := range snap.ProviderSnapshots {
if ps.Id == "standalone-provider" {
found = true
if ps.InFlight != 1 {
t.Errorf("expected InFlight=1 for standalone-provider (adapter empty), got %d", ps.InFlight)
}
if ps.Queued != 1 {
t.Errorf("expected Queued=1 for standalone-provider (adapter empty), got %d", ps.Queued)
}
if ps.Capacity != 2 {
t.Errorf("expected Capacity=2 for standalone-provider, got %d", ps.Capacity)
}
// LoadRatio = InFlight / Capacity = 1 / 2 = 0.5
expectedLoadRatio := float32(1) / float32(2)
if ps.LoadRatio != expectedLoadRatio {
t.Errorf("expected LoadRatio=%.2f for standalone-provider, got %.2f", expectedLoadRatio, ps.LoadRatio)
}
t.Logf("provider snapshot[%d]: id=%s, adapter=%s, InFlight=%d, Queued=%d, Capacity=%d, LoadRatio=%.2f",
i, ps.Id, ps.Adapter, ps.InFlight, ps.Queued, ps.Capacity, ps.LoadRatio)
break
}
}
if !found {
t.Fatalf("expected provider snapshot with id=standalone-provider, got %d provider snapshots", len(snap.ProviderSnapshots))
}
}
func TestListNodeSnapshotsProviderIdDiffersFromAdapterKey(t *testing.T) {
reg := edgenode.NewRegistry()
reg.Register(&edgenode.NodeEntry{NodeID: "node-p-1", Alias: "node-p-1"})
// Node has providers[] with provider id "provider-vllm-primary" and adapter="vllm-gpu".
// The adapter field points to an existing OllamaInstance named "vllm-gpu" (used here as a stand-in for the adapter key).
store := edgenode.NewNodeStore()
rec := &edgenode.NodeRecord{
ID: "node-p-1",
Adapters: config.AdaptersConf{
OllamaInstances: []config.OllamaInstanceConf{
{
Name: "vllm-gpu",
Enabled: true,
Capacity: 4,
},
},
},
Providers: []config.NodeProviderConf{
{
ID: "provider-vllm-primary",
Type: "vllm",
Category: config.CategoryAPI,
Adapter: "vllm-gpu", // adapter key differs from provider id
Models: []string{"nvidia/Qwen3.6-35B"},
Capacity: 4,
},
},
Runtime: config.RuntimeConf{Concurrency: 2},
}
store.Add(rec)
bus := edgeevents.NewBus()
svc := New(reg, bus)
svc.SetNodeStore(store)
// Inject tracking state the way provider-pool dispatch does it:
// inflightByRun entries keyed by providerID, and queue candidates with providerID set.
svc.queue.mu.Lock()
svc.queue.inflightByRun["run-vp-001"] = inflightRec{
groupKey: "test-group",
nodeID: "node-p-1",
providerID: "provider-vllm-primary",
}
svc.queue.inflightByRun["run-vp-002"] = inflightRec{
groupKey: "test-group",
nodeID: "node-p-1",
providerID: "provider-vllm-primary",
}
svc.queue.groups["test-group"] = &modelQueueGroup{
key: "test-group",
adapter: "vllm-gpu",
inflight: map[string]int{"node-p-1": 2},
queue: []*queueItem{
{
candidates: []candidateNode{
{entry: reg.All()[0], capacity: 4, providerID: "provider-vllm-primary"},
},
},
},
}
svc.queue.mu.Unlock()
snaps := svc.ListNodeSnapshots()
if len(snaps) != 1 {
t.Fatalf("expected 1 node snapshot, got %d", len(snaps))
}
snap := snaps[0]
// Find the provider snapshot by its provider id.
var p *config.NodeProviderConf
for i := range snap.ProviderSnapshots {
ps := snap.ProviderSnapshots[i]
if ps.Id == "provider-vllm-primary" {
p = &config.NodeProviderConf{
Capacity: int(ps.Capacity),
}
// Verify queue stats match the injected queue state.
if ps.InFlight != 2 {
t.Errorf("expected InFlight=2 for provider-vllm-primary, got %d", ps.InFlight)
}
if ps.Queued != 1 {
t.Errorf("expected Queued=1 for provider-vllm-primary, got %d", ps.Queued)
}
if ps.Adapter != "vllm-gpu" {
t.Errorf("expected Adapter=vllm-gpu for provider-vllm-primary, got %s", ps.Adapter)
}
break
}
}
if p == nil {
t.Fatalf("expected provider snapshot with id=provider-vllm-primary, got %d provider snapshots", len(snap.ProviderSnapshots))
}
}