110 lines
2.9 KiB
Go
110 lines
2.9 KiB
Go
//go:build integration
|
|
|
|
package redisactivity
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"sync"
|
|
"sync/atomic"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/redis/go-redis/v9"
|
|
|
|
"proxy-pool/internal/platform/credentials"
|
|
)
|
|
|
|
var testNamespaceSequence atomic.Uint64
|
|
|
|
type redisTestFixture struct {
|
|
Adapter *Adapter
|
|
Client *redis.Client
|
|
Credentials *credentials.MemoryStore
|
|
Namespace string
|
|
Cleanup func()
|
|
}
|
|
|
|
func TestRedisFixtureUsesIsolatedNamespace(t *testing.T) {
|
|
fixture := newRedisTestFixture(t)
|
|
key := fixture.Adapter.keys.operation("fixture-probe")
|
|
if err := fixture.Client.Set(t.Context(), key, "ok", time.Minute).Err(); err != nil {
|
|
t.Fatalf("write isolated fixture key: %v", err)
|
|
}
|
|
if value, err := fixture.Client.Get(t.Context(), key).Result(); err != nil || value != "ok" {
|
|
t.Fatalf("read isolated fixture key = (%q, %v)", value, err)
|
|
}
|
|
}
|
|
|
|
func newRedisTestFixture(t *testing.T) redisTestFixture {
|
|
return newRedisFixtureWithCredentialCapacity(t, 10_000)
|
|
}
|
|
|
|
func newRedisFixtureWithCredentialCapacity(t *testing.T, credentialCapacity int) redisTestFixture {
|
|
t.Helper()
|
|
redisURL := os.Getenv("PROXY_POOL_TEST_REDIS_URL")
|
|
if redisURL == "" {
|
|
t.Skip("PROXY_POOL_TEST_REDIS_URL is not set")
|
|
}
|
|
redisOptions, err := redis.ParseURL(redisURL)
|
|
if err != nil {
|
|
t.Fatalf("parse PROXY_POOL_TEST_REDIS_URL: %v", err)
|
|
}
|
|
client := redis.NewClient(redisOptions)
|
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
defer cancel()
|
|
if err := client.Ping(ctx).Err(); err != nil {
|
|
_ = client.Close()
|
|
t.Fatalf("ping test Redis: %v", err)
|
|
}
|
|
credentialStore, err := credentials.NewMemoryStore(credentialCapacity)
|
|
if err != nil {
|
|
_ = client.Close()
|
|
t.Fatalf("NewMemoryStore(): %v", err)
|
|
}
|
|
namespace := fmt.Sprintf("it-%d-%d-%d", os.Getpid(), time.Now().UnixNano(), testNamespaceSequence.Add(1))
|
|
adapter, err := New(client, Options{
|
|
Namespace: namespace, Credentials: credentialStore,
|
|
OperationTTL: time.Minute, MaxCandidateScan: 2_048, CleanupLimit: 128,
|
|
})
|
|
if err != nil {
|
|
_ = client.Close()
|
|
t.Fatalf("New(): %v", err)
|
|
}
|
|
var cleanupOnce sync.Once
|
|
cleanup := func() {
|
|
cleanupOnce.Do(func() {
|
|
cleanupCtx, cleanupCancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
defer cleanupCancel()
|
|
if err := deleteRedisNamespace(cleanupCtx, client, redisKeyPrefix+namespace+":*"); err != nil {
|
|
t.Errorf("clean Redis test namespace: %v", err)
|
|
}
|
|
_ = client.Close()
|
|
})
|
|
}
|
|
t.Cleanup(cleanup)
|
|
return redisTestFixture{
|
|
Adapter: adapter, Client: client, Credentials: credentialStore, Namespace: namespace, Cleanup: cleanup,
|
|
}
|
|
}
|
|
|
|
func deleteRedisNamespace(ctx context.Context, client *redis.Client, pattern string) error {
|
|
var cursor uint64
|
|
for {
|
|
keys, next, err := client.Scan(ctx, cursor, pattern, 128).Result()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if len(keys) > 0 {
|
|
if err := client.Unlink(ctx, keys...).Err(); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
cursor = next
|
|
if cursor == 0 {
|
|
return nil
|
|
}
|
|
}
|
|
}
|