iop/apps/edge/internal/service/status_provider_test.go

768 lines
22 KiB
Go

package service
import (
"testing"
edgeevents "iop/apps/edge/internal/events"
edgenode "iop/apps/edge/internal/node"
"iop/packages/go/config"
iop "iop/proto/gen/iop"
)
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:
svc.queue.mu.Lock()
key := providerResourceKey{nodeID: "node-e-1", providerID: "standalone-provider"}
res := svc.queue.resources[key]
if res == nil {
res = &providerResourceState{
nodeID: "node-e-1",
providerID: "standalone-provider",
capacity: 2,
enabled: true,
}
svc.queue.resources[key] = res
}
res.inFlight = 1
svc.queue.groups["test-group"] = &modelQueueGroup{
key: "test-group",
adapter: "standalone-provider",
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))
}
}
// TestListNodeSnapshotsProviderCatalogSupersedesAdapterSnapshots verifies the
// catalog-first rule: when a node has both adapter instances (CLI + OpenAICompat)
// and a providers[] catalog, ListNodeSnapshots returns only the catalog snapshots
// with no adapter duplicates.
func TestListNodeSnapshotsProviderCatalogSupersedesAdapterSnapshots(t *testing.T) {
reg := edgenode.NewRegistry()
reg.Register(&edgenode.NodeEntry{NodeID: "node-cs-1", Alias: "node-cs-1"})
store := edgenode.NewNodeStore()
rec := &edgenode.NodeRecord{
ID: "node-cs-1",
Adapters: config.AdaptersConf{
CLI: config.CLIConf{Enabled: true},
OpenAICompatInstances: []config.OpenAICompatInstanceConf{
{Name: "vllm-gpu", Enabled: true},
},
},
Providers: []config.NodeProviderConf{
{ID: "prov-cat-1", Adapter: "vllm-gpu", Models: []string{"model-x"}, Health: "available", Capacity: 4},
{ID: "prov-cat-2", Adapter: "vllm-gpu", Models: []string{"model-y"}, Health: "available", Capacity: 2},
},
Runtime: config.RuntimeConf{Concurrency: 1},
}
store.Add(rec)
bus := edgeevents.NewBus()
svc := New(reg, bus)
svc.SetNodeStore(store)
snaps := svc.ListNodeSnapshots()
if len(snaps) != 1 {
t.Fatalf("expected 1 node snapshot, got %d", len(snaps))
}
snap := snaps[0]
// Only catalog snapshots must be returned — exactly 2 (one per provider).
if len(snap.ProviderSnapshots) != 2 {
t.Fatalf("expected 2 catalog snapshots, got %d (cli/openai_compat adapter duplicates must be absent): %+v",
len(snap.ProviderSnapshots), snap.ProviderSnapshots)
}
ids := map[string]bool{}
for _, p := range snap.ProviderSnapshots {
if p.Id == "" {
t.Errorf("unexpected adapter-only snapshot (empty Id): %+v", p)
}
ids[p.Id] = true
}
if !ids["prov-cat-1"] || !ids["prov-cat-2"] {
t.Errorf("expected catalog IDs prov-cat-1 and prov-cat-2, got: %v", ids)
}
}
func TestListNodeSnapshotsCatalogProviderZeroCapacityDoesNotUseRuntimeFallback(t *testing.T) {
reg := edgenode.NewRegistry()
reg.Register(&edgenode.NodeEntry{NodeID: "node-zero-cap", Alias: "node-zero-cap"})
store := edgenode.NewNodeStore()
rec := &edgenode.NodeRecord{
ID: "node-zero-cap",
Adapters: config.AdaptersConf{
OpenAICompatInstances: []config.OpenAICompatInstanceConf{
{Name: "vllm-gpu", Enabled: true, Capacity: 7},
},
},
Providers: []config.NodeProviderConf{
{ID: "prov-zero", Adapter: "vllm-gpu", Models: []string{"model-zero"}, Health: "available", Capacity: 0},
},
Runtime: config.RuntimeConf{Concurrency: 7},
}
store.Add(rec)
bus := edgeevents.NewBus()
svc := New(reg, bus)
svc.SetNodeStore(store)
snaps := svc.ListNodeSnapshots()
if len(snaps) != 1 {
t.Fatalf("expected 1 node snapshot, got %d", len(snaps))
}
if len(snaps[0].ProviderSnapshots) != 1 {
t.Fatalf("expected 1 provider snapshot, got %d", len(snaps[0].ProviderSnapshots))
}
p := snaps[0].ProviderSnapshots[0]
if p.Id != "prov-zero" {
t.Fatalf("expected provider id prov-zero, got %q", p.Id)
}
if p.Capacity != 0 {
t.Fatalf("provider catalog capacity must not fall back to runtime concurrency: got %d", p.Capacity)
}
if p.LoadRatio != 0 {
t.Fatalf("expected zero load ratio for zero capacity provider, got %.2f", p.LoadRatio)
}
}
func TestStaticProviderCatalogSnapshotsZeroCapacityDoesNotUseRuntimeFallback(t *testing.T) {
rec := &edgenode.NodeRecord{
ID: "node-static-zero-cap",
Providers: []config.NodeProviderConf{
{ID: "prov-zero", Adapter: "vllm-gpu", Models: []string{"model-zero"}, Health: "available", Capacity: 0},
},
Runtime: config.RuntimeConf{Concurrency: 7},
}
snaps := staticProviderCatalogSnapshots(rec)
if len(snaps) != 1 {
t.Fatalf("expected 1 provider snapshot, got %d", len(snaps))
}
if snaps[0].Capacity != 0 {
t.Fatalf("static provider catalog capacity must not fall back to runtime concurrency: got %d", snaps[0].Capacity)
}
}
// TestListNodeSnapshotsLegacyAdapterFallbackWhenNoProviders verifies that when
// a node has no providers[] catalog, ListNodeSnapshots returns the legacy adapter
// snapshots (CLI, Ollama, etc.) rather than empty results.
func TestListNodeSnapshotsLegacyAdapterFallbackWhenNoProviders(t *testing.T) {
reg := edgenode.NewRegistry()
reg.Register(&edgenode.NodeEntry{NodeID: "node-legacy-snap", Alias: "node-legacy-snap"})
store := edgenode.NewNodeStore()
rec := &edgenode.NodeRecord{
ID: "node-legacy-snap",
Adapters: config.AdaptersConf{
CLI: config.CLIConf{Enabled: true},
OllamaInstances: []config.OllamaInstanceConf{
{Name: "ollama-local", Enabled: true, Capacity: 3},
},
},
Runtime: config.RuntimeConf{Concurrency: 2},
// Providers is empty → legacy adapter fallback
}
store.Add(rec)
bus := edgeevents.NewBus()
svc := New(reg, bus)
svc.SetNodeStore(store)
snaps := svc.ListNodeSnapshots()
if len(snaps) != 1 {
t.Fatalf("expected 1 node snapshot, got %d", len(snaps))
}
snap := snaps[0]
// Must return CLI + ollama-local adapter snapshots.
if len(snap.ProviderSnapshots) != 2 {
t.Fatalf("expected 2 adapter snapshots (cli + ollama-local), got %d: %+v",
len(snap.ProviderSnapshots), snap.ProviderSnapshots)
}
adapters := map[string]bool{}
for _, p := range snap.ProviderSnapshots {
adapters[p.Adapter] = true
}
if !adapters["cli"] || !adapters["ollama-local"] {
t.Errorf("expected cli and ollama-local adapter snapshots, got: %v", adapters)
}
}
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:
svc.queue.mu.Lock()
key := providerResourceKey{nodeID: "node-p-1", providerID: "provider-vllm-primary"}
res := svc.queue.resources[key]
if res == nil {
res = &providerResourceState{
nodeID: "node-p-1",
providerID: "provider-vllm-primary",
capacity: 4,
enabled: true,
}
svc.queue.resources[key] = res
}
res.inFlight = 2
svc.queue.groups["test-group"] = &modelQueueGroup{
key: "test-group",
adapter: "vllm-gpu",
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))
}
}
func TestListNodeSnapshotsLongContextFields(t *testing.T) {
reg := edgenode.NewRegistry()
reg.Register(&edgenode.NodeEntry{NodeID: "node-long-1", Alias: "node-long-1"})
store := edgenode.NewNodeStore()
rec := &edgenode.NodeRecord{
ID: "node-long-1",
Providers: []config.NodeProviderConf{
{
ID: "long-provider",
Type: "vllm",
Category: config.CategoryAPI,
Adapter: "vllm-gpu",
Models: []string{"long-model"},
Capacity: 4,
LongContextCapacity: 2,
},
},
Runtime: config.RuntimeConf{Concurrency: 2},
}
store.Add(rec)
bus := edgeevents.NewBus()
svc := New(reg, bus)
svc.SetNodeStore(store)
svc.queue.mu.Lock()
key := providerResourceKey{nodeID: "node-long-1", providerID: "long-provider"}
res := svc.queue.resources[key]
if res == nil {
res = &providerResourceState{
nodeID: "node-long-1",
providerID: "long-provider",
capacity: 4,
longCapacity: 2,
enabled: true,
}
svc.queue.resources[key] = res
}
res.inFlight = 1
res.longInFlight = 1
svc.queue.groups["test-group"] = &modelQueueGroup{
key: "test-group",
adapter: "vllm-gpu",
queue: []*queueItem{
{
candidates: []candidateNode{
{entry: reg.All()[0], capacity: 4, providerID: "long-provider"},
},
long: true,
},
},
}
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.Id != "long-provider" {
t.Errorf("expected long-provider, got %s", p.Id)
}
if p.LongContextCapacity != 2 {
t.Errorf("expected LongContextCapacity 2, got %d", p.LongContextCapacity)
}
if p.LongInFlight != 1 {
t.Errorf("expected LongInFlight 1, got %d", p.LongInFlight)
}
if p.LongQueued != 1 {
t.Errorf("expected LongQueued 1, got %d", p.LongQueued)
}
}
func TestProviderSnapshotQueuedCountsCandidatePressureAcrossModelGroups(t *testing.T) {
reg := edgenode.NewRegistry()
entry := &edgenode.NodeEntry{NodeID: "node-pressure", Alias: "node-pressure"}
reg.Register(entry)
store := edgenode.NewNodeStore()
rec := &edgenode.NodeRecord{
ID: "node-pressure",
Providers: []config.NodeProviderConf{
{
ID: "provider-shared",
Type: "vllm",
Category: config.CategoryAPI,
Models: []string{"model-a", "model-b"},
Health: "available",
Capacity: 1,
LongContextCapacity: 1,
},
{
ID: "provider-fallback",
Type: "vllm",
Category: config.CategoryAPI,
Models: []string{"model-a"},
Health: "available",
Capacity: 1,
LongContextCapacity: 1,
},
},
}
store.Add(rec)
svc := New(reg, edgeevents.NewBus())
svc.SetNodeStore(store)
svc.queue.mu.Lock()
svc.queue.groups["model-a"] = &modelQueueGroup{
key: "model-a",
queue: []*queueItem{
{
candidates: []candidateNode{
{entry: entry, providerID: "provider-shared"},
{entry: entry, providerID: "provider-fallback"},
},
},
},
}
svc.queue.groups["model-b"] = &modelQueueGroup{
key: "model-b",
queue: []*queueItem{
{
candidates: []candidateNode{
{entry: entry, providerID: "provider-shared"},
},
long: true,
},
},
}
svc.queue.mu.Unlock()
snaps := svc.ListNodeSnapshots()
if len(snaps) != 1 {
t.Fatalf("expected 1 node snapshot, got %d", len(snaps))
}
if len(snaps[0].ProviderSnapshots) != 2 {
t.Fatalf("expected 2 provider snapshots, got %d", len(snaps[0].ProviderSnapshots))
}
byID := make(map[string]*iop.ProviderSnapshot, len(snaps[0].ProviderSnapshots))
for _, snapshot := range snaps[0].ProviderSnapshots {
byID[snapshot.GetId()] = snapshot
}
shared := byID["provider-shared"]
if shared == nil {
t.Fatal("provider-shared snapshot not found")
}
if shared.GetQueued() != 2 || shared.GetLongQueued() != 1 {
t.Fatalf("shared candidate pressure mismatch: queued=%d long_queued=%d", shared.GetQueued(), shared.GetLongQueued())
}
fallback := byID["provider-fallback"]
if fallback == nil {
t.Fatal("provider-fallback snapshot not found")
}
if fallback.GetQueued() != 1 || fallback.GetLongQueued() != 0 {
t.Fatalf("fallback candidate pressure mismatch: queued=%d long_queued=%d", fallback.GetQueued(), fallback.GetLongQueued())
}
if total := shared.GetQueued() + fallback.GetQueued(); total != 3 {
t.Fatalf("provider candidate pressure should be non-additive across 2 Edge pending requests: got total=%d", total)
}
}
func TestProviderSnapshotReadsResourceState(t *testing.T) {
reg := edgenode.NewRegistry()
reg.Register(&edgenode.NodeEntry{NodeID: "node-snap-test", Alias: "node-snap-test"})
store := edgenode.NewNodeStore()
rec := &edgenode.NodeRecord{
ID: "node-snap-test",
Runtime: config.RuntimeConf{Concurrency: 5},
Providers: []config.NodeProviderConf{
{
ID: "snap-prov",
Adapter: "vllm",
Capacity: 3,
LongContextCapacity: 2,
Enabled: nil,
},
},
}
store.Add(rec)
bus := edgeevents.NewBus()
svc := New(reg, bus)
svc.SetNodeStore(store)
// Increment resource counts directly
svc.queue.mu.Lock()
key := providerResourceKey{nodeID: "node-snap-test", providerID: "snap-prov"}
res := svc.queue.resources[key]
if res == nil {
svc.queue.mu.Unlock()
t.Fatal("resource state not found after SetNodeStore")
}
res.inFlight = 2
res.longInFlight = 1
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.InFlight != 2 {
t.Errorf("expected InFlight 2, got %d", p.InFlight)
}
if p.LongInFlight != 1 {
t.Errorf("expected LongInFlight 1, got %d", p.LongInFlight)
}
}
func TestProviderSnapshotIgnoresLegacyFallbackState(t *testing.T) {
reg := edgenode.NewRegistry()
reg.Register(&edgenode.NodeEntry{NodeID: "node-fallback-test", Alias: "node-fallback-test"})
store := edgenode.NewNodeStore()
rec := &edgenode.NodeRecord{
ID: "node-fallback-test",
Runtime: config.RuntimeConf{Concurrency: 5},
Providers: []config.NodeProviderConf{
{
ID: "fallback-prov",
Adapter: "vllm",
Capacity: 3,
LongContextCapacity: 2,
Enabled: nil,
},
},
}
store.Add(rec)
bus := edgeevents.NewBus()
svc := New(reg, bus)
svc.SetNodeStore(store)
trackTestLease(svc.queue, "test-group", "run-legacy", "node-fallback-test", "fallback-prov", true)
svc.queue.mu.Lock()
// Legacy fallback states are present, but resource counts are 0
svc.queue.groups["test-group"] = &modelQueueGroup{
key: "test-group",
adapter: "vllm",
inflight: map[string]int{"node-fallback-test:fallback-prov": 1},
longInflight: map[string]int{"node-fallback-test:fallback-prov": 1},
}
// Explicit resource state is 0/0
key := providerResourceKey{nodeID: "node-fallback-test", providerID: "fallback-prov"}
res := svc.queue.resources[key]
if res == nil {
svc.queue.mu.Unlock()
t.Fatal("resource state not found")
}
res.inFlight = 0
res.longInFlight = 0
svc.queue.mu.Unlock()
snaps := svc.ListNodeSnapshots()
if len(snaps) != 1 {
t.Fatalf("expected 1 node snapshot")
}
p := snaps[0].ProviderSnapshots[0]
if p.InFlight != 0 {
t.Errorf("expected InFlight 0, got %d", p.InFlight)
}
if p.LongInFlight != 0 {
t.Errorf("expected LongInFlight 0, got %d", p.LongInFlight)
}
}