github.com/daragao/go-ethereum@v1.8.14-0.20180809141559-45eaef243198/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.lstore == nil { 86 t.Error("localstore 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.lstore.Validators == nil { 95 t.Error("localstore validators not initialized") 96 } 97 if s.bzz == nil { 98 t.Error("bzz not initialized") 99 } 100 if s.ps == nil { 101 t.Error("pss not initialized") 102 } 103 if s.api == nil { 104 t.Error("api not initialized") 105 } 106 if s.sfs == nil { 107 t.Error("swarm filesystem not initialized") 108 } 109 }, 110 }, 111 { 112 name: "with swap", 113 configure: func(config *api.Config) { 114 config.SwapAPI = ipcEndpoint 115 config.SwapEnabled = true 116 }, 117 check: func(t *testing.T, s *Swarm, _ *api.Config) { 118 if s.backend == nil { 119 t.Error("backend is nil") 120 } 121 }, 122 }, 123 { 124 name: "with swap disabled", 125 configure: func(config *api.Config) { 126 config.SwapAPI = ipcEndpoint 127 config.SwapEnabled = false 128 }, 129 check: func(t *testing.T, s *Swarm, _ *api.Config) { 130 if s.backend != nil { 131 t.Error("backend is not nil") 132 } 133 }, 134 }, 135 { 136 name: "with swap enabled and api endpoint blank", 137 configure: func(config *api.Config) { 138 config.SwapAPI = "" 139 config.SwapEnabled = true 140 }, 141 check: func(t *testing.T, s *Swarm, _ *api.Config) { 142 if s.backend != nil { 143 t.Error("backend is not nil") 144 } 145 }, 146 }, 147 { 148 name: "ens", 149 configure: func(config *api.Config) { 150 config.EnsAPIs = []string{ 151 "http://127.0.0.1:8888", 152 } 153 }, 154 check: func(t *testing.T, s *Swarm, _ *api.Config) { 155 if s.dns == nil { 156 t.Error("dns is not initialized") 157 } 158 }, 159 }, 160 } { 161 t.Run(tc.name, func(t *testing.T) { 162 config := api.NewConfig() 163 164 dir, err := ioutil.TempDir("", "swarm") 165 if err != nil { 166 t.Fatal(err) 167 } 168 defer os.RemoveAll(dir) 169 170 config.Path = dir 171 172 privkey, err := crypto.GenerateKey() 173 if err != nil { 174 t.Fatal(err) 175 } 176 177 config.Init(privkey) 178 179 if tc.configure != nil { 180 tc.configure(config) 181 } 182 183 s, err := NewSwarm(config, nil) 184 if err != nil { 185 t.Fatal(err) 186 } 187 188 if tc.check != nil { 189 tc.check(t, s, config) 190 } 191 }) 192 } 193 } 194 195 func TestParseEnsAPIAddress(t *testing.T) { 196 for _, x := range []struct { 197 description string 198 value string 199 tld string 200 endpoint string 201 addr common.Address 202 }{ 203 { 204 description: "IPC endpoint", 205 value: "/data/testnet/geth.ipc", 206 endpoint: "/data/testnet/geth.ipc", 207 }, 208 { 209 description: "HTTP endpoint", 210 value: "http://127.0.0.1:1234", 211 endpoint: "http://127.0.0.1:1234", 212 }, 213 { 214 description: "WS endpoint", 215 value: "ws://127.0.0.1:1234", 216 endpoint: "ws://127.0.0.1:1234", 217 }, 218 { 219 description: "IPC Endpoint and TLD", 220 value: "test:/data/testnet/geth.ipc", 221 endpoint: "/data/testnet/geth.ipc", 222 tld: "test", 223 }, 224 { 225 description: "HTTP endpoint and TLD", 226 value: "test:http://127.0.0.1:1234", 227 endpoint: "http://127.0.0.1:1234", 228 tld: "test", 229 }, 230 { 231 description: "WS endpoint and TLD", 232 value: "test:ws://127.0.0.1:1234", 233 endpoint: "ws://127.0.0.1:1234", 234 tld: "test", 235 }, 236 { 237 description: "IPC Endpoint and contract address", 238 value: "314159265dD8dbb310642f98f50C066173C1259b@/data/testnet/geth.ipc", 239 endpoint: "/data/testnet/geth.ipc", 240 addr: common.HexToAddress("314159265dD8dbb310642f98f50C066173C1259b"), 241 }, 242 { 243 description: "HTTP endpoint and contract address", 244 value: "314159265dD8dbb310642f98f50C066173C1259b@http://127.0.0.1:1234", 245 endpoint: "http://127.0.0.1:1234", 246 addr: common.HexToAddress("314159265dD8dbb310642f98f50C066173C1259b"), 247 }, 248 { 249 description: "WS endpoint and contract address", 250 value: "314159265dD8dbb310642f98f50C066173C1259b@ws://127.0.0.1:1234", 251 endpoint: "ws://127.0.0.1:1234", 252 addr: common.HexToAddress("314159265dD8dbb310642f98f50C066173C1259b"), 253 }, 254 { 255 description: "IPC Endpoint, TLD and contract address", 256 value: "test:314159265dD8dbb310642f98f50C066173C1259b@/data/testnet/geth.ipc", 257 endpoint: "/data/testnet/geth.ipc", 258 addr: common.HexToAddress("314159265dD8dbb310642f98f50C066173C1259b"), 259 tld: "test", 260 }, 261 { 262 description: "HTTP endpoint, TLD and contract address", 263 value: "eth:314159265dD8dbb310642f98f50C066173C1259b@http://127.0.0.1:1234", 264 endpoint: "http://127.0.0.1:1234", 265 addr: common.HexToAddress("314159265dD8dbb310642f98f50C066173C1259b"), 266 tld: "eth", 267 }, 268 { 269 description: "WS endpoint, TLD and contract address", 270 value: "eth:314159265dD8dbb310642f98f50C066173C1259b@ws://127.0.0.1:1234", 271 endpoint: "ws://127.0.0.1:1234", 272 addr: common.HexToAddress("314159265dD8dbb310642f98f50C066173C1259b"), 273 tld: "eth", 274 }, 275 } { 276 t.Run(x.description, func(t *testing.T) { 277 tld, endpoint, addr := parseEnsAPIAddress(x.value) 278 if endpoint != x.endpoint { 279 t.Errorf("expected Endpoint %q, got %q", x.endpoint, endpoint) 280 } 281 if addr != x.addr { 282 t.Errorf("expected ContractAddress %q, got %q", x.addr.String(), addr.String()) 283 } 284 if tld != x.tld { 285 t.Errorf("expected TLD %q, got %q", x.tld, tld) 286 } 287 }) 288 } 289 } 290 291 // TestLocalStoreAndRetrieve runs multiple tests where different size files are uploaded 292 // to a single Swarm instance using API Store and checked against the content returned 293 // by API Retrieve function. 294 // 295 // This test is intended to validate functionality of chunker store and join functions 296 // and their intergartion into Swarm, without comparing results with ones produced by 297 // another chunker implementation, as it is done in swarm/storage tests. 298 func TestLocalStoreAndRetrieve(t *testing.T) { 299 config := api.NewConfig() 300 301 dir, err := ioutil.TempDir("", "node") 302 if err != nil { 303 t.Fatal(err) 304 } 305 defer os.RemoveAll(dir) 306 307 config.Path = dir 308 309 privkey, err := crypto.GenerateKey() 310 if err != nil { 311 t.Fatal(err) 312 } 313 314 config.Init(privkey) 315 316 swarm, err := NewSwarm(config, nil) 317 if err != nil { 318 t.Fatal(err) 319 } 320 321 // by default, test only the lonely chunk cases 322 sizes := []int{1, 60, 4097, 524288 + 1, 7*524288 + 1, 128*524288 + 1} 323 324 if *longrunning { 325 // test broader set of cases if -longruning flag is set 326 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, 128*524288+4096, 128*524288+4097, 816778334) 327 } 328 for _, n := range sizes { 329 testLocalStoreAndRetrieve(t, swarm, n, true) 330 testLocalStoreAndRetrieve(t, swarm, n, false) 331 } 332 } 333 334 // testLocalStoreAndRetrieve is using a single Swarm instance, to upload 335 // a file of length n with optional random data using API Store function, 336 // and checks the output of API Retrieve function on the same instance. 337 // This is a regression test for issue 338 // https://github.com/ethersphere/go-ethereum/issues/639 339 // where pyramid chunker did not split correctly files with lengths that 340 // are edge cases for chunk and tree parameters, depending whether there 341 // is a tree chunk with only one data chunk and how the compress functionality 342 // changed the tree. 343 func testLocalStoreAndRetrieve(t *testing.T, swarm *Swarm, n int, randomData bool) { 344 slice := make([]byte, n) 345 if randomData { 346 rand.Seed(time.Now().UnixNano()) 347 rand.Read(slice) 348 } 349 dataPut := string(slice) 350 351 ctx := context.TODO() 352 k, wait, err := swarm.api.Store(ctx, strings.NewReader(dataPut), int64(len(dataPut)), false) 353 if err != nil { 354 t.Fatal(err) 355 } 356 if wait != nil { 357 err = wait(ctx) 358 if err != nil { 359 t.Fatal(err) 360 } 361 } 362 363 r, _ := swarm.api.Retrieve(context.TODO(), k) 364 365 d, err := ioutil.ReadAll(r) 366 if err != nil { 367 t.Fatal(err) 368 } 369 dataGet := string(d) 370 371 if len(dataPut) != len(dataGet) { 372 t.Fatalf("data not matched: length expected %v, got %v", len(dataPut), len(dataGet)) 373 } else { 374 if dataPut != dataGet { 375 t.Fatal("data not matched") 376 } 377 } 378 }