@@ -7,7 +7,9 @@ package redis
77
88import (
99 "context"
10+ "strconv"
1011 "testing"
12+ "time"
1113
1214 "github.com/agrea/ptr"
1315 miniredis "github.com/alicebob/miniredis/v2"
@@ -90,6 +92,48 @@ func TestParseEtag(t *testing.T) {
9092 })
9193}
9294
95+ func TestParseTTL (t * testing.T ) {
96+ store := NewRedisStateStore (logger .NewLogger ("test" ))
97+ t .Run ("TTL Not an integer" , func (t * testing.T ) {
98+ ttlInSeconds := "not an integer"
99+ ttl := store .parseTTL (& state.SetRequest {
100+ Metadata : map [string ]string {
101+ "ttlInSeconds" : ttlInSeconds ,
102+ },
103+ })
104+ assert .Equal (t , ttl , 0 )
105+ })
106+ t .Run ("TTL specified with wrong key" , func (t * testing.T ) {
107+ ttlInSeconds := 12345
108+ ttl := store .parseTTL (& state.SetRequest {
109+ Metadata : map [string ]string {
110+ "expirationTime" : strconv .Itoa (ttlInSeconds ),
111+ },
112+ })
113+ assert .Equal (t , ttl , 0 )
114+ })
115+ t .Run ("TTL is a number" , func (t * testing.T ) {
116+ ttlInSeconds := 12345
117+ ttl := store .parseTTL (& state.SetRequest {
118+ Metadata : map [string ]string {
119+ "ttlInSeconds" : strconv .Itoa (ttlInSeconds ),
120+ },
121+ })
122+ assert .Equal (t , ttl , ttlInSeconds )
123+ })
124+
125+ t .Run ("TTL never expires" , func (t * testing.T ) {
126+ ttlInSeconds := - 1
127+ ttl := store .parseTTL (& state.SetRequest {
128+ Metadata : map [string ]string {
129+ "ttlInSeconds" : strconv .Itoa (ttlInSeconds ),
130+ },
131+ })
132+ assert .Equal (t , ttl , ttlInSeconds )
133+ })
134+
135+ }
136+
93137func TestParseConnectedSlavs (t * testing.T ) {
94138 store := NewRedisStateStore (logger .NewLogger ("test" ))
95139
@@ -126,13 +170,35 @@ func TestTransactionalUpsert(t *testing.T) {
126170 ss .ctx , ss .cancel = context .WithCancel (context .Background ())
127171
128172 err := ss .Multi (& state.TransactionalStateRequest {
129- Operations : []state.TransactionalStateOperation {{
130- Operation : state .Upsert ,
131- Request : state.SetRequest {
132- Key : "weapon" ,
133- Value : "deathstar" ,
173+ Operations : []state.TransactionalStateOperation {
174+ {
175+ Operation : state .Upsert ,
176+ Request : state.SetRequest {
177+ Key : "weapon" ,
178+ Value : "deathstar" ,
179+ },
134180 },
135- }},
181+ {
182+ Operation : state .Upsert ,
183+ Request : state.SetRequest {
184+ Key : "weapon2" ,
185+ Value : "deathstar2" ,
186+ Metadata : map [string ]string {
187+ "ttlInSeconds" : "123" ,
188+ },
189+ },
190+ },
191+ {
192+ Operation : state .Upsert ,
193+ Request : state.SetRequest {
194+ Key : "weapon3" ,
195+ Value : "deathstar3" ,
196+ Metadata : map [string ]string {
197+ "ttlInSeconds" : "-1" ,
198+ },
199+ },
200+ },
201+ },
136202 })
137203 assert .Equal (t , nil , err )
138204
@@ -144,6 +210,18 @@ func TestTransactionalUpsert(t *testing.T) {
144210 assert .Equal (t , nil , err )
145211 assert .Equal (t , ptr .String ("1" ), version )
146212 assert .Equal (t , `"deathstar"` , data )
213+
214+ res , err = c .Do (context .Background (), "TTL" , "weapon" ).Result ()
215+ assert .Equal (t , nil , err )
216+ assert .Equal (t , int64 (- 1 ), res )
217+
218+ res , err = c .Do (context .Background (), "TTL" , "weapon2" ).Result ()
219+ assert .Equal (t , nil , err )
220+ assert .Equal (t , int64 (123 ), res )
221+
222+ res , err = c .Do (context .Background (), "TTL" , "weapon3" ).Result ()
223+ assert .Equal (t , nil , err )
224+ assert .Equal (t , int64 (- 1 ), res )
147225}
148226
149227func TestTransactionalDelete (t * testing.T ) {
@@ -201,6 +279,76 @@ func TestPing(t *testing.T) {
201279 assert .Error (t , err )
202280}
203281
282+ func TestSetRequestWithTTL (t * testing.T ) {
283+ s , c := setupMiniredis ()
284+ defer s .Close ()
285+
286+ ss := & StateStore {
287+ client : c ,
288+ json : jsoniter .ConfigFastest ,
289+ logger : logger .NewLogger ("test" ),
290+ }
291+ ss .ctx , ss .cancel = context .WithCancel (context .Background ())
292+
293+ t .Run ("TTL specified" , func (t * testing.T ) {
294+ ttlInSeconds := 100
295+ ss .Set (& state.SetRequest {
296+ Key : "weapon100" ,
297+ Value : "deathstar100" ,
298+ Metadata : map [string ]string {
299+ "ttlInSeconds" : strconv .Itoa (ttlInSeconds ),
300+ },
301+ })
302+
303+ ttl , _ := ss .client .TTL (ss .ctx , "weapon100" ).Result ()
304+
305+ assert .Equal (t , time .Duration (ttlInSeconds )* time .Second , ttl )
306+ })
307+
308+ t .Run ("TTL not specified" , func (t * testing.T ) {
309+ ss .Set (& state.SetRequest {
310+ Key : "weapon200" ,
311+ Value : "deathstar200" ,
312+ })
313+
314+ ttl , _ := ss .client .TTL (ss .ctx , "weapon200" ).Result ()
315+
316+ assert .Equal (t , time .Duration (- 1 ), ttl )
317+ })
318+
319+ t .Run ("TTL Changed for Existing Key" , func (t * testing.T ) {
320+ ss .Set (& state.SetRequest {
321+ Key : "weapon300" ,
322+ Value : "deathstar300" ,
323+ })
324+ ttl , _ := ss .client .TTL (ss .ctx , "weapon300" ).Result ()
325+ assert .Equal (t , time .Duration (- 1 ), ttl )
326+
327+ // make the key no longer persistent
328+ ttlInSeconds := 123
329+ ss .Set (& state.SetRequest {
330+ Key : "weapon300" ,
331+ Value : "deathstar300" ,
332+ Metadata : map [string ]string {
333+ "ttlInSeconds" : strconv .Itoa (ttlInSeconds ),
334+ },
335+ })
336+ ttl , _ = ss .client .TTL (ss .ctx , "weapon300" ).Result ()
337+ assert .Equal (t , time .Duration (ttlInSeconds )* time .Second , ttl )
338+
339+ // make the key persistent again
340+ ss .Set (& state.SetRequest {
341+ Key : "weapon300" ,
342+ Value : "deathstar301" ,
343+ Metadata : map [string ]string {
344+ "ttlInSeconds" : strconv .Itoa (- 1 ),
345+ },
346+ })
347+ ttl , _ = ss .client .TTL (ss .ctx , "weapon300" ).Result ()
348+ assert .Equal (t , time .Duration (- 1 ), ttl )
349+ })
350+ }
351+
204352func TestTransactionalDeleteNoEtag (t * testing.T ) {
205353 s , c := setupMiniredis ()
206354 defer s .Close ()
0 commit comments