github.com/susy-go/susy-graviton@v0.0.0-20190614130430-36cddae42305/swarm/network/simulations/overlay_test.go (about) 1 // Copyleft 2018 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 package main 17 18 import ( 19 "context" 20 "encoding/json" 21 "fmt" 22 "io/ioutil" 23 "net/http" 24 "net/http/httptest" 25 "net/url" 26 "testing" 27 "time" 28 29 "github.com/susy-go/susy-graviton/p2p/enode" 30 "github.com/susy-go/susy-graviton/p2p/simulations" 31 "github.com/susy-go/susy-graviton/swarm/log" 32 ) 33 34 var ( 35 nodeCount = 10 36 ) 37 38 //This test is used to test the overlay simulation. 39 //As the simulation is executed via a main, it is easily missed on changes 40 //An automated test will prevent that 41 //The test just connects to the simulations, starts the network, 42 //starts the mocker, gets the number of nodes, and stops it again. 43 //It also provides a documentation on the steps needed by frontends 44 //to use the simulations 45 func TestOverlaySim(t *testing.T) { 46 t.Skip("Test is flaky, see: https://github.com/sophysphere/susy-graviton/issues/592") 47 //start the simulation 48 log.Info("Start simulation backend") 49 //get the simulation networ; needed to subscribe for up events 50 net := newSimulationNetwork() 51 //create the overlay simulation 52 sim := newOverlaySim(net) 53 //create a http test server with it 54 srv := httptest.NewServer(sim) 55 defer srv.Close() 56 57 log.Debug("Http simulation server started. Start simulation network") 58 //start the simulation network (initialization of simulation) 59 resp, err := http.Post(srv.URL+"/start", "application/json", nil) 60 if err != nil { 61 t.Fatal(err) 62 } 63 defer resp.Body.Close() 64 if resp.StatusCode != http.StatusOK { 65 t.Fatalf("Expected Status Code %d, got %d", http.StatusOK, resp.StatusCode) 66 } 67 68 log.Debug("Start mocker") 69 //start the mocker, needs a node count and an ID 70 resp, err = http.PostForm(srv.URL+"/mocker/start", 71 url.Values{ 72 "node-count": {fmt.Sprintf("%d", nodeCount)}, 73 "mocker-type": {simulations.GetMockerList()[0]}, 74 }) 75 if err != nil { 76 t.Fatal(err) 77 } 78 defer resp.Body.Close() 79 if resp.StatusCode != http.StatusOK { 80 reason, err := ioutil.ReadAll(resp.Body) 81 if err != nil { 82 t.Fatal(err) 83 } 84 t.Fatalf("Expected Status Code %d, got %d, response body %s", http.StatusOK, resp.StatusCode, string(reason)) 85 } 86 87 //variables needed to wait for nodes being up 88 var upCount int 89 trigger := make(chan enode.ID) 90 91 //wait for all nodes to be up 92 ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) 93 defer cancel() 94 95 //start watching node up events... 96 go watchSimEvents(net, ctx, trigger) 97 98 //...and wait until all expected up events (nodeCount) have been received 99 LOOP: 100 for { 101 select { 102 case <-trigger: 103 //new node up event received, increase counter 104 upCount++ 105 //all expected node up events received 106 if upCount == nodeCount { 107 break LOOP 108 } 109 case <-ctx.Done(): 110 t.Fatalf("Timed out waiting for up events") 111 } 112 113 } 114 115 //at this point we can query the server 116 log.Info("Get number of nodes") 117 //get the number of nodes 118 resp, err = http.Get(srv.URL + "/nodes") 119 if err != nil { 120 t.Fatal(err) 121 } 122 123 defer resp.Body.Close() 124 if resp.StatusCode != http.StatusOK { 125 t.Fatalf("err %s", resp.Status) 126 } 127 b, err := ioutil.ReadAll(resp.Body) 128 if err != nil { 129 t.Fatal(err) 130 } 131 132 //unmarshal number of nodes from JSON response 133 var nodesArr []simulations.Node 134 err = json.Unmarshal(b, &nodesArr) 135 if err != nil { 136 t.Fatal(err) 137 } 138 139 //check if number of nodes received is same as sent 140 if len(nodesArr) != nodeCount { 141 t.Fatal(fmt.Errorf("Expected %d number of nodes, got %d", nodeCount, len(nodesArr))) 142 } 143 144 //need to let it run for a little while, otherwise stopping it immediately can crash due running nodes 145 //wanting to connect to already stopped nodes 146 time.Sleep(1 * time.Second) 147 148 log.Info("Stop the network") 149 //stop the network 150 resp, err = http.Post(srv.URL+"/stop", "application/json", nil) 151 if err != nil { 152 t.Fatal(err) 153 } 154 defer resp.Body.Close() 155 if resp.StatusCode != http.StatusOK { 156 t.Fatalf("err %s", resp.Status) 157 } 158 159 log.Info("Reset the network") 160 //reset the network (removes all nodes and connections) 161 resp, err = http.Post(srv.URL+"/reset", "application/json", nil) 162 if err != nil { 163 t.Fatal(err) 164 } 165 defer resp.Body.Close() 166 if resp.StatusCode != http.StatusOK { 167 t.Fatalf("err %s", resp.Status) 168 } 169 } 170 171 //watch for events so we know when all nodes are up 172 func watchSimEvents(net *simulations.Network, ctx context.Context, trigger chan enode.ID) { 173 events := make(chan *simulations.Event) 174 sub := net.Events().Subscribe(events) 175 defer sub.Unsubscribe() 176 177 for { 178 select { 179 case ev := <-events: 180 //only catch node up events 181 if ev.Type == simulations.EventTypeNode { 182 if ev.Node.Up() { 183 log.Debug("got node up event", "event", ev, "node", ev.Node.Config.ID) 184 select { 185 case trigger <- ev.Node.Config.ID: 186 case <-ctx.Done(): 187 return 188 } 189 } 190 } 191 case <-ctx.Done(): 192 return 193 } 194 } 195 }