github.com/luckypickle/go-ethereum-vet@v1.14.2/p2p/simulations/mocker_test.go (about)

     1  // Copyright 2017 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  // Package simulations simulates p2p networks.
    18  // A mokcer simulates starting and stopping real nodes in a network.
    19  package simulations
    20  
    21  import (
    22  	"encoding/json"
    23  	"net/http"
    24  	"net/url"
    25  	"strconv"
    26  	"sync"
    27  	"testing"
    28  	"time"
    29  
    30  	"github.com/luckypickle/go-ethereum-vet/p2p/discover"
    31  )
    32  
    33  func TestMocker(t *testing.T) {
    34  	//start the simulation HTTP server
    35  	_, s := testHTTPServer(t)
    36  	defer s.Close()
    37  
    38  	//create a client
    39  	client := NewClient(s.URL)
    40  
    41  	//start the network
    42  	err := client.StartNetwork()
    43  	if err != nil {
    44  		t.Fatalf("Could not start test network: %s", err)
    45  	}
    46  	//stop the network to terminate
    47  	defer func() {
    48  		err = client.StopNetwork()
    49  		if err != nil {
    50  			t.Fatalf("Could not stop test network: %s", err)
    51  		}
    52  	}()
    53  
    54  	//get the list of available mocker types
    55  	resp, err := http.Get(s.URL + "/mocker")
    56  	if err != nil {
    57  		t.Fatalf("Could not get mocker list: %s", err)
    58  	}
    59  	defer resp.Body.Close()
    60  
    61  	if resp.StatusCode != 200 {
    62  		t.Fatalf("Invalid Status Code received, expected 200, got %d", resp.StatusCode)
    63  	}
    64  
    65  	//check the list is at least 1 in size
    66  	var mockerlist []string
    67  	err = json.NewDecoder(resp.Body).Decode(&mockerlist)
    68  	if err != nil {
    69  		t.Fatalf("Error decoding JSON mockerlist: %s", err)
    70  	}
    71  
    72  	if len(mockerlist) < 1 {
    73  		t.Fatalf("No mockers available")
    74  	}
    75  
    76  	nodeCount := 10
    77  	var wg sync.WaitGroup
    78  
    79  	events := make(chan *Event, 10)
    80  	var opts SubscribeOpts
    81  	sub, err := client.SubscribeNetwork(events, opts)
    82  	defer sub.Unsubscribe()
    83  	//wait until all nodes are started and connected
    84  	//store every node up event in a map (value is irrelevant, mimic Set datatype)
    85  	nodemap := make(map[discover.NodeID]bool)
    86  	wg.Add(1)
    87  	nodesComplete := false
    88  	connCount := 0
    89  	go func() {
    90  		for {
    91  			select {
    92  			case event := <-events:
    93  				//if the event is a node Up event only
    94  				if event.Node != nil && event.Node.Up {
    95  					//add the correspondent node ID to the map
    96  					nodemap[event.Node.Config.ID] = true
    97  					//this means all nodes got a nodeUp event, so we can continue the test
    98  					if len(nodemap) == nodeCount {
    99  						nodesComplete = true
   100  						//wait for 3s as the mocker will need time to connect the nodes
   101  						//time.Sleep( 3 *time.Second)
   102  					}
   103  				} else if event.Conn != nil && nodesComplete {
   104  					connCount += 1
   105  					if connCount == (nodeCount-1)*2 {
   106  						wg.Done()
   107  						return
   108  					}
   109  				}
   110  			case <-time.After(30 * time.Second):
   111  				wg.Done()
   112  				t.Errorf("Timeout waiting for nodes being started up!")
   113  			}
   114  		}
   115  	}()
   116  
   117  	//take the last element of the mockerlist as the default mocker-type to ensure one is enabled
   118  	mockertype := mockerlist[len(mockerlist)-1]
   119  	//still, use hardcoded "probabilistic" one if available ;)
   120  	for _, m := range mockerlist {
   121  		if m == "probabilistic" {
   122  			mockertype = m
   123  			break
   124  		}
   125  	}
   126  	//start the mocker with nodeCount number of nodes
   127  	resp, err = http.PostForm(s.URL+"/mocker/start", url.Values{"mocker-type": {mockertype}, "node-count": {strconv.Itoa(nodeCount)}})
   128  	if err != nil {
   129  		t.Fatalf("Could not start mocker: %s", err)
   130  	}
   131  	if resp.StatusCode != 200 {
   132  		t.Fatalf("Invalid Status Code received for starting mocker, expected 200, got %d", resp.StatusCode)
   133  	}
   134  
   135  	wg.Wait()
   136  
   137  	//check there are nodeCount number of nodes in the network
   138  	nodes_info, err := client.GetNodes()
   139  	if err != nil {
   140  		t.Fatalf("Could not get nodes list: %s", err)
   141  	}
   142  
   143  	if len(nodes_info) != nodeCount {
   144  		t.Fatalf("Expected %d number of nodes, got: %d", nodeCount, len(nodes_info))
   145  	}
   146  
   147  	//stop the mocker
   148  	resp, err = http.Post(s.URL+"/mocker/stop", "", nil)
   149  	if err != nil {
   150  		t.Fatalf("Could not stop mocker: %s", err)
   151  	}
   152  	if resp.StatusCode != 200 {
   153  		t.Fatalf("Invalid Status Code received for stopping mocker, expected 200, got %d", resp.StatusCode)
   154  	}
   155  
   156  	//reset the network
   157  	_, err = http.Post(s.URL+"/reset", "", nil)
   158  	if err != nil {
   159  		t.Fatalf("Could not reset network: %s", err)
   160  	}
   161  
   162  	//now the number of nodes in the network should be zero
   163  	nodes_info, err = client.GetNodes()
   164  	if err != nil {
   165  		t.Fatalf("Could not get nodes list: %s", err)
   166  	}
   167  
   168  	if len(nodes_info) != 0 {
   169  		t.Fatalf("Expected empty list of nodes, got: %d", len(nodes_info))
   170  	}
   171  }