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