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