From 05b5be3f18a68ca4227054db3b9ae1186c9e10df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20de=20la=20Pe=C3=B1a?= Date: Wed, 30 Apr 2025 12:37:58 +0200 Subject: [PATCH] chore: consume the testredis module in redis --- redis/go.mod | 10 ++- redis/go.sum | 16 ++--- redis/redis_test.go | 167 +++++--------------------------------------- 3 files changed, 33 insertions(+), 160 deletions(-) diff --git a/redis/go.mod b/redis/go.mod index 0ab3209e..d169b1d5 100644 --- a/redis/go.mod +++ b/redis/go.mod @@ -3,18 +3,19 @@ module github.com/gofiber/storage/redis/v3 go 1.23.0 require ( + github.com/gofiber/storage/testhelpers/redis v0.0.0-00010101000000-000000000000 github.com/redis/go-redis/v9 v9.7.3 github.com/stretchr/testify v1.10.0 - github.com/testcontainers/testcontainers-go v0.37.0 - github.com/testcontainers/testcontainers-go/modules/redis v0.37.0 ) +replace github.com/gofiber/storage/testhelpers/redis => ../testhelpers/redis + require ( dario.cat/mergo v1.0.1 // indirect github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect github.com/cenkalti/backoff/v4 v4.2.1 // indirect - github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/containerd/log v0.1.0 // indirect github.com/containerd/platforms v0.2.1 // indirect github.com/cpuguy83/dockercfg v0.3.2 // indirect @@ -49,6 +50,8 @@ require ( github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/shirou/gopsutil/v4 v4.25.1 // indirect github.com/sirupsen/logrus v1.9.3 // indirect + github.com/testcontainers/testcontainers-go v0.37.0 // indirect + github.com/testcontainers/testcontainers-go/modules/redis v0.37.0 // indirect github.com/tklauser/go-sysconf v0.3.12 // indirect github.com/tklauser/numcpus v0.6.1 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect @@ -62,6 +65,7 @@ require ( go.opentelemetry.io/proto/otlp v1.5.0 // indirect golang.org/x/crypto v0.37.0 // indirect golang.org/x/sys v0.32.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250414145226-207652e42e2e // indirect google.golang.org/protobuf v1.36.6 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/redis/go.sum b/redis/go.sum index e870d7b3..7acf264a 100644 --- a/redis/go.sum +++ b/redis/go.sum @@ -12,8 +12,8 @@ github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A= @@ -53,8 +53,8 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1 h1:VNqngBF40hVlDloBruUehVYC3ArSgIyScOAyMRqBxRg= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.25.1/go.mod h1:RBRO7fro65R6tjKzYgLAFo0t1QEXY1Dp+i/bvpRiqiQ= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= @@ -180,12 +180,12 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d h1:H8tOf8XM88HvKqLTxe755haY6r1fqqzLbEnfrmLXlSA= -google.golang.org/genproto/googleapis/api v0.0.0-20250102185135-69823020774d/go.mod h1:2v7Z7gP2ZUOGsaFyxATQSRoBnKygqVq2Cwnvom7QiqY= +google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb h1:p31xT4yrYrSM/G4Sn2+TNUkVhFCbG9y8itM2S6Th950= +google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:jbe3Bkdp+Dh2IrslsFCklNhweNTBgSYanP1UXhJDhKg= google.golang.org/genproto/googleapis/rpc v0.0.0-20250414145226-207652e42e2e h1:ztQaXfzEXTmCBvbtWYRhJxW+0iJcz2qXfd38/e9l7bA= google.golang.org/genproto/googleapis/rpc v0.0.0-20250414145226-207652e42e2e/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= -google.golang.org/grpc v1.69.2 h1:U3S9QEtbXC0bYNvRtcoklF3xGtLViumSYxWykJS+7AU= -google.golang.org/grpc v1.69.2/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4= +google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ= +google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw= google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/redis/redis_test.go b/redis/redis_test.go index 36e9f204..f32adde2 100644 --- a/redis/redis_test.go +++ b/redis/redis_test.go @@ -1,161 +1,30 @@ package redis import ( - "context" - "os" - "strings" "testing" "time" "github.com/stretchr/testify/require" - "github.com/testcontainers/testcontainers-go" - "github.com/testcontainers/testcontainers-go/modules/redis" + testredis "github.com/gofiber/storage/testhelpers/redis" ) -const ( - // redisImage is the default image used for running Redis in tests. - redisImage = "docker.io/redis:7" - redisImageEnvVar = "TEST_REDIS_IMAGE" - redisPort = "6379/tcp" -) - -type testStoreSettings struct { - address bool - hostPort bool - url bool - - // TLS settings - secureURL bool - mtlsDisabled bool - tls bool -} - -type testStoreOption func(*testStoreSettings) - -// withAddress sets the test store to use address-based connection. -func withAddress() testStoreOption { - return func(o *testStoreSettings) { - o.address = true - } -} - -// withHostPort sets the test store to use host and port based connection. -func withHostPort() testStoreOption { - return func(o *testStoreSettings) { - o.hostPort = true - } -} - -// withTLS configures the test store to use TLS. -// Parameters: -// - secureURL: when true, uses "rediss://" scheme, otherwise uses "redis://" -// - mtlsDisabled: when true, disables mutual TLS authentication (--tls-auth-clients no) -func withTLS(secureURL bool, mtlsDisabled bool) testStoreOption { - return func(o *testStoreSettings) { - o.tls = true - o.secureURL = secureURL - o.mtlsDisabled = mtlsDisabled - } -} - -// withURL sets the test store to use a URL. -// Use it when you want to explicitly combine multiple addresses in the same test -// to verify which one is being used. -// - true: the URL will receive the URI provided by the testcontainer -// - false: the URL will be set to an empty string -func withURL(useContainerURI bool) testStoreOption { - return func(o *testStoreSettings) { - o.url = useContainerURI - } -} - -// newConfigFromContainer creates a Redis configuration using a test container. +// newConfigFromContainer creates a Redis configuration using Testcontainers. // It configures the container based on the provided options and returns a Config // that can be used to connect to the container. // The container is cleaned up when the test completes. -func newConfigFromContainer(t testing.TB, opts ...testStoreOption) Config { +func newConfigFromContainer(t testing.TB, opts ...testredis.Option) Config { t.Helper() - settings := &testStoreSettings{ - url: true, // by default, the URL will be set to the URI provided by the testcontainer - address: false, - hostPort: false, - } - for _, o := range opts { - o(settings) - } - - img := redisImage - if imgFromEnv := os.Getenv(redisImageEnvVar); imgFromEnv != "" { - img = imgFromEnv - } + redisCtr := testredis.Start(t, opts...) cfg := Config{ - Reset: true, - } - - ctx := context.Background() - - tcOpts := []testcontainers.ContainerCustomizer{} - - if settings.tls { - tcOpts = append(tcOpts, redis.WithTLS()) - - // Use Redis module's TLS options, but for the MTLS case, disable the auth-clients flag - cmds := []string{ - "--port", "0", - "--tls-port", "6379", - "--tls-cert-file", "/tls/server.crt", - "--tls-key-file", "/tls/server.key", - "--tls-ca-cert-file", "/tls/ca.crt", - } - - cmds = append(cmds, "--tls-auth-clients", func() string { - if settings.mtlsDisabled { - return "no" - } - return "yes" - }()) - - // completely override the default CMD, as the Redis module is opinionated about the CMD - tcOpts = append(tcOpts, testcontainers.WithCmd(cmds...)) - } - - c, err := redis.Run(ctx, img, tcOpts...) - testcontainers.CleanupContainer(t, c) - require.NoError(t, err) - - cfg.TLSConfig = c.TLSConfig() - - uri, err := c.ConnectionString(ctx) - require.NoError(t, err) - - if settings.hostPort { - host, err := c.Host(ctx) - require.NoError(t, err) - - port, err := c.MappedPort(ctx, redisPort) - require.NoError(t, err) - - cfg.Host = host - cfg.Port = port.Int() - } - - if settings.address { - // trim the schemes from the URI - addr := strings.TrimPrefix(uri, "redis://") - addr = strings.TrimPrefix(addr, "rediss://") - cfg.Addrs = []string{addr} - } - - if settings.url { - cfg.URL = uri - } - - if !settings.secureURL { - // Replace the scheme with the insecure one - cfg.URL = strings.Replace(cfg.URL, "rediss://", "redis://", 1) + Reset: true, + TLSConfig: redisCtr.TLSConfig, + Host: redisCtr.Host, + Port: redisCtr.Port, + Addrs: redisCtr.Addrs, + URL: redisCtr.URL, } return cfg @@ -165,7 +34,7 @@ func newConfigFromContainer(t testing.TB, opts ...testStoreOption) Config { // It configures the container based on the provided options and returns a Storage // instance connected to the container. The caller is responsible for calling // Close() on the returned Storage when done. -func newTestStore(t testing.TB, opts ...testStoreOption) *Storage { +func newTestStore(t testing.TB, opts ...testredis.Option) *Storage { return New(newConfigFromContainer(t, opts...)) } @@ -330,7 +199,7 @@ func Test_Redis_Initialize_WithHostPort(t *testing.T) { val = []byte("kent") ) - testStore := newTestStore(t, withHostPort()) + testStore := newTestStore(t, testredis.WithHostPort()) defer testStore.Close() err := testStore.Set(key, val, 0) @@ -348,7 +217,7 @@ func Test_Redis_Initialize_WithURL_TLS_Verify(t *testing.T) { testFn := func(t *testing.T, secureURL bool, mtlsDisabled bool) { t.Helper() - testStore := newTestStore(t, withTLS(secureURL, mtlsDisabled)) + testStore := newTestStore(t, testredis.WithTLS(secureURL, mtlsDisabled)) defer testStore.Close() var ( @@ -390,7 +259,7 @@ func Test_Redis_Initialize_WithURL_TLS_Verify(t *testing.T) { func Test_Redis_Universal_Addrs(t *testing.T) { // This should failover and create a Single Node connection. - testStoreUniversal := newTestStore(t, withAddress()) + testStoreUniversal := newTestStore(t, testredis.WithAddress()) defer testStoreUniversal.Close() var ( key = "bruce" @@ -416,7 +285,7 @@ func Test_Redis_Universal_With_URL_Undefined(t *testing.T) { // This should failover to creating a regular *redis.Client // The URL should get ignored since it's empty // the withURL option goes last to include it in the config - testStoreUniversal := newTestStore(t, withAddress(), withURL(false)) + testStoreUniversal := newTestStore(t, testredis.WithAddress(), testredis.WithURL(false)) defer testStoreUniversal.Close() var ( key = "bruce" @@ -441,7 +310,7 @@ func Test_Redis_Universal_With_URL_Undefined(t *testing.T) { func Test_Redis_Universal_With_URL_Defined(t *testing.T) { // This should failover to creating a regular *redis.Client // The Addrs field should get ignored since URL is defined - testStoreUniversal := newTestStore(t, withAddress(), withURL(true)) + testStoreUniversal := newTestStore(t, testredis.WithAddress(), testredis.WithURL(true)) defer testStoreUniversal.Close() var ( @@ -467,7 +336,7 @@ func Test_Redis_Universal_With_URL_Defined(t *testing.T) { func Test_Redis_Universal_With_HostPort(t *testing.T) { // This should failover to creating a regular *redis.Client // The Host and Port should get ignored since Addrs is defined - testStoreUniversal := newTestStore(t, withAddress(), withHostPort(), withURL(false)) + testStoreUniversal := newTestStore(t, testredis.WithAddress(), testredis.WithHostPort(), testredis.WithURL(false)) defer testStoreUniversal.Close() var ( key = "bruce" @@ -492,7 +361,7 @@ func Test_Redis_Universal_With_HostPort(t *testing.T) { func Test_Redis_Universal_With_HostPort_And_URL(t *testing.T) { // This should failover to creating a regular *redis.Client // The Host and Port should get ignored since Addrs is defined - testStoreUniversal := newTestStore(t, withAddress(), withHostPort(), withURL(true)) + testStoreUniversal := newTestStore(t, testredis.WithAddress(), testredis.WithHostPort(), testredis.WithURL(true)) defer testStoreUniversal.Close() var (