github.com/oskarth/go-ethereum@v1.6.8-0.20191013093314-dac24a9d3494/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/storage/feed/lookup" 29 30 "github.com/ethereum/go-ethereum/common" 31 "github.com/ethereum/go-ethereum/crypto" 32 "github.com/ethereum/go-ethereum/swarm/api" 33 swarmhttp "github.com/ethereum/go-ethereum/swarm/api/http" 34 "github.com/ethereum/go-ethereum/swarm/multihash" 35 "github.com/ethereum/go-ethereum/swarm/storage/feed" 36 "github.com/ethereum/go-ethereum/swarm/testutil" 37 ) 38 39 func serverFunc(api *api.API) testutil.TestServer { 40 return swarmhttp.NewServer(api, "") 41 } 42 43 // TestClientUploadDownloadRaw test uploading and downloading raw data to swarm 44 func TestClientUploadDownloadRaw(t *testing.T) { 45 testClientUploadDownloadRaw(false, t) 46 } 47 func TestClientUploadDownloadRawEncrypted(t *testing.T) { 48 testClientUploadDownloadRaw(true, t) 49 } 50 51 func testClientUploadDownloadRaw(toEncrypt bool, t *testing.T) { 52 srv := testutil.NewTestSwarmServer(t, serverFunc, nil) 53 defer srv.Close() 54 55 client := NewClient(srv.URL) 56 57 // upload some raw data 58 data := []byte("foo123") 59 hash, err := client.UploadRaw(bytes.NewReader(data), int64(len(data)), toEncrypt) 60 if err != nil { 61 t.Fatal(err) 62 } 63 64 // check we can download the same data 65 res, isEncrypted, err := client.DownloadRaw(hash) 66 if err != nil { 67 t.Fatal(err) 68 } 69 if isEncrypted != toEncrypt { 70 t.Fatalf("Expected encyption status %v got %v", toEncrypt, isEncrypted) 71 } 72 defer res.Close() 73 gotData, err := ioutil.ReadAll(res) 74 if err != nil { 75 t.Fatal(err) 76 } 77 if !bytes.Equal(gotData, data) { 78 t.Fatalf("expected downloaded data to be %q, got %q", data, gotData) 79 } 80 } 81 82 // TestClientUploadDownloadFiles test uploading and downloading files to swarm 83 // manifests 84 func TestClientUploadDownloadFiles(t *testing.T) { 85 testClientUploadDownloadFiles(false, t) 86 } 87 88 func TestClientUploadDownloadFilesEncrypted(t *testing.T) { 89 testClientUploadDownloadFiles(true, t) 90 } 91 92 func testClientUploadDownloadFiles(toEncrypt bool, t *testing.T) { 93 srv := testutil.NewTestSwarmServer(t, serverFunc, nil) 94 defer srv.Close() 95 96 client := NewClient(srv.URL) 97 upload := func(manifest, path string, data []byte) string { 98 file := &File{ 99 ReadCloser: ioutil.NopCloser(bytes.NewReader(data)), 100 ManifestEntry: api.ManifestEntry{ 101 Path: path, 102 ContentType: "text/plain", 103 Size: int64(len(data)), 104 }, 105 } 106 hash, err := client.Upload(file, manifest, toEncrypt) 107 if err != nil { 108 t.Fatal(err) 109 } 110 return hash 111 } 112 checkDownload := func(manifest, path string, expected []byte) { 113 file, err := client.Download(manifest, path) 114 if err != nil { 115 t.Fatal(err) 116 } 117 defer file.Close() 118 if file.Size != int64(len(expected)) { 119 t.Fatalf("expected downloaded file to be %d bytes, got %d", len(expected), file.Size) 120 } 121 if file.ContentType != "text/plain" { 122 t.Fatalf("expected downloaded file to have type %q, got %q", "text/plain", file.ContentType) 123 } 124 data, err := ioutil.ReadAll(file) 125 if err != nil { 126 t.Fatal(err) 127 } 128 if !bytes.Equal(data, expected) { 129 t.Fatalf("expected downloaded data to be %q, got %q", expected, data) 130 } 131 } 132 133 // upload a file to the root of a manifest 134 rootData := []byte("some-data") 135 rootHash := upload("", "", rootData) 136 137 // check we can download the root file 138 checkDownload(rootHash, "", rootData) 139 140 // upload another file to the same manifest 141 otherData := []byte("some-other-data") 142 newHash := upload(rootHash, "some/other/path", otherData) 143 144 // check we can download both files from the new manifest 145 checkDownload(newHash, "", rootData) 146 checkDownload(newHash, "some/other/path", otherData) 147 148 // replace the root file with different data 149 newHash = upload(newHash, "", otherData) 150 151 // check both files have the other data 152 checkDownload(newHash, "", otherData) 153 checkDownload(newHash, "some/other/path", otherData) 154 } 155 156 var testDirFiles = []string{ 157 "file1.txt", 158 "file2.txt", 159 "dir1/file3.txt", 160 "dir1/file4.txt", 161 "dir2/file5.txt", 162 "dir2/dir3/file6.txt", 163 "dir2/dir4/file7.txt", 164 "dir2/dir4/file8.txt", 165 } 166 167 func newTestDirectory(t *testing.T) string { 168 dir, err := ioutil.TempDir("", "swarm-client-test") 169 if err != nil { 170 t.Fatal(err) 171 } 172 173 for _, file := range testDirFiles { 174 path := filepath.Join(dir, file) 175 if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil { 176 os.RemoveAll(dir) 177 t.Fatalf("error creating dir for %s: %s", path, err) 178 } 179 if err := ioutil.WriteFile(path, []byte(file), 0644); err != nil { 180 os.RemoveAll(dir) 181 t.Fatalf("error writing file %s: %s", path, err) 182 } 183 } 184 185 return dir 186 } 187 188 // TestClientUploadDownloadDirectory tests uploading and downloading a 189 // directory of files to a swarm manifest 190 func TestClientUploadDownloadDirectory(t *testing.T) { 191 srv := testutil.NewTestSwarmServer(t, serverFunc, nil) 192 defer srv.Close() 193 194 dir := newTestDirectory(t) 195 defer os.RemoveAll(dir) 196 197 // upload the directory 198 client := NewClient(srv.URL) 199 defaultPath := testDirFiles[0] 200 hash, err := client.UploadDirectory(dir, defaultPath, "", false) 201 if err != nil { 202 t.Fatalf("error uploading directory: %s", err) 203 } 204 205 // check we can download the individual files 206 checkDownloadFile := func(path string, expected []byte) { 207 file, err := client.Download(hash, path) 208 if err != nil { 209 t.Fatal(err) 210 } 211 defer file.Close() 212 data, err := ioutil.ReadAll(file) 213 if err != nil { 214 t.Fatal(err) 215 } 216 if !bytes.Equal(data, expected) { 217 t.Fatalf("expected data to be %q, got %q", expected, data) 218 } 219 } 220 for _, file := range testDirFiles { 221 checkDownloadFile(file, []byte(file)) 222 } 223 224 // check we can download the default path 225 checkDownloadFile("", []byte(testDirFiles[0])) 226 227 // check we can download the directory 228 tmp, err := ioutil.TempDir("", "swarm-client-test") 229 if err != nil { 230 t.Fatal(err) 231 } 232 defer os.RemoveAll(tmp) 233 if err := client.DownloadDirectory(hash, "", tmp, ""); err != nil { 234 t.Fatal(err) 235 } 236 for _, file := range testDirFiles { 237 data, err := ioutil.ReadFile(filepath.Join(tmp, file)) 238 if err != nil { 239 t.Fatal(err) 240 } 241 if !bytes.Equal(data, []byte(file)) { 242 t.Fatalf("expected data to be %q, got %q", file, data) 243 } 244 } 245 } 246 247 // TestClientFileList tests listing files in a swarm manifest 248 func TestClientFileList(t *testing.T) { 249 testClientFileList(false, t) 250 } 251 252 func TestClientFileListEncrypted(t *testing.T) { 253 testClientFileList(true, t) 254 } 255 256 func testClientFileList(toEncrypt bool, t *testing.T) { 257 srv := testutil.NewTestSwarmServer(t, serverFunc, nil) 258 defer srv.Close() 259 260 dir := newTestDirectory(t) 261 defer os.RemoveAll(dir) 262 263 client := NewClient(srv.URL) 264 hash, err := client.UploadDirectory(dir, "", "", toEncrypt) 265 if err != nil { 266 t.Fatalf("error uploading directory: %s", err) 267 } 268 269 ls := func(prefix string) []string { 270 list, err := client.List(hash, prefix, "") 271 if err != nil { 272 t.Fatal(err) 273 } 274 paths := make([]string, 0, len(list.CommonPrefixes)+len(list.Entries)) 275 paths = append(paths, list.CommonPrefixes...) 276 for _, entry := range list.Entries { 277 paths = append(paths, entry.Path) 278 } 279 sort.Strings(paths) 280 return paths 281 } 282 283 tests := map[string][]string{ 284 "": {"dir1/", "dir2/", "file1.txt", "file2.txt"}, 285 "file": {"file1.txt", "file2.txt"}, 286 "file1": {"file1.txt"}, 287 "file2.txt": {"file2.txt"}, 288 "file12": {}, 289 "dir": {"dir1/", "dir2/"}, 290 "dir1": {"dir1/"}, 291 "dir1/": {"dir1/file3.txt", "dir1/file4.txt"}, 292 "dir1/file": {"dir1/file3.txt", "dir1/file4.txt"}, 293 "dir1/file3.txt": {"dir1/file3.txt"}, 294 "dir1/file34": {}, 295 "dir2/": {"dir2/dir3/", "dir2/dir4/", "dir2/file5.txt"}, 296 "dir2/file": {"dir2/file5.txt"}, 297 "dir2/dir": {"dir2/dir3/", "dir2/dir4/"}, 298 "dir2/dir3/": {"dir2/dir3/file6.txt"}, 299 "dir2/dir4/": {"dir2/dir4/file7.txt", "dir2/dir4/file8.txt"}, 300 "dir2/dir4/file": {"dir2/dir4/file7.txt", "dir2/dir4/file8.txt"}, 301 "dir2/dir4/file7.txt": {"dir2/dir4/file7.txt"}, 302 "dir2/dir4/file78": {}, 303 } 304 for prefix, expected := range tests { 305 actual := ls(prefix) 306 if !reflect.DeepEqual(actual, expected) { 307 t.Fatalf("expected prefix %q to return %v, got %v", prefix, expected, actual) 308 } 309 } 310 } 311 312 // TestClientMultipartUpload tests uploading files to swarm using a multipart 313 // upload 314 func TestClientMultipartUpload(t *testing.T) { 315 srv := testutil.NewTestSwarmServer(t, serverFunc, nil) 316 defer srv.Close() 317 318 // define an uploader which uploads testDirFiles with some data 319 data := []byte("some-data") 320 uploader := UploaderFunc(func(upload UploadFn) error { 321 for _, name := range testDirFiles { 322 file := &File{ 323 ReadCloser: ioutil.NopCloser(bytes.NewReader(data)), 324 ManifestEntry: api.ManifestEntry{ 325 Path: name, 326 ContentType: "text/plain", 327 Size: int64(len(data)), 328 }, 329 } 330 if err := upload(file); err != nil { 331 return err 332 } 333 } 334 return nil 335 }) 336 337 // upload the files as a multipart upload 338 client := NewClient(srv.URL) 339 hash, err := client.MultipartUpload("", uploader) 340 if err != nil { 341 t.Fatal(err) 342 } 343 344 // check we can download the individual files 345 checkDownloadFile := func(path string) { 346 file, err := client.Download(hash, path) 347 if err != nil { 348 t.Fatal(err) 349 } 350 defer file.Close() 351 gotData, err := ioutil.ReadAll(file) 352 if err != nil { 353 t.Fatal(err) 354 } 355 if !bytes.Equal(gotData, data) { 356 t.Fatalf("expected data to be %q, got %q", data, gotData) 357 } 358 } 359 for _, file := range testDirFiles { 360 checkDownloadFile(file) 361 } 362 } 363 364 func newTestSigner() (*feed.GenericSigner, error) { 365 privKey, err := crypto.HexToECDSA("deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef") 366 if err != nil { 367 return nil, err 368 } 369 return feed.NewGenericSigner(privKey), nil 370 } 371 372 // test the transparent resolving of multihash feed updates with bzz:// scheme 373 // 374 // first upload data, and store the multihash to the resulting manifest in a feed update 375 // retrieving the update with the multihash should return the manifest pointing directly to the data 376 // and raw retrieve of that hash should return the data 377 func TestClientCreateFeedMultihash(t *testing.T) { 378 379 signer, _ := newTestSigner() 380 381 srv := testutil.NewTestSwarmServer(t, serverFunc, nil) 382 client := NewClient(srv.URL) 383 defer srv.Close() 384 385 // add the data our multihash aliased manifest will point to 386 databytes := []byte("bar") 387 388 swarmHash, err := client.UploadRaw(bytes.NewReader(databytes), int64(len(databytes)), false) 389 if err != nil { 390 t.Fatalf("Error uploading raw test data: %s", err) 391 } 392 393 s := common.FromHex(swarmHash) 394 mh := multihash.ToMultihash(s) 395 396 // our feed topic 397 topic, _ := feed.NewTopic("foo.eth", nil) 398 399 createRequest := feed.NewFirstRequest(topic) 400 401 createRequest.SetData(mh) 402 if err := createRequest.Sign(signer); err != nil { 403 t.Fatalf("Error signing update: %s", err) 404 } 405 406 feedManifestHash, err := client.CreateFeedWithManifest(createRequest) 407 408 if err != nil { 409 t.Fatalf("Error creating feed manifest: %s", err) 410 } 411 412 correctManifestAddrHex := "bb056a5264c295c2b0f613c8409b9c87ce9d71576ace02458160df4cc894210b" 413 if feedManifestHash != correctManifestAddrHex { 414 t.Fatalf("Response feed manifest mismatch, expected '%s', got '%s'", correctManifestAddrHex, feedManifestHash) 415 } 416 417 // Check we get a not found error when trying to get feed updates with a made-up manifest 418 _, err = client.QueryFeed(nil, "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb") 419 if err != ErrNoFeedUpdatesFound { 420 t.Fatalf("Expected to receive ErrNoFeedUpdatesFound error. Got: %s", err) 421 } 422 423 reader, err := client.QueryFeed(nil, correctManifestAddrHex) 424 if err != nil { 425 t.Fatalf("Error retrieving feed updates: %s", err) 426 } 427 defer reader.Close() 428 gotData, err := ioutil.ReadAll(reader) 429 if err != nil { 430 t.Fatal(err) 431 } 432 if !bytes.Equal(mh, gotData) { 433 t.Fatalf("Expected: %v, got %v", mh, gotData) 434 } 435 436 } 437 438 // TestClientCreateUpdateFeed will check that feeds can be created and updated via the HTTP client. 439 func TestClientCreateUpdateFeed(t *testing.T) { 440 441 signer, _ := newTestSigner() 442 443 srv := testutil.NewTestSwarmServer(t, serverFunc, nil) 444 client := NewClient(srv.URL) 445 defer srv.Close() 446 447 // set raw data for the feed update 448 databytes := []byte("En un lugar de La Mancha, de cuyo nombre no quiero acordarme...") 449 450 // our feed topic name 451 topic, _ := feed.NewTopic("El Quijote", nil) 452 createRequest := feed.NewFirstRequest(topic) 453 454 createRequest.SetData(databytes) 455 if err := createRequest.Sign(signer); err != nil { 456 t.Fatalf("Error signing update: %s", err) 457 } 458 459 feedManifestHash, err := client.CreateFeedWithManifest(createRequest) 460 461 correctManifestAddrHex := "0e9b645ebc3da167b1d56399adc3276f7a08229301b72a03336be0e7d4b71882" 462 if feedManifestHash != correctManifestAddrHex { 463 t.Fatalf("Response feed manifest mismatch, expected '%s', got '%s'", correctManifestAddrHex, feedManifestHash) 464 } 465 466 reader, err := client.QueryFeed(nil, correctManifestAddrHex) 467 if err != nil { 468 t.Fatalf("Error retrieving feed updates: %s", err) 469 } 470 defer reader.Close() 471 gotData, err := ioutil.ReadAll(reader) 472 if err != nil { 473 t.Fatal(err) 474 } 475 if !bytes.Equal(databytes, gotData) { 476 t.Fatalf("Expected: %v, got %v", databytes, gotData) 477 } 478 479 // define different data 480 databytes = []byte("... no ha mucho tiempo que vivĂa un hidalgo de los de lanza en astillero ...") 481 482 updateRequest, err := client.GetFeedRequest(nil, correctManifestAddrHex) 483 if err != nil { 484 t.Fatalf("Error retrieving update request template: %s", err) 485 } 486 487 updateRequest.SetData(databytes) 488 if err := updateRequest.Sign(signer); err != nil { 489 t.Fatalf("Error signing update: %s", err) 490 } 491 492 if err = client.UpdateFeed(updateRequest); err != nil { 493 t.Fatalf("Error updating feed: %s", err) 494 } 495 496 reader, err = client.QueryFeed(nil, correctManifestAddrHex) 497 if err != nil { 498 t.Fatalf("Error retrieving feed updates: %s", err) 499 } 500 defer reader.Close() 501 gotData, err = ioutil.ReadAll(reader) 502 if err != nil { 503 t.Fatal(err) 504 } 505 if !bytes.Equal(databytes, gotData) { 506 t.Fatalf("Expected: %v, got %v", databytes, gotData) 507 } 508 509 // now try retrieving feed updates without a manifest 510 511 fd := &feed.Feed{ 512 Topic: topic, 513 User: signer.Address(), 514 } 515 516 lookupParams := feed.NewQueryLatest(fd, lookup.NoClue) 517 reader, err = client.QueryFeed(lookupParams, "") 518 if err != nil { 519 t.Fatalf("Error retrieving feed updates: %s", err) 520 } 521 defer reader.Close() 522 gotData, err = ioutil.ReadAll(reader) 523 if err != nil { 524 t.Fatal(err) 525 } 526 if !bytes.Equal(databytes, gotData) { 527 t.Fatalf("Expected: %v, got %v", databytes, gotData) 528 } 529 }