github.com/oskarth/go-ethereum@v1.6.8-0.20191013093314-dac24a9d3494/swarm/network/stream/visualized_snapshot_sync_sim_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 // +build withserver 18 19 package stream 20 21 import ( 22 "context" 23 "fmt" 24 "testing" 25 "time" 26 27 "github.com/ethereum/go-ethereum/p2p" 28 "github.com/ethereum/go-ethereum/p2p/discover" 29 "github.com/ethereum/go-ethereum/p2p/simulations" 30 "github.com/ethereum/go-ethereum/swarm/log" 31 "github.com/ethereum/go-ethereum/swarm/network/simulation" 32 "github.com/ethereum/go-ethereum/swarm/storage" 33 ) 34 35 /* 36 The tests in this file need to be executed with 37 38 -tags=withserver 39 40 Also, they will stall if executed stand-alone, because they wait 41 for the visualization frontend to send a POST /runsim message. 42 */ 43 44 //setup the sim, evaluate nodeCount and chunkCount and create the sim 45 func setupSim(serviceMap map[string]simulation.ServiceFunc) (int, int, *simulation.Simulation) { 46 nodeCount := *nodes 47 chunkCount := *chunks 48 49 if nodeCount == 0 || chunkCount == 0 { 50 nodeCount = 32 51 chunkCount = 1 52 } 53 54 //setup the simulation with server, which means the sim won't run 55 //until it receives a POST /runsim from the frontend 56 sim := simulation.New(serviceMap).WithServer(":8888") 57 return nodeCount, chunkCount, sim 58 } 59 60 //watch for disconnections and wait for healthy 61 func watchSim(sim *simulation.Simulation) (context.Context, context.CancelFunc) { 62 ctx, cancelSimRun := context.WithTimeout(context.Background(), 1*time.Minute) 63 64 if _, err := sim.WaitTillHealthy(ctx, 2); err != nil { 65 panic(err) 66 } 67 68 disconnections := sim.PeerEvents( 69 context.Background(), 70 sim.NodeIDs(), 71 simulation.NewPeerEventsFilter().Type(p2p.PeerEventTypeDrop), 72 ) 73 74 go func() { 75 for d := range disconnections { 76 log.Error("peer drop", "node", d.NodeID, "peer", d.Event.Peer) 77 panic("unexpected disconnect") 78 cancelSimRun() 79 } 80 }() 81 82 return ctx, cancelSimRun 83 } 84 85 //This test requests bogus hashes into the network 86 func TestNonExistingHashesWithServer(t *testing.T) { 87 nodeCount, _, sim := setupSim(retrievalSimServiceMap) 88 defer sim.Close() 89 90 err := sim.UploadSnapshot(fmt.Sprintf("testing/snapshot_%d.json", nodeCount)) 91 if err != nil { 92 panic(err) 93 } 94 95 ctx, cancelSimRun := watchSim(sim) 96 defer cancelSimRun() 97 98 //in order to get some meaningful visualization, it is beneficial 99 //to define a minimum duration of this test 100 testDuration := 20 * time.Second 101 102 result := sim.Run(ctx, func(ctx context.Context, sim *simulation.Simulation) error { 103 //check on the node's FileStore (netstore) 104 id := sim.RandomUpNode().ID 105 item, ok := sim.NodeItem(id, bucketKeyFileStore) 106 if !ok { 107 t.Fatalf("No filestore") 108 } 109 fileStore := item.(*storage.FileStore) 110 //create a bogus hash 111 fakeHash := storage.GenerateRandomChunk(1000).Address() 112 //try to retrieve it - will propagate RetrieveRequestMsg into the network 113 reader, _ := fileStore.Retrieve(context.TODO(), fakeHash) 114 if _, err := reader.Size(ctx, nil); err != nil { 115 log.Debug("expected error for non-existing chunk") 116 } 117 //sleep so that the frontend can have something to display 118 time.Sleep(testDuration) 119 120 return nil 121 }) 122 if result.Error != nil { 123 sendSimTerminatedEvent(sim) 124 t.Fatal(result.Error) 125 } 126 127 sendSimTerminatedEvent(sim) 128 129 } 130 131 //send a termination event to the frontend 132 func sendSimTerminatedEvent(sim *simulation.Simulation) { 133 evt := &simulations.Event{ 134 Type: EventTypeSimTerminated, 135 Control: false, 136 } 137 sim.Net.Events().Send(evt) 138 } 139 140 //This test is the same as the snapshot sync test, 141 //but with a HTTP server 142 //It also sends some custom events so that the frontend 143 //can visualize messages like SendOfferedMsg, WantedHashesMsg, DeliveryMsg 144 func TestSnapshotSyncWithServer(t *testing.T) { 145 146 nodeCount, chunkCount, sim := setupSim(simServiceMap) 147 defer sim.Close() 148 149 log.Info("Initializing test config") 150 151 conf := &synctestConfig{} 152 //map of discover ID to indexes of chunks expected at that ID 153 conf.idToChunksMap = make(map[discover.NodeID][]int) 154 //map of overlay address to discover ID 155 conf.addrToIDMap = make(map[string]discover.NodeID) 156 //array where the generated chunk hashes will be stored 157 conf.hashes = make([]storage.Address, 0) 158 159 err := sim.UploadSnapshot(fmt.Sprintf("testing/snapshot_%d.json", nodeCount)) 160 if err != nil { 161 panic(err) 162 } 163 164 ctx, cancelSimRun := watchSim(sim) 165 defer cancelSimRun() 166 167 //setup filters in the event feed 168 offeredHashesFilter := simulation.NewPeerEventsFilter().Type(p2p.PeerEventTypeMsgRecv).Protocol("stream").MsgCode(1) 169 wantedFilter := simulation.NewPeerEventsFilter().Type(p2p.PeerEventTypeMsgRecv).Protocol("stream").MsgCode(2) 170 deliveryFilter := simulation.NewPeerEventsFilter().Type(p2p.PeerEventTypeMsgRecv).Protocol("stream").MsgCode(6) 171 eventC := sim.PeerEvents(ctx, sim.UpNodeIDs(), offeredHashesFilter, wantedFilter, deliveryFilter) 172 173 quit := make(chan struct{}) 174 175 go func() { 176 for e := range eventC { 177 select { 178 case <-quit: 179 fmt.Println("quitting event loop") 180 return 181 default: 182 } 183 if e.Error != nil { 184 t.Fatal(e.Error) 185 } 186 if *e.Event.MsgCode == uint64(1) { 187 evt := &simulations.Event{ 188 Type: EventTypeChunkOffered, 189 Node: sim.Net.GetNode(e.NodeID), 190 Control: false, 191 } 192 sim.Net.Events().Send(evt) 193 } else if *e.Event.MsgCode == uint64(2) { 194 evt := &simulations.Event{ 195 Type: EventTypeChunkWanted, 196 Node: sim.Net.GetNode(e.NodeID), 197 Control: false, 198 } 199 sim.Net.Events().Send(evt) 200 } else if *e.Event.MsgCode == uint64(6) { 201 evt := &simulations.Event{ 202 Type: EventTypeChunkDelivered, 203 Node: sim.Net.GetNode(e.NodeID), 204 Control: false, 205 } 206 sim.Net.Events().Send(evt) 207 } 208 } 209 }() 210 //run the sim 211 result := runSim(conf, ctx, sim, chunkCount) 212 213 //send terminated event 214 evt := &simulations.Event{ 215 Type: EventTypeSimTerminated, 216 Control: false, 217 } 218 sim.Net.Events().Send(evt) 219 220 if result.Error != nil { 221 panic(result.Error) 222 } 223 close(quit) 224 log.Info("Simulation ended") 225 }