mocker_test.go 4.7 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
			}
		}
	}()

	//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)
	}
127
	resp.Body.Close()
128 129 130 131 132 133 134
	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
135
	nodesInfo, err := client.GetNodes()
136 137 138 139
	if err != nil {
		t.Fatalf("Could not get nodes list: %s", err)
	}

140 141
	if len(nodesInfo) != nodeCount {
		t.Fatalf("Expected %d number of nodes, got: %d", nodeCount, len(nodesInfo))
142 143 144 145 146 147 148
	}

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

	//reset the network
155
	resp, err = http.Post(s.URL+"/reset", "", nil)
156 157 158
	if err != nil {
		t.Fatalf("Could not reset network: %s", err)
	}
159
	resp.Body.Close()
160 161

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

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

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