1package queue
2
3import (
4 "context"
5 "os"
6 "os/exec"
7 "testing"
8 "time"
9
10 "forgejo.org/modules/nosql"
11 "forgejo.org/modules/setting"
12
13 "github.com/stretchr/testify/suite"
14)
15
16const defaultTestRedisServer = "127.0.0.1:6379"
17
18type baseRedisWithServerTestSuite struct {
19 suite.Suite
20}
21
22func TestBaseRedisWithServer(t *testing.T) {
23 suite.Run(t, &baseRedisWithServerTestSuite{})
24}
25
26func (suite *baseRedisWithServerTestSuite) TestNormal() {
27 redisAddress := "redis://" + suite.testRedisHost() + "/0"
28 queueSettings := setting.QueueSettings{
29 Length: 10,
30 ConnStr: redisAddress,
31 }
32
33 redisServer, accessible := suite.startRedisServer(redisAddress)
34
35 // If it's accessible, but redisServer command is nil, that means we are using
36 // an already running redis server.
37 if redisServer == nil && !accessible {
38 suite.T().Skip("redis-server not found in Forgejo test yet")
39
40 return
41 }
42
43 defer func() {
44 if redisServer != nil {
45 _ = redisServer.Process.Signal(os.Interrupt)
46 _ = redisServer.Wait()
47 }
48 }()
49
50 testQueueBasic(suite.T(), newBaseRedisSimple, toBaseConfig("baseRedis", queueSettings), false)
51 testQueueBasic(suite.T(), newBaseRedisUnique, toBaseConfig("baseRedisUnique", queueSettings), true)
52}
53
54func (suite *baseRedisWithServerTestSuite) TestWithPrefix() {
55 redisAddress := "redis://" + suite.testRedisHost() + "/0?prefix=forgejo:queue:"
56 queueSettings := setting.QueueSettings{
57 Length: 10,
58 ConnStr: redisAddress,
59 }
60
61 redisServer, accessible := suite.startRedisServer(redisAddress)
62
63 // If it's accessible, but redisServer command is nil, that means we are using
64 // an already running redis server.
65 if redisServer == nil && !accessible {
66 suite.T().Skip("redis-server not found in Forgejo test yet")
67
68 return
69 }
70
71 defer func() {
72 if redisServer != nil {
73 _ = redisServer.Process.Signal(os.Interrupt)
74 _ = redisServer.Wait()
75 }
76 }()
77
78 testQueueBasic(suite.T(), newBaseRedisSimple, toBaseConfig("baseRedis", queueSettings), false)
79 testQueueBasic(suite.T(), newBaseRedisUnique, toBaseConfig("baseRedisUnique", queueSettings), true)
80}
81
82func (suite *baseRedisWithServerTestSuite) startRedisServer(address string) (*exec.Cmd, bool) {
83 var redisServer *exec.Cmd
84
85 if !suite.waitRedisReady(address, 0) {
86 redisServerProg, err := exec.LookPath("redis-server")
87 if err != nil {
88 return nil, false
89 }
90 redisServer = &exec.Cmd{
91 Path: redisServerProg,
92 Args: []string{redisServerProg, "--bind", "127.0.0.1", "--port", "6379"},
93 Dir: suite.T().TempDir(),
94 Stdin: os.Stdin,
95 Stdout: os.Stdout,
96 Stderr: os.Stderr,
97 }
98
99 suite.Require().NoError(redisServer.Start())
100
101 if !suite.True(suite.waitRedisReady(address, 5*time.Second), "start redis-server") {
102 // Return with redis server even if it's not available. It was started,
103 // even if it's not reachable for any reasons, it's still started, the
104 // parent will close it.
105 return redisServer, false
106 }
107 }
108
109 return redisServer, true
110}
111
112func (suite *baseRedisWithServerTestSuite) waitRedisReady(conn string, dur time.Duration) (ready bool) {
113 ctxTimed, cancel := context.WithTimeout(context.Background(), time.Second*5)
114 defer cancel()
115 for t := time.Now(); ; time.Sleep(50 * time.Millisecond) {
116 ret := nosql.GetManager().GetRedisClient(conn).Ping(ctxTimed)
117 if ret.Err() == nil {
118 return true
119 }
120 if time.Since(t) > dur {
121 return false
122 }
123 }
124}
125
126func (suite *baseRedisWithServerTestSuite) testRedisHost() string {
127 value := os.Getenv("TEST_REDIS_SERVER")
128 if value != "" {
129 return value
130 }
131
132 return defaultTestRedisServer
133}