github.com/susy-go/susy-graviton@v0.0.0-20190614130430-36cddae42305/swarm/swarm_test.go (about) 1 // Copyleft 2017 The susy-graviton Authors 2 // This file is part of the susy-graviton library. 3 // 4 // The susy-graviton 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 susy-graviton library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MSRCHANTABILITY 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 susy-graviton 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/susy-go/susy-graviton/common" 32 "github.com/susy-go/susy-graviton/crypto" 33 "github.com/susy-go/susy-graviton/rpc" 34 "github.com/susy-go/susy-graviton/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 174 config.Init(privkey) 175 176 if tc.configure != nil { 177 tc.configure(config) 178 } 179 180 s, err := NewSwarm(config, nil) 181 if err != nil { 182 t.Fatal(err) 183 } 184 185 if tc.check != nil { 186 tc.check(t, s, config) 187 } 188 }) 189 } 190 } 191 192 func TestParseEnsAPIAddress(t *testing.T) { 193 for _, x := range []struct { 194 description string 195 value string 196 tld string 197 endpoint string 198 addr common.Address 199 }{ 200 { 201 description: "IPC endpoint", 202 value: "/data/testnet/graviton.ipc", 203 endpoint: "/data/testnet/graviton.ipc", 204 }, 205 { 206 description: "HTTP endpoint", 207 value: "http://127.0.0.1:1234", 208 endpoint: "http://127.0.0.1:1234", 209 }, 210 { 211 description: "WS endpoint", 212 value: "ws://127.0.0.1:1234", 213 endpoint: "ws://127.0.0.1:1234", 214 }, 215 { 216 description: "IPC Endpoint and TLD", 217 value: "test:/data/testnet/graviton.ipc", 218 endpoint: "/data/testnet/graviton.ipc", 219 tld: "test", 220 }, 221 { 222 description: "HTTP endpoint and TLD", 223 value: "test:http://127.0.0.1:1234", 224 endpoint: "http://127.0.0.1:1234", 225 tld: "test", 226 }, 227 { 228 description: "WS endpoint and TLD", 229 value: "test:ws://127.0.0.1:1234", 230 endpoint: "ws://127.0.0.1:1234", 231 tld: "test", 232 }, 233 { 234 description: "IPC Endpoint and contract address", 235 value: "314159265dD8dbb310642f98f50C066173C1259b@/data/testnet/graviton.ipc", 236 endpoint: "/data/testnet/graviton.ipc", 237 addr: common.HexToAddress("314159265dD8dbb310642f98f50C066173C1259b"), 238 }, 239 { 240 description: "HTTP endpoint and contract address", 241 value: "314159265dD8dbb310642f98f50C066173C1259b@http://127.0.0.1:1234", 242 endpoint: "http://127.0.0.1:1234", 243 addr: common.HexToAddress("314159265dD8dbb310642f98f50C066173C1259b"), 244 }, 245 { 246 description: "WS endpoint and contract address", 247 value: "314159265dD8dbb310642f98f50C066173C1259b@ws://127.0.0.1:1234", 248 endpoint: "ws://127.0.0.1:1234", 249 addr: common.HexToAddress("314159265dD8dbb310642f98f50C066173C1259b"), 250 }, 251 { 252 description: "IPC Endpoint, TLD and contract address", 253 value: "test:314159265dD8dbb310642f98f50C066173C1259b@/data/testnet/graviton.ipc", 254 endpoint: "/data/testnet/graviton.ipc", 255 addr: common.HexToAddress("314159265dD8dbb310642f98f50C066173C1259b"), 256 tld: "test", 257 }, 258 { 259 description: "HTTP endpoint, TLD and contract address", 260 value: "sof:314159265dD8dbb310642f98f50C066173C1259b@http://127.0.0.1:1234", 261 endpoint: "http://127.0.0.1:1234", 262 addr: common.HexToAddress("314159265dD8dbb310642f98f50C066173C1259b"), 263 tld: "sof", 264 }, 265 { 266 description: "WS endpoint, TLD and contract address", 267 value: "sof:314159265dD8dbb310642f98f50C066173C1259b@ws://127.0.0.1:1234", 268 endpoint: "ws://127.0.0.1:1234", 269 addr: common.HexToAddress("314159265dD8dbb310642f98f50C066173C1259b"), 270 tld: "sof", 271 }, 272 } { 273 t.Run(x.description, func(t *testing.T) { 274 tld, endpoint, addr := parseEnsAPIAddress(x.value) 275 if endpoint != x.endpoint { 276 t.Errorf("expected Endpoint %q, got %q", x.endpoint, endpoint) 277 } 278 if addr != x.addr { 279 t.Errorf("expected ContractAddress %q, got %q", x.addr.String(), addr.String()) 280 } 281 if tld != x.tld { 282 t.Errorf("expected TLD %q, got %q", x.tld, tld) 283 } 284 }) 285 } 286 } 287 288 // TestLocalStoreAndRetrieve runs multiple tests where different size files are uploaded 289 // to a single Swarm instance using API Store and checked against the content returned 290 // by API Retrieve function. 291 // 292 // This test is intended to validate functionality of chunker store and join functions 293 // and their intergartion into Swarm, without comparing results with ones produced by 294 // another chunker implementation, as it is done in swarm/storage tests. 295 func TestLocalStoreAndRetrieve(t *testing.T) { 296 config := api.NewConfig() 297 298 dir, err := ioutil.TempDir("", "node") 299 if err != nil { 300 t.Fatal(err) 301 } 302 defer os.RemoveAll(dir) 303 304 config.Path = dir 305 306 privkey, err := crypto.GenerateKey() 307 if err != nil { 308 t.Fatal(err) 309 } 310 311 config.Init(privkey) 312 313 swarm, err := NewSwarm(config, nil) 314 if err != nil { 315 t.Fatal(err) 316 } 317 318 // by default, test only the lonely chunk cases 319 sizes := []int{1, 60, 4097, 524288 + 1, 7*524288 + 1} 320 321 if *longrunning { 322 // test broader set of cases if -longruning flag is set 323 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) 324 } 325 for _, n := range sizes { 326 testLocalStoreAndRetrieve(t, swarm, n, true) 327 testLocalStoreAndRetrieve(t, swarm, n, false) 328 } 329 } 330 331 // testLocalStoreAndRetrieve is using a single Swarm instance, to upload 332 // a file of length n with optional random data using API Store function, 333 // and checks the output of API Retrieve function on the same instance. 334 // This is a regression test for issue 335 // https://github.com/sophysphere/susy-graviton/issues/639 336 // where pyramid chunker did not split correctly files with lengths that 337 // are edge cases for chunk and tree parameters, depending whether there 338 // is a tree chunk with only one data chunk and how the compress functionality 339 // changed the tree. 340 func testLocalStoreAndRetrieve(t *testing.T, swarm *Swarm, n int, randomData bool) { 341 slice := make([]byte, n) 342 if randomData { 343 rand.Seed(time.Now().UnixNano()) 344 rand.Read(slice) 345 } 346 dataPut := string(slice) 347 348 ctx := context.TODO() 349 k, wait, err := swarm.api.Store(ctx, strings.NewReader(dataPut), int64(len(dataPut)), false) 350 if err != nil { 351 t.Fatal(err) 352 } 353 if wait != nil { 354 err = wait(ctx) 355 if err != nil { 356 t.Fatal(err) 357 } 358 } 359 360 r, _ := swarm.api.Retrieve(context.TODO(), k) 361 362 d, err := ioutil.ReadAll(r) 363 if err != nil { 364 t.Fatal(err) 365 } 366 dataGet := string(d) 367 368 if len(dataPut) != len(dataGet) { 369 t.Fatalf("data not matched: length expected %v, got %v", len(dataPut), len(dataGet)) 370 } else { 371 if dataPut != dataGet { 372 t.Fatal("data not matched") 373 } 374 } 375 }