package pool import ( "testing" "time" ) func TestEmptyPool(t *testing.T) { p := NewAccountPool(nil) if got := p.GetNextConfigDir(); got != "" { t.Fatalf("expected empty string for empty pool, got %q", got) } if p.Count() != 0 { t.Fatalf("expected count 0, got %d", p.Count()) } } func TestSingleDir(t *testing.T) { p := NewAccountPool([]string{"/dir1"}) if got := p.GetNextConfigDir(); got != "/dir1" { t.Fatalf("expected /dir1, got %q", got) } if got := p.GetNextConfigDir(); got != "/dir1" { t.Fatalf("expected /dir1 again, got %q", got) } } func TestRoundRobin(t *testing.T) { p := NewAccountPool([]string{"/a", "/b", "/c"}) got := []string{ p.GetNextConfigDir(), p.GetNextConfigDir(), p.GetNextConfigDir(), p.GetNextConfigDir(), } want := []string{"/a", "/b", "/c", "/a"} for i, w := range want { if got[i] != w { t.Fatalf("call %d: expected %q, got %q", i, w, got[i]) } } } func TestLeastBusy(t *testing.T) { p := NewAccountPool([]string{"/dir1", "/dir2", "/dir3"}) p.ReportRequestStart("/dir1") p.ReportRequestStart("/dir2") if got := p.GetNextConfigDir(); got != "/dir3" { t.Fatalf("expected /dir3 (least busy), got %q", got) } p.ReportRequestStart("/dir3") p.ReportRequestEnd("/dir1") if got := p.GetNextConfigDir(); got != "/dir1" { t.Fatalf("expected /dir1 after end, got %q", got) } } func TestSkipsRateLimited(t *testing.T) { p := NewAccountPool([]string{"/dir1", "/dir2"}) p.ReportRateLimit("/dir1", 60000) if got := p.GetNextConfigDir(); got != "/dir2" { t.Fatalf("expected /dir2, got %q", got) } if got := p.GetNextConfigDir(); got != "/dir2" { t.Fatalf("expected /dir2 again, got %q", got) } } func TestFallbackToSoonestRecovery(t *testing.T) { p := NewAccountPool([]string{"/dir1", "/dir2"}) p.ReportRateLimit("/dir1", 60000) p.ReportRateLimit("/dir2", 30000) // dir2 recovers sooner — should be selected if got := p.GetNextConfigDir(); got != "/dir2" { t.Fatalf("expected /dir2 (sooner recovery), got %q", got) } } func TestActiveRequestsDoesNotGoNegative(t *testing.T) { p := NewAccountPool([]string{"/dir1"}) p.ReportRequestEnd("/dir1") p.ReportRequestEnd("/dir1") if got := p.GetNextConfigDir(); got != "/dir1" { t.Fatalf("pool should still work, got %q", got) } } func TestIgnoreUnknownConfigDir(t *testing.T) { p := NewAccountPool([]string{"/dir1"}) p.ReportRequestStart("/nonexistent") p.ReportRequestEnd("/nonexistent") p.ReportRateLimit("/nonexistent", 60000) if got := p.GetNextConfigDir(); got != "/dir1" { t.Fatalf("expected /dir1, got %q", got) } } func TestRateLimitExpires(t *testing.T) { p := NewAccountPool([]string{"/dir1", "/dir2"}) p.ReportRateLimit("/dir1", 50) if got := p.GetNextConfigDir(); got != "/dir2" { t.Fatalf("immediately expected /dir2, got %q", got) } time.Sleep(100 * time.Millisecond) if got := p.GetNextConfigDir(); got != "/dir1" { t.Fatalf("after expiry expected /dir1, got %q", got) } } func TestGlobalPool(t *testing.T) { InitAccountPool([]string{"/g1", "/g2"}) if got := GetNextAccountConfigDir(); got != "/g1" { t.Fatalf("expected /g1, got %q", got) } if got := GetNextAccountConfigDir(); got != "/g2" { t.Fatalf("expected /g2, got %q", got) } if got := GetNextAccountConfigDir(); got != "/g1" { t.Fatalf("expected /g1 again, got %q", got) } } func TestGlobalPoolEmpty(t *testing.T) { InitAccountPool(nil) if got := GetNextAccountConfigDir(); got != "" { t.Fatalf("expected empty string for empty global pool, got %q", got) } } func TestGlobalPoolReinit(t *testing.T) { InitAccountPool([]string{"/old1", "/old2"}) GetNextAccountConfigDir() InitAccountPool([]string{"/new1"}) if got := GetNextAccountConfigDir(); got != "/new1" { t.Fatalf("expected /new1 after reinit, got %q", got) } } func TestGlobalPoolFunctionsNoopBeforeInit(t *testing.T) { InitAccountPool(nil) ReportRequestStart("/dir1") ReportRequestEnd("/dir1") ReportRateLimit("/dir1", 1000) }