github.com/decred/dcrlnd@v0.7.6/channeldb/channel_cache_test.go (about) 1 package channeldb 2 3 import ( 4 "reflect" 5 "testing" 6 ) 7 8 // TestChannelCache checks the behavior of the channelCache with respect to 9 // insertion, eviction, and removal of cache entries. 10 func TestChannelCache(t *testing.T) { 11 const cacheSize = 100 12 13 // Create a new channel cache with the configured max size. 14 c := newChannelCache(cacheSize) 15 16 // As a sanity check, assert that querying the empty cache does not 17 // return an entry. 18 _, ok := c.get(0) 19 if ok { 20 t.Fatalf("channel cache should be empty") 21 } 22 23 // Now, fill up the cache entirely. 24 for i := uint64(0); i < cacheSize; i++ { 25 c.insert(i, channelForInt(i)) 26 } 27 28 // Assert that the cache has all of the entries just inserted, since no 29 // eviction should occur until we try to surpass the max size. 30 assertHasChanEntries(t, c, 0, cacheSize) 31 32 // Now, insert a new element that causes the cache to evict an element. 33 c.insert(cacheSize, channelForInt(cacheSize)) 34 35 // Assert that the cache has this last entry, as the cache should evict 36 // some prior element and not the newly inserted one. 37 assertHasChanEntries(t, c, cacheSize, cacheSize) 38 39 // Iterate over all inserted elements and construct a set of the evicted 40 // elements. 41 evicted := make(map[uint64]struct{}) 42 for i := uint64(0); i < cacheSize+1; i++ { 43 _, ok := c.get(i) 44 if !ok { 45 evicted[i] = struct{}{} 46 } 47 } 48 49 // Assert that exactly one element has been evicted. 50 numEvicted := len(evicted) 51 if numEvicted != 1 { 52 t.Fatalf("expected one evicted entry, got: %d", numEvicted) 53 } 54 55 // Remove the highest item which initially caused the eviction and 56 // reinsert the element that was evicted prior. 57 c.remove(cacheSize) 58 for i := range evicted { 59 c.insert(i, channelForInt(i)) 60 } 61 62 // Since the removal created an extra slot, the last insertion should 63 // not have caused an eviction and the entries for all channels in the 64 // original set that filled the cache should be present. 65 assertHasChanEntries(t, c, 0, cacheSize) 66 67 // Finally, reinsert the existing set back into the cache and test that 68 // the cache still has all the entries. If the randomized eviction were 69 // happening on inserts for existing cache items, we expect this to fail 70 // with high probability. 71 for i := uint64(0); i < cacheSize; i++ { 72 c.insert(i, channelForInt(i)) 73 } 74 assertHasChanEntries(t, c, 0, cacheSize) 75 76 } 77 78 // assertHasEntries queries the edge cache for all channels in the range [start, 79 // end), asserting that they exist and their value matches the entry produced by 80 // entryForInt. 81 func assertHasChanEntries(t *testing.T, c *channelCache, start, end uint64) { 82 t.Helper() 83 84 for i := start; i < end; i++ { 85 entry, ok := c.get(i) 86 if !ok { 87 t.Fatalf("channel cache should contain chan %d", i) 88 } 89 90 expEntry := channelForInt(i) 91 if !reflect.DeepEqual(entry, expEntry) { 92 t.Fatalf("entry mismatch, want: %v, got: %v", 93 expEntry, entry) 94 } 95 } 96 } 97 98 // channelForInt generates a unique ChannelEdge given an integer. 99 func channelForInt(i uint64) ChannelEdge { 100 return ChannelEdge{ 101 Info: &ChannelEdgeInfo{ 102 ChannelID: i, 103 }, 104 } 105 }