github.com/shyftnetwork/go-empyrean@v1.8.3-0.20191127201940-fbfca9338f04/swarm/network/stream/common_test.go (about) 1 // Copyright 2018 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 stream 18 19 import ( 20 "context" 21 "errors" 22 "flag" 23 "fmt" 24 "io" 25 "io/ioutil" 26 "math/rand" 27 "os" 28 "strings" 29 "sync/atomic" 30 "testing" 31 "time" 32 33 "github.com/ShyftNetwork/go-empyrean/log" 34 "github.com/ShyftNetwork/go-empyrean/p2p/enode" 35 p2ptest "github.com/ShyftNetwork/go-empyrean/p2p/testing" 36 "github.com/ShyftNetwork/go-empyrean/swarm/network" 37 "github.com/ShyftNetwork/go-empyrean/swarm/network/simulation" 38 "github.com/ShyftNetwork/go-empyrean/swarm/state" 39 "github.com/ShyftNetwork/go-empyrean/swarm/storage" 40 "github.com/ShyftNetwork/go-empyrean/swarm/testutil" 41 colorable "github.com/mattn/go-colorable" 42 ) 43 44 var ( 45 loglevel = flag.Int("loglevel", 2, "verbosity of logs") 46 nodes = flag.Int("nodes", 0, "number of nodes") 47 chunks = flag.Int("chunks", 0, "number of chunks") 48 useMockStore = flag.Bool("mockstore", false, "disabled mock store (default: enabled)") 49 longrunning = flag.Bool("longrunning", false, "do run long-running tests") 50 51 bucketKeyDB = simulation.BucketKey("db") 52 bucketKeyStore = simulation.BucketKey("store") 53 bucketKeyFileStore = simulation.BucketKey("filestore") 54 bucketKeyNetStore = simulation.BucketKey("netstore") 55 bucketKeyDelivery = simulation.BucketKey("delivery") 56 bucketKeyRegistry = simulation.BucketKey("registry") 57 58 chunkSize = 4096 59 pof = network.Pof 60 ) 61 62 func init() { 63 flag.Parse() 64 rand.Seed(time.Now().UnixNano()) 65 66 log.PrintOrigins(true) 67 log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(colorable.NewColorableStderr(), log.TerminalFormat(true)))) 68 } 69 70 func newStreamerTester(t *testing.T, registryOptions *RegistryOptions) (*p2ptest.ProtocolTester, *Registry, *storage.LocalStore, func(), error) { 71 // setup 72 addr := network.RandomAddr() // tested peers peer address 73 to := network.NewKademlia(addr.OAddr, network.NewKadParams()) 74 75 // temp datadir 76 datadir, err := ioutil.TempDir("", "streamer") 77 if err != nil { 78 return nil, nil, nil, func() {}, err 79 } 80 removeDataDir := func() { 81 os.RemoveAll(datadir) 82 } 83 84 params := storage.NewDefaultLocalStoreParams() 85 params.Init(datadir) 86 params.BaseKey = addr.Over() 87 88 localStore, err := storage.NewTestLocalStoreForAddr(params) 89 if err != nil { 90 return nil, nil, nil, removeDataDir, err 91 } 92 93 netStore, err := storage.NewNetStore(localStore, nil) 94 if err != nil { 95 return nil, nil, nil, removeDataDir, err 96 } 97 98 delivery := NewDelivery(to, netStore) 99 netStore.NewNetFetcherFunc = network.NewFetcherFactory(delivery.RequestFromPeers, true).New 100 streamer := NewRegistry(addr.ID(), delivery, netStore, state.NewInmemoryStore(), registryOptions, nil) 101 teardown := func() { 102 streamer.Close() 103 removeDataDir() 104 } 105 protocolTester := p2ptest.NewProtocolTester(t, addr.ID(), 1, streamer.runProtocol) 106 107 err = waitForPeers(streamer, 1*time.Second, 1) 108 if err != nil { 109 return nil, nil, nil, nil, errors.New("timeout: peer is not created") 110 } 111 112 return protocolTester, streamer, localStore, teardown, nil 113 } 114 115 func waitForPeers(streamer *Registry, timeout time.Duration, expectedPeers int) error { 116 ticker := time.NewTicker(10 * time.Millisecond) 117 timeoutTimer := time.NewTimer(timeout) 118 for { 119 select { 120 case <-ticker.C: 121 if streamer.peersCount() >= expectedPeers { 122 return nil 123 } 124 case <-timeoutTimer.C: 125 return errors.New("timeout") 126 } 127 } 128 } 129 130 type roundRobinStore struct { 131 index uint32 132 stores []storage.ChunkStore 133 } 134 135 func newRoundRobinStore(stores ...storage.ChunkStore) *roundRobinStore { 136 return &roundRobinStore{ 137 stores: stores, 138 } 139 } 140 141 func (rrs *roundRobinStore) Get(ctx context.Context, addr storage.Address) (storage.Chunk, error) { 142 return nil, errors.New("get not well defined on round robin store") 143 } 144 145 func (rrs *roundRobinStore) Put(ctx context.Context, chunk storage.Chunk) error { 146 i := atomic.AddUint32(&rrs.index, 1) 147 idx := int(i) % len(rrs.stores) 148 return rrs.stores[idx].Put(ctx, chunk) 149 } 150 151 func (rrs *roundRobinStore) Close() { 152 for _, store := range rrs.stores { 153 store.Close() 154 } 155 } 156 157 func readAll(fileStore *storage.FileStore, hash []byte) (int64, error) { 158 r, _ := fileStore.Retrieve(context.TODO(), hash) 159 buf := make([]byte, 1024) 160 var n int 161 var total int64 162 var err error 163 for (total == 0 || n > 0) && err == nil { 164 n, err = r.ReadAt(buf, total) 165 total += int64(n) 166 } 167 if err != nil && err != io.EOF { 168 return total, err 169 } 170 return total, nil 171 } 172 173 func uploadFilesToNodes(sim *simulation.Simulation) ([]storage.Address, []string, error) { 174 nodes := sim.UpNodeIDs() 175 nodeCnt := len(nodes) 176 log.Debug(fmt.Sprintf("Uploading %d files to nodes", nodeCnt)) 177 //array holding generated files 178 rfiles := make([]string, nodeCnt) 179 //array holding the root hashes of the files 180 rootAddrs := make([]storage.Address, nodeCnt) 181 182 var err error 183 //for every node, generate a file and upload 184 for i, id := range nodes { 185 item, ok := sim.NodeItem(id, bucketKeyFileStore) 186 if !ok { 187 return nil, nil, fmt.Errorf("Error accessing localstore") 188 } 189 fileStore := item.(*storage.FileStore) 190 //generate a file 191 rfiles[i], err = generateRandomFile() 192 if err != nil { 193 return nil, nil, err 194 } 195 //store it (upload it) on the FileStore 196 ctx := context.TODO() 197 rk, wait, err := fileStore.Store(ctx, strings.NewReader(rfiles[i]), int64(len(rfiles[i])), false) 198 log.Debug("Uploaded random string file to node") 199 if err != nil { 200 return nil, nil, err 201 } 202 err = wait(ctx) 203 if err != nil { 204 return nil, nil, err 205 } 206 rootAddrs[i] = rk 207 } 208 return rootAddrs, rfiles, nil 209 } 210 211 //generate a random file (string) 212 func generateRandomFile() (string, error) { 213 //generate a random file size between minFileSize and maxFileSize 214 fileSize := rand.Intn(maxFileSize-minFileSize) + minFileSize 215 log.Debug(fmt.Sprintf("Generated file with filesize %d kB", fileSize)) 216 b := testutil.RandomBytes(1, fileSize*1024) 217 return string(b), nil 218 } 219 220 //create a local store for the given node 221 func createTestLocalStorageForID(id enode.ID, addr *network.BzzAddr) (storage.ChunkStore, string, error) { 222 var datadir string 223 var err error 224 datadir, err = ioutil.TempDir("", fmt.Sprintf("syncer-test-%s", id.TerminalString())) 225 if err != nil { 226 return nil, "", err 227 } 228 var store storage.ChunkStore 229 params := storage.NewDefaultLocalStoreParams() 230 params.ChunkDbPath = datadir 231 params.BaseKey = addr.Over() 232 store, err = storage.NewTestLocalStoreForAddr(params) 233 if err != nil { 234 os.RemoveAll(datadir) 235 return nil, "", err 236 } 237 return store, datadir, nil 238 }