summaryrefslogtreecommitdiff
path: root/lib/containers/lrucache_test.go
blob: f04df99f5c68cafe8f8806a9da5cf751c3b2c7b4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
// Copyright (C) 2023  Luke Shumaker <lukeshu@lukeshu.com>
//
// SPDX-License-Identifier: GPL-2.0-or-later

package containers

import (
	"runtime/debug"
	"testing"

	"github.com/stretchr/testify/assert"
)

//nolint:paralleltest // Can't be parallel because we test testing.AllocsPerRun.
func TestLRU(t *testing.T) {
	const (
		cacheLen  = 8
		bigNumber = 128
	)
	evictions := 0
	cache := &lruCache[int, int]{
		OnEvict: func(_, _ int) {
			evictions++
		},
	}
	i := 0
	store := func() {
		for cache.Len()+1 > cacheLen {
			cache.EvictOldest()
		}
		cache.Store(i, i)
		i++
	}

	// Disable the GC temporarily to prevent cache.byAge.pool from
	// being cleaned in the middle of an AllocsPerRun and causing
	// spurious allocations.
	percent := debug.SetGCPercent(-1)
	defer debug.SetGCPercent(percent)

	// 1 alloc each as we fill the cache
	assert.Equal(t, float64(1), testing.AllocsPerRun(cacheLen-1, store))
	assert.Equal(t, 0, evictions)
	// after that, it should be alloc-free
	assert.Equal(t, float64(0), testing.AllocsPerRun(1, store))
	assert.Equal(t, 2, evictions)
	assert.Equal(t, float64(0), testing.AllocsPerRun(bigNumber, store))
	assert.Equal(t, 3+bigNumber, evictions)
	// check the len
	assert.Equal(t, cacheLen, len(cache.byName))
	cnt := 0
	for entry := cache.byAge.newest; entry != nil; entry = entry.older {
		cnt++
	}
	assert.Equal(t, cacheLen, cnt)
	cnt = 0
	for entry := cache.byAge.oldest; entry != nil; entry = entry.newer {
		cnt++
	}
	assert.Equal(t, cacheLen, cnt)
	// check contents
	cnt = 0
	for j := i - 1; j >= 0; j-- {
		if cnt < cacheLen {
			assert.True(t, cache.Has(j), j)
			cnt++
		} else {
			assert.False(t, cache.Has(j), j)
		}
	}
}