@@ -44,6 +44,7 @@ func Test_Cache_updateExpirations(t *testing.T) {
4444 TimerChValue time.Duration
4545 Fresh bool
4646 EmptyQueue bool
47+ SingleItem bool
4748 OldExpiresAt time.Time
4849 NewExpiresAt time.Time
4950 Result time.Duration
@@ -116,6 +117,12 @@ func Test_Cache_updateExpirations(t *testing.T) {
116117 NewExpiresAt : newExp ,
117118 Result : time .Until (newExp ),
118119 },
120+ "Update with non fresh item, single item in queue and shortened expiresAt field" : {
121+ SingleItem : true ,
122+ OldExpiresAt : oldExp ,
123+ NewExpiresAt : newExp ,
124+ Result : time .Until (newExp ),
125+ },
119126 }
120127
121128 for cn , c := range cc {
@@ -137,11 +144,13 @@ func Test_Cache_updateExpirations(t *testing.T) {
137144 }
138145
139146 if ! c .EmptyQueue {
140- cache .items .expQueue .push (& list.Element {
141- Value : & Item [string , string ]{
142- expiresAt : c .OldExpiresAt ,
143- },
144- })
147+ if ! c .SingleItem {
148+ cache .items .expQueue .push (& list.Element {
149+ Value : & Item [string , string ]{
150+ expiresAt : c .OldExpiresAt ,
151+ },
152+ })
153+ }
145154
146155 if ! c .Fresh {
147156 elem = & list.Element {
@@ -155,7 +164,11 @@ func Test_Cache_updateExpirations(t *testing.T) {
155164 }
156165 }
157166
158- cache .updateExpirations (c .Fresh , elem )
167+ var oldExpiresAt time.Time
168+ if ! c .EmptyQueue {
169+ oldExpiresAt = c .OldExpiresAt
170+ }
171+ cache .updateExpirations (c .Fresh , elem , oldExpiresAt )
159172
160173 var res time.Duration
161174
@@ -173,13 +186,14 @@ func Test_Cache_set(t *testing.T) {
173186 const newKey , existingKey , evictedKey = "newKey123" , "existingKey" , "evicted"
174187
175188 cc := map [string ]struct {
176- Capacity uint64
177- MaxCost uint64
178- Key string
179- TTL time.Duration
180- Metrics Metrics
181- InsertCalled bool
182- UpdateCalled bool
189+ Capacity uint64
190+ MaxCost uint64
191+ Key string
192+ TTL time.Duration
193+ Metrics Metrics
194+ InsertCalled bool
195+ UpdateCalled bool
196+ ExpectedTimerNotification time.Duration
183197 }{
184198 "Set with existing key and custom TTL" : {
185199 Key : existingKey ,
@@ -295,6 +309,24 @@ func Test_Cache_set(t *testing.T) {
295309 Evictions : 1 ,
296310 },
297311 },
312+ "Set with existing key and shortened TTL" : {
313+ Key : existingKey ,
314+ TTL : time .Minute ,
315+ Metrics : Metrics {
316+ Updates : 1 ,
317+ },
318+ UpdateCalled : true ,
319+ ExpectedTimerNotification : time .Minute ,
320+ },
321+ "Set with new key and shortened TTL" : {
322+ Key : newKey ,
323+ TTL : time .Minute ,
324+ Metrics : Metrics {
325+ Insertions : 1 ,
326+ },
327+ InsertCalled : true ,
328+ ExpectedTimerNotification : time .Minute ,
329+ },
298330 }
299331
300332 for cn , c := range cc {
@@ -385,6 +417,16 @@ func Test_Cache_set(t *testing.T) {
385417 assert .Zero (t , item .expiresAt )
386418 assert .NotEqual (t , c .Key , cache .items .expQueue [0 ].Value .(* Item [string , string ]).key )
387419 }
420+
421+ if c .ExpectedTimerNotification > 0 {
422+ var res time.Duration
423+ select {
424+ case res = <- cache .items .timerCh :
425+ default :
426+ t .Fatal ("expected timer notification but channel was empty" )
427+ }
428+ assert .InDelta (t , c .ExpectedTimerNotification , res , float64 (time .Second ))
429+ }
388430 })
389431 }
390432
@@ -423,28 +465,37 @@ func Test_Cache_get(t *testing.T) {
423465 const existingKey , notFoundKey , expiredKey = "existing" , "notfound" , "expired"
424466
425467 cc := map [string ]struct {
426- Key string
427- Touch bool
428- WithTTL bool
468+ Key string
469+ Touch bool
470+ TTL time.Duration
471+ AddExpiredKey bool
472+ ExpectedTimerNotification time.Duration
429473 }{
430474 "Retrieval of non-existent item" : {
431475 Key : notFoundKey ,
432476 },
433477 "Retrieval of expired item" : {
434- Key : expiredKey ,
478+ Key : expiredKey ,
479+ AddExpiredKey : true ,
435480 },
436481 "Retrieval of existing item without update" : {
437482 Key : existingKey ,
438483 },
439484 "Retrieval of existing item with touch and non zero TTL" : {
440- Key : existingKey ,
441- Touch : true ,
442- WithTTL : true ,
485+ Key : existingKey ,
486+ Touch : true ,
487+ TTL : time . Hour * 30 ,
443488 },
444489 "Retrieval of existing item with touch and zero TTL" : {
445490 Key : existingKey ,
446491 Touch : true ,
447492 },
493+ "Retrieval of existing item with touch and shortened TTL" : {
494+ Key : existingKey ,
495+ Touch : true ,
496+ TTL : time .Millisecond ,
497+ ExpectedTimerNotification : time .Millisecond ,
498+ },
448499 }
449500
450501 for cn , c := range cc {
@@ -454,18 +505,16 @@ func Test_Cache_get(t *testing.T) {
454505 t .Parallel ()
455506
456507 cache := prepCache (0 , time .Hour , existingKey , "test2" , "test3" )
457- addExpiredCacheItems (cache , expiredKey )
458- time .Sleep (time .Millisecond ) // force expiration
508+ if c .AddExpiredKey {
509+ addExpiredCacheItems (cache , expiredKey )
510+ time .Sleep (time .Millisecond ) // force expiration
511+ }
459512
460513 oldItem := cache .items .values [existingKey ].Value .(* Item [string , string ])
461514 oldQueueIndex := oldItem .queueIndex
462515 oldExpiresAt := oldItem .expiresAt
463516
464- if c .WithTTL {
465- oldItem .ttl = time .Hour * 30
466- } else {
467- oldItem .ttl = 0
468- }
517+ oldItem .ttl = c .TTL
469518
470519 elem := cache .get (c .Key , c .Touch , false )
471520
@@ -483,14 +532,30 @@ func Test_Cache_get(t *testing.T) {
483532 require .NotNil (t , elem )
484533 item := elem .Value .(* Item [string , string ])
485534
486- if c .Touch && c .WithTTL {
487- assert .True (t , item .expiresAt .After (oldExpiresAt ))
488- assert .NotEqual (t , oldQueueIndex , item .queueIndex )
535+ if c .Touch && c .TTL > 0 {
536+ if item .expiresAt .Before (oldExpiresAt ) {
537+ assert .Equal (t , oldQueueIndex , item .queueIndex )
538+ } else {
539+ assert .True (t , item .expiresAt .After (oldExpiresAt ))
540+ assert .NotEqual (t , oldQueueIndex , item .queueIndex )
541+ }
489542 } else {
490543 assert .True (t , item .expiresAt .Equal (oldExpiresAt ))
491544 assert .Equal (t , oldQueueIndex , item .queueIndex )
492545 }
493546
547+ select {
548+ case res := <- cache .items .timerCh :
549+ if c .ExpectedTimerNotification == 0 {
550+ t .Fatalf ("unexpected timer notification: %v" , res )
551+ }
552+ assert .InDelta (t , c .ExpectedTimerNotification , res , float64 (time .Second ))
553+ default :
554+ if c .ExpectedTimerNotification > 0 {
555+ t .Fatal ("expected timer notification but channel was empty" )
556+ }
557+ }
558+
494559 assert .Equal (t , c .Key , cache .items .lru .Front ().Value .(* Item [string , string ]).key )
495560 })
496561 }
0 commit comments