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