github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/swarm/network/stream/common_test.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 19:16:43</date> 10 //</624450115121188864> 11 12 13 package stream 14 15 import ( 16 "context" 17 "errors" 18 "flag" 19 "fmt" 20 "io" 21 "io/ioutil" 22 "math/rand" 23 "os" 24 "strings" 25 "sync/atomic" 26 "testing" 27 "time" 28 29 "github.com/ethereum/go-ethereum/log" 30 "github.com/ethereum/go-ethereum/p2p/enode" 31 p2ptest "github.com/ethereum/go-ethereum/p2p/testing" 32 "github.com/ethereum/go-ethereum/swarm/network" 33 "github.com/ethereum/go-ethereum/swarm/network/simulation" 34 "github.com/ethereum/go-ethereum/swarm/state" 35 "github.com/ethereum/go-ethereum/swarm/storage" 36 "github.com/ethereum/go-ethereum/swarm/testutil" 37 colorable "github.com/mattn/go-colorable" 38 ) 39 40 var ( 41 loglevel = flag.Int("loglevel", 2, "verbosity of logs") 42 nodes = flag.Int("nodes", 0, "number of nodes") 43 chunks = flag.Int("chunks", 0, "number of chunks") 44 useMockStore = flag.Bool("mockstore", false, "disabled mock store (default: enabled)") 45 longrunning = flag.Bool("longrunning", false, "do run long-running tests") 46 47 bucketKeyDB = simulation.BucketKey("db") 48 bucketKeyStore = simulation.BucketKey("store") 49 bucketKeyFileStore = simulation.BucketKey("filestore") 50 bucketKeyNetStore = simulation.BucketKey("netstore") 51 bucketKeyDelivery = simulation.BucketKey("delivery") 52 bucketKeyRegistry = simulation.BucketKey("registry") 53 54 chunkSize = 4096 55 pof = network.Pof 56 ) 57 58 func init() { 59 flag.Parse() 60 rand.Seed(time.Now().UnixNano()) 61 62 log.PrintOrigins(true) 63 log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(colorable.NewColorableStderr(), log.TerminalFormat(true)))) 64 } 65 66 func newStreamerTester(t *testing.T, registryOptions *RegistryOptions) (*p2ptest.ProtocolTester, *Registry, *storage.LocalStore, func(), error) { 67 //设置 68 addr := network.RandomAddr() //测试的对等地址 69 to := network.NewKademlia(addr.OAddr, network.NewKadParams()) 70 71 //临时数据 72 datadir, err := ioutil.TempDir("", "streamer") 73 if err != nil { 74 return nil, nil, nil, func() {}, err 75 } 76 removeDataDir := func() { 77 os.RemoveAll(datadir) 78 } 79 80 params := storage.NewDefaultLocalStoreParams() 81 params.Init(datadir) 82 params.BaseKey = addr.Over() 83 84 localStore, err := storage.NewTestLocalStoreForAddr(params) 85 if err != nil { 86 return nil, nil, nil, removeDataDir, err 87 } 88 89 netStore, err := storage.NewNetStore(localStore, nil) 90 if err != nil { 91 return nil, nil, nil, removeDataDir, err 92 } 93 94 delivery := NewDelivery(to, netStore) 95 netStore.NewNetFetcherFunc = network.NewFetcherFactory(delivery.RequestFromPeers, true).New 96 streamer := NewRegistry(addr.ID(), delivery, netStore, state.NewInmemoryStore(), registryOptions, nil) 97 teardown := func() { 98 streamer.Close() 99 removeDataDir() 100 } 101 protocolTester := p2ptest.NewProtocolTester(t, addr.ID(), 1, streamer.runProtocol) 102 103 err = waitForPeers(streamer, 1*time.Second, 1) 104 if err != nil { 105 return nil, nil, nil, nil, errors.New("timeout: peer is not created") 106 } 107 108 return protocolTester, streamer, localStore, teardown, nil 109 } 110 111 func waitForPeers(streamer *Registry, timeout time.Duration, expectedPeers int) error { 112 ticker := time.NewTicker(10 * time.Millisecond) 113 timeoutTimer := time.NewTimer(timeout) 114 for { 115 select { 116 case <-ticker.C: 117 if streamer.peersCount() >= expectedPeers { 118 return nil 119 } 120 case <-timeoutTimer.C: 121 return errors.New("timeout") 122 } 123 } 124 } 125 126 type roundRobinStore struct { 127 index uint32 128 stores []storage.ChunkStore 129 } 130 131 func newRoundRobinStore(stores ...storage.ChunkStore) *roundRobinStore { 132 return &roundRobinStore{ 133 stores: stores, 134 } 135 } 136 137 func (rrs *roundRobinStore) Get(ctx context.Context, addr storage.Address) (storage.Chunk, error) { 138 return nil, errors.New("get not well defined on round robin store") 139 } 140 141 func (rrs *roundRobinStore) Put(ctx context.Context, chunk storage.Chunk) error { 142 i := atomic.AddUint32(&rrs.index, 1) 143 idx := int(i) % len(rrs.stores) 144 return rrs.stores[idx].Put(ctx, chunk) 145 } 146 147 func (rrs *roundRobinStore) Close() { 148 for _, store := range rrs.stores { 149 store.Close() 150 } 151 } 152 153 func readAll(fileStore *storage.FileStore, hash []byte) (int64, error) { 154 r, _ := fileStore.Retrieve(context.TODO(), hash) 155 buf := make([]byte, 1024) 156 var n int 157 var total int64 158 var err error 159 for (total == 0 || n > 0) && err == nil { 160 n, err = r.ReadAt(buf, total) 161 total += int64(n) 162 } 163 if err != nil && err != io.EOF { 164 return total, err 165 } 166 return total, nil 167 } 168 169 func uploadFilesToNodes(sim *simulation.Simulation) ([]storage.Address, []string, error) { 170 nodes := sim.UpNodeIDs() 171 nodeCnt := len(nodes) 172 log.Debug(fmt.Sprintf("Uploading %d files to nodes", nodeCnt)) 173 //保存生成文件的数组 174 rfiles := make([]string, nodeCnt) 175 //保存文件根哈希的数组 176 rootAddrs := make([]storage.Address, nodeCnt) 177 178 var err error 179 //对于每个节点,生成一个文件并上载 180 for i, id := range nodes { 181 item, ok := sim.NodeItem(id, bucketKeyFileStore) 182 if !ok { 183 return nil, nil, fmt.Errorf("Error accessing localstore") 184 } 185 fileStore := item.(*storage.FileStore) 186 //生成文件 187 rfiles[i], err = generateRandomFile() 188 if err != nil { 189 return nil, nil, err 190 } 191 //将其存储(上载)到文件存储区 192 ctx := context.TODO() 193 rk, wait, err := fileStore.Store(ctx, strings.NewReader(rfiles[i]), int64(len(rfiles[i])), false) 194 log.Debug("Uploaded random string file to node") 195 if err != nil { 196 return nil, nil, err 197 } 198 err = wait(ctx) 199 if err != nil { 200 return nil, nil, err 201 } 202 rootAddrs[i] = rk 203 } 204 return rootAddrs, rfiles, nil 205 } 206 207 //生成随机文件(字符串) 208 func generateRandomFile() (string, error) { 209 //在minfileSize和maxfileSize之间生成随机文件大小 210 fileSize := rand.Intn(maxFileSize-minFileSize) + minFileSize 211 log.Debug(fmt.Sprintf("Generated file with filesize %d kB", fileSize)) 212 b := testutil.RandomBytes(1, fileSize*1024) 213 return string(b), nil 214 } 215 216 //为给定节点创建本地存储 217 func createTestLocalStorageForID(id enode.ID, addr *network.BzzAddr) (storage.ChunkStore, string, error) { 218 var datadir string 219 var err error 220 datadir, err = ioutil.TempDir("", fmt.Sprintf("syncer-test-%s", id.TerminalString())) 221 if err != nil { 222 return nil, "", err 223 } 224 var store storage.ChunkStore 225 params := storage.NewDefaultLocalStoreParams() 226 params.ChunkDbPath = datadir 227 params.BaseKey = addr.Over() 228 store, err = storage.NewTestLocalStoreForAddr(params) 229 if err != nil { 230 os.RemoveAll(datadir) 231 return nil, "", err 232 } 233 return store, datadir, nil 234 } 235