github.com/codingfuture/orig-energi3@v0.8.4/cmd/swarm/manifest_test.go (about) 1 // Copyright 2018 The Energi Core Authors 2 // Copyright 2018 The go-ethereum Authors 3 // This file is part of Energi Core. 4 // 5 // Energi Core is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // Energi Core is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU General Public License for more details. 14 // 15 // You should have received a copy of the GNU General Public License 16 // along with Energi Core. If not, see <http://www.gnu.org/licenses/>. 17 18 package main 19 20 import ( 21 "bytes" 22 "io/ioutil" 23 "os" 24 "path/filepath" 25 "runtime" 26 "testing" 27 28 "github.com/ethereum/go-ethereum/swarm/api" 29 swarm "github.com/ethereum/go-ethereum/swarm/api/client" 30 swarmhttp "github.com/ethereum/go-ethereum/swarm/api/http" 31 ) 32 33 // TestManifestChange tests manifest add, update and remove 34 // cli commands without encryption. 35 func TestManifestChange(t *testing.T) { 36 if runtime.GOOS == "windows" { 37 t.Skip() 38 } 39 40 testManifestChange(t, false) 41 } 42 43 // TestManifestChange tests manifest add, update and remove 44 // cli commands with encryption enabled. 45 func TestManifestChangeEncrypted(t *testing.T) { 46 if runtime.GOOS == "windows" { 47 t.Skip() 48 } 49 50 testManifestChange(t, true) 51 } 52 53 // testManifestChange performs cli commands: 54 // - manifest add 55 // - manifest update 56 // - manifest remove 57 // on a manifest, testing the functionality of this 58 // comands on paths that are in root manifest or a nested one. 59 // Argument encrypt controls whether to use encryption or not. 60 func testManifestChange(t *testing.T, encrypt bool) { 61 t.Parallel() 62 srv := swarmhttp.NewTestSwarmServer(t, serverFunc, nil) 63 defer srv.Close() 64 65 tmp, err := ioutil.TempDir("", "swarm-manifest-test") 66 if err != nil { 67 t.Fatal(err) 68 } 69 defer os.RemoveAll(tmp) 70 71 origDir := filepath.Join(tmp, "orig") 72 if err := os.Mkdir(origDir, 0777); err != nil { 73 t.Fatal(err) 74 } 75 76 indexDataFilename := filepath.Join(origDir, "index.html") 77 err = ioutil.WriteFile(indexDataFilename, []byte("<h1>Test</h1>"), 0666) 78 if err != nil { 79 t.Fatal(err) 80 } 81 // Files paths robots.txt and robots.html share the same prefix "robots." 82 // which will result a manifest with a nested manifest under path "robots.". 83 // This will allow testing manifest changes on both root and nested manifest. 84 err = ioutil.WriteFile(filepath.Join(origDir, "robots.txt"), []byte("Disallow: /"), 0666) 85 if err != nil { 86 t.Fatal(err) 87 } 88 err = ioutil.WriteFile(filepath.Join(origDir, "robots.html"), []byte("<strong>No Robots Allowed</strong>"), 0666) 89 if err != nil { 90 t.Fatal(err) 91 } 92 err = ioutil.WriteFile(filepath.Join(origDir, "mutants.txt"), []byte("Frank\nMarcus"), 0666) 93 if err != nil { 94 t.Fatal(err) 95 } 96 97 args := []string{ 98 "--bzzapi", 99 srv.URL, 100 "--recursive", 101 "--defaultpath", 102 indexDataFilename, 103 "up", 104 origDir, 105 } 106 if encrypt { 107 args = append(args, "--encrypt") 108 } 109 110 origManifestHash := runSwarmExpectHash(t, args...) 111 112 checkHashLength(t, origManifestHash, encrypt) 113 114 client := swarm.NewClient(srv.URL) 115 116 // upload a new file and use its manifest to add it the original manifest. 117 t.Run("add", func(t *testing.T) { 118 humansData := []byte("Ann\nBob") 119 humansDataFilename := filepath.Join(tmp, "humans.txt") 120 err = ioutil.WriteFile(humansDataFilename, humansData, 0666) 121 if err != nil { 122 t.Fatal(err) 123 } 124 125 humansManifestHash := runSwarmExpectHash(t, 126 "--bzzapi", 127 srv.URL, 128 "up", 129 humansDataFilename, 130 ) 131 132 newManifestHash := runSwarmExpectHash(t, 133 "--bzzapi", 134 srv.URL, 135 "manifest", 136 "add", 137 origManifestHash, 138 "humans.txt", 139 humansManifestHash, 140 ) 141 142 checkHashLength(t, newManifestHash, encrypt) 143 144 newManifest := downloadManifest(t, client, newManifestHash, encrypt) 145 146 var found bool 147 for _, e := range newManifest.Entries { 148 if e.Path == "humans.txt" { 149 found = true 150 if e.Size != int64(len(humansData)) { 151 t.Errorf("expected humans.txt size %v, got %v", len(humansData), e.Size) 152 } 153 if e.ModTime.IsZero() { 154 t.Errorf("got zero mod time for humans.txt") 155 } 156 ct := "text/plain; charset=utf-8" 157 if e.ContentType != ct { 158 t.Errorf("expected content type %q, got %q", ct, e.ContentType) 159 } 160 break 161 } 162 } 163 if !found { 164 t.Fatal("no humans.txt in new manifest") 165 } 166 167 checkFile(t, client, newManifestHash, "humans.txt", humansData) 168 }) 169 170 // upload a new file and use its manifest to add it the original manifest, 171 // but ensure that the file will be in the nested manifest of the original one. 172 t.Run("add nested", func(t *testing.T) { 173 robotsData := []byte(`{"disallow": "/"}`) 174 robotsDataFilename := filepath.Join(tmp, "robots.json") 175 err = ioutil.WriteFile(robotsDataFilename, robotsData, 0666) 176 if err != nil { 177 t.Fatal(err) 178 } 179 180 robotsManifestHash := runSwarmExpectHash(t, 181 "--bzzapi", 182 srv.URL, 183 "up", 184 robotsDataFilename, 185 ) 186 187 newManifestHash := runSwarmExpectHash(t, 188 "--bzzapi", 189 srv.URL, 190 "manifest", 191 "add", 192 origManifestHash, 193 "robots.json", 194 robotsManifestHash, 195 ) 196 197 checkHashLength(t, newManifestHash, encrypt) 198 199 newManifest := downloadManifest(t, client, newManifestHash, encrypt) 200 201 var found bool 202 loop: 203 for _, e := range newManifest.Entries { 204 if e.Path == "robots." { 205 nestedManifest := downloadManifest(t, client, e.Hash, encrypt) 206 for _, e := range nestedManifest.Entries { 207 if e.Path == "json" { 208 found = true 209 if e.Size != int64(len(robotsData)) { 210 t.Errorf("expected robots.json size %v, got %v", len(robotsData), e.Size) 211 } 212 if e.ModTime.IsZero() { 213 t.Errorf("got zero mod time for robots.json") 214 } 215 ct := "application/json" 216 if e.ContentType != ct { 217 t.Errorf("expected content type %q, got %q", ct, e.ContentType) 218 } 219 break loop 220 } 221 } 222 } 223 } 224 if !found { 225 t.Fatal("no robots.json in new manifest") 226 } 227 228 checkFile(t, client, newManifestHash, "robots.json", robotsData) 229 }) 230 231 // upload a new file and use its manifest to change the file it the original manifest. 232 t.Run("update", func(t *testing.T) { 233 indexData := []byte("<h1>Energi Swarm</h1>") 234 indexDataFilename := filepath.Join(tmp, "index.html") 235 err = ioutil.WriteFile(indexDataFilename, indexData, 0666) 236 if err != nil { 237 t.Fatal(err) 238 } 239 240 indexManifestHash := runSwarmExpectHash(t, 241 "--bzzapi", 242 srv.URL, 243 "up", 244 indexDataFilename, 245 ) 246 247 newManifestHash := runSwarmExpectHash(t, 248 "--bzzapi", 249 srv.URL, 250 "manifest", 251 "update", 252 origManifestHash, 253 "index.html", 254 indexManifestHash, 255 ) 256 257 checkHashLength(t, newManifestHash, encrypt) 258 259 newManifest := downloadManifest(t, client, newManifestHash, encrypt) 260 261 var found bool 262 for _, e := range newManifest.Entries { 263 if e.Path == "index.html" { 264 found = true 265 if e.Size != int64(len(indexData)) { 266 t.Errorf("expected index.html size %v, got %v", len(indexData), e.Size) 267 } 268 if e.ModTime.IsZero() { 269 t.Errorf("got zero mod time for index.html") 270 } 271 ct := "text/html; charset=utf-8" 272 if e.ContentType != ct { 273 t.Errorf("expected content type %q, got %q", ct, e.ContentType) 274 } 275 break 276 } 277 } 278 if !found { 279 t.Fatal("no index.html in new manifest") 280 } 281 282 checkFile(t, client, newManifestHash, "index.html", indexData) 283 284 // check default entry change 285 checkFile(t, client, newManifestHash, "", indexData) 286 }) 287 288 // upload a new file and use its manifest to change the file it the original manifest, 289 // but ensure that the file is in the nested manifest of the original one. 290 t.Run("update nested", func(t *testing.T) { 291 robotsData := []byte(`<string>Only humans allowed!!!</strong>`) 292 robotsDataFilename := filepath.Join(tmp, "robots.html") 293 err = ioutil.WriteFile(robotsDataFilename, robotsData, 0666) 294 if err != nil { 295 t.Fatal(err) 296 } 297 298 humansManifestHash := runSwarmExpectHash(t, 299 "--bzzapi", 300 srv.URL, 301 "up", 302 robotsDataFilename, 303 ) 304 305 newManifestHash := runSwarmExpectHash(t, 306 "--bzzapi", 307 srv.URL, 308 "manifest", 309 "update", 310 origManifestHash, 311 "robots.html", 312 humansManifestHash, 313 ) 314 315 checkHashLength(t, newManifestHash, encrypt) 316 317 newManifest := downloadManifest(t, client, newManifestHash, encrypt) 318 319 var found bool 320 loop: 321 for _, e := range newManifest.Entries { 322 if e.Path == "robots." { 323 nestedManifest := downloadManifest(t, client, e.Hash, encrypt) 324 for _, e := range nestedManifest.Entries { 325 if e.Path == "html" { 326 found = true 327 if e.Size != int64(len(robotsData)) { 328 t.Errorf("expected robots.html size %v, got %v", len(robotsData), e.Size) 329 } 330 if e.ModTime.IsZero() { 331 t.Errorf("got zero mod time for robots.html") 332 } 333 ct := "text/html; charset=utf-8" 334 if e.ContentType != ct { 335 t.Errorf("expected content type %q, got %q", ct, e.ContentType) 336 } 337 break loop 338 } 339 } 340 } 341 } 342 if !found { 343 t.Fatal("no robots.html in new manifest") 344 } 345 346 checkFile(t, client, newManifestHash, "robots.html", robotsData) 347 }) 348 349 // remove a file from the manifest. 350 t.Run("remove", func(t *testing.T) { 351 newManifestHash := runSwarmExpectHash(t, 352 "--bzzapi", 353 srv.URL, 354 "manifest", 355 "remove", 356 origManifestHash, 357 "mutants.txt", 358 ) 359 360 checkHashLength(t, newManifestHash, encrypt) 361 362 newManifest := downloadManifest(t, client, newManifestHash, encrypt) 363 364 var found bool 365 for _, e := range newManifest.Entries { 366 if e.Path == "mutants.txt" { 367 found = true 368 break 369 } 370 } 371 if found { 372 t.Fatal("mutants.txt is not removed") 373 } 374 }) 375 376 // remove a file from the manifest, but ensure that the file is in 377 // the nested manifest of the original one. 378 t.Run("remove nested", func(t *testing.T) { 379 newManifestHash := runSwarmExpectHash(t, 380 "--bzzapi", 381 srv.URL, 382 "manifest", 383 "remove", 384 origManifestHash, 385 "robots.html", 386 ) 387 388 checkHashLength(t, newManifestHash, encrypt) 389 390 newManifest := downloadManifest(t, client, newManifestHash, encrypt) 391 392 var found bool 393 loop: 394 for _, e := range newManifest.Entries { 395 if e.Path == "robots." { 396 nestedManifest := downloadManifest(t, client, e.Hash, encrypt) 397 for _, e := range nestedManifest.Entries { 398 if e.Path == "html" { 399 found = true 400 break loop 401 } 402 } 403 } 404 } 405 if found { 406 t.Fatal("robots.html in not removed") 407 } 408 }) 409 } 410 411 // TestNestedDefaultEntryUpdate tests if the default entry is updated 412 // if the file in nested manifest used for it is also updated. 413 func TestNestedDefaultEntryUpdate(t *testing.T) { 414 if runtime.GOOS == "windows" { 415 t.Skip() 416 } 417 418 testNestedDefaultEntryUpdate(t, false) 419 } 420 421 // TestNestedDefaultEntryUpdateEncrypted tests if the default entry 422 // of encrypted upload is updated if the file in nested manifest 423 // used for it is also updated. 424 func TestNestedDefaultEntryUpdateEncrypted(t *testing.T) { 425 if runtime.GOOS == "windows" { 426 t.Skip() 427 } 428 429 testNestedDefaultEntryUpdate(t, true) 430 } 431 432 func testNestedDefaultEntryUpdate(t *testing.T, encrypt bool) { 433 t.Parallel() 434 srv := swarmhttp.NewTestSwarmServer(t, serverFunc, nil) 435 defer srv.Close() 436 437 tmp, err := ioutil.TempDir("", "swarm-manifest-test") 438 if err != nil { 439 t.Fatal(err) 440 } 441 defer os.RemoveAll(tmp) 442 443 origDir := filepath.Join(tmp, "orig") 444 if err := os.Mkdir(origDir, 0777); err != nil { 445 t.Fatal(err) 446 } 447 448 indexData := []byte("<h1>Test</h1>") 449 indexDataFilename := filepath.Join(origDir, "index.html") 450 err = ioutil.WriteFile(indexDataFilename, indexData, 0666) 451 if err != nil { 452 t.Fatal(err) 453 } 454 // Add another file with common prefix as the default entry to test updates of 455 // default entry with nested manifests. 456 err = ioutil.WriteFile(filepath.Join(origDir, "index.txt"), []byte("Test"), 0666) 457 if err != nil { 458 t.Fatal(err) 459 } 460 461 args := []string{ 462 "--bzzapi", 463 srv.URL, 464 "--recursive", 465 "--defaultpath", 466 indexDataFilename, 467 "up", 468 origDir, 469 } 470 if encrypt { 471 args = append(args, "--encrypt") 472 } 473 474 origManifestHash := runSwarmExpectHash(t, args...) 475 476 checkHashLength(t, origManifestHash, encrypt) 477 478 client := swarm.NewClient(srv.URL) 479 480 newIndexData := []byte("<h1>Energi Swarm</h1>") 481 newIndexDataFilename := filepath.Join(tmp, "index.html") 482 err = ioutil.WriteFile(newIndexDataFilename, newIndexData, 0666) 483 if err != nil { 484 t.Fatal(err) 485 } 486 487 newIndexManifestHash := runSwarmExpectHash(t, 488 "--bzzapi", 489 srv.URL, 490 "up", 491 newIndexDataFilename, 492 ) 493 494 newManifestHash := runSwarmExpectHash(t, 495 "--bzzapi", 496 srv.URL, 497 "manifest", 498 "update", 499 origManifestHash, 500 "index.html", 501 newIndexManifestHash, 502 ) 503 504 checkHashLength(t, newManifestHash, encrypt) 505 506 newManifest := downloadManifest(t, client, newManifestHash, encrypt) 507 508 var found bool 509 for _, e := range newManifest.Entries { 510 if e.Path == "index." { 511 found = true 512 newManifest = downloadManifest(t, client, e.Hash, encrypt) 513 break 514 } 515 } 516 if !found { 517 t.Fatal("no index. path in new manifest") 518 } 519 520 found = false 521 for _, e := range newManifest.Entries { 522 if e.Path == "html" { 523 found = true 524 if e.Size != int64(len(newIndexData)) { 525 t.Errorf("expected index.html size %v, got %v", len(newIndexData), e.Size) 526 } 527 if e.ModTime.IsZero() { 528 t.Errorf("got zero mod time for index.html") 529 } 530 ct := "text/html; charset=utf-8" 531 if e.ContentType != ct { 532 t.Errorf("expected content type %q, got %q", ct, e.ContentType) 533 } 534 break 535 } 536 } 537 if !found { 538 t.Fatal("no html in new manifest") 539 } 540 541 checkFile(t, client, newManifestHash, "index.html", newIndexData) 542 543 // check default entry change 544 checkFile(t, client, newManifestHash, "", newIndexData) 545 } 546 547 func runSwarmExpectHash(t *testing.T, args ...string) (hash string) { 548 t.Helper() 549 hashRegexp := `[a-f\d]{64,128}` 550 up := runSwarm(t, args...) 551 _, matches := up.ExpectRegexp(hashRegexp) 552 up.ExpectExit() 553 554 if len(matches) < 1 { 555 t.Fatal("no matches found") 556 } 557 return matches[0] 558 } 559 560 func checkHashLength(t *testing.T, hash string, encrypted bool) { 561 t.Helper() 562 l := len(hash) 563 if encrypted && l != 128 { 564 t.Errorf("expected hash length 128, got %v", l) 565 } 566 if !encrypted && l != 64 { 567 t.Errorf("expected hash length 64, got %v", l) 568 } 569 } 570 571 func downloadManifest(t *testing.T, client *swarm.Client, hash string, encrypted bool) (manifest *api.Manifest) { 572 t.Helper() 573 m, isEncrypted, err := client.DownloadManifest(hash) 574 if err != nil { 575 t.Fatal(err) 576 } 577 578 if encrypted != isEncrypted { 579 t.Error("new manifest encryption flag is not correct") 580 } 581 return m 582 } 583 584 func checkFile(t *testing.T, client *swarm.Client, hash, path string, expected []byte) { 585 t.Helper() 586 f, err := client.Download(hash, path) 587 if err != nil { 588 t.Fatal(err) 589 } 590 591 got, err := ioutil.ReadAll(f) 592 if err != nil { 593 t.Fatal(err) 594 } 595 if !bytes.Equal(got, expected) { 596 t.Errorf("expected file content %q, got %q", expected, got) 597 } 598 }