client_test.go 18 KB

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