gitlab.com/SiaPrime/SiaPrime@v1.4.1/modules/renter/directoryheap_test.go (about) 1 package renter 2 3 import ( 4 "fmt" 5 "testing" 6 7 "gitlab.com/SiaPrime/SiaPrime/modules" 8 "gitlab.com/SiaPrime/SiaPrime/siatest/dependencies" 9 ) 10 11 // updateSiaDirHealth is a helper method to update the health and the aggregate 12 // health of a siadir 13 func (r *Renter) updateSiaDirHealth(siaPath modules.SiaPath, health, aggregateHealth float64) error { 14 siaDir, err := r.staticDirSet.Open(siaPath) 15 if err != nil { 16 return err 17 } 18 defer siaDir.Close() 19 metadata := siaDir.Metadata() 20 metadata.Health = health 21 metadata.AggregateHealth = aggregateHealth 22 err = siaDir.UpdateMetadata(metadata) 23 if err != nil { 24 return err 25 } 26 return nil 27 } 28 29 // TestDirectoryHeap probes the directory heap implementation 30 func TestDirectoryHeap(t *testing.T) { 31 if testing.Short() { 32 t.SkipNow() 33 } 34 t.Parallel() 35 36 // Create renter 37 rt, err := newRenterTesterWithDependency(t.Name(), &dependencies.DependencyDisableRepairAndHealthLoops{}) 38 if err != nil { 39 t.Fatal(err) 40 } 41 defer rt.Close() 42 43 // Add directories to heap. Using these settings ensures that neither the 44 // first of the last element added remains at the top of the health. The 45 // heap should look like the following: 46 // 47 // &{5 1 false {5} {0 0}} 48 // &{2 4 true {2} {0 0}} 49 // &{3 3 false {3} {0 0}} 50 // &{4 2 true {4} {0 0}} 51 // &{1 5 false {1} {0 0}} 52 // &{6 0 true {6} {0 0}} 53 54 // Reset the directory heap because the root directory is added at init. 55 rt.renter.directoryHeap.managedReset() 56 heapLen := 6 57 for i := 1; i <= heapLen; i++ { 58 siaPath, err := modules.NewSiaPath(fmt.Sprint(i)) 59 if err != nil { 60 t.Fatal(err) 61 } 62 d := &directory{ 63 aggregateHealth: float64(i), 64 health: float64(heapLen - i), 65 explored: i%2 == 0, 66 siaPath: siaPath, 67 } 68 rt.renter.directoryHeap.managedPush(d) 69 } 70 71 // Confirm all elements added. 72 if rt.renter.directoryHeap.managedLen() != heapLen { 73 t.Fatalf("heap should have length of %v but was %v", heapLen, rt.renter.directoryHeap.managedLen()) 74 } 75 76 // Check health of heap 77 if rt.renter.directoryHeap.managedPeekHealth() != float64(5) { 78 t.Fatalf("Expected health of heap to be the value of the aggregate health of top chunk %v, got %v", 5, rt.renter.directoryHeap.managedPeekHealth()) 79 } 80 81 // Pop off top element and check against expected values 82 d := rt.renter.directoryHeap.managedPop() 83 if d.health != float64(1) { 84 t.Fatal("Expected Health of 1, got", d.health) 85 } 86 if d.aggregateHealth != float64(5) { 87 t.Fatal("Expected AggregateHealth of 5, got", d.aggregateHealth) 88 } 89 if d.explored { 90 t.Fatal("Expected the directory to be unexplored") 91 } 92 93 // Check health of heap 94 if rt.renter.directoryHeap.managedPeekHealth() != float64(4) { 95 t.Fatalf("Expected health of heap to be the value of the health of top chunk %v, got %v", 4, rt.renter.directoryHeap.managedPeekHealth()) 96 } 97 98 // Push directory back on. 99 rt.renter.directoryHeap.managedPush(d) 100 // A second push will be an update, which should change nothing, and 101 // therefore not impact the outcome of the test. 102 rt.renter.directoryHeap.managedPush(d) 103 104 // Now update directory and confirm it is not the top directory and the top 105 // element is as expected 106 d.aggregateHealth = 0 107 d.health = 0 108 d.explored = true 109 rt.renter.directoryHeap.managedPush(d) 110 topDir := rt.renter.directoryHeap.managedPop() 111 if topDir.health != float64(4) { 112 t.Fatal("Expected Health of 4, got", topDir.health) 113 } 114 if topDir.aggregateHealth != float64(2) { 115 t.Fatal("Expected AggregateHealth of 2, got", topDir.aggregateHealth) 116 } 117 if !topDir.explored { 118 t.Fatal("Expected the directory to be explored") 119 } 120 // Find Directory in heap and confirm that it was updated 121 found := false 122 for rt.renter.directoryHeap.managedLen() > 0 { 123 topDir = rt.renter.directoryHeap.managedPop() 124 if !topDir.siaPath.Equals(d.siaPath) { 125 continue 126 } 127 if found { 128 t.Fatal("Duplicate directory in heap") 129 } 130 found = true 131 if topDir.health != d.health { 132 t.Fatalf("Expected Health of %v, got %v", d.health, topDir.health) 133 } 134 if topDir.aggregateHealth != d.aggregateHealth { 135 t.Fatalf("Expected AggregateHealth of %v, got %v", d.aggregateHealth, topDir.aggregateHealth) 136 } 137 if !topDir.explored { 138 t.Fatal("Expected the directory to be explored") 139 } 140 } 141 142 // Reset Directory heap 143 rt.renter.directoryHeap.managedReset() 144 145 // Confirm that the heap is empty 146 if rt.renter.directoryHeap.managedLen() != 0 { 147 t.Fatal("heap should empty but has length of", rt.renter.directoryHeap.managedLen()) 148 } 149 150 // Test initializing directory heap 151 err = rt.renter.managedPushUnexploredDirectory(modules.RootSiaPath()) 152 if err != nil { 153 t.Fatal(err) 154 } 155 if rt.renter.directoryHeap.managedLen() != 1 { 156 t.Fatal("directory heap should have length of 1 but has length of", rt.renter.directoryHeap.managedLen()) 157 } 158 d = rt.renter.directoryHeap.managedPop() 159 if d.explored { 160 t.Fatal("directory should be unexplored root") 161 } 162 if !d.siaPath.Equals(modules.RootSiaPath()) { 163 t.Fatal("Directory should be root directory but is", d.siaPath) 164 } 165 } 166 167 // TestPushSubDirectories probes the methods that add sub directories to the 168 // heap. This in turn tests the methods for adding unexplored directories 169 func TestPushSubDirectories(t *testing.T) { 170 if testing.Short() { 171 t.SkipNow() 172 } 173 t.Parallel() 174 175 // Create renter 176 rt, err := newRenterTesterWithDependency(t.Name(), &dependencies.DependencyDisableRepairAndHealthLoops{}) 177 if err != nil { 178 t.Fatal(err) 179 } 180 defer rt.Close() 181 182 // Create a test directory with the following healths 183 // 184 // root/ 1 185 // root/SubDir1/ 2 186 // root/SubDir2/ 3 187 188 // Create directory tree 189 siaPath1, err := modules.NewSiaPath("SubDir1") 190 if err != nil { 191 t.Fatal(err) 192 } 193 siaPath2, err := modules.NewSiaPath("SubDir2") 194 if err != nil { 195 t.Fatal(err) 196 } 197 if err := rt.renter.CreateDir(siaPath1); err != nil { 198 t.Fatal(err) 199 } 200 if err := rt.renter.CreateDir(siaPath2); err != nil { 201 t.Fatal(err) 202 } 203 204 // Update metadata 205 err = rt.renter.updateSiaDirHealth(siaPath1, float64(2), float64(2)) 206 if err != nil { 207 t.Fatal(err) 208 } 209 210 err = rt.renter.updateSiaDirHealth(siaPath2, float64(3), float64(3)) 211 if err != nil { 212 t.Fatal(err) 213 } 214 215 // Make sure we are starting with an empty heap 216 rt.renter.directoryHeap.managedReset() 217 218 // Add root sub directories 219 d := &directory{ 220 siaPath: modules.RootSiaPath(), 221 } 222 err = rt.renter.managedPushSubDirectories(d) 223 if err != nil { 224 t.Fatal(err) 225 } 226 227 // Heap should have a length of 2 228 if rt.renter.directoryHeap.managedLen() != 2 { 229 t.Fatal("Heap should have length of 2 but was", rt.renter.directoryHeap.managedLen()) 230 } 231 232 // Pop off elements and confirm the are correct 233 d = rt.renter.directoryHeap.managedPop() 234 if !d.siaPath.Equals(siaPath2) { 235 t.Fatalf("Expected directory %v but found %v", siaPath2.String(), d.siaPath.String()) 236 } 237 if d.aggregateHealth != float64(3) { 238 t.Fatal("Expected AggregateHealth to be 3 but was", d.aggregateHealth) 239 } 240 if d.health != float64(3) { 241 t.Fatal("Expected Health to be 3 but was", d.health) 242 } 243 if d.explored { 244 t.Fatal("Expected directory to be unexplored") 245 } 246 d = rt.renter.directoryHeap.managedPop() 247 if !d.siaPath.Equals(siaPath1) { 248 t.Fatalf("Expected directory %v but found %v", siaPath1.String(), d.siaPath.String()) 249 } 250 if d.aggregateHealth != float64(2) { 251 t.Fatal("Expected AggregateHealth to be 2 but was", d.aggregateHealth) 252 } 253 if d.health != float64(2) { 254 t.Fatal("Expected Health to be 2 but was", d.health) 255 } 256 if d.explored { 257 t.Fatal("Expected directory to be unexplored") 258 } 259 } 260 261 // TestNextExploredDirectory probes managedNextExploredDirectory to ensure that 262 // the directory traverses the filesystem as expected 263 func TestNextExploredDirectory(t *testing.T) { 264 if testing.Short() { 265 t.SkipNow() 266 } 267 t.Parallel() 268 269 // Create renter 270 rt, err := newRenterTesterWithDependency(t.Name(), &dependencies.DependencyDisableRepairAndHealthLoops{}) 271 if err != nil { 272 t.Fatal(err) 273 } 274 defer rt.Close() 275 276 // Create a test directory with the following healths/aggregateHealths 277 // 278 // root/ 0/3 279 // root/SubDir1/ 1/2 280 // root/SubDir1/SubDir1/ 1/1 281 // root/SubDir1/SubDir2/ 2/2 282 // root/SubDir2/ 1/3 283 // root/SubDir2/SubDir1/ 1/1 284 // root/SubDir2/SubDir2/ 3/3 285 // 286 // Overall we would expect to see root/SubDir2/SubDir2 popped first followed 287 // by root/SubDir1/SubDir2 288 289 // Create SiaPaths 290 siaPath1, err := modules.NewSiaPath("SubDir1") 291 if err != nil { 292 t.Fatal(err) 293 } 294 siaPath2, err := modules.NewSiaPath("SubDir2") 295 if err != nil { 296 t.Fatal(err) 297 } 298 siaPath1_1, err := siaPath1.Join("SubDir1") 299 if err != nil { 300 t.Fatal(err) 301 } 302 siaPath1_2, err := siaPath1.Join("SubDir2") 303 if err != nil { 304 t.Fatal(err) 305 } 306 siaPath2_1, err := siaPath2.Join("SubDir1") 307 if err != nil { 308 t.Fatal(err) 309 } 310 siaPath2_2, err := siaPath2.Join("SubDir2") 311 if err != nil { 312 t.Fatal(err) 313 } 314 // Create Directories 315 if err := rt.renter.CreateDir(siaPath1_1); err != nil { 316 t.Fatal(err) 317 } 318 if err := rt.renter.CreateDir(siaPath1_2); err != nil { 319 t.Fatal(err) 320 } 321 if err := rt.renter.CreateDir(siaPath2_1); err != nil { 322 t.Fatal(err) 323 } 324 if err := rt.renter.CreateDir(siaPath2_2); err != nil { 325 t.Fatal(err) 326 } 327 328 // Update metadata 329 err = rt.renter.updateSiaDirHealth(modules.RootSiaPath(), float64(0), float64(3)) 330 if err != nil { 331 t.Fatal(err) 332 } 333 err = rt.renter.updateSiaDirHealth(siaPath1, float64(1), float64(2)) 334 if err != nil { 335 t.Fatal(err) 336 } 337 err = rt.renter.updateSiaDirHealth(siaPath1_1, float64(1), float64(1)) 338 if err != nil { 339 t.Fatal(err) 340 } 341 err = rt.renter.updateSiaDirHealth(siaPath1_2, float64(2), float64(2)) 342 if err != nil { 343 t.Fatal(err) 344 } 345 err = rt.renter.updateSiaDirHealth(siaPath2, float64(1), float64(3)) 346 if err != nil { 347 t.Fatal(err) 348 } 349 err = rt.renter.updateSiaDirHealth(siaPath2_1, float64(1), float64(1)) 350 if err != nil { 351 t.Fatal(err) 352 } 353 err = rt.renter.updateSiaDirHealth(siaPath2_2, float64(3), float64(3)) 354 if err != nil { 355 t.Fatal(err) 356 } 357 358 // Make sure we are starting with an empty heap, this helps with ndfs and 359 // tests proper handling of empty heaps 360 rt.renter.directoryHeap.managedReset() 361 err = rt.renter.managedPushUnexploredDirectory(modules.RootSiaPath()) 362 if err != nil { 363 t.Fatal(err) 364 } 365 366 // Pop off next explored directory 367 d, err := rt.renter.managedNextExploredDirectory() 368 if err != nil { 369 t.Fatal(err) 370 } 371 if d == nil { 372 t.Fatal("No directory popped off heap") 373 } 374 375 // Directory should be root/SubDir2/SubDir2 376 if !d.siaPath.Equals(siaPath2_2) { 377 t.Fatalf("Expected directory %v but found %v", siaPath2_2.String(), d.siaPath.String()) 378 } 379 if d.aggregateHealth != float64(3) { 380 t.Fatal("Expected AggregateHealth to be 3 but was", d.aggregateHealth) 381 } 382 if d.health != float64(3) { 383 t.Fatal("Expected Health to be 3 but was", d.health) 384 } 385 if !d.explored { 386 t.Fatal("Expected directory to be explored") 387 } 388 389 // Pop off next explored directory 390 d, err = rt.renter.managedNextExploredDirectory() 391 if err != nil { 392 t.Fatal(err) 393 } 394 if d == nil { 395 t.Fatal("No directory popped off heap") 396 } 397 398 // Directory should be root/SubDir1/SubDir2 399 if !d.siaPath.Equals(siaPath1_2) { 400 t.Fatalf("Expected directory %v but found %v", siaPath1_2.String(), d.siaPath.String()) 401 } 402 if d.aggregateHealth != float64(2) { 403 t.Fatal("Expected AggregateHealth to be 2 but was", d.aggregateHealth) 404 } 405 if d.health != float64(2) { 406 t.Fatal("Expected Health to be 2 but was", d.health) 407 } 408 if !d.explored { 409 t.Fatal("Expected directory to be explored") 410 } 411 }