github.com/codingfuture/orig-energi3@v0.8.4/swarm/network/simulations/overlay_test.go (about)

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