259 lines
6.2 KiB
Go
259 lines
6.2 KiB
Go
package redisconn_test
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"galaxy/redisconn"
|
|
|
|
"github.com/alicebob/miniredis/v2"
|
|
"go.opentelemetry.io/otel/metric/noop"
|
|
tracenoop "go.opentelemetry.io/otel/trace/noop"
|
|
)
|
|
|
|
func TestDefaultConfigReturnsExpectedTuning(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
cfg := redisconn.DefaultConfig()
|
|
if cfg.OperationTimeout != redisconn.DefaultOperationTimeout {
|
|
t.Fatalf("operation timeout = %v, want %v", cfg.OperationTimeout, redisconn.DefaultOperationTimeout)
|
|
}
|
|
if cfg.DB != redisconn.DefaultDB {
|
|
t.Fatalf("db = %d, want %d", cfg.DB, redisconn.DefaultDB)
|
|
}
|
|
}
|
|
|
|
func TestConfigValidateRejectsInvalidValues(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
name string
|
|
mutate func(*redisconn.Config)
|
|
wantSub string
|
|
}{
|
|
{
|
|
name: "missing master",
|
|
mutate: func(c *redisconn.Config) {
|
|
c.MasterAddr = ""
|
|
},
|
|
wantSub: "master addr",
|
|
},
|
|
{
|
|
name: "missing password",
|
|
mutate: func(c *redisconn.Config) {
|
|
c.Password = ""
|
|
},
|
|
wantSub: "password",
|
|
},
|
|
{
|
|
name: "blank replica entry",
|
|
mutate: func(c *redisconn.Config) {
|
|
c.ReplicaAddrs = []string{" "}
|
|
},
|
|
wantSub: "replica addr",
|
|
},
|
|
{
|
|
name: "negative db",
|
|
mutate: func(c *redisconn.Config) {
|
|
c.DB = -1
|
|
},
|
|
wantSub: "db must not be negative",
|
|
},
|
|
{
|
|
name: "non-positive timeout",
|
|
mutate: func(c *redisconn.Config) {
|
|
c.OperationTimeout = 0
|
|
},
|
|
wantSub: "operation timeout",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
cfg := redisconn.DefaultConfig()
|
|
cfg.MasterAddr = "127.0.0.1:6379"
|
|
cfg.Password = "secret"
|
|
tt.mutate(&cfg)
|
|
|
|
err := cfg.Validate()
|
|
if err == nil {
|
|
t.Fatalf("expected validate error, got nil")
|
|
}
|
|
if !strings.Contains(err.Error(), tt.wantSub) {
|
|
t.Fatalf("error %q does not contain %q", err, tt.wantSub)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestLoadFromEnvHappyPath(t *testing.T) {
|
|
const prefix = "TESTSVC"
|
|
t.Setenv(prefix+"_REDIS_MASTER_ADDR", "127.0.0.1:6379")
|
|
t.Setenv(prefix+"_REDIS_REPLICA_ADDRS", "127.0.0.1:6380, 127.0.0.1:6381 ,")
|
|
t.Setenv(prefix+"_REDIS_PASSWORD", "secret")
|
|
t.Setenv(prefix+"_REDIS_DB", "3")
|
|
t.Setenv(prefix+"_REDIS_OPERATION_TIMEOUT", "500ms")
|
|
|
|
cfg, err := redisconn.LoadFromEnv(prefix)
|
|
if err != nil {
|
|
t.Fatalf("load from env: %v", err)
|
|
}
|
|
if cfg.MasterAddr != "127.0.0.1:6379" {
|
|
t.Fatalf("master addr = %q", cfg.MasterAddr)
|
|
}
|
|
if cfg.Password != "secret" {
|
|
t.Fatalf("password = %q", cfg.Password)
|
|
}
|
|
if got, want := cfg.DB, 3; got != want {
|
|
t.Fatalf("db = %d, want %d", got, want)
|
|
}
|
|
if got, want := cfg.OperationTimeout, 500*time.Millisecond; got != want {
|
|
t.Fatalf("operation timeout = %v, want %v", got, want)
|
|
}
|
|
if got, want := len(cfg.ReplicaAddrs), 2; got != want {
|
|
t.Fatalf("replica count = %d, want %d", got, want)
|
|
}
|
|
}
|
|
|
|
func TestLoadFromEnvRejectsDeprecatedTLSEnabled(t *testing.T) {
|
|
const prefix = "TESTSVC"
|
|
t.Setenv(prefix+"_REDIS_MASTER_ADDR", "127.0.0.1:6379")
|
|
t.Setenv(prefix+"_REDIS_PASSWORD", "secret")
|
|
t.Setenv(prefix+"_REDIS_TLS_ENABLED", "true")
|
|
|
|
_, err := redisconn.LoadFromEnv(prefix)
|
|
if err == nil {
|
|
t.Fatal("expected error when TLS_ENABLED is set")
|
|
}
|
|
if !strings.Contains(err.Error(), "TLS_ENABLED") {
|
|
t.Fatalf("error %q should name TLS_ENABLED", err)
|
|
}
|
|
if !strings.Contains(err.Error(), "ARCHITECTURE.md") {
|
|
t.Fatalf("error %q should reference ARCHITECTURE.md", err)
|
|
}
|
|
}
|
|
|
|
func TestLoadFromEnvRejectsDeprecatedUsername(t *testing.T) {
|
|
const prefix = "TESTSVC"
|
|
t.Setenv(prefix+"_REDIS_MASTER_ADDR", "127.0.0.1:6379")
|
|
t.Setenv(prefix+"_REDIS_PASSWORD", "secret")
|
|
t.Setenv(prefix+"_REDIS_USERNAME", "anything")
|
|
|
|
_, err := redisconn.LoadFromEnv(prefix)
|
|
if err == nil {
|
|
t.Fatal("expected error when USERNAME is set")
|
|
}
|
|
if !strings.Contains(err.Error(), "USERNAME") {
|
|
t.Fatalf("error %q should name USERNAME", err)
|
|
}
|
|
}
|
|
|
|
func TestLoadFromEnvRequiresPassword(t *testing.T) {
|
|
const prefix = "TESTSVC"
|
|
t.Setenv(prefix+"_REDIS_MASTER_ADDR", "127.0.0.1:6379")
|
|
t.Setenv(prefix+"_REDIS_PASSWORD", "")
|
|
|
|
if _, err := redisconn.LoadFromEnv(prefix); err == nil {
|
|
t.Fatal("expected error when password is empty")
|
|
}
|
|
}
|
|
|
|
func TestNewMasterClientPingsMiniredis(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
server := miniredis.RunT(t)
|
|
server.RequireAuth("secret")
|
|
|
|
cfg := redisconn.DefaultConfig()
|
|
cfg.MasterAddr = server.Addr()
|
|
cfg.Password = "secret"
|
|
if err := cfg.Validate(); err != nil {
|
|
t.Fatalf("validate: %v", err)
|
|
}
|
|
|
|
client := redisconn.NewMasterClient(cfg)
|
|
t.Cleanup(func() {
|
|
_ = client.Close()
|
|
})
|
|
|
|
if err := redisconn.Ping(context.Background(), client, cfg.OperationTimeout); err != nil {
|
|
t.Fatalf("ping miniredis: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestNewReplicaClientsReturnsExpectedLength(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
server1 := miniredis.RunT(t)
|
|
server2 := miniredis.RunT(t)
|
|
|
|
cfg := redisconn.DefaultConfig()
|
|
cfg.MasterAddr = "ignored:6379"
|
|
cfg.Password = "secret"
|
|
cfg.ReplicaAddrs = []string{server1.Addr(), server2.Addr()}
|
|
|
|
clients := redisconn.NewReplicaClients(cfg)
|
|
t.Cleanup(func() {
|
|
for _, client := range clients {
|
|
_ = client.Close()
|
|
}
|
|
})
|
|
|
|
if got, want := len(clients), 2; got != want {
|
|
t.Fatalf("client count = %d, want %d", got, want)
|
|
}
|
|
}
|
|
|
|
func TestNewReplicaClientsReturnsNilWhenUnconfigured(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
cfg := redisconn.DefaultConfig()
|
|
cfg.MasterAddr = "ignored:6379"
|
|
cfg.Password = "secret"
|
|
|
|
if clients := redisconn.NewReplicaClients(cfg); clients != nil {
|
|
t.Fatalf("clients = %v, want nil", clients)
|
|
}
|
|
}
|
|
|
|
func TestInstrumentAcceptsNoopProviders(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
server := miniredis.RunT(t)
|
|
server.RequireAuth("secret")
|
|
|
|
cfg := redisconn.DefaultConfig()
|
|
cfg.MasterAddr = server.Addr()
|
|
cfg.Password = "secret"
|
|
|
|
client := redisconn.NewMasterClient(cfg)
|
|
t.Cleanup(func() {
|
|
_ = client.Close()
|
|
})
|
|
|
|
err := redisconn.Instrument(
|
|
client,
|
|
redisconn.WithTracerProvider(tracenoop.NewTracerProvider()),
|
|
redisconn.WithMeterProvider(noop.NewMeterProvider()),
|
|
)
|
|
if err != nil {
|
|
t.Fatalf("instrument: %v", err)
|
|
}
|
|
|
|
if err := redisconn.Ping(context.Background(), client, cfg.OperationTimeout); err != nil {
|
|
t.Fatalf("ping after instrument: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestInstrumentRejectsNilClient(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
if err := redisconn.Instrument(nil); err == nil {
|
|
t.Fatal("expected error for nil client")
|
|
}
|
|
}
|