github.com/outbrain/consul@v1.4.5/agent/cache/entry_test.go (about)

     1  package cache
     2  
     3  import (
     4  	"container/heap"
     5  	"testing"
     6  	"time"
     7  
     8  	"github.com/stretchr/testify/require"
     9  )
    10  
    11  func TestExpiryHeap_impl(t *testing.T) {
    12  	var _ heap.Interface = new(expiryHeap)
    13  }
    14  
    15  func TestExpiryHeap(t *testing.T) {
    16  	require := require.New(t)
    17  	now := time.Now()
    18  	ch := make(chan struct{}, 10) // buffered to prevent blocking in tests
    19  	h := &expiryHeap{NotifyCh: ch}
    20  
    21  	// Init, shouldn't trigger anything
    22  	heap.Init(h)
    23  	testNoMessage(t, ch)
    24  
    25  	// Push an initial value, expect one message
    26  	entry := &cacheEntryExpiry{Key: "foo", HeapIndex: -1, Expires: now.Add(100)}
    27  	heap.Push(h, entry)
    28  	require.Equal(0, entry.HeapIndex)
    29  	testMessage(t, ch)
    30  	testNoMessage(t, ch) // exactly one asserted above
    31  
    32  	// Push another that goes earlier than entry
    33  	entry2 := &cacheEntryExpiry{Key: "bar", HeapIndex: -1, Expires: now.Add(50)}
    34  	heap.Push(h, entry2)
    35  	require.Equal(0, entry2.HeapIndex)
    36  	require.Equal(1, entry.HeapIndex)
    37  	testMessage(t, ch)
    38  	testNoMessage(t, ch) // exactly one asserted above
    39  
    40  	// Push another that goes at the end
    41  	entry3 := &cacheEntryExpiry{Key: "bar", HeapIndex: -1, Expires: now.Add(1000)}
    42  	heap.Push(h, entry3)
    43  	require.Equal(2, entry3.HeapIndex)
    44  	testNoMessage(t, ch) // no notify cause index 0 stayed the same
    45  
    46  	// Remove the first entry (not Pop, since we don't use Pop, but that works too)
    47  	remove := h.Entries[0]
    48  	heap.Remove(h, remove.HeapIndex)
    49  	require.Equal(0, entry.HeapIndex)
    50  	require.Equal(1, entry3.HeapIndex)
    51  	testMessage(t, ch)
    52  	testMessage(t, ch) // we have two because two swaps happen
    53  	testNoMessage(t, ch)
    54  
    55  	// Let's change entry 3 to be early, and fix it
    56  	entry3.Expires = now.Add(10)
    57  	h.Fix(entry3)
    58  	require.Equal(1, entry.HeapIndex)
    59  	require.Equal(0, entry3.HeapIndex)
    60  	testMessage(t, ch)
    61  	testNoMessage(t, ch)
    62  
    63  	// Let's change entry 3 again, this is an edge case where if the 0th
    64  	// element changed, we didn't trigger the channel. Our Fix func should.
    65  	entry.Expires = now.Add(20)
    66  	h.Fix(entry3)
    67  	require.Equal(1, entry.HeapIndex) // no move
    68  	require.Equal(0, entry3.HeapIndex)
    69  	testMessage(t, ch)
    70  	testNoMessage(t, ch) // one message
    71  }
    72  
    73  func testNoMessage(t *testing.T, ch <-chan struct{}) {
    74  	t.Helper()
    75  
    76  	select {
    77  	case <-ch:
    78  		t.Fatal("should not have a message")
    79  	default:
    80  	}
    81  }
    82  
    83  func testMessage(t *testing.T, ch <-chan struct{}) {
    84  	t.Helper()
    85  
    86  	select {
    87  	case <-ch:
    88  	default:
    89  		t.Fatal("should have a message")
    90  	}
    91  }