github.com/shyftnetwork/go-empyrean@v1.8.3-0.20191127201940-fbfca9338f04/swarm/swarm_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 swarm 18 19 import ( 20 "context" 21 "encoding/hex" 22 "io/ioutil" 23 "math/rand" 24 "os" 25 "os/exec" 26 "path" 27 "runtime" 28 "strings" 29 "testing" 30 "time" 31 32 "github.com/ShyftNetwork/go-empyrean/common" 33 "github.com/ShyftNetwork/go-empyrean/crypto" 34 "github.com/ShyftNetwork/go-empyrean/rpc" 35 "github.com/ShyftNetwork/go-empyrean/swarm/api" 36 ) 37 38 func TestMain(m *testing.M) { 39 exec.Command("/bin/sh", "../shyft-cli/shyftTestDbClean.sh") 40 retCode := m.Run() 41 exec.Command("/bin/sh", "../shyft-cli/shyftTestDbClean.sh") 42 os.Exit(retCode) 43 } 44 45 // TestNewSwarm validates Swarm fields in repsect to the provided configuration. 46 func TestNewSwarm(t *testing.T) { 47 dir, err := ioutil.TempDir("", "swarm") 48 if err != nil { 49 t.Fatal(err) 50 } 51 defer os.RemoveAll(dir) 52 53 // a simple rpc endpoint for testing dialing 54 ipcEndpoint := path.Join(dir, "TestSwarm.ipc") 55 56 // windows namedpipes are not on filesystem but on NPFS 57 if runtime.GOOS == "windows" { 58 b := make([]byte, 8) 59 rand.Read(b) 60 ipcEndpoint = `\\.\pipe\TestSwarm-` + hex.EncodeToString(b) 61 } 62 63 _, server, err := rpc.StartIPCEndpoint(ipcEndpoint, nil) 64 if err != nil { 65 t.Error(err) 66 } 67 defer server.Stop() 68 69 for _, tc := range []struct { 70 name string 71 configure func(*api.Config) 72 check func(*testing.T, *Swarm, *api.Config) 73 }{ 74 { 75 name: "defaults", 76 configure: nil, 77 check: func(t *testing.T, s *Swarm, config *api.Config) { 78 if s.config != config { 79 t.Error("config is not the same object") 80 } 81 if s.backend != nil { 82 t.Error("backend is not nil") 83 } 84 if s.privateKey == nil { 85 t.Error("private key is not set") 86 } 87 if !s.config.HiveParams.Discovery { 88 t.Error("config.HiveParams.Discovery is false, must be true regardless the configuration") 89 } 90 if s.dns != nil { 91 t.Error("dns initialized, but it should not be") 92 } 93 if s.netStore == nil { 94 t.Error("netStore not initialized") 95 } 96 if s.streamer == nil { 97 t.Error("streamer not initialized") 98 } 99 if s.fileStore == nil { 100 t.Error("fileStore not initialized") 101 } 102 if s.bzz == nil { 103 t.Error("bzz not initialized") 104 } 105 if s.ps == nil { 106 t.Error("pss not initialized") 107 } 108 if s.api == nil { 109 t.Error("api not initialized") 110 } 111 if s.sfs == nil { 112 t.Error("swarm filesystem not initialized") 113 } 114 }, 115 }, 116 { 117 name: "with swap", 118 configure: func(config *api.Config) { 119 config.SwapAPI = ipcEndpoint 120 config.SwapEnabled = true 121 }, 122 check: func(t *testing.T, s *Swarm, _ *api.Config) { 123 if s.backend == nil { 124 t.Error("backend is nil") 125 } 126 }, 127 }, 128 { 129 name: "with swap disabled", 130 configure: func(config *api.Config) { 131 config.SwapAPI = ipcEndpoint 132 config.SwapEnabled = false 133 }, 134 check: func(t *testing.T, s *Swarm, _ *api.Config) { 135 if s.backend != nil { 136 t.Error("backend is not nil") 137 } 138 }, 139 }, 140 { 141 name: "with swap enabled and api endpoint blank", 142 configure: func(config *api.Config) { 143 config.SwapAPI = "" 144 config.SwapEnabled = true 145 }, 146 check: func(t *testing.T, s *Swarm, _ *api.Config) { 147 if s.backend != nil { 148 t.Error("backend is not nil") 149 } 150 }, 151 }, 152 { 153 name: "ens", 154 configure: func(config *api.Config) { 155 config.EnsAPIs = []string{ 156 "http://127.0.0.1:8888", 157 } 158 }, 159 check: func(t *testing.T, s *Swarm, _ *api.Config) { 160 if s.dns == nil { 161 t.Error("dns is not initialized") 162 } 163 }, 164 }, 165 } { 166 t.Run(tc.name, func(t *testing.T) { 167 config := api.NewConfig() 168 169 dir, err := ioutil.TempDir("", "swarm") 170 if err != nil { 171 t.Fatal(err) 172 } 173 defer os.RemoveAll(dir) 174 175 config.Path = dir 176 177 privkey, err := crypto.GenerateKey() 178 if err != nil { 179 t.Fatal(err) 180 } 181 182 config.Init(privkey) 183 184 if tc.configure != nil { 185 tc.configure(config) 186 } 187 188 s, err := NewSwarm(config, nil) 189 if err != nil { 190 t.Fatal(err) 191 } 192 193 if tc.check != nil { 194 tc.check(t, s, config) 195 } 196 }) 197 } 198 } 199 200 func TestParseEnsAPIAddress(t *testing.T) { 201 for _, x := range []struct { 202 description string 203 value string 204 tld string 205 endpoint string 206 addr common.Address 207 }{ 208 { 209 description: "IPC endpoint", 210 value: "/data/testnet/geth.ipc", 211 endpoint: "/data/testnet/geth.ipc", 212 }, 213 { 214 description: "HTTP endpoint", 215 value: "http://127.0.0.1:1234", 216 endpoint: "http://127.0.0.1:1234", 217 }, 218 { 219 description: "WS endpoint", 220 value: "ws://127.0.0.1:1234", 221 endpoint: "ws://127.0.0.1:1234", 222 }, 223 { 224 description: "IPC Endpoint and TLD", 225 value: "test:/data/testnet/geth.ipc", 226 endpoint: "/data/testnet/geth.ipc", 227 tld: "test", 228 }, 229 { 230 description: "HTTP endpoint and TLD", 231 value: "test:http://127.0.0.1:1234", 232 endpoint: "http://127.0.0.1:1234", 233 tld: "test", 234 }, 235 { 236 description: "WS endpoint and TLD", 237 value: "test:ws://127.0.0.1:1234", 238 endpoint: "ws://127.0.0.1:1234", 239 tld: "test", 240 }, 241 { 242 description: "IPC Endpoint and contract address", 243 value: "314159265dD8dbb310642f98f50C066173C1259b@/data/testnet/geth.ipc", 244 endpoint: "/data/testnet/geth.ipc", 245 addr: common.HexToAddress("314159265dD8dbb310642f98f50C066173C1259b"), 246 }, 247 { 248 description: "HTTP endpoint and contract address", 249 value: "314159265dD8dbb310642f98f50C066173C1259b@http://127.0.0.1:1234", 250 endpoint: "http://127.0.0.1:1234", 251 addr: common.HexToAddress("314159265dD8dbb310642f98f50C066173C1259b"), 252 }, 253 { 254 description: "WS endpoint and contract address", 255 value: "314159265dD8dbb310642f98f50C066173C1259b@ws://127.0.0.1:1234", 256 endpoint: "ws://127.0.0.1:1234", 257 addr: common.HexToAddress("314159265dD8dbb310642f98f50C066173C1259b"), 258 }, 259 { 260 description: "IPC Endpoint, TLD and contract address", 261 value: "test:314159265dD8dbb310642f98f50C066173C1259b@/data/testnet/geth.ipc", 262 endpoint: "/data/testnet/geth.ipc", 263 addr: common.HexToAddress("314159265dD8dbb310642f98f50C066173C1259b"), 264 tld: "test", 265 }, 266 { 267 description: "HTTP endpoint, TLD and contract address", 268 value: "eth:314159265dD8dbb310642f98f50C066173C1259b@http://127.0.0.1:1234", 269 endpoint: "http://127.0.0.1:1234", 270 addr: common.HexToAddress("314159265dD8dbb310642f98f50C066173C1259b"), 271 tld: "eth", 272 }, 273 { 274 description: "WS endpoint, TLD and contract address", 275 value: "eth:314159265dD8dbb310642f98f50C066173C1259b@ws://127.0.0.1:1234", 276 endpoint: "ws://127.0.0.1:1234", 277 addr: common.HexToAddress("314159265dD8dbb310642f98f50C066173C1259b"), 278 tld: "eth", 279 }, 280 } { 281 t.Run(x.description, func(t *testing.T) { 282 tld, endpoint, addr := parseEnsAPIAddress(x.value) 283 if endpoint != x.endpoint { 284 t.Errorf("expected Endpoint %q, got %q", x.endpoint, endpoint) 285 } 286 if addr != x.addr { 287 t.Errorf("expected ContractAddress %q, got %q", x.addr.String(), addr.String()) 288 } 289 if tld != x.tld { 290 t.Errorf("expected TLD %q, got %q", x.tld, tld) 291 } 292 }) 293 } 294 } 295 296 // TestLocalStoreAndRetrieve runs multiple tests where different size files are uploaded 297 // to a single Swarm instance using API Store and checked against the content returned 298 // by API Retrieve function. 299 // 300 // This test is intended to validate functionality of chunker store and join functions 301 // and their intergartion into Swarm, without comparing results with ones produced by 302 // another chunker implementation, as it is done in swarm/storage tests. 303 func TestLocalStoreAndRetrieve(t *testing.T) { 304 config := api.NewConfig() 305 306 dir, err := ioutil.TempDir("", "node") 307 if err != nil { 308 t.Fatal(err) 309 } 310 defer os.RemoveAll(dir) 311 312 config.Path = dir 313 314 privkey, err := crypto.GenerateKey() 315 if err != nil { 316 t.Fatal(err) 317 } 318 319 config.Init(privkey) 320 321 swarm, err := NewSwarm(config, nil) 322 if err != nil { 323 t.Fatal(err) 324 } 325 326 // by default, test only the lonely chunk cases 327 sizes := []int{1, 60, 4097, 524288 + 1, 7*524288 + 1} 328 329 if *longrunning { 330 // test broader set of cases if -longruning flag is set 331 sizes = append(sizes, 83, 179, 253, 1024, 4095, 4096, 8191, 8192, 8193, 12287, 12288, 12289, 123456, 2345678, 67298391, 524288, 524288+4096, 524288+4097, 7*524288, 7*524288+4096, 7*524288+4097, 128*524288+1, 128*524288, 128*524288+4096, 128*524288+4097, 816778334) 332 } 333 for _, n := range sizes { 334 testLocalStoreAndRetrieve(t, swarm, n, true) 335 testLocalStoreAndRetrieve(t, swarm, n, false) 336 } 337 } 338 339 // testLocalStoreAndRetrieve is using a single Swarm instance, to upload 340 // a file of length n with optional random data using API Store function, 341 // and checks the output of API Retrieve function on the same instance. 342 // This is a regression test for issue 343 // https://github.com/ethersphere/go-ethereum/issues/639 344 // where pyramid chunker did not split correctly files with lengths that 345 // are edge cases for chunk and tree parameters, depending whether there 346 // is a tree chunk with only one data chunk and how the compress functionality 347 // changed the tree. 348 func testLocalStoreAndRetrieve(t *testing.T, swarm *Swarm, n int, randomData bool) { 349 slice := make([]byte, n) 350 if randomData { 351 rand.Seed(time.Now().UnixNano()) 352 rand.Read(slice) 353 } 354 dataPut := string(slice) 355 356 ctx := context.TODO() 357 k, wait, err := swarm.api.Store(ctx, strings.NewReader(dataPut), int64(len(dataPut)), false) 358 if err != nil { 359 t.Fatal(err) 360 } 361 if wait != nil { 362 err = wait(ctx) 363 if err != nil { 364 t.Fatal(err) 365 } 366 } 367 368 r, _ := swarm.api.Retrieve(context.TODO(), k) 369 370 d, err := ioutil.ReadAll(r) 371 if err != nil { 372 t.Fatal(err) 373 } 374 dataGet := string(d) 375 376 if len(dataPut) != len(dataGet) { 377 t.Fatalf("data not matched: length expected %v, got %v", len(dataPut), len(dataGet)) 378 } else { 379 if dataPut != dataGet { 380 t.Fatal("data not matched") 381 } 382 } 383 }