github.com/ZuluSpl0it/Sia@v1.3.7/node/api/renterhost_test.go (about) 1 package api 2 3 // renterhost_test.go sets up larger integration tests between renters and 4 // hosts, checking that the whole storage ecosystem is functioning cohesively. 5 6 import ( 7 "bytes" 8 "errors" 9 "fmt" 10 "io/ioutil" 11 "net/url" 12 "os" 13 "path/filepath" 14 "strconv" 15 "sync" 16 "testing" 17 "time" 18 19 "github.com/NebulousLabs/Sia/build" 20 "github.com/NebulousLabs/Sia/crypto" 21 "github.com/NebulousLabs/Sia/modules" 22 "github.com/NebulousLabs/Sia/types" 23 ) 24 25 // TestHostObligationAcceptingContracts verifies that the host will complete 26 // storage proofs and the renter will successfully download even if the host 27 // has set accepting contracts to false. 28 func TestHostObligationAcceptingContracts(t *testing.T) { 29 if testing.Short() { 30 t.SkipNow() 31 } 32 st, err := createServerTester(t.Name()) 33 if err != nil { 34 t.Fatal(err) 35 } 36 defer st.server.Close() 37 err = st.setHostStorage() 38 if err != nil { 39 t.Fatal(err) 40 } 41 err = st.acceptContracts() 42 if err != nil { 43 t.Fatal(err) 44 } 45 err = st.announceHost() 46 if err != nil { 47 t.Fatal(err) 48 } 49 allowanceValues := url.Values{} 50 allowanceValues.Set("funds", "50000000000000000000000000000") // 50k SC 51 allowanceValues.Set("hosts", "1") 52 allowanceValues.Set("period", "10") 53 allowanceValues.Set("renewwindow", "5") 54 err = st.stdPostAPI("/renter", allowanceValues) 55 if err != nil { 56 t.Fatal(err) 57 } 58 59 // Block until the allowance has finished forming contracts. 60 err = build.Retry(50, time.Millisecond*250, func() error { 61 var rc RenterContracts 62 err = st.getAPI("/renter/contracts", &rc) 63 if err != nil { 64 return errors.New("couldn't get renter stats") 65 } 66 if len(rc.Contracts) != 1 { 67 return errors.New("no contracts") 68 } 69 return nil 70 }) 71 if err != nil { 72 t.Fatal("allowance setting failed") 73 } 74 75 filesize := int(1024) 76 path := filepath.Join(st.dir, "test.dat") 77 err = createRandFile(path, filesize) 78 if err != nil { 79 t.Fatal(err) 80 } 81 82 // upload the file 83 uploadValues := url.Values{} 84 uploadValues.Set("source", path) 85 err = st.stdPostAPI("/renter/upload/test", uploadValues) 86 if err != nil { 87 t.Fatal(err) 88 } 89 90 // redundancy should reach 1 91 var rf RenterFiles 92 err = build.Retry(120, time.Millisecond*250, func() error { 93 st.getAPI("/renter/files", &rf) 94 if len(rf.Files) >= 1 && rf.Files[0].Available { 95 return nil 96 } 97 return errors.New("file not uploaded") 98 }) 99 if err != nil { 100 t.Fatal(err) 101 } 102 103 // Get contracts via API call 104 var cts ContractInfoGET 105 err = st.getAPI("/host/contracts", &cts) 106 if err != nil { 107 t.Fatal(err) 108 } 109 110 // There should be some contracts returned 111 if len(cts.Contracts) == 0 { 112 t.Fatal("No contracts returned from /host/contracts API call.") 113 } 114 115 // Check if the number of contracts are equal to the number of storage obligations 116 if len(cts.Contracts) != len(st.host.StorageObligations()) { 117 t.Fatal("Number of contracts returned by API call and host method don't match.") 118 } 119 120 // set acceptingcontracts = false, mine some blocks, verify we can download 121 settings := st.host.InternalSettings() 122 settings.AcceptingContracts = false 123 st.host.SetInternalSettings(settings) 124 for i := 0; i < 3; i++ { 125 _, err := st.miner.AddBlock() 126 if err != nil { 127 t.Fatal(err) 128 } 129 time.Sleep(time.Millisecond * 100) 130 } 131 downloadPath := filepath.Join(st.dir, "test-downloaded-verify.dat") 132 err = st.stdGetAPI("/renter/download/test?destination=" + downloadPath) 133 if err != nil { 134 t.Fatal(err) 135 } 136 137 // mine blocks to cause the host to submit storage proofs to the blockchain. 138 for i := 0; i < 15; i++ { 139 _, err := st.miner.AddBlock() 140 if err != nil { 141 t.Fatal(err) 142 } 143 time.Sleep(time.Millisecond * 100) 144 } 145 146 // should have successful proofs 147 success := false 148 for _, so := range st.host.StorageObligations() { 149 if so.ProofConfirmed { 150 success = true 151 break 152 } 153 } 154 if !success { 155 t.Fatal("no successful storage proofs") 156 } 157 } 158 159 // TestHostAndRentVanilla sets up an integration test where a host and renter 160 // do basic uploads and downloads. 161 func TestHostAndRentVanilla(t *testing.T) { 162 if testing.Short() { 163 t.SkipNow() 164 } 165 t.Parallel() 166 st, err := createServerTester(t.Name()) 167 if err != nil { 168 t.Fatal(err) 169 } 170 defer st.server.panicClose() 171 172 // Announce the host and start accepting contracts. 173 err = st.announceHost() 174 if err != nil { 175 t.Fatal(err) 176 } 177 err = st.setHostStorage() 178 if err != nil { 179 t.Fatal(err) 180 } 181 err = st.acceptContracts() 182 if err != nil { 183 t.Fatal(err) 184 } 185 186 // Set an allowance for the renter, allowing a contract to be formed. 187 allowanceValues := url.Values{} 188 testFunds := "10000000000000000000000000000" // 10k SC 189 testPeriod := "20" 190 renewWindow := "10" 191 testPeriodInt := 20 192 allowanceValues.Set("funds", testFunds) 193 allowanceValues.Set("period", testPeriod) 194 allowanceValues.Set("renewwindow", renewWindow) 195 allowanceValues.Set("hosts", fmt.Sprint(recommendedHosts)) 196 err = st.stdPostAPI("/renter", allowanceValues) 197 if err != nil { 198 t.Fatal(err) 199 } 200 201 // Block until the allowance has finished forming contracts. 202 err = build.Retry(50, time.Millisecond*250, func() error { 203 var rc RenterContracts 204 err = st.getAPI("/renter/contracts", &rc) 205 if err != nil { 206 return errors.New("couldn't get renter stats") 207 } 208 if len(rc.Contracts) != 1 { 209 return errors.New("no contracts") 210 } 211 return nil 212 }) 213 if err != nil { 214 t.Fatal("allowance setting failed") 215 } 216 217 // Check the host, who should now be reporting file contracts. 218 var cts ContractInfoGET 219 err = st.getAPI("/host/contracts", &cts) 220 if err != nil { 221 t.Fatal(err) 222 } 223 224 if len(cts.Contracts) != 1 { 225 t.Error("Host has wrong number of obligations:", len(cts.Contracts)) 226 } 227 // Check if the obligation status is unresolved 228 if cts.Contracts[0].ObligationStatus != "obligationUnresolved" { 229 t.Error("Wrong obligation status for new contract:", cts.Contracts[0].ObligationStatus) 230 } 231 // Check if there are no sector roots on a new contract 232 if cts.Contracts[0].SectorRootsCount != 0 { 233 t.Error("Wrong number of sector roots for new contract:", cts.Contracts[0].SectorRootsCount) 234 } 235 // Check if there is locked collateral 236 if cts.Contracts[0].LockedCollateral.IsZero() { 237 t.Error("No locked collateral in contract.") 238 } 239 // Check if risked collateral is not equal to zero 240 if !cts.Contracts[0].RiskedCollateral.IsZero() { 241 t.Error("Risked collateral not zero in new contract.") 242 } 243 // Check if all potential revenues are zero 244 if !(cts.Contracts[0].PotentialDownloadRevenue.IsZero() && cts.Contracts[0].PotentialUploadRevenue.IsZero() && cts.Contracts[0].PotentialStorageRevenue.IsZero()) { 245 t.Error("Potential values not zero in new contract.") 246 } 247 248 // Create a file. 249 path := filepath.Join(st.dir, "test.dat") 250 err = createRandFile(path, 1024) 251 if err != nil { 252 t.Fatal(err) 253 } 254 255 // Upload the file to the renter. 256 uploadValues := url.Values{} 257 uploadValues.Set("source", path) 258 err = st.stdPostAPI("/renter/upload/test", uploadValues) 259 if err != nil { 260 t.Fatal(err) 261 } 262 // Only one piece will be uploaded (10% at current redundancy). 263 var rf RenterFiles 264 for i := 0; i < 200 && (len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10); i++ { 265 st.getAPI("/renter/files", &rf) 266 time.Sleep(100 * time.Millisecond) 267 } 268 if len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10 { 269 t.Fatal("the uploading is not succeeding for some reason:", rf.Files[0]) 270 } 271 272 // On a second connection, upload another file. 273 path2 := filepath.Join(st.dir, "test2.dat") 274 test2Size := modules.SectorSize*2 + 1 275 err = createRandFile(path2, int(test2Size)) 276 if err != nil { 277 t.Fatal(err) 278 } 279 uploadValues = url.Values{} 280 uploadValues.Set("source", path2) 281 err = st.stdPostAPI("/renter/upload/test2", uploadValues) 282 if err != nil { 283 t.Fatal(err) 284 } 285 // Only one piece will be uploaded (10% at current redundancy). 286 for i := 0; i < 200 && (len(rf.Files) != 2 || rf.Files[0].UploadProgress < 10 || rf.Files[1].UploadProgress < 10); i++ { 287 st.getAPI("/renter/files", &rf) 288 time.Sleep(100 * time.Millisecond) 289 } 290 if len(rf.Files) != 2 || rf.Files[0].UploadProgress < 10 || rf.Files[1].UploadProgress < 10 { 291 t.Fatal("the uploading is not succeeding for some reason:", rf.Files[0], rf.Files[1]) 292 } 293 294 // Try downloading the first file. 295 downpath := filepath.Join(st.dir, "testdown.dat") 296 err = st.stdGetAPI("/renter/download/test?destination=" + downpath) 297 if err != nil { 298 t.Fatal(err) 299 } 300 // Check that the download has the right contents. 301 orig, err := ioutil.ReadFile(path) 302 if err != nil { 303 t.Fatal(err) 304 } 305 download, err := ioutil.ReadFile(downpath) 306 if err != nil { 307 t.Fatal(err) 308 } 309 if bytes.Compare(orig, download) != 0 { 310 t.Fatal("data mismatch when downloading a file") 311 } 312 313 // The renter's downloads queue should have 1 entry now. 314 var queue RenterDownloadQueue 315 if err = st.getAPI("/renter/downloads", &queue); err != nil { 316 t.Fatal(err) 317 } 318 if len(queue.Downloads) != 1 { 319 t.Fatalf("expected renter to have 1 download in the queue; got %v", len(queue.Downloads)) 320 } 321 322 // Try downloading the second file. 323 downpath2 := filepath.Join(st.dir, "testdown2.dat") 324 err = st.stdGetAPI("/renter/download/test2?destination=" + downpath2) 325 if err != nil { 326 t.Fatal(err) 327 } 328 // Check that the download has the right contents. 329 orig2, err := ioutil.ReadFile(path2) 330 if err != nil { 331 t.Fatal(err) 332 } 333 download2, err := ioutil.ReadFile(downpath2) 334 if err != nil { 335 t.Fatal(err) 336 } 337 if bytes.Compare(orig2, download2) != 0 { 338 t.Fatal("data mismatch when downloading a file") 339 } 340 341 // The renter's downloads queue should have 2 entries now. 342 if err = st.getAPI("/renter/downloads", &queue); err != nil { 343 t.Fatal(err) 344 } 345 if len(queue.Downloads) != 2 { 346 t.Fatalf("expected renter to have 1 download in the queue; got %v", len(queue.Downloads)) 347 } 348 349 // Mine two blocks, which should cause the host to submit the storage 350 // obligation to the blockchain. 351 for i := 0; i < 2; i++ { 352 _, err := st.miner.AddBlock() 353 if err != nil { 354 t.Fatal(err) 355 } 356 time.Sleep(time.Millisecond * 200) 357 } 358 359 // Check that the host was able to get the file contract confirmed on the 360 // blockchain. 361 cts = ContractInfoGET{} 362 err = st.getAPI("/host/contracts", &cts) 363 if err != nil { 364 t.Fatal(err) 365 } 366 367 if len(cts.Contracts) != 1 { 368 t.Error("Host has wrong number of obligations:", len(cts.Contracts)) 369 } 370 if !cts.Contracts[0].OriginConfirmed { 371 t.Error("Host has not seen the file contract on the blockchain.") 372 } 373 // Check if there are sector roots 374 if cts.Contracts[0].SectorRootsCount == 0 { 375 t.Error("Sector roots count is zero for used obligation.") 376 } 377 // Check if risked collateral is not equal to zero 378 if cts.Contracts[0].RiskedCollateral.IsZero() { 379 t.Error("Risked collateral is zero for used obligation.") 380 } 381 // There should be some potential revenues in this contract 382 if cts.Contracts[0].PotentialDownloadRevenue.IsZero() || cts.Contracts[0].PotentialUploadRevenue.IsZero() || cts.Contracts[0].PotentialStorageRevenue.IsZero() { 383 t.Error("Potential revenue value is zero for used obligation.") 384 } 385 386 // Mine blocks until the host should have submitted a storage proof. 387 for i := 0; i <= testPeriodInt+5; i++ { 388 _, err := st.miner.AddBlock() 389 if err != nil { 390 t.Fatal(err) 391 } 392 time.Sleep(time.Millisecond * 200) 393 } 394 395 cts = ContractInfoGET{} 396 err = st.getAPI("/host/contracts", &cts) 397 if err != nil { 398 t.Fatal(err) 399 } 400 401 success := false 402 for _, contract := range cts.Contracts { 403 if contract.ProofConfirmed { 404 // Sector roots should be removed from storage obligation 405 if contract.SectorRootsCount > 0 { 406 t.Error("There are sector roots on completed storage obligation.") 407 } 408 success = true 409 break 410 } 411 } 412 if !success { 413 t.Error("does not seem like the host has submitted a storage proof successfully to the network") 414 } 415 } 416 417 // TestHostAndRentMultiHost sets up an integration test where three hosts and a 418 // renter do basic (parallel) uploads and downloads. 419 func TestHostAndRentMultiHost(t *testing.T) { 420 if testing.Short() || !build.VLONG { 421 t.SkipNow() 422 } 423 t.Parallel() 424 st, err := createServerTester(t.Name()) 425 if err != nil { 426 t.Fatal(err) 427 } 428 defer st.server.panicClose() 429 stH1, err := blankServerTester(t.Name() + " - Host 2") 430 if err != nil { 431 t.Fatal(err) 432 } 433 defer stH1.server.panicClose() 434 stH2, err := blankServerTester(t.Name() + " - Host 3") 435 if err != nil { 436 t.Fatal(err) 437 } 438 defer stH2.server.panicClose() 439 testGroup := []*serverTester{st, stH1, stH2} 440 441 // Connect the testers to eachother so that they are all on the same 442 // blockchain. 443 err = fullyConnectNodes(testGroup) 444 if err != nil { 445 t.Fatal(err) 446 } 447 448 // Make sure that every wallet has money in it. 449 err = fundAllNodes(testGroup) 450 if err != nil { 451 t.Fatal(err) 452 } 453 454 // Add storage to every host. 455 err = addStorageToAllHosts(testGroup) 456 if err != nil { 457 t.Fatal(err) 458 } 459 460 // Announce every host. 461 err = announceAllHosts(testGroup) 462 if err != nil { 463 t.Fatal(err) 464 } 465 466 // Set an allowance with three hosts. 467 allowanceValues := url.Values{} 468 allowanceValues.Set("funds", "50000000000000000000000000000") // 50k SC 469 allowanceValues.Set("hosts", "3") 470 allowanceValues.Set("period", "10") 471 allowanceValues.Set("renewwindow", "2") 472 err = st.stdPostAPI("/renter", allowanceValues) 473 if err != nil { 474 t.Fatal(err) 475 } 476 477 // Create a file to upload. 478 filesize := int(45678) 479 path := filepath.Join(st.dir, "test.dat") 480 err = createRandFile(path, filesize) 481 if err != nil { 482 t.Fatal(err) 483 } 484 485 // Upload a file with 2-of-6 redundancy. 486 uploadValues := url.Values{} 487 uploadValues.Set("source", path) 488 uploadValues.Set("datapieces", "2") 489 uploadValues.Set("paritypieces", "4") 490 err = st.stdPostAPI("/renter/upload/test", uploadValues) 491 if err != nil { 492 t.Fatal(err) 493 } 494 // Three pieces should get uploaded. 495 var rf RenterFiles 496 for i := 0; i < 200 && (len(rf.Files) != 1 || rf.Files[0].UploadProgress < 50); i++ { 497 st.getAPI("/renter/files", &rf) 498 time.Sleep(100 * time.Millisecond) 499 } 500 if len(rf.Files) != 1 || rf.Files[0].UploadProgress < 50 { 501 t.Fatal("the uploading is not succeeding for some reason:", rf.Files[0]) 502 } 503 504 // Try downloading the file. 505 downpath := filepath.Join(st.dir, "testdown.dat") 506 err = st.stdGetAPI("/renter/download/test?destination=" + downpath) 507 if err != nil { 508 t.Fatal(err) 509 } 510 // Check that the download has the right contents. 511 orig, err := ioutil.ReadFile(path) 512 if err != nil { 513 t.Fatal(err) 514 } 515 download, err := ioutil.ReadFile(downpath) 516 if err != nil { 517 t.Fatal(err) 518 } 519 if bytes.Compare(orig, download) != 0 { 520 t.Fatal("data mismatch when downloading a file") 521 } 522 523 // The renter's downloads queue should have 1 entry now. 524 var queue RenterDownloadQueue 525 if err = st.getAPI("/renter/downloads", &queue); err != nil { 526 t.Fatal(err) 527 } 528 if len(queue.Downloads) != 1 { 529 t.Fatalf("expected renter to have 1 download in the queue; got %v", len(queue.Downloads)) 530 } 531 } 532 533 // TestHostAndRentManyFiles sets up an integration test where a single renter 534 // is uploading many files to the network. 535 func TestHostAndRentManyFiles(t *testing.T) { 536 if testing.Short() || !build.VLONG { 537 t.SkipNow() 538 } 539 t.Parallel() 540 st, err := createServerTester(t.Name()) 541 if err != nil { 542 t.Fatal(err) 543 } 544 defer st.server.panicClose() 545 stH1, err := blankServerTester(t.Name() + " - Host 2") 546 if err != nil { 547 t.Fatal(err) 548 } 549 defer stH1.server.panicClose() 550 stH2, err := blankServerTester(t.Name() + " - Host 3") 551 if err != nil { 552 t.Fatal(err) 553 } 554 defer stH2.server.panicClose() 555 stH3, err := blankServerTester(t.Name() + " - Host 4") 556 if err != nil { 557 t.Fatal(err) 558 } 559 defer stH3.server.panicClose() 560 testGroup := []*serverTester{st, stH1, stH2, stH3} 561 562 // Connect the testers to eachother so that they are all on the same 563 // blockchain. 564 err = fullyConnectNodes(testGroup) 565 if err != nil { 566 t.Fatal(err) 567 } 568 569 // Make sure that every wallet has money in it. 570 err = fundAllNodes(testGroup) 571 if err != nil { 572 t.Fatal(err) 573 } 574 575 // Add storage to every host. 576 err = addStorageToAllHosts(testGroup) 577 if err != nil { 578 t.Fatal(err) 579 } 580 581 // Announce every host. 582 err = announceAllHosts(testGroup) 583 if err != nil { 584 t.Fatal(err) 585 } 586 587 // Set an allowance with four hosts. 588 allowanceValues := url.Values{} 589 allowanceValues.Set("funds", "50000000000000000000000000000") // 50k SC 590 allowanceValues.Set("hosts", "4") 591 allowanceValues.Set("period", "5") 592 allowanceValues.Set("renewwindow", "2") 593 err = st.stdPostAPI("/renter", allowanceValues) 594 if err != nil { 595 t.Fatal(err) 596 } 597 598 // Create 3 files to upload at the same time. 599 filesize1 := int(12347) 600 filesize2 := int(22343) 601 filesize3 := int(32349) 602 path1 := filepath.Join(st.dir, "test1.dat") 603 path2 := filepath.Join(st.dir, "test2.dat") 604 path3 := filepath.Join(st.dir, "test3.dat") 605 err = createRandFile(path1, filesize1) 606 if err != nil { 607 t.Fatal(err) 608 } 609 err = createRandFile(path2, filesize2) 610 if err != nil { 611 t.Fatal(err) 612 } 613 err = createRandFile(path3, filesize3) 614 if err != nil { 615 t.Fatal(err) 616 } 617 618 // Concurrently upload a file with 1-of-4 redundancy, 2-of-4 redundancy, 619 // and 3-of-4 redundancy. 620 var wg sync.WaitGroup 621 wg.Add(3) 622 go func() { 623 defer wg.Done() 624 uploadValues := url.Values{} 625 uploadValues.Set("source", path1) 626 uploadValues.Set("datapieces", "1") 627 uploadValues.Set("paritypieces", "3") 628 err := st.stdPostAPI("/renter/upload/test1", uploadValues) 629 if err != nil { 630 t.Error(err) 631 } 632 }() 633 go func() { 634 defer wg.Done() 635 uploadValues := url.Values{} 636 uploadValues.Set("source", path2) 637 uploadValues.Set("datapieces", "2") 638 uploadValues.Set("paritypieces", "2") 639 err := st.stdPostAPI("/renter/upload/test2", uploadValues) 640 if err != nil { 641 t.Error(err) 642 } 643 }() 644 go func() { 645 defer wg.Done() 646 uploadValues := url.Values{} 647 uploadValues.Set("source", path3) 648 uploadValues.Set("datapieces", "3") 649 uploadValues.Set("paritypieces", "1") 650 err := st.stdPostAPI("/renter/upload/test3", uploadValues) 651 if err != nil { 652 t.Error(err) 653 } 654 }() 655 656 // Block until the upload call is complete for all three files. 657 wg.Wait() 658 659 // Block until all files hit 100% uploaded. 660 var rf RenterFiles 661 for i := 0; i < 200 && (len(rf.Files) != 3 || rf.Files[0].UploadProgress < 100 || rf.Files[1].UploadProgress < 100 || rf.Files[2].UploadProgress < 100); i++ { 662 st.getAPI("/renter/files", &rf) 663 time.Sleep(500 * time.Millisecond) 664 } 665 if len(rf.Files) != 3 || rf.Files[0].UploadProgress < 100 || rf.Files[1].UploadProgress < 100 || rf.Files[2].UploadProgress < 100 { 666 t.Fatal("the uploading is not succeeding for some reason:", rf.Files[0], rf.Files[1], rf.Files[2]) 667 } 668 669 // Download all three files in parallel. 670 wg.Add(3) 671 go func() { 672 defer wg.Done() 673 downpath := filepath.Join(st.dir, "testdown1.dat") 674 err := st.stdGetAPI("/renter/download/test1?destination=" + downpath) 675 if err != nil { 676 t.Error(err) 677 } 678 // Check that the download has the right contents. 679 orig, err := ioutil.ReadFile(path1) 680 if err != nil { 681 t.Error(err) 682 } 683 download, err := ioutil.ReadFile(downpath) 684 if err != nil { 685 t.Error(err) 686 } 687 if bytes.Compare(orig, download) != 0 { 688 t.Error("data mismatch when downloading a file") 689 } 690 }() 691 go func() { 692 defer wg.Done() 693 downpath := filepath.Join(st.dir, "testdown2.dat") 694 err := st.stdGetAPI("/renter/download/test2?destination=" + downpath) 695 if err != nil { 696 t.Error(err) 697 } 698 // Check that the download has the right contents. 699 orig, err := ioutil.ReadFile(path2) 700 if err != nil { 701 t.Error(err) 702 } 703 download, err := ioutil.ReadFile(downpath) 704 if err != nil { 705 t.Error(err) 706 } 707 if bytes.Compare(orig, download) != 0 { 708 t.Error("data mismatch when downloading a file") 709 } 710 }() 711 go func() { 712 defer wg.Done() 713 downpath := filepath.Join(st.dir, "testdown3.dat") 714 err := st.stdGetAPI("/renter/download/test3?destination=" + downpath) 715 if err != nil { 716 t.Error(err) 717 } 718 // Check that the download has the right contents. 719 orig, err := ioutil.ReadFile(path3) 720 if err != nil { 721 t.Error(err) 722 } 723 download, err := ioutil.ReadFile(downpath) 724 if err != nil { 725 t.Error(err) 726 } 727 if bytes.Compare(orig, download) != 0 { 728 t.Error("data mismatch when downloading a file") 729 } 730 }() 731 wg.Wait() 732 733 // The renter's downloads queue should have 3 entries now. 734 var queue RenterDownloadQueue 735 if err = st.getAPI("/renter/downloads", &queue); err != nil { 736 t.Fatal(err) 737 } 738 if len(queue.Downloads) != 3 { 739 t.Fatalf("expected renter to have 1 download in the queue; got %v", len(queue.Downloads)) 740 } 741 } 742 743 // TestRenterUploadDownload tests that downloading and uploading in parallel 744 // does not result in failures or stalling. 745 func TestRenterUploadDownload(t *testing.T) { 746 if testing.Short() { 747 t.SkipNow() 748 } 749 st, err := createServerTester(t.Name()) 750 if err != nil { 751 t.Fatal(err) 752 } 753 defer st.server.panicClose() 754 755 // Announce the host and start accepting contracts. 756 err = st.announceHost() 757 if err != nil { 758 t.Fatal(err) 759 } 760 err = st.acceptContracts() 761 if err != nil { 762 t.Fatal(err) 763 } 764 err = st.setHostStorage() 765 if err != nil { 766 t.Fatal(err) 767 } 768 769 // Set an allowance for the renter, allowing a contract to be formed. 770 allowanceValues := url.Values{} 771 testFunds := "10000000000000000000000000000" // 10k SC 772 testPeriod := "10" 773 allowanceValues.Set("funds", testFunds) 774 allowanceValues.Set("period", testPeriod) 775 allowanceValues.Set("renewwindow", testRenewWindow) 776 allowanceValues.Set("hosts", fmt.Sprint(recommendedHosts)) 777 err = st.stdPostAPI("/renter", allowanceValues) 778 if err != nil { 779 t.Fatal(err) 780 } 781 782 // Block until the allowance has finished forming contracts. 783 err = build.Retry(50, time.Millisecond*250, func() error { 784 var rc RenterContracts 785 err = st.getAPI("/renter/contracts", &rc) 786 if err != nil { 787 return errors.New("couldn't get renter stats") 788 } 789 if len(rc.Contracts) != 1 { 790 return errors.New("no contracts") 791 } 792 return nil 793 }) 794 if err != nil { 795 t.Fatal("allowance setting failed") 796 } 797 798 // Check financial metrics; coins should have been spent on contracts 799 var rg RenterGET 800 err = st.getAPI("/renter", &rg) 801 if err != nil { 802 t.Fatal(err) 803 } 804 spent := rg.Settings.Allowance.Funds.Sub(rg.FinancialMetrics.Unspent) 805 if spent.IsZero() { 806 t.Fatal("financial metrics do not reflect contract spending") 807 } 808 809 // Create a file. 810 path := filepath.Join(st.dir, "test.dat") 811 err = createRandFile(path, 1024) 812 if err != nil { 813 t.Fatal(err) 814 } 815 816 // Upload to host. 817 uploadValues := url.Values{} 818 uploadValues.Set("source", path) 819 err = st.stdPostAPI("/renter/upload/test", uploadValues) 820 if err != nil { 821 t.Fatal(err) 822 } 823 // Only one piece will be uploaded (10% at current redundancy). 824 var rf RenterFiles 825 for i := 0; i < 200 && (len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10); i++ { 826 st.getAPI("/renter/files", &rf) 827 time.Sleep(100 * time.Millisecond) 828 } 829 if len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10 { 830 t.Fatal("the uploading is not succeeding for some reason:", rf.Files[0]) 831 } 832 833 // In parallel, upload another file and download the first file. 834 path2 := filepath.Join(st.dir, "test2.dat") 835 test2Size := modules.SectorSize*2 + 1 836 err = createRandFile(path2, int(test2Size)) 837 if err != nil { 838 t.Fatal(err) 839 } 840 uploadValues = url.Values{} 841 uploadValues.Set("source", path2) 842 err = st.stdPostAPI("/renter/upload/test2", uploadValues) 843 if err != nil { 844 t.Fatal(err) 845 } 846 downpath := filepath.Join(st.dir, "testdown.dat") 847 err = st.stdGetAPI("/renter/download/test?destination=" + downpath) 848 if err != nil { 849 t.Fatal(err) 850 } 851 // Check that the download has the right contents. 852 orig, err := ioutil.ReadFile(path) 853 if err != nil { 854 t.Fatal(err) 855 } 856 download, err := ioutil.ReadFile(downpath) 857 if err != nil { 858 t.Fatal(err) 859 } 860 if bytes.Compare(orig, download) != 0 { 861 t.Fatal("data mismatch when downloading a file") 862 } 863 864 // Wait for upload to complete. 865 for i := 0; i < 200 && (len(rf.Files) != 2 || rf.Files[0].UploadProgress < 10 || rf.Files[1].UploadProgress < 10); i++ { 866 st.getAPI("/renter/files", &rf) 867 time.Sleep(100 * time.Millisecond) 868 } 869 if len(rf.Files) != 2 || rf.Files[0].UploadProgress < 10 || rf.Files[1].UploadProgress < 10 { 870 t.Fatal("the uploading is not succeeding for some reason:", rf.Files[0], rf.Files[1]) 871 } 872 873 // Check financial metrics; funds should have been spent on uploads/downloads 874 err = st.getAPI("/renter", &rg) 875 if err != nil { 876 t.Fatal(err) 877 } 878 fm := rg.FinancialMetrics 879 newSpent := rg.Settings.Allowance.Funds.Sub(fm.Unspent) 880 // all new spending should be reflected in upload/download/storage spending 881 diff := fm.UploadSpending.Add(fm.DownloadSpending).Add(fm.StorageSpending) 882 if !diff.Equals(newSpent.Sub(spent)) { 883 t.Fatal("all new spending should be reflected in metrics:", diff, newSpent.Sub(spent)) 884 } 885 } 886 887 // TestRenterParallelDelete tests that uploading and deleting parallel does not 888 // result in failures or stalling. 889 func TestRenterParallelDelete(t *testing.T) { 890 if testing.Short() { 891 t.SkipNow() 892 } 893 st, err := createServerTester(t.Name()) 894 if err != nil { 895 t.Fatal(err) 896 } 897 defer st.server.panicClose() 898 899 // Announce the host and start accepting contracts. 900 err = st.announceHost() 901 if err != nil { 902 t.Fatal(err) 903 } 904 err = st.acceptContracts() 905 if err != nil { 906 t.Fatal(err) 907 } 908 err = st.setHostStorage() 909 if err != nil { 910 t.Fatal(err) 911 } 912 913 // Set an allowance for the renter, allowing a contract to be formed. 914 allowanceValues := url.Values{} 915 testFunds := "10000000000000000000000000000" // 10k SC 916 testPeriod := "10" 917 allowanceValues.Set("funds", testFunds) 918 allowanceValues.Set("period", testPeriod) 919 allowanceValues.Set("renewwindow", testRenewWindow) 920 allowanceValues.Set("hosts", fmt.Sprint(recommendedHosts)) 921 err = st.stdPostAPI("/renter", allowanceValues) 922 if err != nil { 923 t.Fatal(err) 924 } 925 926 // Create two files. 927 path := filepath.Join(st.dir, "test.dat") 928 err = createRandFile(path, 1024) 929 if err != nil { 930 t.Fatal(err) 931 } 932 path2 := filepath.Join(st.dir, "test2.dat") 933 err = createRandFile(path2, 1024) 934 if err != nil { 935 t.Fatal(err) 936 } 937 938 // Upload the first file to host. 939 uploadValues := url.Values{} 940 uploadValues.Set("source", path) 941 err = st.stdPostAPI("/renter/upload/test", uploadValues) 942 if err != nil { 943 t.Fatal(err) 944 } 945 // Wait for the first file to be registered in the renter. 946 var rf RenterFiles 947 for i := 0; i < 200 && len(rf.Files) != 1; i++ { 948 st.getAPI("/renter/files", &rf) 949 time.Sleep(100 * time.Millisecond) 950 } 951 if len(rf.Files) != 1 { 952 t.Fatal("file is not being registered:", rf.Files) 953 } 954 955 // In parallel, start uploading the other file, and delete the first file. 956 uploadValues = url.Values{} 957 uploadValues.Set("source", path2) 958 err = st.stdPostAPI("/renter/upload/test2", uploadValues) 959 if err != nil { 960 t.Fatal(err) 961 } 962 963 err = st.stdPostAPI("/renter/delete/test", url.Values{}) 964 if err != nil { 965 t.Fatal(err) 966 } 967 // Only the second file should be present 968 st.getAPI("/renter/files", &rf) 969 if len(rf.Files) != 1 || rf.Files[0].SiaPath != "test2" { 970 t.Fatal("file was not deleted properly:", rf.Files) 971 } 972 973 // Wait for the second upload to complete. 974 for i := 0; i < 200 && (len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10); i++ { 975 st.getAPI("/renter/files", &rf) 976 time.Sleep(100 * time.Millisecond) 977 } 978 if len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10 { 979 t.Fatal("the uploading is not succeeding for some reason:", rf.Files) 980 } 981 982 // In parallel, download and delete the second file. 983 go st.stdPostAPI("/renter/delete/test2", url.Values{}) 984 time.Sleep(100 * time.Millisecond) 985 downpath := filepath.Join(st.dir, "testdown.dat") 986 err = st.stdGetAPI("/renter/download/test2?destination=" + downpath) 987 if err == nil { 988 t.Fatal("download should fail after delete") 989 } 990 991 // No files should be present 992 st.getAPI("/renter/files", &rf) 993 if len(rf.Files) != 0 { 994 t.Fatal("file was not deleted properly:", rf.Files) 995 } 996 } 997 998 // TestRenterRenew sets up an integration test where a renter renews a 999 // contract with a host. 1000 func TestRenterRenew(t *testing.T) { 1001 if testing.Short() { 1002 t.SkipNow() 1003 } 1004 st, err := createServerTester(t.Name()) 1005 if err != nil { 1006 t.Fatal(err) 1007 } 1008 defer st.server.panicClose() 1009 1010 // Announce the host and start accepting contracts. 1011 err = st.announceHost() 1012 if err != nil { 1013 t.Fatal(err) 1014 } 1015 err = st.acceptContracts() 1016 if err != nil { 1017 t.Fatal(err) 1018 } 1019 err = st.setHostStorage() 1020 if err != nil { 1021 t.Fatal(err) 1022 } 1023 var ah HostdbActiveGET 1024 for i := 0; i < 50; i++ { 1025 if err = st.getAPI("/hostdb/active", &ah); err != nil { 1026 t.Fatal(err) 1027 } 1028 if len(ah.Hosts) == 1 { 1029 break 1030 } 1031 time.Sleep(time.Millisecond * 100) 1032 } 1033 if len(ah.Hosts) != 1 { 1034 t.Fatalf("expected 1 host, got %v", len(ah.Hosts)) 1035 } 1036 1037 // Set an allowance for the renter, allowing a contract to be formed. 1038 allowanceValues := url.Values{} 1039 testFunds := "10000000000000000000000000000" // 10k SC 1040 testPeriod := 10 1041 allowanceValues.Set("funds", testFunds) 1042 allowanceValues.Set("period", strconv.Itoa(testPeriod)) 1043 allowanceValues.Set("renewwindow", strconv.Itoa(testPeriod/2)) 1044 allowanceValues.Set("hosts", fmt.Sprint(recommendedHosts)) 1045 err = st.stdPostAPI("/renter", allowanceValues) 1046 if err != nil { 1047 t.Fatal(err) 1048 } 1049 1050 // Block until the allowance has finished forming contracts. 1051 err = build.Retry(50, time.Millisecond*250, func() error { 1052 var rc RenterContracts 1053 err = st.getAPI("/renter/contracts", &rc) 1054 if err != nil { 1055 return errors.New("couldn't get renter stats") 1056 } 1057 if len(rc.Contracts) != 1 { 1058 return errors.New("no contracts") 1059 } 1060 return nil 1061 }) 1062 if err != nil { 1063 t.Fatal("allowance setting failed") 1064 } 1065 1066 // Create a file. 1067 path := filepath.Join(st.dir, "test.dat") 1068 err = createRandFile(path, 1024) 1069 if err != nil { 1070 t.Fatal(err) 1071 } 1072 1073 // Upload the file to the renter. 1074 uploadValues := url.Values{} 1075 uploadValues.Set("source", path) 1076 err = st.stdPostAPI("/renter/upload/test", uploadValues) 1077 if err != nil { 1078 t.Fatal(err) 1079 } 1080 // Only one piece will be uploaded (10% at current redundancy). 1081 var rf RenterFiles 1082 for i := 0; i < 200 && (len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10); i++ { 1083 st.getAPI("/renter/files", &rf) 1084 time.Sleep(100 * time.Millisecond) 1085 } 1086 if len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10 { 1087 t.Fatal("the uploading is not succeeding for some reason:", rf.Files[0]) 1088 } 1089 1090 // Get current contract ID. 1091 var rc RenterContracts 1092 err = st.getAPI("/renter/contracts", &rc) 1093 if err != nil { 1094 t.Fatal(err) 1095 } 1096 contractID := rc.Contracts[0].ID 1097 1098 // Mine enough blocks to enter the renewal window. 1099 testWindow := testPeriod / 2 1100 for i := 0; i < testWindow+1; i++ { 1101 _, err = st.miner.AddBlock() 1102 if err != nil { 1103 t.Fatal(err) 1104 } 1105 } 1106 // Wait for the contract to be renewed. 1107 for i := 0; i < 200 && (len(rc.Contracts) != 1 || rc.Contracts[0].ID == contractID); i++ { 1108 st.getAPI("/renter/contracts", &rc) 1109 time.Sleep(100 * time.Millisecond) 1110 } 1111 if rc.Contracts[0].ID == contractID { 1112 t.Fatal("contract was not renewed:", rc.Contracts[0]) 1113 } 1114 1115 // Try downloading the file. 1116 downpath := filepath.Join(st.dir, "testdown.dat") 1117 err = st.stdGetAPI("/renter/download/test?destination=" + downpath) 1118 if err != nil { 1119 t.Fatal(err) 1120 } 1121 // Check that the download has the right contents. 1122 orig, err := ioutil.ReadFile(path) 1123 if err != nil { 1124 t.Fatal(err) 1125 } 1126 download, err := ioutil.ReadFile(downpath) 1127 if err != nil { 1128 t.Fatal(err) 1129 } 1130 if bytes.Compare(orig, download) != 0 { 1131 t.Fatal("data mismatch when downloading a file") 1132 } 1133 } 1134 1135 // TestRenterAllowance sets up an integration test where a renter attempts to 1136 // download a file after changing the allowance. 1137 func TestRenterAllowance(t *testing.T) { 1138 t.Skip("bypassing NDF") 1139 if testing.Short() { 1140 t.SkipNow() 1141 } 1142 t.Parallel() 1143 1144 st, err := createServerTester(t.Name()) 1145 if err != nil { 1146 t.Fatal(err) 1147 } 1148 defer st.server.panicClose() 1149 1150 // Announce the host and start accepting contracts. 1151 err = st.announceHost() 1152 if err != nil { 1153 t.Fatal(err) 1154 } 1155 err = st.acceptContracts() 1156 if err != nil { 1157 t.Fatal(err) 1158 } 1159 err = st.setHostStorage() 1160 if err != nil { 1161 t.Fatal(err) 1162 } 1163 1164 // Set an allowance for the renter, allowing a contract to be formed. 1165 allowanceValues := url.Values{} 1166 testFunds := types.SiacoinPrecision.Mul64(10000) // 10k SC 1167 testPeriod := 20 1168 allowanceValues.Set("funds", testFunds.String()) 1169 allowanceValues.Set("period", strconv.Itoa(testPeriod)) 1170 err = st.stdPostAPI("/renter", allowanceValues) 1171 if err != nil { 1172 t.Fatal(err) 1173 } 1174 1175 // Create a file. 1176 path := filepath.Join(st.dir, "test.dat") 1177 err = createRandFile(path, 1024) 1178 if err != nil { 1179 t.Fatal(err) 1180 } 1181 1182 // Upload the file to the renter. 1183 uploadValues := url.Values{} 1184 uploadValues.Set("source", path) 1185 err = st.stdPostAPI("/renter/upload/test", uploadValues) 1186 if err != nil { 1187 t.Fatal(err) 1188 } 1189 // Only one piece will be uploaded (10% at current redundancy). 1190 var rf RenterFiles 1191 for i := 0; i < 200 && (len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10); i++ { 1192 st.getAPI("/renter/files", &rf) 1193 time.Sleep(100 * time.Millisecond) 1194 } 1195 if len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10 { 1196 t.Fatal("the uploading is not succeeding for some reason:", rf.Files[0]) 1197 } 1198 1199 t.Skip("ndf - re-enable after contractor overhaul") 1200 1201 // Try downloading the file after modifying the allowance in various ways. 1202 allowances := []struct { 1203 funds types.Currency 1204 period int 1205 }{ 1206 {testFunds.Mul64(10), testPeriod / 2}, 1207 {testFunds, testPeriod / 2}, 1208 {testFunds.Div64(10), testPeriod / 2}, 1209 {testFunds.Mul64(10), testPeriod}, 1210 {testFunds, testPeriod}, 1211 {testFunds.Div64(10), testPeriod}, 1212 {testFunds.Mul64(10), testPeriod * 2}, 1213 {testFunds, testPeriod * 2}, 1214 {testFunds.Div64(10), testPeriod * 2}, 1215 } 1216 1217 for _, a := range allowances { 1218 allowanceValues.Set("funds", a.funds.String()) 1219 allowanceValues.Set("period", strconv.Itoa(a.period)) 1220 err = st.stdPostAPI("/renter", allowanceValues) 1221 if err != nil { 1222 t.Fatal(err) 1223 } 1224 time.Sleep(100 * time.Millisecond) 1225 1226 // Try downloading the file. 1227 downpath := filepath.Join(st.dir, "testdown.dat") 1228 err = st.stdGetAPI("/renter/download/test?destination=" + downpath) 1229 if err != nil { 1230 t.Fatal(err) 1231 } 1232 // Check that the download has the right contents. 1233 orig, err := ioutil.ReadFile(path) 1234 if err != nil { 1235 t.Fatal(err) 1236 } 1237 download, err := ioutil.ReadFile(downpath) 1238 if err != nil { 1239 t.Fatal(err) 1240 } 1241 if bytes.Compare(orig, download) != 0 { 1242 t.Fatal("data mismatch when downloading a file") 1243 } 1244 } 1245 } 1246 1247 // TestHostAndRentReload sets up an integration test where a host and renter 1248 // do basic uploads and downloads, with an intervening shutdown+startup. 1249 func TestHostAndRentReload(t *testing.T) { 1250 if testing.Short() { 1251 t.SkipNow() 1252 } 1253 t.Parallel() 1254 st, err := createServerTester(t.Name()) 1255 if err != nil { 1256 t.Fatal(err) 1257 } 1258 1259 // Announce the host and start accepting contracts. 1260 err = st.announceHost() 1261 if err != nil { 1262 t.Fatal(err) 1263 } 1264 err = st.acceptContracts() 1265 if err != nil { 1266 t.Fatal(err) 1267 } 1268 err = st.setHostStorage() 1269 if err != nil { 1270 t.Fatal(err) 1271 } 1272 // Mine a block so that the wallet reclaims refund outputs 1273 _, err = st.miner.AddBlock() 1274 if err != nil { 1275 t.Fatal(err) 1276 } 1277 1278 // Set an allowance for the renter, allowing a contract to be formed. 1279 allowanceValues := url.Values{} 1280 testFunds := "10000000000000000000000000000" // 10k SC 1281 testPeriod := "10" 1282 allowanceValues.Set("funds", testFunds) 1283 allowanceValues.Set("period", testPeriod) 1284 allowanceValues.Set("renewwindow", testRenewWindow) 1285 allowanceValues.Set("hosts", fmt.Sprint(recommendedHosts)) 1286 err = st.stdPostAPI("/renter", allowanceValues) 1287 if err != nil { 1288 t.Fatal(err) 1289 } 1290 1291 // Block until the allowance has finished forming contracts. 1292 err = build.Retry(50, time.Millisecond*250, func() error { 1293 var rc RenterContracts 1294 err = st.getAPI("/renter/contracts", &rc) 1295 if err != nil { 1296 return errors.New("couldn't get renter stats") 1297 } 1298 if len(rc.Contracts) != 1 { 1299 return errors.New("no contracts") 1300 } 1301 return nil 1302 }) 1303 if err != nil { 1304 t.Fatal("allowance setting failed") 1305 } 1306 1307 // Create a file. 1308 path := filepath.Join(st.dir, "test.dat") 1309 err = createRandFile(path, 1024) 1310 if err != nil { 1311 t.Fatal(err) 1312 } 1313 1314 // Upload the file to the renter. 1315 uploadValues := url.Values{} 1316 uploadValues.Set("source", path) 1317 err = st.stdPostAPI("/renter/upload/test", uploadValues) 1318 if err != nil { 1319 t.Fatal(err) 1320 } 1321 // Only one piece will be uploaded (10% at current redundancy). 1322 var rf RenterFiles 1323 for i := 0; i < 200 && (len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10); i++ { 1324 st.getAPI("/renter/files", &rf) 1325 time.Sleep(100 * time.Millisecond) 1326 } 1327 if len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10 { 1328 t.Fatal("the uploading is not succeeding for some reason:", rf.Files[0]) 1329 } 1330 1331 // Try downloading the file. 1332 downpath := filepath.Join(st.dir, "testdown.dat") 1333 err = st.stdGetAPI("/renter/download/test?destination=" + downpath) 1334 if err != nil { 1335 t.Fatal(err) 1336 } 1337 // Check that the download has the right contents. 1338 orig, err := ioutil.ReadFile(path) 1339 if err != nil { 1340 t.Fatal(err) 1341 } 1342 download, err := ioutil.ReadFile(downpath) 1343 if err != nil { 1344 t.Fatal(err) 1345 } 1346 if bytes.Compare(orig, download) != 0 { 1347 t.Fatal("data mismatch when downloading a file") 1348 } 1349 1350 // The renter's downloads queue should have 1 entry now. 1351 var queue RenterDownloadQueue 1352 if err = st.getAPI("/renter/downloads", &queue); err != nil { 1353 t.Fatal(err) 1354 } 1355 if len(queue.Downloads) != 1 { 1356 t.Fatalf("expected renter to have 1 download in the queue; got %v", len(queue.Downloads)) 1357 } 1358 1359 // close and reopen the server 1360 err = st.server.Close() 1361 if err != nil { 1362 t.Fatal(err) 1363 } 1364 st, err = assembleServerTester(st.walletKey, st.dir) 1365 if err != nil { 1366 t.Fatal(err) 1367 } 1368 defer st.server.panicClose() 1369 1370 // Announce the host again and wait until the host is re-scanned and put 1371 // back into the hostdb as an active host. 1372 announceValues := url.Values{} 1373 announceValues.Set("address", string(st.host.ExternalSettings().NetAddress)) 1374 err = st.stdPostAPI("/host/announce", announceValues) 1375 if err != nil { 1376 t.Fatal(err) 1377 } 1378 // Mine a block. 1379 _, err = st.miner.AddBlock() 1380 if err != nil { 1381 t.Fatal(err) 1382 } 1383 err = build.Retry(100, time.Millisecond*100, func() error { 1384 var hosts HostdbActiveGET 1385 err := st.getAPI("/hostdb/active", &hosts) 1386 if err != nil { 1387 return err 1388 } 1389 if len(hosts.Hosts) != 1 { 1390 return errors.New("host is not in the set of active hosts") 1391 } 1392 return nil 1393 }) 1394 if err != nil { 1395 t.Fatal(err) 1396 } 1397 1398 // Try downloading the file. 1399 err = st.stdGetAPI("/renter/download/test?destination=" + downpath) 1400 if err != nil { 1401 t.Fatal(err) 1402 } 1403 // Check that the download has the right contents. 1404 orig, err = ioutil.ReadFile(path) 1405 if err != nil { 1406 t.Fatal(err) 1407 } 1408 download, err = ioutil.ReadFile(downpath) 1409 if err != nil { 1410 t.Fatal(err) 1411 } 1412 if bytes.Compare(orig, download) != 0 { 1413 t.Fatal("data mismatch when downloading a file") 1414 } 1415 } 1416 1417 // TestHostAndRenterRenewInterrupt 1418 func TestHostAndRenterRenewInterrupt(t *testing.T) { 1419 t.Skip("active test following contractor overhaul") 1420 if testing.Short() { 1421 t.SkipNow() 1422 } 1423 t.Parallel() 1424 st, err := createServerTester(t.Name()) 1425 if err != nil { 1426 t.Fatal(err) 1427 } 1428 stHost, err := blankServerTester(t.Name() + "-Host") 1429 if err != nil { 1430 t.Fatal(err) 1431 } 1432 sts := []*serverTester{st, stHost} 1433 err = fullyConnectNodes(sts) 1434 if err != nil { 1435 t.Fatal(err) 1436 } 1437 err = fundAllNodes(sts) 1438 if err != nil { 1439 t.Fatal(err) 1440 } 1441 1442 // Announce the host. 1443 err = stHost.acceptContracts() 1444 if err != nil { 1445 t.Fatal(err) 1446 } 1447 err = stHost.setHostStorage() 1448 if err != nil { 1449 t.Fatal(err) 1450 } 1451 err = stHost.announceHost() 1452 if err != nil { 1453 t.Fatal(err) 1454 } 1455 1456 // Wait for host to be seen in renter's hostdb 1457 var ah HostdbActiveGET 1458 for i := 0; i < 50; i++ { 1459 if err = st.getAPI("/hostdb/active", &ah); err != nil { 1460 t.Fatal(err) 1461 } 1462 if len(ah.Hosts) == 1 { 1463 break 1464 } 1465 time.Sleep(time.Millisecond * 100) 1466 } 1467 if len(ah.Hosts) != 1 { 1468 t.Fatalf("expected 1 host, got %v", len(ah.Hosts)) 1469 } 1470 1471 // Upload a file to the host. 1472 allowanceValues := url.Values{} 1473 testFunds := "10000000000000000000000000000" // 10k SC 1474 testPeriod := "10" 1475 testPeriodInt := 10 1476 allowanceValues.Set("funds", testFunds) 1477 allowanceValues.Set("period", testPeriod) 1478 err = st.stdPostAPI("/renter", allowanceValues) 1479 if err != nil { 1480 t.Fatal(err) 1481 } 1482 // Create a file. 1483 path := filepath.Join(st.dir, "test.dat") 1484 err = createRandFile(path, 10e3) 1485 if err != nil { 1486 t.Fatal(err) 1487 } 1488 // Upload the file to the renter. 1489 uploadValues := url.Values{} 1490 uploadValues.Set("source", path) 1491 err = st.stdPostAPI("/renter/upload/test", uploadValues) 1492 if err != nil { 1493 t.Fatal(err) 1494 } 1495 1496 // Get current contract ID. 1497 var rc RenterContracts 1498 err = st.getAPI("/renter/contracts", &rc) 1499 if err != nil { 1500 t.Fatal(err) 1501 } 1502 contractID := rc.Contracts[0].ID 1503 1504 // Mine enough blocks to enter the renewal window. 1505 testWindow := testPeriodInt / 2 1506 for i := 0; i < testWindow+1; i++ { 1507 _, err = st.miner.AddBlock() 1508 if err != nil { 1509 t.Fatal(err) 1510 } 1511 } 1512 // Wait for the contract to be renewed. 1513 for i := 0; i < 200 && (len(rc.Contracts) != 1 || rc.Contracts[0].ID == contractID); i++ { 1514 st.getAPI("/renter/contracts", &rc) 1515 time.Sleep(100 * time.Millisecond) 1516 } 1517 if rc.Contracts[0].ID == contractID { 1518 t.Fatal("contract was not renewed:", rc.Contracts[0]) 1519 } 1520 1521 // Only one piece will be uploaded (10% at current redundancy). 1522 var rf RenterFiles 1523 for i := 0; i < 200 && (len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10); i++ { 1524 st.getAPI("/renter/files", &rf) 1525 time.Sleep(1000 * time.Millisecond) 1526 } 1527 if len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10 { 1528 t.Fatal("the uploading is not succeeding for some reason:", rf.Files[0]) 1529 } 1530 1531 // Try downloading the file. 1532 downpath := filepath.Join(st.dir, "testdown.dat") 1533 err = st.stdGetAPI("/renter/download/test?destination=" + downpath) 1534 if err != nil { 1535 t.Fatal(err) 1536 } 1537 // Check that the download has the right contents. 1538 orig, err := ioutil.ReadFile(path) 1539 if err != nil { 1540 t.Fatal(err) 1541 } 1542 download, err := ioutil.ReadFile(downpath) 1543 if err != nil { 1544 t.Fatal(err) 1545 } 1546 if bytes.Compare(orig, download) != 0 { 1547 t.Fatal("data mismatch when downloading a file") 1548 } 1549 } 1550 1551 // TestUploadedBytesReporting verifies that reporting of how many bytes have 1552 // been uploaded via active contracts is accurate 1553 func TestUploadedBytesReporting(t *testing.T) { 1554 if testing.Short() { 1555 t.SkipNow() 1556 } 1557 t.Parallel() 1558 st, err := createServerTester(t.Name()) 1559 if err != nil { 1560 t.Fatal(err) 1561 } 1562 defer st.server.Close() 1563 stH1, err := blankServerTester(t.Name() + " - Host 2") 1564 if err != nil { 1565 t.Fatal(err) 1566 } 1567 defer stH1.server.Close() 1568 testGroup := []*serverTester{st, stH1} 1569 1570 // Connect the testers to eachother so that they are all on the same 1571 // blockchain. 1572 err = fullyConnectNodes(testGroup) 1573 if err != nil { 1574 t.Fatal(err) 1575 } 1576 // Make sure that every wallet has money in it. 1577 err = fundAllNodes(testGroup) 1578 if err != nil { 1579 t.Fatal(err) 1580 } 1581 // Add storage to every host. 1582 err = addStorageToAllHosts(testGroup) 1583 if err != nil { 1584 t.Fatal(err) 1585 } 1586 // Announce every host. 1587 err = announceAllHosts(testGroup) 1588 if err != nil { 1589 t.Fatal(err) 1590 } 1591 1592 // Set an allowance with two hosts. 1593 allowanceValues := url.Values{} 1594 allowanceValues.Set("funds", "50000000000000000000000000000") // 50k SC 1595 allowanceValues.Set("hosts", "2") 1596 allowanceValues.Set("period", "10") 1597 allowanceValues.Set("renewwindow", "5") 1598 err = st.stdPostAPI("/renter", allowanceValues) 1599 if err != nil { 1600 t.Fatal(err) 1601 } 1602 1603 // Block until the allowance has finished forming contracts. 1604 err = build.Retry(50, time.Millisecond*250, func() error { 1605 var rc RenterContracts 1606 err = st.getAPI("/renter/contracts", &rc) 1607 if err != nil { 1608 return errors.New("couldn't get renter stats") 1609 } 1610 if len(rc.Contracts) != 2 { 1611 return errors.New("no contracts") 1612 } 1613 return nil 1614 }) 1615 if err != nil { 1616 t.Fatal("allowance setting failed") 1617 } 1618 1619 // Create a file to upload. 1620 filesize := int(modules.SectorSize * 2) 1621 path := filepath.Join(st.dir, "test.dat") 1622 err = createRandFile(path, filesize) 1623 if err != nil { 1624 t.Fatal(err) 1625 } 1626 1627 // Upload the file 1628 dataPieces := 1 1629 parityPieces := 1 1630 uploadValues := url.Values{} 1631 uploadValues.Set("source", path) 1632 uploadValues.Set("datapieces", fmt.Sprint(dataPieces)) 1633 uploadValues.Set("paritypieces", fmt.Sprint(parityPieces)) 1634 err = st.stdPostAPI("/renter/upload/test", uploadValues) 1635 if err != nil { 1636 t.Fatal(err) 1637 } 1638 1639 // Calculate the encrypted size of our fully redundant encoded file 1640 pieceSize := modules.SectorSize - crypto.TwofishOverhead 1641 chunkSize := pieceSize * uint64(dataPieces) 1642 numChunks := uint64(filesize) / chunkSize 1643 if uint64(filesize)%chunkSize != 0 { 1644 numChunks++ 1645 } 1646 fullyRedundantSize := modules.SectorSize * uint64(dataPieces+parityPieces) * uint64(numChunks) 1647 1648 // Monitor the file as it uploads. Ensure that the UploadProgress times 1649 // the fully redundant file size always equals UploadedBytes reported 1650 var rf RenterFiles 1651 for i := 0; i < 60 && (len(rf.Files) != 1 || rf.Files[0].UploadProgress < 100); i++ { 1652 st.getAPI("/renter/files", &rf) 1653 if len(rf.Files) >= 1 { 1654 uploadProgressBytes := uint64(float64(fullyRedundantSize) * rf.Files[0].UploadProgress / 100.0) 1655 // Note: in Go 1.10 we will be able to write Math.Round(uploadProgressBytes) != rf.Files[0].UploadedBytes 1656 if uploadProgressBytes != rf.Files[0].UploadedBytes && (uploadProgressBytes+1) != rf.Files[0].UploadedBytes { 1657 t.Fatalf("api reports having uploaded %v bytes when upload progress is %v%%, but the actual uploaded bytes count should be %v\n", 1658 rf.Files[0].UploadedBytes, rf.Files[0].UploadProgress, uploadProgressBytes) 1659 } 1660 } 1661 time.Sleep(time.Second) 1662 } 1663 if err != nil { 1664 t.Fatal(err) 1665 } 1666 1667 // Upload progress should be 100% and redundancy should reach 2 1668 if len(rf.Files) != 1 || rf.Files[0].UploadProgress < 100 || rf.Files[0].Redundancy != 2 { 1669 t.Fatal("the uploading is not succeeding for some reason:", rf.Files[0]) 1670 } 1671 1672 // When the file is fully redundantly uploaded, UploadedBytes should 1673 // equal the file's fully redundant size 1674 if rf.Files[0].UploadedBytes != fullyRedundantSize { 1675 t.Fatalf("api reports having uploaded %v bytes when upload progress is 100%%, but the actual fully redundant file size is %v\n", 1676 rf.Files[0].UploadedBytes, fullyRedundantSize) 1677 } 1678 1679 } 1680 1681 // TestRenterMissingHosts verifies that if hosts are taken offline, downloads 1682 // fail. 1683 func TestRenterMissingHosts(t *testing.T) { 1684 if testing.Short() || !build.VLONG { 1685 t.SkipNow() 1686 } 1687 st, err := createServerTester(t.Name()) 1688 if err != nil { 1689 t.Fatal(err) 1690 } 1691 defer st.server.Close() 1692 stH1, err := blankServerTester(t.Name() + " - Host 1") 1693 if err != nil { 1694 t.Fatal(err) 1695 } 1696 defer stH1.server.Close() 1697 stH2, err := blankServerTester(t.Name() + " - Host 2") 1698 if err != nil { 1699 t.Fatal(err) 1700 } 1701 defer stH2.server.Close() 1702 stH3, err := blankServerTester(t.Name() + " - Host 3") 1703 if err != nil { 1704 t.Fatal(err) 1705 } 1706 defer stH3.server.Close() 1707 testGroup := []*serverTester{st, stH1, stH2, stH3} 1708 1709 // Connect the testers to eachother so that they are all on the same 1710 // blockchain. 1711 err = fullyConnectNodes(testGroup) 1712 if err != nil { 1713 t.Fatal(err) 1714 } 1715 // Make sure that every wallet has money in it. 1716 err = fundAllNodes(testGroup) 1717 if err != nil { 1718 t.Fatal(err) 1719 } 1720 1721 // Add storage to every host. 1722 err = addStorageToAllHosts(testGroup) 1723 if err != nil { 1724 t.Fatal(err) 1725 } 1726 err = announceAllHosts(testGroup) 1727 if err != nil { 1728 t.Fatal(err) 1729 } 1730 1731 // Set an allowance with two hosts. 1732 allowanceValues := url.Values{} 1733 allowanceValues.Set("funds", "50000000000000000000000000000") // 50k SC 1734 allowanceValues.Set("hosts", "3") 1735 allowanceValues.Set("period", "20") 1736 err = st.stdPostAPI("/renter", allowanceValues) 1737 if err != nil { 1738 t.Fatal(err) 1739 } 1740 1741 // Block until the allowance has finished forming contracts. 1742 err = build.Retry(50, time.Millisecond*250, func() error { 1743 var rc RenterContracts 1744 err = st.getAPI("/renter/contracts", &rc) 1745 if err != nil { 1746 return errors.New("couldn't get renter stats") 1747 } 1748 if len(rc.Contracts) != 3 { 1749 return errors.New("no contracts") 1750 } 1751 return nil 1752 }) 1753 if err != nil { 1754 t.Fatal("allowance setting failed:", err) 1755 } 1756 1757 // Create a file to upload. 1758 filesize := int(100) 1759 path := filepath.Join(st.dir, "test.dat") 1760 err = createRandFile(path, filesize) 1761 if err != nil { 1762 t.Fatal(err) 1763 } 1764 1765 // upload the file 1766 uploadValues := url.Values{} 1767 uploadValues.Set("source", path) 1768 uploadValues.Set("datapieces", "2") 1769 uploadValues.Set("paritypieces", "1") 1770 err = st.stdPostAPI("/renter/upload/test", uploadValues) 1771 if err != nil { 1772 t.Fatal(err) 1773 } 1774 1775 // redundancy should reach 1.5 1776 var rf RenterFiles 1777 err = build.Retry(20, time.Second, func() error { 1778 st.getAPI("/renter/files", &rf) 1779 if len(rf.Files) >= 1 && rf.Files[0].Redundancy == 1.5 { 1780 return nil 1781 } 1782 return errors.New("file not uploaded") 1783 }) 1784 if err != nil { 1785 t.Fatal(err) 1786 } 1787 1788 // verify we can download 1789 downloadPath := filepath.Join(st.dir, "test-downloaded-verify.dat") 1790 err = st.stdGetAPI("/renter/download/test?destination=" + downloadPath) 1791 if err != nil { 1792 t.Fatal(err) 1793 } 1794 1795 // take down one of the hosts 1796 err = stH1.server.Close() 1797 if err != nil { 1798 t.Fatal(err) 1799 } 1800 1801 // redundancy should not decrement, we have a backup host we can use. 1802 err = build.Retry(60, time.Second, func() error { 1803 st.getAPI("/renter/files", &rf) 1804 if len(rf.Files) >= 1 && rf.Files[0].Redundancy == 1.5 { 1805 return nil 1806 } 1807 return errors.New("file redundancy not decremented: " + fmt.Sprint(rf.Files[0].Redundancy)) 1808 }) 1809 if err != nil { 1810 t.Log(err) 1811 } 1812 1813 // verify we still can download 1814 downloadPath = filepath.Join(st.dir, "test-downloaded-verify2.dat") 1815 err = st.stdGetAPI("/renter/download/test?destination=" + downloadPath) 1816 if err != nil { 1817 t.Fatal(err) 1818 } 1819 1820 // take down another host 1821 err = stH2.server.Close() 1822 if err != nil { 1823 t.Fatal(err) 1824 } 1825 1826 // wait for the redundancy to decrement 1827 err = build.Retry(60, time.Second, func() error { 1828 st.getAPI("/renter/files", &rf) 1829 if len(rf.Files) >= 1 && rf.Files[0].Redundancy == 1 { 1830 return nil 1831 } 1832 return errors.New("file redundancy not decremented: " + fmt.Sprint(rf.Files[0].Redundancy)) 1833 }) 1834 if err != nil { 1835 t.Log(err) 1836 } 1837 1838 // verify we still can download 1839 downloadPath = filepath.Join(st.dir, "test-downloaded-verify2.dat") 1840 err = st.stdGetAPI("/renter/download/test?destination=" + downloadPath) 1841 if err != nil { 1842 t.Fatal(err) 1843 } 1844 1845 // take down another host 1846 err = stH3.server.Close() 1847 if err != nil { 1848 t.Fatal(err) 1849 } 1850 1851 // wait for the redundancy to decrement 1852 err = build.Retry(60, time.Second, func() error { 1853 st.getAPI("/renter/files", &rf) 1854 if len(rf.Files) >= 1 && rf.Files[0].Redundancy == 0 { 1855 return nil 1856 } 1857 return errors.New("file redundancy not decremented: " + fmt.Sprint(rf.Files[0].Redundancy)) 1858 }) 1859 if err != nil { 1860 t.Log(err) 1861 } 1862 1863 // verify that the download fails 1864 downloadPath = filepath.Join(st.dir, "test-downloaded-verify4.dat") 1865 err = st.stdGetAPI("/renter/download/test?destination=" + downloadPath) 1866 if err == nil { 1867 t.Fatal("expected download to fail with redundancy <1") 1868 } 1869 } 1870 1871 // TestRepairLoopBlocking checks if the repair loop blocks operations while a 1872 // non local file is being downloaded for repair. 1873 func TestRepairLoopBlocking(t *testing.T) { 1874 // TODO: Refactor dependency management to block download 1875 t.Skip("Test requires refactoring") 1876 if testing.Short() || !build.VLONG { 1877 t.SkipNow() 1878 } 1879 st, err := createServerTester(t.Name()) 1880 if err != nil { 1881 t.Fatal(err) 1882 } 1883 //st.renter.SetDependencies(renter.BlockRepairUpload{}) 1884 defer st.server.Close() 1885 stH1, err := blankServerTester(t.Name() + " - Host 1") 1886 if err != nil { 1887 t.Fatal(err) 1888 } 1889 defer stH1.server.Close() 1890 testGroup := []*serverTester{st, stH1} 1891 1892 // Connect the testers to eachother so that they are all on the same 1893 // blockchain. 1894 err = fullyConnectNodes(testGroup) 1895 if err != nil { 1896 t.Fatal(err) 1897 } 1898 // Make sure that every wallet has money in it. 1899 err = fundAllNodes(testGroup) 1900 if err != nil { 1901 t.Fatal(err) 1902 } 1903 1904 // Add storage to every host. 1905 err = addStorageToAllHosts(testGroup) 1906 if err != nil { 1907 t.Fatal(err) 1908 } 1909 err = announceAllHosts(testGroup) 1910 if err != nil { 1911 t.Fatal(err) 1912 } 1913 1914 // Set an allowance with two hosts. 1915 allowanceValues := url.Values{} 1916 allowanceValues.Set("funds", "50000000000000000000000000000") // 50k SC 1917 allowanceValues.Set("hosts", "2") 1918 allowanceValues.Set("period", "10") 1919 err = st.stdPostAPI("/renter", allowanceValues) 1920 if err != nil { 1921 t.Fatal(err) 1922 } 1923 1924 // Create a file with 1 chunk to upload. 1925 filesize := int(1) 1926 path := filepath.Join(st.dir, "test.dat") 1927 err = createRandFile(path, filesize) 1928 if err != nil { 1929 t.Fatal(err) 1930 } 1931 1932 // upload the file 1933 uploadValues := url.Values{} 1934 uploadValues.Set("source", path) 1935 err = st.stdPostAPI("/renter/upload/test", uploadValues) 1936 if err != nil { 1937 t.Fatal(err) 1938 } 1939 1940 // redundancy should reach 2 1941 var rf RenterFiles 1942 err = build.Retry(60, time.Second, func() error { 1943 st.getAPI("/renter/files", &rf) 1944 if len(rf.Files) >= 1 && rf.Files[0].Redundancy == 2 { 1945 return nil 1946 } 1947 return errors.New("file not uploaded") 1948 }) 1949 if err != nil { 1950 t.Fatal(err) 1951 } 1952 1953 // verify we can download 1954 downloadPath := filepath.Join(st.dir, "test-downloaded-verify.dat") 1955 err = st.stdGetAPI("/renter/download/test?destination=" + downloadPath) 1956 if err != nil { 1957 t.Fatal(err) 1958 } 1959 1960 // remove the local copy of the file 1961 err = os.Remove(path) 1962 if err != nil { 1963 t.Fatal(err) 1964 } 1965 1966 // take down one of the hosts 1967 err = stH1.server.Close() 1968 if err != nil { 1969 t.Fatal(err) 1970 } 1971 1972 // wait for the redundancy to decrement 1973 err = build.Retry(60, time.Second, func() error { 1974 st.getAPI("/renter/files", &rf) 1975 if len(rf.Files) >= 1 && rf.Files[0].Redundancy == 1 { 1976 return nil 1977 } 1978 return errors.New("file redundancy not decremented") 1979 }) 1980 if err != nil { 1981 t.Fatal(err) 1982 } 1983 1984 // verify we still can download 1985 downloadPath = filepath.Join(st.dir, "test-downloaded-verify2.dat") 1986 err = st.stdGetAPI("/renter/download/test?destination=" + downloadPath) 1987 if err != nil { 1988 t.Fatal(err) 1989 } 1990 1991 // bring up a few new hosts 1992 testGroup = []*serverTester{st} 1993 for i := 0; i < 3; i++ { 1994 stNewHost, err := blankServerTester(t.Name() + fmt.Sprintf("-newhost%d", i)) 1995 if err != nil { 1996 t.Fatal(err) 1997 } 1998 defer stNewHost.server.Close() 1999 testGroup = append(testGroup, stNewHost) 2000 } 2001 2002 // Connect the testers to eachother so that they are all on the same 2003 // blockchain. 2004 err = fullyConnectNodes(testGroup) 2005 if err != nil { 2006 t.Fatal(err) 2007 } 2008 _, err = synchronizationCheck(testGroup) 2009 if err != nil { 2010 t.Fatal(err) 2011 } 2012 2013 // Make sure that every wallet has money in it. 2014 err = fundAllNodes(testGroup) 2015 if err != nil { 2016 t.Fatal(err) 2017 } 2018 2019 for _, stNewHost := range testGroup[1 : len(testGroup)-1] { 2020 err = stNewHost.setHostStorage() 2021 if err != nil { 2022 t.Fatal(err) 2023 } 2024 err = stNewHost.announceHost() 2025 if err != nil { 2026 t.Fatal(err) 2027 } 2028 err = waitForBlock(stNewHost.cs.CurrentBlock().ID(), st) 2029 if err != nil { 2030 t.Fatal(err) 2031 } 2032 2033 // add a few new blocks in order to cause the renter to form contracts with the new host 2034 for i := 0; i < 10; i++ { 2035 b, err := testGroup[0].miner.AddBlock() 2036 if err != nil { 2037 t.Fatal(err) 2038 } 2039 tipID, err := synchronizationCheck(testGroup) 2040 if err != nil { 2041 t.Fatal(err) 2042 } 2043 if b.ID() != tipID { 2044 t.Fatal("test group does not have the tip block") 2045 } 2046 } 2047 } 2048 2049 // wait a few seconds for the the repair to be queued and started 2050 time.Sleep(3 * time.Second) 2051 2052 // redundancy should not increment back to 2 because the renter should be blocked 2053 st.getAPI("/renter/files", &rf) 2054 if len(rf.Files) >= 1 && rf.Files[0].Redundancy >= 2 && rf.Files[0].Available { 2055 t.Error("The file's redundancy incremented back to 2 but shouldn't") 2056 } 2057 2058 // create a second file to upload 2059 filesize = int(1) 2060 path2 := filepath.Join(st.dir, "test2.dat") 2061 err = createRandFile(path2, filesize) 2062 if err != nil { 2063 t.Fatal(err) 2064 } 2065 2066 // upload the second file 2067 uploadValues = url.Values{} 2068 uploadValues.Set("source", path2) 2069 2070 wait := make(chan error) 2071 go func() { 2072 wait <- st.stdPostAPI("/renter/upload/test2", uploadValues) 2073 }() 2074 select { 2075 case <-time.After(time.Minute): 2076 t.Fatal("/renter/upload API call didn't return within 60 seconds") 2077 case err = <-wait: 2078 } 2079 if err != nil { 2080 t.Fatal(err) 2081 } 2082 2083 // redundancy should reach 2 for the second file 2084 err = build.Retry(60, time.Second, func() error { 2085 st.getAPI("/renter/files", &rf) 2086 if len(rf.Files) >= 2 && rf.Files[1].Redundancy >= 2 { 2087 return nil 2088 } 2089 return errors.New("file 2 not uploaded") 2090 }) 2091 if err != nil { 2092 t.Fatal(err) 2093 } 2094 2095 // verify we can download the second file 2096 downloadPath = filepath.Join(st.dir, "test-downloaded-verify2.dat") 2097 err = st.stdGetAPI("/renter/download/test2?destination=" + downloadPath) 2098 if err != nil { 2099 t.Fatal(err) 2100 } 2101 } 2102 2103 // TestRemoteFileRepairMassive is similar to TestRemoteFileRepair but uploads 2104 // more files to find potential deadlocks or crashes 2105 func TestRemoteFileRepairMassive(t *testing.T) { 2106 if testing.Short() || !build.VLONG { 2107 t.SkipNow() 2108 } 2109 st, err := createServerTester(t.Name()) 2110 if err != nil { 2111 t.Fatal(err) 2112 } 2113 defer st.server.Close() 2114 stH1, err := blankServerTester(t.Name() + " - Host 1") 2115 if err != nil { 2116 t.Fatal(err) 2117 } 2118 defer stH1.server.Close() 2119 testGroup := []*serverTester{st, stH1} 2120 2121 // Connect the testers to eachother so that they are all on the same 2122 // blockchain. 2123 err = fullyConnectNodes(testGroup) 2124 if err != nil { 2125 t.Fatal(err) 2126 } 2127 // Make sure that every wallet has money in it. 2128 err = fundAllNodes(testGroup) 2129 if err != nil { 2130 t.Fatal(err) 2131 } 2132 2133 // Add storage to every host. 2134 err = addStorageToAllHosts(testGroup) 2135 if err != nil { 2136 t.Fatal(err) 2137 } 2138 err = announceAllHosts(testGroup) 2139 if err != nil { 2140 t.Fatal(err) 2141 } 2142 2143 // Set an allowance with two hosts. 2144 allowanceValues := url.Values{} 2145 allowanceValues.Set("funds", "50000000000000000000000000000") // 50k SC 2146 allowanceValues.Set("hosts", "2") 2147 allowanceValues.Set("period", "10") 2148 err = st.stdPostAPI("/renter", allowanceValues) 2149 if err != nil { 2150 t.Fatal(err) 2151 } 2152 2153 // Create a file to upload. 2154 filesize := int(4000) 2155 path := filepath.Join(st.dir, "test.dat") 2156 err = createRandFile(path, filesize) 2157 if err != nil { 2158 t.Fatal(err) 2159 } 2160 2161 // upload the file numUploads times 2162 numUploads := 10 2163 uploadValues := url.Values{} 2164 uploadValues.Set("source", path) 2165 2166 for i := 0; i < numUploads; i++ { 2167 err = st.stdPostAPI(fmt.Sprintf("/renter/upload/test%v", i), uploadValues) 2168 if err != nil { 2169 t.Fatal(err) 2170 } 2171 } 2172 2173 // redundancy should reach 2 for all files 2174 var rf RenterFiles 2175 err = build.Retry(600, time.Second, func() error { 2176 st.getAPI("/renter/files", &rf) 2177 if len(rf.Files) != numUploads { 2178 return errors.New("file not uploaded") 2179 } 2180 for i, f := range rf.Files { 2181 if f.Redundancy != 2 { 2182 return fmt.Errorf("file %v only reached %v redundancy", i, f.Redundancy) 2183 } 2184 } 2185 return nil 2186 }) 2187 if err != nil { 2188 t.Fatal(err) 2189 } 2190 2191 // remove the local copy of the file 2192 err = os.Remove(path) 2193 if err != nil { 2194 t.Fatal(err) 2195 } 2196 2197 // take down one of the hosts 2198 err = stH1.server.Close() 2199 if err != nil { 2200 t.Fatal(err) 2201 } 2202 2203 // wait for the redundancy to decrement 2204 err = build.Retry(60, time.Second, func() error { 2205 st.getAPI("/renter/files", &rf) 2206 if len(rf.Files) != numUploads { 2207 return errors.New("file not uploaded") 2208 } 2209 for _, f := range rf.Files { 2210 if f.Redundancy != 1 { 2211 return errors.New("file redudancy didn't decrement to x1") 2212 } 2213 } 2214 return nil 2215 }) 2216 if err != nil { 2217 t.Fatal(err) 2218 } 2219 2220 // bring up a new host 2221 stNewHost, err := blankServerTester(t.Name() + "-newhost") 2222 if err != nil { 2223 t.Fatal(err) 2224 } 2225 defer stNewHost.server.Close() 2226 2227 testGroup = []*serverTester{st, stNewHost} 2228 2229 // Connect the testers to eachother so that they are all on the same 2230 // blockchain. 2231 err = fullyConnectNodes(testGroup) 2232 if err != nil { 2233 t.Fatal(err) 2234 } 2235 _, err = synchronizationCheck(testGroup) 2236 if err != nil { 2237 t.Fatal(err) 2238 } 2239 2240 // Make sure that every wallet has money in it. 2241 err = fundAllNodes(testGroup) 2242 if err != nil { 2243 t.Fatal(err) 2244 } 2245 2246 err = stNewHost.setHostStorage() 2247 if err != nil { 2248 t.Fatal(err) 2249 } 2250 err = stNewHost.announceHost() 2251 if err != nil { 2252 t.Fatal(err) 2253 } 2254 err = waitForBlock(stNewHost.cs.CurrentBlock().ID(), st) 2255 if err != nil { 2256 t.Fatal(err) 2257 } 2258 2259 // add a few new blocks in order to cause the renter to form contracts with the new host 2260 for i := 0; i < 10; i++ { 2261 b, err := testGroup[0].miner.AddBlock() 2262 if err != nil { 2263 t.Fatal(err) 2264 } 2265 tipID, err := synchronizationCheck(testGroup) 2266 if err != nil { 2267 t.Fatal(err) 2268 } 2269 if b.ID() != tipID { 2270 t.Fatal("test group does not have the tip block") 2271 } 2272 } 2273 2274 // redundancy should increment back to 2 as the renter uploads to the new 2275 // host using the download-to-upload strategy 2276 err = build.Retry(300, time.Second, func() error { 2277 st.getAPI("/renter/files", &rf) 2278 if len(rf.Files) != numUploads { 2279 return errors.New("file not uploaded") 2280 } 2281 for i, f := range rf.Files { 2282 if f.Redundancy != 2 { 2283 return fmt.Errorf("file %v only reached %v redundancy", i, f.Redundancy) 2284 } 2285 } 2286 return nil 2287 }) 2288 if err != nil { 2289 t.Fatal(err) 2290 } 2291 }