2023-03-28 22:48:58 +00:00
|
|
|
// Copyright (c) HashiCorp, Inc.
|
2023-08-11 13:12:13 +00:00
|
|
|
// SPDX-License-Identifier: BUSL-1.1
|
2023-03-28 22:48:58 +00:00
|
|
|
|
2020-10-20 22:34:42 +00:00
|
|
|
package ttlcache
|
2020-10-20 17:19:21 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"container/heap"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/stretchr/testify/assert"
|
2022-05-10 20:25:51 +00:00
|
|
|
|
|
|
|
"github.com/hashicorp/consul/sdk/testutil"
|
2020-10-20 17:19:21 +00:00
|
|
|
)
|
|
|
|
|
2020-10-20 21:38:12 +00:00
|
|
|
var _ heap.Interface = (*entryHeap)(nil)
|
2020-10-20 17:19:21 +00:00
|
|
|
|
|
|
|
func TestExpiryHeap(t *testing.T) {
|
2020-10-20 21:38:12 +00:00
|
|
|
h := NewExpiryHeap()
|
|
|
|
ch := h.NotifyCh
|
2020-10-20 22:34:42 +00:00
|
|
|
var entry, entry2, entry3 *Entry
|
2020-10-20 17:19:21 +00:00
|
|
|
|
|
|
|
// Init, shouldn't trigger anything
|
|
|
|
testNoMessage(t, ch)
|
|
|
|
|
2022-05-10 20:25:51 +00:00
|
|
|
testutil.RunStep(t, "add an entry", func(t *testing.T) {
|
2020-10-20 17:19:21 +00:00
|
|
|
entry = h.Add("foo", 100*time.Millisecond)
|
2020-10-20 22:34:42 +00:00
|
|
|
assert.Equal(t, 0, entry.heapIndex)
|
2020-10-20 17:19:21 +00:00
|
|
|
testMessage(t, ch)
|
|
|
|
testNoMessage(t, ch) // exactly one asserted above
|
|
|
|
})
|
|
|
|
|
2022-05-10 20:25:51 +00:00
|
|
|
testutil.RunStep(t, "add a second entry in front", func(t *testing.T) {
|
2020-10-20 17:19:21 +00:00
|
|
|
entry2 = h.Add("bar", 50*time.Millisecond)
|
2020-10-20 22:34:42 +00:00
|
|
|
assert.Equal(t, 0, entry2.heapIndex)
|
|
|
|
assert.Equal(t, 1, entry.heapIndex)
|
2020-10-20 17:19:21 +00:00
|
|
|
testMessage(t, ch)
|
|
|
|
testNoMessage(t, ch) // exactly one asserted above
|
|
|
|
})
|
|
|
|
|
2022-05-10 20:25:51 +00:00
|
|
|
testutil.RunStep(t, "add a third entry at the end", func(t *testing.T) {
|
2020-10-20 17:19:21 +00:00
|
|
|
entry3 = h.Add("baz", 1000*time.Millisecond)
|
2020-10-20 22:34:42 +00:00
|
|
|
assert.Equal(t, 2, entry3.heapIndex)
|
2020-10-20 17:19:21 +00:00
|
|
|
testNoMessage(t, ch) // no notify cause index 0 stayed the same
|
|
|
|
})
|
|
|
|
|
2022-05-10 20:25:51 +00:00
|
|
|
testutil.RunStep(t, "remove the first entry", func(t *testing.T) {
|
2020-10-20 17:59:53 +00:00
|
|
|
h.Remove(0)
|
2020-10-20 22:34:42 +00:00
|
|
|
assert.Equal(t, 0, entry.heapIndex)
|
|
|
|
assert.Equal(t, 1, entry3.heapIndex)
|
2020-10-20 17:19:21 +00:00
|
|
|
testMessage(t, ch)
|
|
|
|
testNoMessage(t, ch)
|
|
|
|
})
|
|
|
|
|
2022-05-10 20:25:51 +00:00
|
|
|
testutil.RunStep(t, "update so that entry3 expires first", func(t *testing.T) {
|
2021-02-23 17:13:41 +00:00
|
|
|
h.Update(entry.heapIndex, 2000*time.Millisecond)
|
2020-10-20 22:34:42 +00:00
|
|
|
assert.Equal(t, 1, entry.heapIndex)
|
|
|
|
assert.Equal(t, 0, entry3.heapIndex)
|
2020-10-20 17:19:21 +00:00
|
|
|
testMessage(t, ch)
|
|
|
|
testNoMessage(t, ch)
|
|
|
|
})
|
|
|
|
|
2022-05-10 20:25:51 +00:00
|
|
|
testutil.RunStep(t, "0th element change triggers a notify", func(t *testing.T) {
|
2021-02-23 17:13:41 +00:00
|
|
|
h.Update(entry3.heapIndex, 1500*time.Millisecond)
|
2020-10-20 22:34:42 +00:00
|
|
|
assert.Equal(t, 1, entry.heapIndex) // no move
|
|
|
|
assert.Equal(t, 0, entry3.heapIndex)
|
2020-10-20 17:19:21 +00:00
|
|
|
testMessage(t, ch)
|
|
|
|
testNoMessage(t, ch) // one message
|
|
|
|
})
|
2021-02-23 17:13:41 +00:00
|
|
|
|
2022-05-10 20:25:51 +00:00
|
|
|
testutil.RunStep(t, "update can not decrease expiry time", func(t *testing.T) {
|
2021-02-23 17:13:41 +00:00
|
|
|
h.Update(entry.heapIndex, 100*time.Millisecond)
|
|
|
|
assert.Equal(t, 1, entry.heapIndex) // no move
|
|
|
|
assert.Equal(t, 0, entry3.heapIndex)
|
|
|
|
testNoMessage(t, ch) // no notify, because no change in the heap
|
|
|
|
})
|
2020-10-20 17:19:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func testNoMessage(t *testing.T, ch <-chan struct{}) {
|
|
|
|
t.Helper()
|
|
|
|
|
|
|
|
select {
|
|
|
|
case <-ch:
|
|
|
|
t.Fatal("should not have a message")
|
|
|
|
default:
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func testMessage(t *testing.T, ch <-chan struct{}) {
|
|
|
|
t.Helper()
|
|
|
|
|
|
|
|
select {
|
|
|
|
case <-ch:
|
|
|
|
default:
|
|
|
|
t.Fatal("should have a message")
|
|
|
|
}
|
|
|
|
}
|