flamingo.me/flamingo-commerce/v3@v3.11.0/checkout/infrastructure/locker/redis_test.go (about) 1 package locker_test 2 3 import ( 4 "context" 5 "fmt" 6 "os/exec" 7 "testing" 8 "time" 9 10 "github.com/stretchr/testify/assert" 11 "github.com/stretchr/testify/require" 12 "github.com/stvp/tempredis" 13 "github.com/testcontainers/testcontainers-go" 14 "github.com/testcontainers/testcontainers-go/wait" 15 "go.uber.org/goleak" 16 17 "flamingo.me/flamingo-commerce/v3/checkout/infrastructure/locker" 18 ) 19 20 func startUp(t *testing.T) *tempredis.Server { 21 t.Helper() 22 server, err := tempredis.Start(tempredis.Config{}) 23 if err != nil { 24 t.Fatal(err) 25 } 26 27 return server 28 } 29 30 func getRedisLocker(network, address string) *locker.Redis { 31 redis := locker.NewRedis(&struct { 32 MaxIdle int `inject:"config:commerce.checkout.placeorder.lock.redis.maxIdle"` 33 IdleTimeoutMilliseconds int `inject:"config:commerce.checkout.placeorder.lock.redis.idleTimeoutMilliseconds"` 34 Network string `inject:"config:commerce.checkout.placeorder.lock.redis.network"` 35 Address string `inject:"config:commerce.checkout.placeorder.lock.redis.address"` 36 Database int `inject:"config:commerce.checkout.placeorder.lock.redis.database"` 37 }{MaxIdle: 3, IdleTimeoutMilliseconds: 240000, Network: network, Address: address, Database: 0}) 38 return redis 39 } 40 41 func TestRedis_TryLockDocker(t *testing.T) { 42 ctx := context.Background() 43 req := testcontainers.ContainerRequest{ 44 Image: "redis:latest", 45 ExposedPorts: []string{"6379/tcp"}, 46 WaitingFor: wait.ForLog("Ready to accept connections"), 47 } 48 redisC, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ 49 ContainerRequest: req, 50 Started: true, 51 }) 52 require.NoError(t, err) 53 defer func() { _ = redisC.Terminate(ctx) }() 54 defer goleak.VerifyNone(t, goleak.IgnoreCurrent()) 55 56 port, err := redisC.MappedPort(ctx, "6379") 57 require.NoError(t, err) 58 59 host, err := redisC.Host(ctx) 60 require.NoError(t, err) 61 address := fmt.Sprintf("%s:%s", host, port.Port()) 62 63 redisLocker := getRedisLocker("tcp", address) 64 runTestCases(t, redisLocker) 65 66 } 67 68 func TestRedis_TryLock(t *testing.T) { 69 defer goleak.VerifyNone(t, goleak.IgnoreCurrent()) 70 71 if _, err := exec.LookPath("redis-server"); err != nil { 72 t.Skip("redis-server not installed") 73 } 74 75 server := startUp(t) 76 defer func() { _ = server.Term() }() 77 redisLocker := getRedisLocker("unix", server.Socket()) 78 79 runTestCases(t, redisLocker) 80 81 } 82 83 func runTestCases(t *testing.T, redisLocker *locker.Redis) { 84 t.Run("really locked", func(t *testing.T) { 85 key := "test" 86 start := time.Now() 87 // get a long lock 88 unlock, err := redisLocker.TryLock(context.Background(), key, time.Minute) 89 require.NoError(t, err) 90 91 // try to get same lock 92 _, err = redisLocker.TryLock(context.Background(), key, time.Second) 93 assert.Error(t, err) 94 // assert if we were really in the lock period 95 assert.True(t, time.Now().Before(start.Add(time.Minute))) 96 97 // unlock 98 require.NoError(t, unlock()) 99 100 // get the lock successfully again after unlock 101 unlock, err = redisLocker.TryLock(context.Background(), key, time.Minute) 102 require.NoError(t, err) 103 require.NoError(t, unlock()) 104 }) 105 106 t.Run("lock should be expanded", func(t *testing.T) { 107 key := "test_expanded" 108 109 unlock, err := redisLocker.TryLock(context.Background(), key, 100*time.Millisecond) 110 require.NoError(t, err) 111 defer func() { _ = unlock() }() 112 113 time.Sleep(200 * time.Millisecond) 114 // try to get same lock 115 _, err = redisLocker.TryLock(context.Background(), key, time.Second) 116 assert.Error(t, err) 117 }) 118 } 119 120 func TestRedis_StatusDocker(t *testing.T) { 121 t.Run("redis not ready", func(t *testing.T) { 122 redisLocker := getRedisLocker("tcp", "127.0.0.1:80") 123 alive, _ := redisLocker.Status() 124 125 assert.False(t, alive) 126 }) 127 128 t.Run("redis is there", func(t *testing.T) { 129 ctx := context.Background() 130 req := testcontainers.ContainerRequest{ 131 Image: "redis:latest", 132 ExposedPorts: []string{"6379/tcp"}, 133 WaitingFor: wait.ForLog("Ready to accept connections"), 134 } 135 redisC, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{ 136 ContainerRequest: req, 137 Started: true, 138 }) 139 require.NoError(t, err) 140 defer func() { _ = redisC.Terminate(ctx) }() 141 defer goleak.VerifyNone(t, goleak.IgnoreCurrent()) 142 143 port, err := redisC.MappedPort(ctx, "6379") 144 require.NoError(t, err) 145 146 host, err := redisC.Host(ctx) 147 require.NoError(t, err) 148 address := fmt.Sprintf("%s:%s", host, port.Port()) 149 150 redisLocker := getRedisLocker("tcp", address) 151 alive, _ := redisLocker.Status() 152 153 assert.True(t, alive) 154 }) 155 }