gitlab.com/SkynetLabs/skyd@v1.6.9/skymodules/renter/streambufferlru_test.go (about) 1 package renter 2 3 import ( 4 "context" 5 "testing" 6 7 "github.com/opentracing/opentracing-go" 8 "gitlab.com/NebulousLabs/fastrand" 9 "gitlab.com/NebulousLabs/threadgroup" 10 "gitlab.com/SkynetLabs/skyd/skymodules" 11 "go.sia.tech/siad/types" 12 ) 13 14 // TestStreamLRU checks that all of the code that forms the LRU for a 15 // stream 16 // 17 // This test has 100% coverage of the streambufferlru.go file. 18 func TestStreamLRU(t *testing.T) { 19 if testing.Short() { 20 t.SkipNow() 21 } 22 23 // create a ctx with test span 24 ctx := opentracing.ContextWithSpan(context.Background(), testSpan()) 25 26 // Create a usable stream, this creates the stream buffer that the LRU talks 27 // to and gives a good opporutnity to probe the LRU. 28 var tg threadgroup.ThreadGroup 29 data := fastrand.Bytes(15999) // 1 byte short of 1000 data sections. 30 dataSource := newMockDataSource(data, 16) 31 dt := skymodules.NewDistributionTrackerStandard() 32 sbs := newStreamBufferSet(dt, &tg, newNoOpLRU()) 33 stream := sbs.callNewStream(ctx, dataSource, 0, 0, types.ZeroCurrency, 0, false) 34 35 // Extract the LRU from the stream to test it directly. 36 lru := stream.lru 37 // Empty the LRU so that we are working with a clean slate. 38 lru.callEvictAll() 39 // Set the size of the LRU to 4. 40 lru.staticSize = 4 41 42 // Check that the LRU is empty / a clean slate. 43 if lru.head != nil { 44 t.Fatal("lru is not empty") 45 } 46 if lru.tail != nil { 47 t.Fatal("lru is not empty") 48 } 49 if len(lru.nodes) != 0 { 50 t.Fatal("lru is not empty") 51 } 52 53 // Check that the stream buffer is empty. 54 sb := lru.staticStreamBuffer 55 if len(sb.dataSections) != 0 { 56 t.Fatal("stream buffer is not empty") 57 } 58 59 // Add the first node. 60 lru.callUpdate(0) 61 // Check that the lru has one node. 62 if lru.head == nil { 63 t.Fatal("bad") 64 } 65 if lru.head != lru.tail { 66 t.Fatal("bad") 67 } 68 if len(lru.nodes) != 1 { 69 t.Fatal("bad") 70 } 71 if len(sb.dataSections) != 1 { 72 t.Fatal("bad") 73 } 74 _, exists := sb.dataSections[0] 75 if !exists { 76 t.Fatal("bad") 77 } 78 79 // Add nodes 1, 2, 3, then perform an integrity check. 80 lru.callUpdate(1) 81 lru.callUpdate(2) 82 lru.callUpdate(3) 83 if len(lru.nodes) != 4 { 84 t.Fatal("bad") 85 } 86 if len(sb.dataSections) != 4 { 87 t.Fatal("bad") 88 } 89 if lru.head.index != 3 { 90 t.Fatal("bad") 91 } 92 if lru.head.next.index != 2 { 93 t.Fatal("bad") 94 } 95 if lru.head.next.next.index != 1 { 96 t.Fatal("bad") 97 } 98 if lru.tail.index != 0 { 99 t.Fatal("bad") 100 } 101 if lru.tail.prev.index != 1 { 102 t.Fatal("bad") 103 } 104 105 // Call update with 4, this should cause an eviction. 106 lru.callUpdate(4) 107 if len(lru.nodes) != 4 { 108 t.Fatal("bad", len(lru.nodes)) 109 } 110 if len(sb.dataSections) != 4 { 111 t.Fatal("bad") 112 } 113 if lru.head.index != 4 { 114 t.Fatal("bad") 115 } 116 if lru.head.next.index != 3 { 117 t.Fatal("bad") 118 } 119 if lru.head.next.next.index != 2 { 120 t.Fatal("bad") 121 } 122 if lru.tail.index != 1 { 123 t.Fatal("bad") 124 } 125 if lru.tail.prev.index != 2 { 126 t.Fatal("bad") 127 } 128 _, exists = lru.nodes[0] 129 if exists { 130 t.Fatal("bad") 131 } 132 _, exists = sb.dataSections[0] 133 if exists { 134 t.Fatal("bad") 135 } 136 137 // Call update with 1, this should move 1 to the head of the LRU. 138 lru.callUpdate(1) 139 if len(lru.nodes) != 4 { 140 t.Fatal("bad", len(lru.nodes)) 141 } 142 if len(sb.dataSections) != 4 { 143 t.Fatal("bad") 144 } 145 if lru.head.index != 1 { 146 t.Fatal("bad") 147 } 148 if lru.head.next.index != 4 { 149 t.Fatal("bad") 150 } 151 if lru.head.next.next.index != 3 { 152 t.Fatal("bad") 153 } 154 if lru.tail.index != 2 { 155 t.Fatal("bad", lru.tail.index) 156 } 157 if lru.tail.prev.index != 3 { 158 t.Fatal("bad") 159 } 160 161 // Call update with 3, this should move 3 to the head of the LRU. Unlike the 162 // previous check, which updated the tail, this check updates a center node. 163 lru.callUpdate(3) 164 if len(lru.nodes) != 4 { 165 t.Fatal("bad", len(lru.nodes)) 166 } 167 if len(sb.dataSections) != 4 { 168 t.Fatal("bad") 169 } 170 if lru.head.index != 3 { 171 t.Fatal("bad") 172 } 173 if lru.head.next.index != 1 { 174 t.Fatal("bad") 175 } 176 if lru.head.next.next.index != 4 { 177 t.Fatal("bad") 178 } 179 if lru.head.next.next.next.index != 2 { 180 t.Fatal("bad") 181 } 182 if lru.tail.index != 2 { 183 t.Fatal("bad", lru.tail.index) 184 } 185 if lru.tail.prev.index != 4 { 186 t.Fatal("bad") 187 } 188 if lru.tail.prev.prev.index != 1 { 189 t.Fatal("bad") 190 } 191 if lru.tail.prev.prev.prev.index != 3 { 192 t.Fatal("bad") 193 } 194 195 // Call update with 3 again, nothing should change. 196 lru.callUpdate(3) 197 if len(lru.nodes) != 4 { 198 t.Fatal("bad", len(lru.nodes)) 199 } 200 if len(sb.dataSections) != 4 { 201 t.Fatal("bad") 202 } 203 if lru.head.index != 3 { 204 t.Fatal("bad") 205 } 206 if lru.head.next.index != 1 { 207 t.Fatal("bad") 208 } 209 if lru.head.next.next.index != 4 { 210 t.Fatal("bad") 211 } 212 if lru.head.next.next.next.index != 2 { 213 t.Fatal("bad") 214 } 215 if lru.tail.index != 2 { 216 t.Fatal("bad", lru.tail.index) 217 } 218 if lru.tail.prev.index != 4 { 219 t.Fatal("bad") 220 } 221 if lru.tail.prev.prev.index != 1 { 222 t.Fatal("bad") 223 } 224 if lru.tail.prev.prev.prev.index != 3 { 225 t.Fatal("bad") 226 } 227 228 // streamBuffer should have data pieces 1,2,3,4. 229 _, exists = sb.dataSections[1] 230 if !exists { 231 t.Fatal("bad") 232 } 233 _, exists = sb.dataSections[2] 234 if !exists { 235 t.Fatal("bad") 236 } 237 _, exists = sb.dataSections[3] 238 if !exists { 239 t.Fatal("bad") 240 } 241 _, exists = sb.dataSections[4] 242 if !exists { 243 t.Fatal("bad") 244 } 245 246 // Try inserting another new node, this should evict '2'. 247 lru.callUpdate(10) 248 if len(lru.nodes) != 4 { 249 t.Fatal("bad", len(lru.nodes)) 250 } 251 if len(sb.dataSections) != 4 { 252 t.Fatal("bad") 253 } 254 if lru.head.index != 10 { 255 t.Fatal("bad") 256 } 257 if lru.head.next.index != 3 { 258 t.Fatal("bad") 259 } 260 if lru.head.next.next.index != 1 { 261 t.Fatal("bad") 262 } 263 if lru.head.next.next.next.index != 4 { 264 t.Fatal("bad") 265 } 266 if lru.tail.index != 4 { 267 t.Fatal("bad", lru.tail.index) 268 } 269 if lru.tail.prev.index != 1 { 270 t.Fatal("bad") 271 } 272 if lru.tail.prev.prev.index != 3 { 273 t.Fatal("bad") 274 } 275 if lru.tail.prev.prev.prev.index != 10 { 276 t.Fatal("bad") 277 } 278 279 // streamBuffer should have data pieces 1,3,4,10. 280 _, exists = sb.dataSections[1] 281 if !exists { 282 t.Fatal("bad") 283 } 284 _, exists = sb.dataSections[10] 285 if !exists { 286 t.Fatal("bad") 287 } 288 _, exists = sb.dataSections[3] 289 if !exists { 290 t.Fatal("bad") 291 } 292 _, exists = sb.dataSections[4] 293 if !exists { 294 t.Fatal("bad") 295 } 296 297 // Add another node and attempt to evict the tail node. 298 lru.callUpdate(2) 299 lru.managedEvict() 300 if len(lru.nodes) != 4 { 301 t.Fatal("bad", len(lru.nodes)) 302 } 303 if len(sb.dataSections) != 4 { 304 t.Fatal("bad", len(sb.dataSections)) 305 } 306 if lru.head.index != 2 { 307 t.Fatal("bad", lru.head.index) 308 } 309 if lru.head.next.index != 10 { 310 t.Fatal("bad", lru.head.next.index) 311 } 312 if lru.tail.index != 1 { 313 t.Fatal("bad", lru.tail.index) 314 } 315 if lru.tail.prev.index != 3 { 316 t.Fatal("bad", lru.tail.prev.index) 317 } 318 319 // streamBuffer should have data pieces 1,2,3,10. 320 _, exists = sb.dataSections[1] 321 if !exists { 322 t.Fatal("bad") 323 } 324 _, exists = sb.dataSections[2] 325 if !exists { 326 t.Fatal("bad") 327 } 328 _, exists = sb.dataSections[3] 329 if !exists { 330 t.Fatal("bad") 331 } 332 _, exists = sb.dataSections[10] 333 if !exists { 334 t.Fatal("bad") 335 } 336 337 // Evict again. Should be a no-op now. 338 lru.managedEvict() 339 if len(lru.nodes) != 4 { 340 t.Fatal("bad", len(lru.nodes)) 341 } 342 343 // streamBuffer should have data pieces 1,3. 344 _, exists = sb.dataSections[1] 345 if !exists { 346 t.Fatal("bad") 347 } 348 _, exists = sb.dataSections[3] 349 if !exists { 350 t.Fatal("bad") 351 } 352 353 // Evict everything again. 354 lru.callEvictAll() 355 if len(lru.nodes) != 0 { 356 t.Fatal("bad", len(lru.nodes)) 357 } 358 if len(sb.dataSections) != 0 { 359 t.Fatal("bad") 360 } 361 if lru.head != nil { 362 t.Fatal("lru is not empty") 363 } 364 if lru.tail != nil { 365 t.Fatal("lru is not empty") 366 } 367 }