mocker_test.go 4.64 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
// Copyright 2017 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.

// Package simulations simulates p2p networks.
18
// A mocker simulates starting and stopping real nodes in a network.
19 20 21 22 23 24 25 26 27 28 29
package simulations

import (
	"encoding/json"
	"net/http"
	"net/url"
	"strconv"
	"sync"
	"testing"
	"time"

30
	"github.com/ethereum/go-ethereum/p2p/enode"
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
)

func TestMocker(t *testing.T) {
	//start the simulation HTTP server
	_, s := testHTTPServer(t)
	defer s.Close()

	//create a client
	client := NewClient(s.URL)

	//start the network
	err := client.StartNetwork()
	if err != nil {
		t.Fatalf("Could not start test network: %s", err)
	}
	//stop the network to terminate
	defer func() {
		err = client.StopNetwork()
		if err != nil {
			t.Fatalf("Could not stop test network: %s", err)
		}
	}()

	//get the list of available mocker types
	resp, err := http.Get(s.URL + "/mocker")
	if err != nil {
		t.Fatalf("Could not get mocker list: %s", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != 200 {
		t.Fatalf("Invalid Status Code received, expected 200, got %d", resp.StatusCode)
	}

	//check the list is at least 1 in size
	var mockerlist []string
	err = json.NewDecoder(resp.Body).Decode(&mockerlist)
	if err != nil {
		t.Fatalf("Error decoding JSON mockerlist: %s", err)
	}

	if len(mockerlist) < 1 {
		t.Fatalf("No mockers available")
	}

	nodeCount := 10
	var wg sync.WaitGroup

	events := make(chan *Event, 10)
	var opts SubscribeOpts
	sub, err := client.SubscribeNetwork(events, opts)
	defer sub.Unsubscribe()
83 84 85

	// wait until all nodes are started and connected
	// store every node up event in a map (value is irrelevant, mimic Set datatype)
86
	nodemap := make(map[enode.ID]bool)
87 88
	nodesComplete := false
	connCount := 0
89
	wg.Add(1)
90
	go func() {
91 92 93
		defer wg.Done()

		for connCount < (nodeCount-1)*2 {
94 95
			select {
			case event := <-events:
96
				if isNodeUp(event) {
97 98 99 100 101 102 103 104 105 106
					//add the correspondent node ID to the map
					nodemap[event.Node.Config.ID] = true
					//this means all nodes got a nodeUp event, so we can continue the test
					if len(nodemap) == nodeCount {
						nodesComplete = true
					}
				} else if event.Conn != nil && nodesComplete {
					connCount += 1
				}
			case <-time.After(30 * time.Second):
107 108
				t.Errorf("Timeout waiting for nodes being started up!")
				return
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
			}
		}
	}()

	//take the last element of the mockerlist as the default mocker-type to ensure one is enabled
	mockertype := mockerlist[len(mockerlist)-1]
	//still, use hardcoded "probabilistic" one if available ;)
	for _, m := range mockerlist {
		if m == "probabilistic" {
			mockertype = m
			break
		}
	}
	//start the mocker with nodeCount number of nodes
	resp, err = http.PostForm(s.URL+"/mocker/start", url.Values{"mocker-type": {mockertype}, "node-count": {strconv.Itoa(nodeCount)}})
	if err != nil {
		t.Fatalf("Could not start mocker: %s", err)
	}
	if resp.StatusCode != 200 {
		t.Fatalf("Invalid Status Code received for starting mocker, expected 200, got %d", resp.StatusCode)
	}

	wg.Wait()

	//check there are nodeCount number of nodes in the network
134
	nodesInfo, err := client.GetNodes()
135 136 137 138
	if err != nil {
		t.Fatalf("Could not get nodes list: %s", err)
	}

139 140
	if len(nodesInfo) != nodeCount {
		t.Fatalf("Expected %d number of nodes, got: %d", nodeCount, len(nodesInfo))
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
	}

	//stop the mocker
	resp, err = http.Post(s.URL+"/mocker/stop", "", nil)
	if err != nil {
		t.Fatalf("Could not stop mocker: %s", err)
	}
	if resp.StatusCode != 200 {
		t.Fatalf("Invalid Status Code received for stopping mocker, expected 200, got %d", resp.StatusCode)
	}

	//reset the network
	_, err = http.Post(s.URL+"/reset", "", nil)
	if err != nil {
		t.Fatalf("Could not reset network: %s", err)
	}

	//now the number of nodes in the network should be zero
159
	nodesInfo, err = client.GetNodes()
160 161 162 163
	if err != nil {
		t.Fatalf("Could not get nodes list: %s", err)
	}

164 165
	if len(nodesInfo) != 0 {
		t.Fatalf("Expected empty list of nodes, got: %d", len(nodesInfo))
166 167
	}
}
168 169 170 171

func isNodeUp(event *Event) bool {
	return event.Node != nil && event.Node.Up()
}