mirror of https://github.com/ethereum/go-ethereum
Fix a conflict in cmd/swarm envVarsOverride function.pull/15748/head
commit
47a8014559
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,35 @@ |
||||
// 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 adapters |
||||
|
||||
type SimStateStore struct { |
||||
m map[string][]byte |
||||
} |
||||
|
||||
func (self *SimStateStore) Load(s string) ([]byte, error) { |
||||
return self.m[s], nil |
||||
} |
||||
|
||||
func (self *SimStateStore) Save(s string, data []byte) error { |
||||
self.m[s] = data |
||||
return nil |
||||
} |
||||
|
||||
func NewSimStateStore() *SimStateStore { |
||||
return &SimStateStore{ |
||||
make(map[string][]byte), |
||||
} |
||||
} |
@ -0,0 +1,192 @@ |
||||
// 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.
|
||||
// A mocker simulates starting and stopping real nodes in a network.
|
||||
package simulations |
||||
|
||||
import ( |
||||
"fmt" |
||||
"math/rand" |
||||
"sync" |
||||
"time" |
||||
|
||||
"github.com/ethereum/go-ethereum/log" |
||||
"github.com/ethereum/go-ethereum/p2p/discover" |
||||
) |
||||
|
||||
//a map of mocker names to its function
|
||||
var mockerList = map[string]func(net *Network, quit chan struct{}, nodeCount int){ |
||||
"startStop": startStop, |
||||
"probabilistic": probabilistic, |
||||
"boot": boot, |
||||
} |
||||
|
||||
//Lookup a mocker by its name, returns the mockerFn
|
||||
func LookupMocker(mockerType string) func(net *Network, quit chan struct{}, nodeCount int) { |
||||
return mockerList[mockerType] |
||||
} |
||||
|
||||
//Get a list of mockers (keys of the map)
|
||||
//Useful for frontend to build available mocker selection
|
||||
func GetMockerList() []string { |
||||
list := make([]string, 0, len(mockerList)) |
||||
for k := range mockerList { |
||||
list = append(list, k) |
||||
} |
||||
return list |
||||
} |
||||
|
||||
//The boot mockerFn only connects the node in a ring and doesn't do anything else
|
||||
func boot(net *Network, quit chan struct{}, nodeCount int) { |
||||
_, err := connectNodesInRing(net, nodeCount) |
||||
if err != nil { |
||||
panic("Could not startup node network for mocker") |
||||
} |
||||
} |
||||
|
||||
//The startStop mockerFn stops and starts nodes in a defined period (ticker)
|
||||
func startStop(net *Network, quit chan struct{}, nodeCount int) { |
||||
nodes, err := connectNodesInRing(net, nodeCount) |
||||
if err != nil { |
||||
panic("Could not startup node network for mocker") |
||||
} |
||||
tick := time.NewTicker(10 * time.Second) |
||||
defer tick.Stop() |
||||
for { |
||||
select { |
||||
case <-quit: |
||||
log.Info("Terminating simulation loop") |
||||
return |
||||
case <-tick.C: |
||||
id := nodes[rand.Intn(len(nodes))] |
||||
log.Info("stopping node", "id", id) |
||||
if err := net.Stop(id); err != nil { |
||||
log.Error("error stopping node", "id", id, "err", err) |
||||
return |
||||
} |
||||
|
||||
select { |
||||
case <-quit: |
||||
log.Info("Terminating simulation loop") |
||||
return |
||||
case <-time.After(3 * time.Second): |
||||
} |
||||
|
||||
log.Debug("starting node", "id", id) |
||||
if err := net.Start(id); err != nil { |
||||
log.Error("error starting node", "id", id, "err", err) |
||||
return |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
//The probabilistic mocker func has a more probabilistic pattern
|
||||
//(the implementation could probably be improved):
|
||||
//nodes are connected in a ring, then a varying number of random nodes is selected,
|
||||
//mocker then stops and starts them in random intervals, and continues the loop
|
||||
func probabilistic(net *Network, quit chan struct{}, nodeCount int) { |
||||
nodes, err := connectNodesInRing(net, nodeCount) |
||||
if err != nil { |
||||
panic("Could not startup node network for mocker") |
||||
} |
||||
for { |
||||
select { |
||||
case <-quit: |
||||
log.Info("Terminating simulation loop") |
||||
return |
||||
default: |
||||
} |
||||
var lowid, highid int |
||||
var wg sync.WaitGroup |
||||
randWait := time.Duration(rand.Intn(5000)+1000) * time.Millisecond |
||||
rand1 := rand.Intn(nodeCount - 1) |
||||
rand2 := rand.Intn(nodeCount - 1) |
||||
if rand1 < rand2 { |
||||
lowid = rand1 |
||||
highid = rand2 |
||||
} else if rand1 > rand2 { |
||||
highid = rand1 |
||||
lowid = rand2 |
||||
} else { |
||||
if rand1 == 0 { |
||||
rand2 = 9 |
||||
} else if rand1 == 9 { |
||||
rand1 = 0 |
||||
} |
||||
lowid = rand1 |
||||
highid = rand2 |
||||
} |
||||
var steps = highid - lowid |
||||
wg.Add(steps) |
||||
for i := lowid; i < highid; i++ { |
||||
select { |
||||
case <-quit: |
||||
log.Info("Terminating simulation loop") |
||||
return |
||||
case <-time.After(randWait): |
||||
} |
||||
log.Debug(fmt.Sprintf("node %v shutting down", nodes[i])) |
||||
err := net.Stop(nodes[i]) |
||||
if err != nil { |
||||
log.Error(fmt.Sprintf("Error stopping node %s", nodes[i])) |
||||
wg.Done() |
||||
continue |
||||
} |
||||
go func(id discover.NodeID) { |
||||
time.Sleep(randWait) |
||||
err := net.Start(id) |
||||
if err != nil { |
||||
log.Error(fmt.Sprintf("Error starting node %s", id)) |
||||
} |
||||
wg.Done() |
||||
}(nodes[i]) |
||||
} |
||||
wg.Wait() |
||||
} |
||||
|
||||
} |
||||
|
||||
//connect nodeCount number of nodes in a ring
|
||||
func connectNodesInRing(net *Network, nodeCount int) ([]discover.NodeID, error) { |
||||
ids := make([]discover.NodeID, nodeCount) |
||||
for i := 0; i < nodeCount; i++ { |
||||
node, err := net.NewNode() |
||||
if err != nil { |
||||
log.Error("Error creating a node! %s", err) |
||||
return nil, err |
||||
} |
||||
ids[i] = node.ID() |
||||
} |
||||
|
||||
for _, id := range ids { |
||||
if err := net.Start(id); err != nil { |
||||
log.Error("Error starting a node! %s", err) |
||||
return nil, err |
||||
} |
||||
log.Debug(fmt.Sprintf("node %v starting up", id)) |
||||
} |
||||
for i, id := range ids { |
||||
peerID := ids[(i+1)%len(ids)] |
||||
if err := net.Connect(id, peerID); err != nil { |
||||
log.Error("Error connecting a node to a peer! %s", err) |
||||
return nil, err |
||||
} |
||||
} |
||||
|
||||
return ids, nil |
||||
} |
@ -0,0 +1,171 @@ |
||||
// 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.
|
||||
// A mokcer simulates starting and stopping real nodes in a network.
|
||||
package simulations |
||||
|
||||
import ( |
||||
"encoding/json" |
||||
"net/http" |
||||
"net/url" |
||||
"strconv" |
||||
"sync" |
||||
"testing" |
||||
"time" |
||||
|
||||
"github.com/ethereum/go-ethereum/p2p/discover" |
||||
) |
||||
|
||||
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() |
||||
//wait until all nodes are started and connected
|
||||
//store every node up event in a map (value is irrelevant, mimic Set datatype)
|
||||
nodemap := make(map[discover.NodeID]bool) |
||||
wg.Add(1) |
||||
nodesComplete := false |
||||
connCount := 0 |
||||
go func() { |
||||
for { |
||||
select { |
||||
case event := <-events: |
||||
//if the event is a node Up event only
|
||||
if event.Node != nil && event.Node.Up { |
||||
//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 |
||||
//wait for 3s as the mocker will need time to connect the nodes
|
||||
//time.Sleep( 3 *time.Second)
|
||||
} |
||||
} else if event.Conn != nil && nodesComplete { |
||||
connCount += 1 |
||||
if connCount == (nodeCount-1)*2 { |
||||
wg.Done() |
||||
return |
||||
} |
||||
} |
||||
case <-time.After(30 * time.Second): |
||||
wg.Done() |
||||
t.Fatalf("Timeout waiting for nodes being started up!") |
||||
} |
||||
} |
||||
}() |
||||
|
||||
//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
|
||||
nodes_info, err := client.GetNodes() |
||||
if err != nil { |
||||
t.Fatalf("Could not get nodes list: %s", err) |
||||
} |
||||
|
||||
if len(nodes_info) != nodeCount { |
||||
t.Fatalf("Expected %d number of nodes, got: %d", nodeCount, len(nodes_info)) |
||||
} |
||||
|
||||
//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
|
||||
nodes_info, err = client.GetNodes() |
||||
if err != nil { |
||||
t.Fatalf("Could not get nodes list: %s", err) |
||||
} |
||||
|
||||
if len(nodes_info) != 0 { |
||||
t.Fatalf("Expected empty list of nodes, got: %d", len(nodes_info)) |
||||
} |
||||
} |
Loading…
Reference in new issue