//go:build integration package redisactivity import ( "context" "errors" "testing" "time" "proxy-pool/internal/domain/activitypool" extractionDomain "proxy-pool/internal/domain/extraction" proxyDomain "proxy-pool/internal/domain/proxy" ) func TestReadStateInventoryFailsClosedWhileExpiredCleanupIsBacklogged(t *testing.T) { fixture := newRedisTestFixture(t) bounded, err := New(fixture.Client, Options{ Namespace: fixture.Namespace, Credentials: fixture.Credentials, OperationTTL: time.Minute, MaxCandidateScan: 32, CleanupLimit: 1, }) if err != nil { t.Fatalf("New() error = %v", err) } redisTime, err := fixture.Client.Time(context.Background()).Result() if err != nil { t.Fatalf("Redis TIME error = %v", err) } now := redisTime.UTC().Add(time.Minute) _, err = bounded.UpsertFetched(context.Background(), "provider-a", activitypool.FetchedBatch{ ObservedAt: now, ConfiguredTTL: time.Second, MaxSize: 10, Proxies: []proxyDomain.Proxy{ {ID: "expired-a", Scheme: proxyDomain.SchemeHTTP, Host: "192.0.2.10", Port: 8080, State: proxyDomain.StateFetched}, {ID: "expired-b", Scheme: proxyDomain.SchemeHTTP, Host: "192.0.2.11", Port: 8080, State: proxyDomain.StateFetched}, }, }) if err != nil { t.Fatalf("UpsertFetched() error = %v", err) } if _, err = bounded.ReadStateInventory(context.Background(), []string{"provider-a"}, now.Add(2*time.Second)); !errors.Is(err, extractionDomain.ErrStoreUnavailable) { t.Fatalf("ReadStateInventory(backlog) error = %v", err) } inventories, err := bounded.ReadStateInventory(context.Background(), []string{"provider-a"}, now.Add(2*time.Second)) if err != nil || len(inventories) != 1 || inventories[0] != (activitypool.StateInventory{UpstreamID: "provider-a"}) { t.Fatalf("ReadStateInventory(after cleanup) = %+v, %v", inventories, err) } } func TestReadStateInventoryFailsClosedOnNegativeCounters(t *testing.T) { fixture := newRedisTestFixture(t) if err := fixture.Client.HSet( context.Background(), fixture.Adapter.keys.stateInventory, stateInventoryField("provider-a", string(proxyDomain.StateAvailable)), -1, ).Err(); err != nil { t.Fatalf("seed invalid state counter: %v", err) } if _, err := fixture.Adapter.ReadStateInventory( context.Background(), []string{"provider-a"}, time.Now().UTC(), ); !errors.Is(err, extractionDomain.ErrStoreUnavailable) { t.Fatalf("ReadStateInventory(negative counter) error = %v", err) } }