github.com/daeglee/go-ethereum@v0.0.0-20190504220456-cad3e8d18e9b/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 "path" 26 "runtime" 27 "strings" 28 "testing" 29 "time" 30 31 "github.com/ethereum/go-ethereum/common" 32 "github.com/ethereum/go-ethereum/crypto" 33 "github.com/ethereum/go-ethereum/rpc" 34 "github.com/ethereum/go-ethereum/swarm/api" 35 ) 36 37 // TestNewSwarm validates Swarm fields in repsect to the provided configuration. 38 func TestNewSwarm(t *testing.T) { 39 dir, err := ioutil.TempDir("", "swarm") 40 if err != nil { 41 t.Fatal(err) 42 } 43 defer os.RemoveAll(dir) 44 45 // a simple rpc endpoint for testing dialing 46 ipcEndpoint := path.Join(dir, "TestSwarm.ipc") 47 48 // windows namedpipes are not on filesystem but on NPFS 49 if runtime.GOOS == "windows" { 50 b := make([]byte, 8) 51 rand.Read(b) 52 ipcEndpoint = `\\.\pipe\TestSwarm-` + hex.EncodeToString(b) 53 } 54 55 _, server, err := rpc.StartIPCEndpoint(ipcEndpoint, nil) 56 if err != nil { 57 t.Error(err) 58 } 59 defer server.Stop() 60 61 for _, tc := range []struct { 62 name string 63 configure func(*api.Config) 64 check func(*testing.T, *Swarm, *api.Config) 65 }{ 66 { 67 name: "defaults", 68 configure: nil, 69 check: func(t *testing.T, s *Swarm, config *api.Config) { 70 if s.config != config { 71 t.Error("config is not the same object") 72 } 73 if s.backend != nil { 74 t.Error("backend is not nil") 75 } 76 if s.privateKey == nil { 77 t.Error("private key is not set") 78 } 79 if !s.config.HiveParams.Discovery { 80 t.Error("config.HiveParams.Discovery is false, must be true regardless the configuration") 81 } 82 if s.dns != nil { 83 t.Error("dns initialized, but it should not be") 84 } 85 if s.netStore == nil { 86 t.Error("netStore not initialized") 87 } 88 if s.streamer == nil { 89 t.Error("streamer not initialized") 90 } 91 if s.fileStore == nil { 92 t.Error("fileStore not initialized") 93 } 94 if s.bzz == nil { 95 t.Error("bzz not initialized") 96 } 97 if s.ps == nil { 98 t.Error("pss not initialized") 99 } 100 if s.api == nil { 101 t.Error("api not initialized") 102 } 103 if s.sfs == nil { 104 t.Error("swarm filesystem not initialized") 105 } 106 }, 107 }, 108 { 109 name: "with swap", 110 configure: func(config *api.Config) { 111 config.SwapAPI = ipcEndpoint 112 config.SwapEnabled = true 113 }, 114 check: func(t *testing.T, s *Swarm, _ *api.Config) { 115 if s.backend == nil { 116 t.Error("backend is nil") 117 } 118 }, 119 }, 120 { 121 name: "with swap disabled", 122 configure: func(config *api.Config) { 123 config.SwapAPI = ipcEndpoint 124 config.SwapEnabled = false 125 }, 126 check: func(t *testing.T, s *Swarm, _ *api.Config) { 127 if s.backend != nil { 128 t.Error("backend is not nil") 129 } 130 }, 131 }, 132 { 133 name: "with swap enabled and api endpoint blank", 134 configure: func(config *api.Config) { 135 config.SwapAPI = "" 136 config.SwapEnabled = true 137 }, 138 check: func(t *testing.T, s *Swarm, _ *api.Config) { 139 if s.backend != nil { 140 t.Error("backend is not nil") 141 } 142 }, 143 }, 144 { 145 name: "ens", 146 configure: func(config *api.Config) { 147 config.EnsAPIs = []string{ 148 "http://127.0.0.1:8888", 149 } 150 }, 151 check: func(t *testing.T, s *Swarm, _ *api.Config) { 152 if s.dns == nil { 153 t.Error("dns is not initialized") 154 } 155 }, 156 }, 157 } { 158 t.Run(tc.name, func(t *testing.T) { 159 config := api.NewConfig() 160 161 dir, err := ioutil.TempDir("", "swarm") 162 if err != nil { 163 t.Fatal(err) 164 } 165 defer os.RemoveAll(dir) 166 167 config.Path = dir 168 169 privkey, err := crypto.GenerateKey() 170 if err != nil { 171 t.Fatal(err) 172 } 173 nodekey, err := crypto.GenerateKey() 174 if err != nil { 175 t.Fatal(err) 176 } 177 178 config.Init(privkey, nodekey) 179 180 if tc.configure != nil { 181 tc.configure(config) 182 } 183 184 s, err := NewSwarm(config, nil) 185 if err != nil { 186 t.Fatal(err) 187 } 188 189 if tc.check != nil { 190 tc.check(t, s, config) 191 } 192 }) 193 } 194 } 195 196 func TestParseEnsAPIAddress(t *testing.T) { 197 for _, x := range []struct { 198 description string 199 value string 200 tld string 201 endpoint string 202 addr common.Address 203 }{ 204 { 205 description: "IPC endpoint", 206 value: "/data/testnet/geth.ipc", 207 endpoint: "/data/testnet/geth.ipc", 208 }, 209 { 210 description: "HTTP endpoint", 211 value: "http://127.0.0.1:1234", 212 endpoint: "http://127.0.0.1:1234", 213 }, 214 { 215 description: "WS endpoint", 216 value: "ws://127.0.0.1:1234", 217 endpoint: "ws://127.0.0.1:1234", 218 }, 219 { 220 description: "IPC Endpoint and TLD", 221 value: "test:/data/testnet/geth.ipc", 222 endpoint: "/data/testnet/geth.ipc", 223 tld: "test", 224 }, 225 { 226 description: "HTTP endpoint and TLD", 227 value: "test:http://127.0.0.1:1234", 228 endpoint: "http://127.0.0.1:1234", 229 tld: "test", 230 }, 231 { 232 description: "WS endpoint and TLD", 233 value: "test:ws://127.0.0.1:1234", 234 endpoint: "ws://127.0.0.1:1234", 235 tld: "test", 236 }, 237 { 238 description: "IPC Endpoint and contract address", 239 value: "314159265dD8dbb310642f98f50C066173C1259b@/data/testnet/geth.ipc", 240 endpoint: "/data/testnet/geth.ipc", 241 addr: common.HexToAddress("314159265dD8dbb310642f98f50C066173C1259b"), 242 }, 243 { 244 description: "HTTP endpoint and contract address", 245 value: "314159265dD8dbb310642f98f50C066173C1259b@http://127.0.0.1:1234", 246 endpoint: "http://127.0.0.1:1234", 247 addr: common.HexToAddress("314159265dD8dbb310642f98f50C066173C1259b"), 248 }, 249 { 250 description: "WS endpoint and contract address", 251 value: "314159265dD8dbb310642f98f50C066173C1259b@ws://127.0.0.1:1234", 252 endpoint: "ws://127.0.0.1:1234", 253 addr: common.HexToAddress("314159265dD8dbb310642f98f50C066173C1259b"), 254 }, 255 { 256 description: "IPC Endpoint, TLD and contract address", 257 value: "test:314159265dD8dbb310642f98f50C066173C1259b@/data/testnet/geth.ipc", 258 endpoint: "/data/testnet/geth.ipc", 259 addr: common.HexToAddress("314159265dD8dbb310642f98f50C066173C1259b"), 260 tld: "test", 261 }, 262 { 263 description: "HTTP endpoint, TLD and contract address", 264 value: "eth:314159265dD8dbb310642f98f50C066173C1259b@http://127.0.0.1:1234", 265 endpoint: "http://127.0.0.1:1234", 266 addr: common.HexToAddress("314159265dD8dbb310642f98f50C066173C1259b"), 267 tld: "eth", 268 }, 269 { 270 description: "WS endpoint, TLD and contract address", 271 value: "eth:314159265dD8dbb310642f98f50C066173C1259b@ws://127.0.0.1:1234", 272 endpoint: "ws://127.0.0.1:1234", 273 addr: common.HexToAddress("314159265dD8dbb310642f98f50C066173C1259b"), 274 tld: "eth", 275 }, 276 } { 277 t.Run(x.description, func(t *testing.T) { 278 tld, endpoint, addr := parseEnsAPIAddress(x.value) 279 if endpoint != x.endpoint { 280 t.Errorf("expected Endpoint %q, got %q", x.endpoint, endpoint) 281 } 282 if addr != x.addr { 283 t.Errorf("expected ContractAddress %q, got %q", x.addr.String(), addr.String()) 284 } 285 if tld != x.tld { 286 t.Errorf("expected TLD %q, got %q", x.tld, tld) 287 } 288 }) 289 } 290 } 291 292 // TestLocalStoreAndRetrieve runs multiple tests where different size files are uploaded 293 // to a single Swarm instance using API Store and checked against the content returned 294 // by API Retrieve function. 295 // 296 // This test is intended to validate functionality of chunker store and join functions 297 // and their intergartion into Swarm, without comparing results with ones produced by 298 // another chunker implementation, as it is done in swarm/storage tests. 299 func TestLocalStoreAndRetrieve(t *testing.T) { 300 config := api.NewConfig() 301 302 dir, err := ioutil.TempDir("", "node") 303 if err != nil { 304 t.Fatal(err) 305 } 306 defer os.RemoveAll(dir) 307 308 config.Path = dir 309 310 privkey, err := crypto.GenerateKey() 311 if err != nil { 312 t.Fatal(err) 313 } 314 nodekey, err := crypto.GenerateKey() 315 if err != nil { 316 t.Fatal(err) 317 } 318 319 config.Init(privkey, nodekey) 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 }