github.com/nebulouslabs/sia@v1.3.7/modules/renter/streamcache_test.go (about) 1 package renter 2 3 import ( 4 "container/heap" 5 "reflect" 6 "strconv" 7 "testing" 8 "time" 9 ) 10 11 // TestHeapImplementation tests that the streamCache heap functions properly 12 func TestHeapImplementation(t *testing.T) { 13 // Initializing minimum variables 14 streamHeap := make(streamHeap, 0, DefaultStreamCacheSize) 15 heap.Init(&streamHeap) 16 17 // Testing Push to Heap 18 length := len(streamHeap) 19 cd := &chunkData{ 20 id: "Push", 21 data: []byte{}, 22 lastAccess: time.Now(), 23 } 24 heap.Push(&streamHeap, cd) 25 26 // Confirming the length of the heap increased by 1 27 if len(streamHeap) != length+1 { 28 t.Error("Length of heap did not change, chunkData was not pushed onto Heap. Length of heap is still ", len(streamHeap)) 29 } 30 // Confirming the chunk added was the one expected 31 if !reflect.DeepEqual(cd, streamHeap[0]) { 32 t.Error("Chunk on top of heap is not the chunk that was just pushed on, chunkData.id =", streamHeap[0].id) 33 } 34 35 // Add more chunks to heap 36 for i := 0; i < 3; i++ { 37 heap.Push(&streamHeap, &chunkData{ 38 id: strconv.Itoa(i), 39 data: []byte{}, 40 lastAccess: time.Now().Add(-1 * time.Minute), 41 }) 42 } 43 44 // Testing Heap update 45 // Confirming recently accessed elements gets removed from the top of Heap 46 cd = streamHeap[0] 47 streamHeap.update(cd, cd.id, cd.data, time.Now()) 48 if reflect.DeepEqual(cd, streamHeap[0]) { 49 t.Error("Heap order was not updated. Recently accessed element at top of heap") 50 } 51 // Confirming least recently accessed element is moved to the top of Heap 52 cd = streamHeap[len(streamHeap)-1] 53 streamHeap.update(cd, cd.id, cd.data, time.Now().Add(-1*time.Hour)) 54 if !reflect.DeepEqual(cd, streamHeap[0]) { 55 t.Error("Heap order was not updated. Least recently accessed element is not at top of heap") 56 } 57 58 // Testing Pop of Heap 59 // Confirming element at the top of heap is removed 60 cd = streamHeap[0] 61 length = len(streamHeap) 62 if pop := heap.Pop(&streamHeap).(*chunkData); !reflect.DeepEqual(cd, pop) { 63 t.Error("Element at the top of the Heap was not popped off") 64 } 65 if len(streamHeap) != length-1 { 66 t.Error("Heap length was not reduced by 1") 67 } 68 } 69 70 // TestPruneCache tests to make sure that pruneCache always prunes the cache 71 // to the given size 72 func TestPruneCache(t *testing.T) { 73 if testing.Short() { 74 t.SkipNow() 75 } 76 // Initializing minimum required variables 77 sc := newStreamCache(10) 78 79 // Fill Cache 80 // Purposefully trying to fill to a value larger than cacheSize to confirm 81 // cacheSize won't be exceeded 82 for i := 0; i < int(sc.cacheSize)+5; i++ { 83 sc.Add(strconv.Itoa(i), []byte{}) 84 } 85 // Confirm that the streamHeap didn't exceed the cacheSize 86 if len(sc.streamHeap) != int(sc.cacheSize) || len(sc.streamMap) != len(sc.streamHeap) { 87 t.Error("Cache is not equal to the cacheSize") 88 } 89 90 // Prune the cache down to 2 91 sc.pruneCache(2) 92 93 // Confirm that the length of streamHeap was reduced to 2 94 if len(sc.streamHeap) != 2 || len(sc.streamMap) != 2 { 95 t.Error("Cache was not pruned") 96 } 97 98 // Confirm calling pruneCache on a value larger than 99 // the cache size doesn't change the cache 100 sc.pruneCache(20) 101 if len(sc.streamHeap) != 2 || len(sc.streamMap) != 2 { 102 t.Error("Cache size was changed by pruning to larger value") 103 } 104 105 // Confirm the same chunk won't be added if already added 106 sc.pruneCache(0) 107 id := "test" 108 for i := 0; i < 5; i++ { 109 sc.Add(id, []byte{}) 110 } 111 if len(sc.streamHeap) != 1 || len(sc.streamMap) != 1 { 112 t.Fatalf("Chunk added more the once.\nHeap length: %v\nMap length: %v\n", len(sc.streamHeap), len(sc.streamMap)) 113 } 114 } 115 116 // TestStreamCache tests that when Add() is called, chunks are added and removed 117 // from both the Heap and the Map 118 // Retrieve() is tested through the Streaming tests in the siatest packages 119 // SetStreamingCacheSize() is tested through the API endpoint tests in the 120 // siatest packages 121 func TestStreamCache(t *testing.T) { 122 if testing.Short() { 123 t.SkipNow() 124 } 125 // Initializing minimum required variables 126 sc := newStreamCache(10) 127 128 // Fill Cache 129 // Purposefully trying to fill to a value larger than cacheSize to confirm Add() 130 // keeps pruning cache 131 for i := 0; i < int(sc.cacheSize)+5; i++ { 132 sc.Add(strconv.Itoa(i), []byte{}) 133 } 134 // Confirm that the streamHeap didn't exceed the cacheSize 135 if len(sc.streamHeap) != int(sc.cacheSize) || len(sc.streamMap) != len(sc.streamHeap) { 136 t.Error("Cache is not equal to the cacheSize") 137 } 138 139 // Reduce cacheSize and call Add() to confirm cache is pruned 140 sc.cacheSize = 2 141 sc.Add("", []byte{}) 142 if len(sc.streamHeap) != int(sc.cacheSize) || len(sc.streamMap) != len(sc.streamHeap) { 143 t.Error("Cache is not equal to the cacheSize") 144 } 145 146 // Add new chunk with known staticCacheID 147 sc.Add("chunk1", []byte{}) // "chunk1" should be at the bottom of the Heap 148 149 // Confirm chunk is in the Map and at the bottom of the Heap 150 cd, ok := sc.streamMap["chunk1"] 151 if !ok { 152 t.Error("The chunk1 was not added to the Map") 153 } 154 if !reflect.DeepEqual(cd, sc.streamHeap[len(sc.streamHeap)-1]) { 155 t.Error("The chunk1 is not at the bottom of the Heap") 156 } 157 158 // Make chunk1 least recently accessed element, so it is at the top 159 sc.streamHeap.update(cd, cd.id, cd.data, time.Now().Add(-1*time.Hour)) 160 161 // Confirm chunk1 is at the top of the heap 162 if !reflect.DeepEqual(cd, sc.streamHeap[0]) { 163 t.Error("Chunk1 is not at the top of the heap") 164 } 165 166 // Add additional chunk to force deletion of a chunk 167 sc.Add("chunk2", []byte{}) 168 169 // check if chunk1 was removed from Map and Heap 170 if _, ok := sc.streamMap["chunk1"]; ok { 171 t.Error("chunk1 wasn't removed from the map") 172 } 173 if reflect.DeepEqual(cd, sc.streamHeap[0]) { 174 t.Error("chunk1 wasn't removed from the heap") 175 } 176 }