github.com/oskarth/go-ethereum@v1.6.8-0.20191013093314-dac24a9d3494/cmd/swarm/upload_test.go (about) 1 // Copyright 2017 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 "fmt" 22 "io" 23 "io/ioutil" 24 "net/http" 25 "os" 26 "path" 27 "path/filepath" 28 "runtime" 29 "strings" 30 "testing" 31 "time" 32 33 "github.com/ethereum/go-ethereum/log" 34 swarm "github.com/ethereum/go-ethereum/swarm/api/client" 35 "github.com/ethereum/go-ethereum/swarm/testutil" 36 "github.com/mattn/go-colorable" 37 ) 38 39 func init() { 40 log.PrintOrigins(true) 41 log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(colorable.NewColorableStderr(), log.TerminalFormat(true)))) 42 } 43 44 // TestCLISwarmUp tests that running 'swarm up' makes the resulting file 45 // available from all nodes via the HTTP API 46 func TestCLISwarmUp(t *testing.T) { 47 if runtime.GOOS == "windows" { 48 t.Skip() 49 } 50 51 testCLISwarmUp(false, t) 52 } 53 func TestCLISwarmUpRecursive(t *testing.T) { 54 if runtime.GOOS == "windows" { 55 t.Skip() 56 } 57 testCLISwarmUpRecursive(false, t) 58 } 59 60 // TestCLISwarmUpEncrypted tests that running 'swarm encrypted-up' makes the resulting file 61 // available from all nodes via the HTTP API 62 func TestCLISwarmUpEncrypted(t *testing.T) { 63 if runtime.GOOS == "windows" { 64 t.Skip() 65 } 66 testCLISwarmUp(true, t) 67 } 68 func TestCLISwarmUpEncryptedRecursive(t *testing.T) { 69 if runtime.GOOS == "windows" { 70 t.Skip() 71 } 72 testCLISwarmUpRecursive(true, t) 73 } 74 75 func testCLISwarmUp(toEncrypt bool, t *testing.T) { 76 log.Info("starting 3 node cluster") 77 cluster := newTestCluster(t, 3) 78 defer cluster.Shutdown() 79 80 // create a tmp file 81 tmp, err := ioutil.TempFile("", "swarm-test") 82 if err != nil { 83 t.Fatal(err) 84 } 85 defer tmp.Close() 86 defer os.Remove(tmp.Name()) 87 88 // write data to file 89 data := "notsorandomdata" 90 _, err = io.WriteString(tmp, data) 91 if err != nil { 92 t.Fatal(err) 93 } 94 95 hashRegexp := `[a-f\d]{64}` 96 flags := []string{ 97 "--bzzapi", cluster.Nodes[0].URL, 98 "up", 99 tmp.Name()} 100 if toEncrypt { 101 hashRegexp = `[a-f\d]{128}` 102 flags = []string{ 103 "--bzzapi", cluster.Nodes[0].URL, 104 "up", 105 "--encrypt", 106 tmp.Name()} 107 } 108 // upload the file with 'swarm up' and expect a hash 109 log.Info(fmt.Sprintf("uploading file with 'swarm up'")) 110 up := runSwarm(t, flags...) 111 _, matches := up.ExpectRegexp(hashRegexp) 112 up.ExpectExit() 113 hash := matches[0] 114 log.Info("file uploaded", "hash", hash) 115 116 // get the file from the HTTP API of each node 117 for _, node := range cluster.Nodes { 118 log.Info("getting file from node", "node", node.Name) 119 120 res, err := http.Get(node.URL + "/bzz:/" + hash) 121 if err != nil { 122 t.Fatal(err) 123 } 124 defer res.Body.Close() 125 126 reply, err := ioutil.ReadAll(res.Body) 127 if err != nil { 128 t.Fatal(err) 129 } 130 if res.StatusCode != 200 { 131 t.Fatalf("expected HTTP status 200, got %s", res.Status) 132 } 133 if string(reply) != data { 134 t.Fatalf("expected HTTP body %q, got %q", data, reply) 135 } 136 log.Debug("verifying uploaded file using `swarm down`") 137 //try to get the content with `swarm down` 138 tmpDownload, err := ioutil.TempDir("", "swarm-test") 139 tmpDownload = path.Join(tmpDownload, "tmpfile.tmp") 140 if err != nil { 141 t.Fatal(err) 142 } 143 defer os.RemoveAll(tmpDownload) 144 145 bzzLocator := "bzz:/" + hash 146 flags = []string{ 147 "--bzzapi", cluster.Nodes[0].URL, 148 "down", 149 bzzLocator, 150 tmpDownload, 151 } 152 153 down := runSwarm(t, flags...) 154 down.ExpectExit() 155 156 fi, err := os.Stat(tmpDownload) 157 if err != nil { 158 t.Fatalf("could not stat path: %v", err) 159 } 160 161 switch mode := fi.Mode(); { 162 case mode.IsRegular(): 163 downloadedBytes, err := ioutil.ReadFile(tmpDownload) 164 if err != nil { 165 t.Fatalf("had an error reading the downloaded file: %v", err) 166 } 167 if !bytes.Equal(downloadedBytes, bytes.NewBufferString(data).Bytes()) { 168 t.Fatalf("retrieved data and posted data not equal!") 169 } 170 171 default: 172 t.Fatalf("expected to download regular file, got %s", fi.Mode()) 173 } 174 } 175 176 timeout := time.Duration(2 * time.Second) 177 httpClient := http.Client{ 178 Timeout: timeout, 179 } 180 181 // try to squeeze a timeout by getting an non-existent hash from each node 182 for _, node := range cluster.Nodes { 183 _, err := httpClient.Get(node.URL + "/bzz:/1023e8bae0f70be7d7b5f74343088ba408a218254391490c85ae16278e230340") 184 // we're speeding up the timeout here since netstore has a 60 seconds timeout on a request 185 if err != nil && !strings.Contains(err.Error(), "Client.Timeout exceeded while awaiting headers") { 186 t.Fatal(err) 187 } 188 // this is disabled since it takes 60s due to netstore timeout 189 // if res.StatusCode != 404 { 190 // t.Fatalf("expected HTTP status 404, got %s", res.Status) 191 // } 192 } 193 } 194 195 func testCLISwarmUpRecursive(toEncrypt bool, t *testing.T) { 196 fmt.Println("starting 3 node cluster") 197 cluster := newTestCluster(t, 3) 198 defer cluster.Shutdown() 199 200 tmpUploadDir, err := ioutil.TempDir("", "swarm-test") 201 if err != nil { 202 t.Fatal(err) 203 } 204 defer os.RemoveAll(tmpUploadDir) 205 // create tmp files 206 data := "notsorandomdata" 207 for _, path := range []string{"tmp1", "tmp2"} { 208 if err := ioutil.WriteFile(filepath.Join(tmpUploadDir, path), bytes.NewBufferString(data).Bytes(), 0644); err != nil { 209 t.Fatal(err) 210 } 211 } 212 213 hashRegexp := `[a-f\d]{64}` 214 flags := []string{ 215 "--bzzapi", cluster.Nodes[0].URL, 216 "--recursive", 217 "up", 218 tmpUploadDir} 219 if toEncrypt { 220 hashRegexp = `[a-f\d]{128}` 221 flags = []string{ 222 "--bzzapi", cluster.Nodes[0].URL, 223 "--recursive", 224 "up", 225 "--encrypt", 226 tmpUploadDir} 227 } 228 // upload the file with 'swarm up' and expect a hash 229 log.Info(fmt.Sprintf("uploading file with 'swarm up'")) 230 up := runSwarm(t, flags...) 231 _, matches := up.ExpectRegexp(hashRegexp) 232 up.ExpectExit() 233 hash := matches[0] 234 log.Info("dir uploaded", "hash", hash) 235 236 // get the file from the HTTP API of each node 237 for _, node := range cluster.Nodes { 238 log.Info("getting file from node", "node", node.Name) 239 //try to get the content with `swarm down` 240 tmpDownload, err := ioutil.TempDir("", "swarm-test") 241 if err != nil { 242 t.Fatal(err) 243 } 244 defer os.RemoveAll(tmpDownload) 245 bzzLocator := "bzz:/" + hash 246 flagss := []string{} 247 flagss = []string{ 248 "--bzzapi", cluster.Nodes[0].URL, 249 "down", 250 "--recursive", 251 bzzLocator, 252 tmpDownload, 253 } 254 255 fmt.Println("downloading from swarm with recursive") 256 down := runSwarm(t, flagss...) 257 down.ExpectExit() 258 259 files, err := ioutil.ReadDir(tmpDownload) 260 for _, v := range files { 261 fi, err := os.Stat(path.Join(tmpDownload, v.Name())) 262 if err != nil { 263 t.Fatalf("got an error: %v", err) 264 } 265 266 switch mode := fi.Mode(); { 267 case mode.IsRegular(): 268 if file, err := swarm.Open(path.Join(tmpDownload, v.Name())); err != nil { 269 t.Fatalf("encountered an error opening the file returned from the CLI: %v", err) 270 } else { 271 ff := make([]byte, len(data)) 272 io.ReadFull(file, ff) 273 buf := bytes.NewBufferString(data) 274 275 if !bytes.Equal(ff, buf.Bytes()) { 276 t.Fatalf("retrieved data and posted data not equal!") 277 } 278 } 279 default: 280 t.Fatalf("this shouldnt happen") 281 } 282 } 283 if err != nil { 284 t.Fatalf("could not list files at: %v", files) 285 } 286 } 287 } 288 289 // TestCLISwarmUpDefaultPath tests swarm recursive upload with relative and absolute 290 // default paths and with encryption. 291 func TestCLISwarmUpDefaultPath(t *testing.T) { 292 if runtime.GOOS == "windows" { 293 t.Skip() 294 } 295 testCLISwarmUpDefaultPath(false, false, t) 296 testCLISwarmUpDefaultPath(false, true, t) 297 testCLISwarmUpDefaultPath(true, false, t) 298 testCLISwarmUpDefaultPath(true, true, t) 299 } 300 301 func testCLISwarmUpDefaultPath(toEncrypt bool, absDefaultPath bool, t *testing.T) { 302 srv := testutil.NewTestSwarmServer(t, serverFunc, nil) 303 defer srv.Close() 304 305 tmp, err := ioutil.TempDir("", "swarm-defaultpath-test") 306 if err != nil { 307 t.Fatal(err) 308 } 309 defer os.RemoveAll(tmp) 310 311 err = ioutil.WriteFile(filepath.Join(tmp, "index.html"), []byte("<h1>Test</h1>"), 0666) 312 if err != nil { 313 t.Fatal(err) 314 } 315 err = ioutil.WriteFile(filepath.Join(tmp, "robots.txt"), []byte("Disallow: /"), 0666) 316 if err != nil { 317 t.Fatal(err) 318 } 319 320 defaultPath := "index.html" 321 if absDefaultPath { 322 defaultPath = filepath.Join(tmp, defaultPath) 323 } 324 325 args := []string{ 326 "--bzzapi", 327 srv.URL, 328 "--recursive", 329 "--defaultpath", 330 defaultPath, 331 "up", 332 tmp, 333 } 334 if toEncrypt { 335 args = append(args, "--encrypt") 336 } 337 338 up := runSwarm(t, args...) 339 hashRegexp := `[a-f\d]{64,128}` 340 _, matches := up.ExpectRegexp(hashRegexp) 341 up.ExpectExit() 342 hash := matches[0] 343 344 client := swarm.NewClient(srv.URL) 345 346 m, isEncrypted, err := client.DownloadManifest(hash) 347 if err != nil { 348 t.Fatal(err) 349 } 350 351 if toEncrypt != isEncrypted { 352 t.Error("downloaded manifest is not encrypted") 353 } 354 355 var found bool 356 var entriesCount int 357 for _, e := range m.Entries { 358 entriesCount++ 359 if e.Path == "" { 360 found = true 361 } 362 } 363 364 if !found { 365 t.Error("manifest default entry was not found") 366 } 367 368 if entriesCount != 3 { 369 t.Errorf("manifest contains %v entries, expected %v", entriesCount, 3) 370 } 371 }