proxy-pool/internal/adapters/redisactivity/capacity_integration_test.go

106 lines
4.6 KiB
Go

//go:build integration
package redisactivity
import (
"context"
"testing"
"time"
controllerPool "proxy-pool/internal/controller/pool"
"proxy-pool/internal/domain/workerruntime"
)
func TestRedisCapacityInventoryCombinesProxyAndWorkerRuntime(t *testing.T) {
fixture := newRedisTestFixture(t)
now := redisTestNow()
unowned := testProxy("proxy-unowned", "192.0.2.10")
unowned.MaxConcurrency = 10
owned := testProxy("proxy-owned", "192.0.2.11")
owned.MaxConcurrency = 10
seedRedisAvailable(t, fixture.Adapter, "provider-a", now, now.Add(time.Second), 2*time.Minute, unowned)
seedRedisAvailable(t, fixture.Adapter, "provider-a", now, now.Add(time.Second), 2*time.Minute, owned)
assignment, err := fixture.Adapter.Assign(context.Background(), now.Add(2*time.Second),
"proxy-owned", "worker-a", time.Minute)
if err != nil {
t.Fatalf("Assign(): %v", err)
}
if err := fixture.Adapter.ReplaceSession(context.Background(), workerruntime.Session{
WorkerID: "worker-a", InstanceID: "instance-a", SessionID: "session-a",
AckedSnapshotVersion: 1, AckedOwnershipEpoch: assignment.Epoch,
}, time.Minute); err != nil {
t.Fatalf("ReplaceSession(): %v", err)
}
if err := fixture.Adapter.ReplaceRuntime(context.Background(), workerruntime.Report{
WorkerID: "worker-a", SessionID: "session-a", Sequence: 1,
SnapshotVersion: 1, OwnershipEpoch: assignment.Epoch, ObservedAt: now,
Counters: []workerruntime.Counter{{ProxyID: "proxy-owned", Active: 3, Reserved: 2}},
}, time.Minute); err != nil {
t.Fatalf("ReplaceRuntime(): %v", err)
}
inventory, err := fixture.Adapter.ReadInventory(context.Background(), "provider-a", 0)
if err != nil || inventory.Managed != 2 || inventory.AvailableSlots != 15 {
t.Fatalf("ReadInventory() = %+v, %v; want managed=2 slots=15", inventory, err)
}
if _, ok := any(fixture.Adapter).(controllerPool.InventoryReader); !ok {
t.Fatal("Adapter does not implement pool.InventoryReader")
}
inventory, err = fixture.Adapter.ReadInventory(context.Background(), "provider-a", 2*time.Hour)
if err != nil || inventory.Managed != 2 || inventory.AvailableSlots != 0 {
t.Fatalf("ReadInventory(safety margin) = %+v, %v", inventory, err)
}
fixture.Adapter.options.MaxInventoryScan = 1
if _, err := fixture.Adapter.ReadInventory(context.Background(), "provider-a", 0); err == nil {
t.Fatal("ReadInventory(over scan limit) error = nil")
}
}
func TestRedisCapacityInventoryFailsClosedForExpiredRuntime(t *testing.T) {
fixture := newRedisTestFixture(t)
now := redisTestNow()
owned := testProxy("proxy-owned", "192.0.2.11")
owned.MaxConcurrency = 10
seedRedisAvailable(t, fixture.Adapter, "provider-a", now, now.Add(time.Second), 2*time.Minute, owned)
assignment, err := fixture.Adapter.Assign(context.Background(), now.Add(2*time.Second),
"proxy-owned", "worker-a", time.Minute)
if err != nil {
t.Fatalf("Assign(): %v", err)
}
if err := fixture.Adapter.ReplaceSession(context.Background(), workerruntime.Session{
WorkerID: "worker-a", InstanceID: "instance-a", SessionID: "session-a",
AckedSnapshotVersion: 1, AckedOwnershipEpoch: assignment.Epoch,
}, 100*time.Millisecond); err != nil {
t.Fatalf("ReplaceSession(): %v", err)
}
if err := fixture.Adapter.ReplaceRuntime(context.Background(), workerruntime.Report{
WorkerID: "worker-a", SessionID: "session-a", Sequence: 1,
SnapshotVersion: 1, OwnershipEpoch: assignment.Epoch, ObservedAt: now,
}, 100*time.Millisecond); err != nil {
t.Fatalf("ReplaceRuntime(): %v", err)
}
time.Sleep(150 * time.Millisecond)
inventory, err := fixture.Adapter.ReadInventory(context.Background(), "provider-a", 0)
if err != nil || inventory.Managed != 1 || inventory.AvailableSlots != 0 {
t.Fatalf("ReadInventory(expired runtime) = %+v, %v", inventory, err)
}
}
func TestRedisCapacityInventoryScanIsIsolatedPerUpstream(t *testing.T) {
fixture := newRedisTestFixture(t)
fixture.Adapter.options.MaxInventoryScan = 1
now := redisTestNow()
target := testProxy("proxy-target", "192.0.2.10")
target.MaxConcurrency = 4
seedRedisAvailable(t, fixture.Adapter, "provider-a", now, now.Add(time.Second), 2*time.Minute, target)
seedRedisAvailable(t, fixture.Adapter, "provider-b", now, now.Add(time.Second), 2*time.Minute,
testProxy("proxy-other-1", "192.0.2.11"))
seedRedisAvailable(t, fixture.Adapter, "provider-b", now, now.Add(2*time.Second), 2*time.Minute,
testProxy("proxy-other-2", "192.0.2.12"))
inventory, err := fixture.Adapter.ReadInventory(context.Background(), "provider-a", 0)
if err != nil || inventory.Managed != 1 || inventory.AvailableSlots != 4 {
t.Fatalf("ReadInventory(provider-a) = %+v, %v; want isolated managed=1 slots=4", inventory, err)
}
}