github.com/hyperion-hyn/go-ethereum@v2.4.0+incompatible/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 swarmhttp "github.com/ethereum/go-ethereum/swarm/api/http" 36 "github.com/ethereum/go-ethereum/swarm/testutil" 37 "github.com/mattn/go-colorable" 38 ) 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 if runtime.GOOS == "windows" { 49 t.Skip() 50 } 51 52 testCLISwarmUp(false, t) 53 } 54 func TestCLISwarmUpRecursive(t *testing.T) { 55 if runtime.GOOS == "windows" { 56 t.Skip() 57 } 58 testCLISwarmUpRecursive(false, t) 59 } 60 61 // TestCLISwarmUpEncrypted tests that running 'swarm encrypted-up' makes the resulting file 62 // available from all nodes via the HTTP API 63 func TestCLISwarmUpEncrypted(t *testing.T) { 64 if runtime.GOOS == "windows" { 65 t.Skip() 66 } 67 testCLISwarmUp(true, t) 68 } 69 func TestCLISwarmUpEncryptedRecursive(t *testing.T) { 70 if runtime.GOOS == "windows" { 71 t.Skip() 72 } 73 testCLISwarmUpRecursive(true, t) 74 } 75 76 func testCLISwarmUp(toEncrypt bool, t *testing.T) { 77 log.Info("starting 3 node cluster") 78 cluster := newTestCluster(t, 3) 79 defer cluster.Shutdown() 80 81 tmpFileName := testutil.TempFileWithContent(t, data) 82 defer os.Remove(tmpFileName) 83 84 // write data to file 85 hashRegexp := `[a-f\d]{64}` 86 flags := []string{ 87 "--bzzapi", cluster.Nodes[0].URL, 88 "up", 89 tmpFileName} 90 if toEncrypt { 91 hashRegexp = `[a-f\d]{128}` 92 flags = []string{ 93 "--bzzapi", cluster.Nodes[0].URL, 94 "up", 95 "--encrypt", 96 tmpFileName} 97 } 98 // upload the file with 'swarm up' and expect a hash 99 log.Info(fmt.Sprintf("uploading file with 'swarm up'")) 100 up := runSwarm(t, flags...) 101 _, matches := up.ExpectRegexp(hashRegexp) 102 up.ExpectExit() 103 hash := matches[0] 104 log.Info("file uploaded", "hash", hash) 105 106 // get the file from the HTTP API of each node 107 for _, node := range cluster.Nodes { 108 log.Info("getting file from node", "node", node.Name) 109 110 res, err := http.Get(node.URL + "/bzz:/" + hash) 111 if err != nil { 112 t.Fatal(err) 113 } 114 defer res.Body.Close() 115 116 reply, err := ioutil.ReadAll(res.Body) 117 if err != nil { 118 t.Fatal(err) 119 } 120 if res.StatusCode != 200 { 121 t.Fatalf("expected HTTP status 200, got %s", res.Status) 122 } 123 if string(reply) != data { 124 t.Fatalf("expected HTTP body %q, got %q", data, reply) 125 } 126 log.Debug("verifying uploaded file using `swarm down`") 127 //try to get the content with `swarm down` 128 tmpDownload, err := ioutil.TempDir("", "swarm-test") 129 tmpDownload = path.Join(tmpDownload, "tmpfile.tmp") 130 if err != nil { 131 t.Fatal(err) 132 } 133 defer os.RemoveAll(tmpDownload) 134 135 bzzLocator := "bzz:/" + hash 136 flags = []string{ 137 "--bzzapi", cluster.Nodes[0].URL, 138 "down", 139 bzzLocator, 140 tmpDownload, 141 } 142 143 down := runSwarm(t, flags...) 144 down.ExpectExit() 145 146 fi, err := os.Stat(tmpDownload) 147 if err != nil { 148 t.Fatalf("could not stat path: %v", err) 149 } 150 151 switch mode := fi.Mode(); { 152 case mode.IsRegular(): 153 downloadedBytes, err := ioutil.ReadFile(tmpDownload) 154 if err != nil { 155 t.Fatalf("had an error reading the downloaded file: %v", err) 156 } 157 if !bytes.Equal(downloadedBytes, bytes.NewBufferString(data).Bytes()) { 158 t.Fatalf("retrieved data and posted data not equal!") 159 } 160 161 default: 162 t.Fatalf("expected to download regular file, got %s", fi.Mode()) 163 } 164 } 165 166 timeout := time.Duration(2 * time.Second) 167 httpClient := http.Client{ 168 Timeout: timeout, 169 } 170 171 // try to squeeze a timeout by getting an non-existent hash from each node 172 for _, node := range cluster.Nodes { 173 _, err := httpClient.Get(node.URL + "/bzz:/1023e8bae0f70be7d7b5f74343088ba408a218254391490c85ae16278e230340") 174 // we're speeding up the timeout here since netstore has a 60 seconds timeout on a request 175 if err != nil && !strings.Contains(err.Error(), "Client.Timeout exceeded while awaiting headers") { 176 t.Fatal(err) 177 } 178 // this is disabled since it takes 60s due to netstore timeout 179 // if res.StatusCode != 404 { 180 // t.Fatalf("expected HTTP status 404, got %s", res.Status) 181 // } 182 } 183 } 184 185 func testCLISwarmUpRecursive(toEncrypt bool, t *testing.T) { 186 fmt.Println("starting 3 node cluster") 187 cluster := newTestCluster(t, 3) 188 defer cluster.Shutdown() 189 190 tmpUploadDir, err := ioutil.TempDir("", "swarm-test") 191 if err != nil { 192 t.Fatal(err) 193 } 194 defer os.RemoveAll(tmpUploadDir) 195 // create tmp files 196 for _, path := range []string{"tmp1", "tmp2"} { 197 if err := ioutil.WriteFile(filepath.Join(tmpUploadDir, path), bytes.NewBufferString(data).Bytes(), 0644); err != nil { 198 t.Fatal(err) 199 } 200 } 201 202 hashRegexp := `[a-f\d]{64}` 203 flags := []string{ 204 "--bzzapi", cluster.Nodes[0].URL, 205 "--recursive", 206 "up", 207 tmpUploadDir} 208 if toEncrypt { 209 hashRegexp = `[a-f\d]{128}` 210 flags = []string{ 211 "--bzzapi", cluster.Nodes[0].URL, 212 "--recursive", 213 "up", 214 "--encrypt", 215 tmpUploadDir} 216 } 217 // upload the file with 'swarm up' and expect a hash 218 log.Info(fmt.Sprintf("uploading file with 'swarm up'")) 219 up := runSwarm(t, flags...) 220 _, matches := up.ExpectRegexp(hashRegexp) 221 up.ExpectExit() 222 hash := matches[0] 223 log.Info("dir uploaded", "hash", hash) 224 225 // get the file from the HTTP API of each node 226 for _, node := range cluster.Nodes { 227 log.Info("getting file from node", "node", node.Name) 228 //try to get the content with `swarm down` 229 tmpDownload, err := ioutil.TempDir("", "swarm-test") 230 if err != nil { 231 t.Fatal(err) 232 } 233 defer os.RemoveAll(tmpDownload) 234 bzzLocator := "bzz:/" + hash 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 if runtime.GOOS == "windows" { 281 t.Skip() 282 } 283 testCLISwarmUpDefaultPath(false, false, t) 284 testCLISwarmUpDefaultPath(false, true, t) 285 testCLISwarmUpDefaultPath(true, false, t) 286 testCLISwarmUpDefaultPath(true, true, t) 287 } 288 289 func testCLISwarmUpDefaultPath(toEncrypt bool, absDefaultPath bool, t *testing.T) { 290 srv := swarmhttp.NewTestSwarmServer(t, serverFunc, nil) 291 defer srv.Close() 292 293 tmp, err := ioutil.TempDir("", "swarm-defaultpath-test") 294 if err != nil { 295 t.Fatal(err) 296 } 297 defer os.RemoveAll(tmp) 298 299 err = ioutil.WriteFile(filepath.Join(tmp, "index.html"), []byte("<h1>Test</h1>"), 0666) 300 if err != nil { 301 t.Fatal(err) 302 } 303 err = ioutil.WriteFile(filepath.Join(tmp, "robots.txt"), []byte("Disallow: /"), 0666) 304 if err != nil { 305 t.Fatal(err) 306 } 307 308 defaultPath := "index.html" 309 if absDefaultPath { 310 defaultPath = filepath.Join(tmp, defaultPath) 311 } 312 313 args := []string{ 314 "--bzzapi", 315 srv.URL, 316 "--recursive", 317 "--defaultpath", 318 defaultPath, 319 "up", 320 tmp, 321 } 322 if toEncrypt { 323 args = append(args, "--encrypt") 324 } 325 326 up := runSwarm(t, args...) 327 hashRegexp := `[a-f\d]{64,128}` 328 _, matches := up.ExpectRegexp(hashRegexp) 329 up.ExpectExit() 330 hash := matches[0] 331 332 client := swarm.NewClient(srv.URL) 333 334 m, isEncrypted, err := client.DownloadManifest(hash) 335 if err != nil { 336 t.Fatal(err) 337 } 338 339 if toEncrypt != isEncrypted { 340 t.Error("downloaded manifest is not encrypted") 341 } 342 343 var found bool 344 var entriesCount int 345 for _, e := range m.Entries { 346 entriesCount++ 347 if e.Path == "" { 348 found = true 349 } 350 } 351 352 if !found { 353 t.Error("manifest default entry was not found") 354 } 355 356 if entriesCount != 3 { 357 t.Errorf("manifest contains %v entries, expected %v", entriesCount, 3) 358 } 359 }