github.com/nitinawathare/ethereumassignment3@v0.0.0-20211021213010-f07344c2b868/go-ethereum/swarm/api/client/client_test.go (about) 1 // Copyright 2017 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser 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 // The go-ethereum library 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 Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package client 18 19 import ( 20 "bytes" 21 "io/ioutil" 22 "os" 23 "path/filepath" 24 "reflect" 25 "sort" 26 "testing" 27 28 "github.com/ethereum/go-ethereum/swarm/testutil" 29 30 "github.com/ethereum/go-ethereum/swarm/storage" 31 "github.com/ethereum/go-ethereum/swarm/storage/feed/lookup" 32 33 "github.com/ethereum/go-ethereum/common" 34 "github.com/ethereum/go-ethereum/crypto" 35 "github.com/ethereum/go-ethereum/swarm/api" 36 swarmhttp "github.com/ethereum/go-ethereum/swarm/api/http" 37 "github.com/ethereum/go-ethereum/swarm/storage/feed" 38 ) 39 40 func serverFunc(api *api.API) swarmhttp.TestServer { 41 return swarmhttp.NewServer(api, "") 42 } 43 44 // TestClientUploadDownloadRaw test uploading and downloading raw data to swarm 45 func TestClientUploadDownloadRaw(t *testing.T) { 46 testClientUploadDownloadRaw(false, t) 47 } 48 49 func TestClientUploadDownloadRawEncrypted(t *testing.T) { 50 if testutil.RaceEnabled { 51 t.Skip("flaky with -race on Travis") 52 // See: https://github.com/ethersphere/go-ethereum/issues/1254 53 } 54 55 testClientUploadDownloadRaw(true, t) 56 } 57 58 func testClientUploadDownloadRaw(toEncrypt bool, t *testing.T) { 59 srv := swarmhttp.NewTestSwarmServer(t, serverFunc, nil) 60 defer srv.Close() 61 62 client := NewClient(srv.URL) 63 64 // upload some raw data 65 data := []byte("foo123") 66 hash, err := client.UploadRaw(bytes.NewReader(data), int64(len(data)), toEncrypt) 67 if err != nil { 68 t.Fatal(err) 69 } 70 71 // check we can download the same data 72 res, isEncrypted, err := client.DownloadRaw(hash) 73 if err != nil { 74 t.Fatal(err) 75 } 76 if isEncrypted != toEncrypt { 77 t.Fatalf("Expected encyption status %v got %v", toEncrypt, isEncrypted) 78 } 79 defer res.Close() 80 gotData, err := ioutil.ReadAll(res) 81 if err != nil { 82 t.Fatal(err) 83 } 84 if !bytes.Equal(gotData, data) { 85 t.Fatalf("expected downloaded data to be %q, got %q", data, gotData) 86 } 87 } 88 89 // TestClientUploadDownloadFiles test uploading and downloading files to swarm 90 // manifests 91 func TestClientUploadDownloadFiles(t *testing.T) { 92 testClientUploadDownloadFiles(false, t) 93 } 94 95 func TestClientUploadDownloadFilesEncrypted(t *testing.T) { 96 testClientUploadDownloadFiles(true, t) 97 } 98 99 func testClientUploadDownloadFiles(toEncrypt bool, t *testing.T) { 100 srv := swarmhttp.NewTestSwarmServer(t, serverFunc, nil) 101 defer srv.Close() 102 103 client := NewClient(srv.URL) 104 upload := func(manifest, path string, data []byte) string { 105 file := &File{ 106 ReadCloser: ioutil.NopCloser(bytes.NewReader(data)), 107 ManifestEntry: api.ManifestEntry{ 108 Path: path, 109 ContentType: "text/plain", 110 Size: int64(len(data)), 111 }, 112 } 113 hash, err := client.Upload(file, manifest, toEncrypt) 114 if err != nil { 115 t.Fatal(err) 116 } 117 return hash 118 } 119 checkDownload := func(manifest, path string, expected []byte) { 120 file, err := client.Download(manifest, path) 121 if err != nil { 122 t.Fatal(err) 123 } 124 defer file.Close() 125 if file.Size != int64(len(expected)) { 126 t.Fatalf("expected downloaded file to be %d bytes, got %d", len(expected), file.Size) 127 } 128 if file.ContentType != "text/plain" { 129 t.Fatalf("expected downloaded file to have type %q, got %q", "text/plain", file.ContentType) 130 } 131 data, err := ioutil.ReadAll(file) 132 if err != nil { 133 t.Fatal(err) 134 } 135 if !bytes.Equal(data, expected) { 136 t.Fatalf("expected downloaded data to be %q, got %q", expected, data) 137 } 138 } 139 140 // upload a file to the root of a manifest 141 rootData := []byte("some-data") 142 rootHash := upload("", "", rootData) 143 144 // check we can download the root file 145 checkDownload(rootHash, "", rootData) 146 147 // upload another file to the same manifest 148 otherData := []byte("some-other-data") 149 newHash := upload(rootHash, "some/other/path", otherData) 150 151 // check we can download both files from the new manifest 152 checkDownload(newHash, "", rootData) 153 checkDownload(newHash, "some/other/path", otherData) 154 155 // replace the root file with different data 156 newHash = upload(newHash, "", otherData) 157 158 // check both files have the other data 159 checkDownload(newHash, "", otherData) 160 checkDownload(newHash, "some/other/path", otherData) 161 } 162 163 var testDirFiles = []string{ 164 "file1.txt", 165 "file2.txt", 166 "dir1/file3.txt", 167 "dir1/file4.txt", 168 "dir2/file5.txt", 169 "dir2/dir3/file6.txt", 170 "dir2/dir4/file7.txt", 171 "dir2/dir4/file8.txt", 172 } 173 174 func newTestDirectory(t *testing.T) string { 175 dir, err := ioutil.TempDir("", "swarm-client-test") 176 if err != nil { 177 t.Fatal(err) 178 } 179 180 for _, file := range testDirFiles { 181 path := filepath.Join(dir, file) 182 if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil { 183 os.RemoveAll(dir) 184 t.Fatalf("error creating dir for %s: %s", path, err) 185 } 186 if err := ioutil.WriteFile(path, []byte(file), 0644); err != nil { 187 os.RemoveAll(dir) 188 t.Fatalf("error writing file %s: %s", path, err) 189 } 190 } 191 192 return dir 193 } 194 195 // TestClientUploadDownloadDirectory tests uploading and downloading a 196 // directory of files to a swarm manifest 197 func TestClientUploadDownloadDirectory(t *testing.T) { 198 srv := swarmhttp.NewTestSwarmServer(t, serverFunc, nil) 199 defer srv.Close() 200 201 dir := newTestDirectory(t) 202 defer os.RemoveAll(dir) 203 204 // upload the directory 205 client := NewClient(srv.URL) 206 defaultPath := testDirFiles[0] 207 hash, err := client.UploadDirectory(dir, defaultPath, "", false) 208 if err != nil { 209 t.Fatalf("error uploading directory: %s", err) 210 } 211 212 // check we can download the individual files 213 checkDownloadFile := func(path string, expected []byte) { 214 file, err := client.Download(hash, path) 215 if err != nil { 216 t.Fatal(err) 217 } 218 defer file.Close() 219 data, err := ioutil.ReadAll(file) 220 if err != nil { 221 t.Fatal(err) 222 } 223 if !bytes.Equal(data, expected) { 224 t.Fatalf("expected data to be %q, got %q", expected, data) 225 } 226 } 227 for _, file := range testDirFiles { 228 checkDownloadFile(file, []byte(file)) 229 } 230 231 // check we can download the default path 232 checkDownloadFile("", []byte(testDirFiles[0])) 233 234 // check we can download the directory 235 tmp, err := ioutil.TempDir("", "swarm-client-test") 236 if err != nil { 237 t.Fatal(err) 238 } 239 defer os.RemoveAll(tmp) 240 if err := client.DownloadDirectory(hash, "", tmp, ""); err != nil { 241 t.Fatal(err) 242 } 243 for _, file := range testDirFiles { 244 data, err := ioutil.ReadFile(filepath.Join(tmp, file)) 245 if err != nil { 246 t.Fatal(err) 247 } 248 if !bytes.Equal(data, []byte(file)) { 249 t.Fatalf("expected data to be %q, got %q", file, data) 250 } 251 } 252 } 253 254 // TestClientFileList tests listing files in a swarm manifest 255 func TestClientFileList(t *testing.T) { 256 testClientFileList(false, t) 257 } 258 259 func TestClientFileListEncrypted(t *testing.T) { 260 testClientFileList(true, t) 261 } 262 263 func testClientFileList(toEncrypt bool, t *testing.T) { 264 srv := swarmhttp.NewTestSwarmServer(t, serverFunc, nil) 265 defer srv.Close() 266 267 dir := newTestDirectory(t) 268 defer os.RemoveAll(dir) 269 270 client := NewClient(srv.URL) 271 hash, err := client.UploadDirectory(dir, "", "", toEncrypt) 272 if err != nil { 273 t.Fatalf("error uploading directory: %s", err) 274 } 275 276 ls := func(prefix string) []string { 277 list, err := client.List(hash, prefix, "") 278 if err != nil { 279 t.Fatal(err) 280 } 281 paths := make([]string, 0, len(list.CommonPrefixes)+len(list.Entries)) 282 paths = append(paths, list.CommonPrefixes...) 283 for _, entry := range list.Entries { 284 paths = append(paths, entry.Path) 285 } 286 sort.Strings(paths) 287 return paths 288 } 289 290 tests := map[string][]string{ 291 "": {"dir1/", "dir2/", "file1.txt", "file2.txt"}, 292 "file": {"file1.txt", "file2.txt"}, 293 "file1": {"file1.txt"}, 294 "file2.txt": {"file2.txt"}, 295 "file12": {}, 296 "dir": {"dir1/", "dir2/"}, 297 "dir1": {"dir1/"}, 298 "dir1/": {"dir1/file3.txt", "dir1/file4.txt"}, 299 "dir1/file": {"dir1/file3.txt", "dir1/file4.txt"}, 300 "dir1/file3.txt": {"dir1/file3.txt"}, 301 "dir1/file34": {}, 302 "dir2/": {"dir2/dir3/", "dir2/dir4/", "dir2/file5.txt"}, 303 "dir2/file": {"dir2/file5.txt"}, 304 "dir2/dir": {"dir2/dir3/", "dir2/dir4/"}, 305 "dir2/dir3/": {"dir2/dir3/file6.txt"}, 306 "dir2/dir4/": {"dir2/dir4/file7.txt", "dir2/dir4/file8.txt"}, 307 "dir2/dir4/file": {"dir2/dir4/file7.txt", "dir2/dir4/file8.txt"}, 308 "dir2/dir4/file7.txt": {"dir2/dir4/file7.txt"}, 309 "dir2/dir4/file78": {}, 310 } 311 for prefix, expected := range tests { 312 actual := ls(prefix) 313 if !reflect.DeepEqual(actual, expected) { 314 t.Fatalf("expected prefix %q to return %v, got %v", prefix, expected, actual) 315 } 316 } 317 } 318 319 // TestClientMultipartUpload tests uploading files to swarm using a multipart 320 // upload 321 func TestClientMultipartUpload(t *testing.T) { 322 srv := swarmhttp.NewTestSwarmServer(t, serverFunc, nil) 323 defer srv.Close() 324 325 // define an uploader which uploads testDirFiles with some data 326 data := []byte("some-data") 327 uploader := UploaderFunc(func(upload UploadFn) error { 328 for _, name := range testDirFiles { 329 file := &File{ 330 ReadCloser: ioutil.NopCloser(bytes.NewReader(data)), 331 ManifestEntry: api.ManifestEntry{ 332 Path: name, 333 ContentType: "text/plain", 334 Size: int64(len(data)), 335 }, 336 } 337 if err := upload(file); err != nil { 338 return err 339 } 340 } 341 return nil 342 }) 343 344 // upload the files as a multipart upload 345 client := NewClient(srv.URL) 346 hash, err := client.MultipartUpload("", uploader) 347 if err != nil { 348 t.Fatal(err) 349 } 350 351 // check we can download the individual files 352 checkDownloadFile := func(path string) { 353 file, err := client.Download(hash, path) 354 if err != nil { 355 t.Fatal(err) 356 } 357 defer file.Close() 358 gotData, err := ioutil.ReadAll(file) 359 if err != nil { 360 t.Fatal(err) 361 } 362 if !bytes.Equal(gotData, data) { 363 t.Fatalf("expected data to be %q, got %q", data, gotData) 364 } 365 } 366 for _, file := range testDirFiles { 367 checkDownloadFile(file) 368 } 369 } 370 371 func newTestSigner() (*feed.GenericSigner, error) { 372 privKey, err := crypto.HexToECDSA("deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef") 373 if err != nil { 374 return nil, err 375 } 376 return feed.NewGenericSigner(privKey), nil 377 } 378 379 // Test the transparent resolving of feed updates with bzz:// scheme 380 // 381 // First upload data to bzz:, and store the Swarm hash to the resulting manifest in a feed update. 382 // This effectively uses a feed to store a pointer to content rather than the content itself 383 // Retrieving the update with the Swarm hash should return the manifest pointing directly to the data 384 // and raw retrieve of that hash should return the data 385 func TestClientBzzWithFeed(t *testing.T) { 386 387 signer, _ := newTestSigner() 388 389 // Initialize a Swarm test server 390 srv := swarmhttp.NewTestSwarmServer(t, serverFunc, nil) 391 swarmClient := NewClient(srv.URL) 392 defer srv.Close() 393 394 // put together some data for our test: 395 dataBytes := []byte(` 396 // 397 // Create some data our manifest will point to. Data that could be very big and wouldn't fit in a feed update. 398 // So what we are going to do is upload it to Swarm bzz:// and obtain a **manifest hash** pointing to it: 399 // 400 // MANIFEST HASH --> DATA 401 // 402 // Then, we store that **manifest hash** into a Swarm Feed update. Once we have done this, 403 // we can use the **feed manifest hash** in bzz:// instead, this way: bzz://feed-manifest-hash. 404 // 405 // FEED MANIFEST HASH --> MANIFEST HASH --> DATA 406 // 407 // Given that we can update the feed at any time with a new **manifest hash** but the **feed manifest hash** 408 // stays constant, we have effectively created a fixed address to changing content. (Applause) 409 // 410 // FEED MANIFEST HASH (the same) --> MANIFEST HASH(2) --> DATA(2) 411 // 412 `) 413 414 // Create a virtual File out of memory containing the above data 415 f := &File{ 416 ReadCloser: ioutil.NopCloser(bytes.NewReader(dataBytes)), 417 ManifestEntry: api.ManifestEntry{ 418 ContentType: "text/plain", 419 Mode: 0660, 420 Size: int64(len(dataBytes)), 421 }, 422 } 423 424 // upload data to bzz:// and retrieve the content-addressed manifest hash, hex-encoded. 425 manifestAddressHex, err := swarmClient.Upload(f, "", false) 426 if err != nil { 427 t.Fatalf("Error creating manifest: %s", err) 428 } 429 430 // convert the hex-encoded manifest hash to a 32-byte slice 431 manifestAddress := common.FromHex(manifestAddressHex) 432 433 if len(manifestAddress) != storage.AddressLength { 434 t.Fatalf("Something went wrong. Got a hash of an unexpected length. Expected %d bytes. Got %d", storage.AddressLength, len(manifestAddress)) 435 } 436 437 // Now create a **feed manifest**. For that, we need a topic: 438 topic, _ := feed.NewTopic("interesting topic indeed", nil) 439 440 // Build a feed request to update data 441 request := feed.NewFirstRequest(topic) 442 443 // Put the 32-byte address of the manifest into the feed update 444 request.SetData(manifestAddress) 445 446 // Sign the update 447 if err := request.Sign(signer); err != nil { 448 t.Fatalf("Error signing update: %s", err) 449 } 450 451 // Publish the update and at the same time request a **feed manifest** to be created 452 feedManifestAddressHex, err := swarmClient.CreateFeedWithManifest(request) 453 if err != nil { 454 t.Fatalf("Error creating feed manifest: %s", err) 455 } 456 457 // Check we have received the exact **feed manifest** to be expected 458 // given the topic and user signing the updates: 459 correctFeedManifestAddrHex := "747c402e5b9dc715a25a4393147512167bab018a007fad7cdcd9adc7fce1ced2" 460 if feedManifestAddressHex != correctFeedManifestAddrHex { 461 t.Fatalf("Response feed manifest mismatch, expected '%s', got '%s'", correctFeedManifestAddrHex, feedManifestAddressHex) 462 } 463 464 // Check we get a not found error when trying to get feed updates with a made-up manifest 465 _, err = swarmClient.QueryFeed(nil, "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb") 466 if err != ErrNoFeedUpdatesFound { 467 t.Fatalf("Expected to receive ErrNoFeedUpdatesFound error. Got: %s", err) 468 } 469 470 // If we query the feed directly we should get **manifest hash** back: 471 reader, err := swarmClient.QueryFeed(nil, correctFeedManifestAddrHex) 472 if err != nil { 473 t.Fatalf("Error retrieving feed updates: %s", err) 474 } 475 defer reader.Close() 476 gotData, err := ioutil.ReadAll(reader) 477 if err != nil { 478 t.Fatal(err) 479 } 480 481 //Check that indeed the **manifest hash** is retrieved 482 if !bytes.Equal(manifestAddress, gotData) { 483 t.Fatalf("Expected: %v, got %v", manifestAddress, gotData) 484 } 485 486 // Now the final test we were looking for: Use bzz://<feed-manifest> and that should resolve all manifests 487 // and return the original data directly: 488 f, err = swarmClient.Download(feedManifestAddressHex, "") 489 if err != nil { 490 t.Fatal(err) 491 } 492 gotData, err = ioutil.ReadAll(f) 493 if err != nil { 494 t.Fatal(err) 495 } 496 497 // Check that we get back the original data: 498 if !bytes.Equal(dataBytes, gotData) { 499 t.Fatalf("Expected: %v, got %v", manifestAddress, gotData) 500 } 501 } 502 503 // TestClientCreateUpdateFeed will check that feeds can be created and updated via the HTTP client. 504 func TestClientCreateUpdateFeed(t *testing.T) { 505 506 signer, _ := newTestSigner() 507 508 srv := swarmhttp.NewTestSwarmServer(t, serverFunc, nil) 509 client := NewClient(srv.URL) 510 defer srv.Close() 511 512 // set raw data for the feed update 513 databytes := []byte("En un lugar de La Mancha, de cuyo nombre no quiero acordarme...") 514 515 // our feed topic name 516 topic, _ := feed.NewTopic("El Quijote", nil) 517 createRequest := feed.NewFirstRequest(topic) 518 519 createRequest.SetData(databytes) 520 if err := createRequest.Sign(signer); err != nil { 521 t.Fatalf("Error signing update: %s", err) 522 } 523 524 feedManifestHash, err := client.CreateFeedWithManifest(createRequest) 525 if err != nil { 526 t.Fatal(err) 527 } 528 529 correctManifestAddrHex := "0e9b645ebc3da167b1d56399adc3276f7a08229301b72a03336be0e7d4b71882" 530 if feedManifestHash != correctManifestAddrHex { 531 t.Fatalf("Response feed manifest mismatch, expected '%s', got '%s'", correctManifestAddrHex, feedManifestHash) 532 } 533 534 reader, err := client.QueryFeed(nil, correctManifestAddrHex) 535 if err != nil { 536 t.Fatalf("Error retrieving feed updates: %s", err) 537 } 538 defer reader.Close() 539 gotData, err := ioutil.ReadAll(reader) 540 if err != nil { 541 t.Fatal(err) 542 } 543 if !bytes.Equal(databytes, gotData) { 544 t.Fatalf("Expected: %v, got %v", databytes, gotData) 545 } 546 547 // define different data 548 databytes = []byte("... no ha mucho tiempo que vivĂa un hidalgo de los de lanza en astillero ...") 549 550 updateRequest, err := client.GetFeedRequest(nil, correctManifestAddrHex) 551 if err != nil { 552 t.Fatalf("Error retrieving update request template: %s", err) 553 } 554 555 updateRequest.SetData(databytes) 556 if err := updateRequest.Sign(signer); err != nil { 557 t.Fatalf("Error signing update: %s", err) 558 } 559 560 if err = client.UpdateFeed(updateRequest); err != nil { 561 t.Fatalf("Error updating feed: %s", err) 562 } 563 564 reader, err = client.QueryFeed(nil, correctManifestAddrHex) 565 if err != nil { 566 t.Fatalf("Error retrieving feed updates: %s", err) 567 } 568 defer reader.Close() 569 gotData, err = ioutil.ReadAll(reader) 570 if err != nil { 571 t.Fatal(err) 572 } 573 if !bytes.Equal(databytes, gotData) { 574 t.Fatalf("Expected: %v, got %v", databytes, gotData) 575 } 576 577 // now try retrieving feed updates without a manifest 578 579 fd := &feed.Feed{ 580 Topic: topic, 581 User: signer.Address(), 582 } 583 584 lookupParams := feed.NewQueryLatest(fd, lookup.NoClue) 585 reader, err = client.QueryFeed(lookupParams, "") 586 if err != nil { 587 t.Fatalf("Error retrieving feed updates: %s", err) 588 } 589 defer reader.Close() 590 gotData, err = ioutil.ReadAll(reader) 591 if err != nil { 592 t.Fatal(err) 593 } 594 if !bytes.Equal(databytes, gotData) { 595 t.Fatalf("Expected: %v, got %v", databytes, gotData) 596 } 597 }