1// Copyright 2023 The Gitea Authors. All rights reserved.
2// SPDX-License-Identifier: MIT
3
4package queue
5
6import (
7 "context"
8 "testing"
9
10 "forgejo.org/modules/queue/mock"
11 "forgejo.org/modules/setting"
12
13 "github.com/redis/go-redis/v9"
14 "github.com/stretchr/testify/suite"
15 "go.uber.org/mock/gomock"
16)
17
18type baseRedisUnitTestSuite struct {
19 suite.Suite
20
21 mockController *gomock.Controller
22}
23
24func TestBaseRedis(t *testing.T) {
25 suite.Run(t, &baseRedisUnitTestSuite{})
26}
27
28func (suite *baseRedisUnitTestSuite) SetupSuite() {
29 suite.mockController = gomock.NewController(suite.T())
30}
31
32func (suite *baseRedisUnitTestSuite) TestBasic() {
33 queueName := "test-queue"
34 testCases := []struct {
35 Name string
36 ConnectionString string
37 QueueName string
38 Unique bool
39 }{
40 {
41 Name: "unique",
42 ConnectionString: "redis://127.0.0.1/0",
43 QueueName: queueName,
44 Unique: true,
45 },
46 {
47 Name: "non-unique",
48 ConnectionString: "redis://127.0.0.1/0",
49 QueueName: queueName,
50 Unique: false,
51 },
52 {
53 Name: "unique with prefix",
54 ConnectionString: "redis://127.0.0.1/0?prefix=forgejo:queue:",
55 QueueName: "forgejo:queue:" + queueName,
56 Unique: true,
57 },
58 {
59 Name: "non-unique with prefix",
60 ConnectionString: "redis://127.0.0.1/0?prefix=forgejo:queue:",
61 QueueName: "forgejo:queue:" + queueName,
62 Unique: false,
63 },
64 }
65
66 for _, testCase := range testCases {
67 suite.Run(testCase.Name, func() {
68 queueSettings := setting.QueueSettings{
69 Length: 10,
70 ConnStr: testCase.ConnectionString,
71 }
72
73 // Configure expectations.
74 mockRedisStore := mock.NewInMemoryMockRedis()
75 redisClient := mock.NewMockRedisClient(suite.mockController)
76
77 redisClient.EXPECT().
78 Ping(gomock.Any()).
79 Times(1).
80 Return(&redis.StatusCmd{})
81 redisClient.EXPECT().
82 LLen(gomock.Any(), testCase.QueueName).
83 Times(1).
84 DoAndReturn(mockRedisStore.LLen)
85 redisClient.EXPECT().
86 LPop(gomock.Any(), testCase.QueueName).
87 Times(1).
88 DoAndReturn(mockRedisStore.LPop)
89 redisClient.EXPECT().
90 RPush(gomock.Any(), testCase.QueueName, gomock.Any()).
91 Times(1).
92 DoAndReturn(mockRedisStore.RPush)
93
94 if testCase.Unique {
95 redisClient.EXPECT().
96 SAdd(gomock.Any(), testCase.QueueName+"_unique", gomock.Any()).
97 Times(1).
98 DoAndReturn(mockRedisStore.SAdd)
99 redisClient.EXPECT().
100 SRem(gomock.Any(), testCase.QueueName+"_unique", gomock.Any()).
101 Times(1).
102 DoAndReturn(mockRedisStore.SRem)
103 redisClient.EXPECT().
104 SIsMember(gomock.Any(), testCase.QueueName+"_unique", gomock.Any()).
105 Times(2).
106 DoAndReturn(mockRedisStore.SIsMember)
107 }
108
109 client, err := newBaseRedisGeneric(
110 toBaseConfig(queueName, queueSettings),
111 testCase.Unique,
112 redisClient,
113 )
114 suite.Require().NoError(err)
115
116 ctx := context.Background()
117 expectedContent := []byte("test")
118
119 suite.Require().NoError(client.PushItem(ctx, expectedContent))
120
121 found, err := client.HasItem(ctx, expectedContent)
122 suite.Require().NoError(err)
123 if testCase.Unique {
124 suite.True(found)
125 } else {
126 suite.False(found)
127 }
128
129 found, err = client.HasItem(ctx, []byte("not found content"))
130 suite.Require().NoError(err)
131 suite.False(found)
132
133 content, err := client.PopItem(ctx)
134 suite.Require().NoError(err)
135 suite.Equal(expectedContent, content)
136 })
137 }
138}