github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/pkg/util/evicting_queue_test.go (about)

     1  package util
     2  
     3  import (
     4  	"math"
     5  	"math/rand"
     6  	"sync"
     7  	"testing"
     8  
     9  	"github.com/stretchr/testify/require"
    10  )
    11  
    12  func noopOnEvict() {}
    13  
    14  func TestQueueAppend(t *testing.T) {
    15  	q, err := NewEvictingQueue(10, noopOnEvict)
    16  	require.Nil(t, err)
    17  
    18  	q.Append(1)
    19  	q.Append(2)
    20  	q.Append(3)
    21  	q.Append(4)
    22  	q.Append(5)
    23  
    24  	require.Equal(t, 5, q.Length())
    25  }
    26  
    27  func TestQueueCapacity(t *testing.T) {
    28  	q, err := NewEvictingQueue(9, noopOnEvict)
    29  	require.Nil(t, err)
    30  	require.Equal(t, 9, q.Capacity())
    31  
    32  	q.capacity = 11
    33  	require.Equal(t, 11, q.Capacity())
    34  }
    35  
    36  func TestZeroCapacityQueue(t *testing.T) {
    37  	q, err := NewEvictingQueue(0, noopOnEvict)
    38  	require.Error(t, err)
    39  	require.Nil(t, q)
    40  }
    41  
    42  func TestNegativeCapacityQueue(t *testing.T) {
    43  	q, err := NewEvictingQueue(-1, noopOnEvict)
    44  	require.Error(t, err)
    45  	require.Nil(t, q)
    46  }
    47  
    48  func TestQueueEvict(t *testing.T) {
    49  	q, err := NewEvictingQueue(3, noopOnEvict)
    50  	require.Nil(t, err)
    51  
    52  	// appending 5 entries will cause the first (oldest) 2 entries to be evicted
    53  	entries := []interface{}{1, 2, 3, 4, 5}
    54  	for _, entry := range entries {
    55  		q.Append(entry)
    56  	}
    57  
    58  	require.Equal(t, 3, q.Length())
    59  	require.Equal(t, entries[2:], q.Entries())
    60  }
    61  
    62  func TestQueueClear(t *testing.T) {
    63  	q, err := NewEvictingQueue(3, noopOnEvict)
    64  	require.Nil(t, err)
    65  
    66  	q.Append(1)
    67  	q.Clear()
    68  
    69  	require.Equal(t, 0, q.Length())
    70  }
    71  
    72  func TestQueueEvictionCallback(t *testing.T) {
    73  	var evictionCallbackCalls int
    74  
    75  	q, err := NewEvictingQueue(3, func() {
    76  		evictionCallbackCalls++
    77  	})
    78  	require.Nil(t, err)
    79  
    80  	for i := 0; i < 5; i++ {
    81  		q.Append(i)
    82  	}
    83  
    84  	require.Equal(t, 2, evictionCallbackCalls)
    85  }
    86  
    87  func TestSafeConcurrentAccess(t *testing.T) {
    88  	q, err := NewEvictingQueue(3, noopOnEvict)
    89  	require.Nil(t, err)
    90  
    91  	var wg sync.WaitGroup
    92  
    93  	for w := 0; w < 30; w++ {
    94  		wg.Add(1)
    95  		go func() {
    96  			defer wg.Done()
    97  
    98  			for i := 0; i < 500; i++ {
    99  				q.Append(rand.Int())
   100  			}
   101  		}()
   102  	}
   103  
   104  	wg.Wait()
   105  
   106  	require.Equal(t, 3, q.Length())
   107  }
   108  
   109  type queueEntry struct {
   110  	key   string
   111  	value interface{}
   112  }
   113  
   114  func BenchmarkAppendAndEvict(b *testing.B) {
   115  	capacity := 5000
   116  	q, err := NewEvictingQueue(capacity, noopOnEvict)
   117  	require.Nil(b, err)
   118  
   119  	b.ResetTimer()
   120  	b.ReportAllocs()
   121  
   122  	for n := 0; n < b.N; n++ {
   123  		q.Append(&queueEntry{
   124  			key:   "hello",
   125  			value: "world",
   126  		})
   127  	}
   128  
   129  	require.EqualValues(b, math.Min(float64(b.N), float64(capacity)), q.Length())
   130  }