network/simulation: Add ExecAdapter capability to swarm simulations (#1503)

This commit is contained in:
lash
2019-06-24 09:48:40 +02:00
committed by Anton Evangelatov
parent 8afb316399
commit a0a14cc11c
18 changed files with 107 additions and 54 deletions

View File

@ -32,7 +32,7 @@ func TestServiceBucket(t *testing.T) {
testKey := "Key"
testValue := "Value"
sim := New(map[string]ServiceFunc{
sim := NewInProc(map[string]ServiceFunc{
"noop": func(ctx *adapters.ServiceContext, b *sync.Map) (node.Service, func(), error) {
b.Store(testKey, testValue+ctx.Config.ID.String())
return newNoopService(), nil, nil

View File

@ -28,7 +28,7 @@ import (
// and waits for the number of connection events to
// be received.
func TestPeerEvents(t *testing.T) {
sim := New(noopServiceFuncMap)
sim := NewInProc(noopServiceFuncMap)
defer sim.Close()
_, err := sim.AddNodes(2)
@ -68,7 +68,7 @@ func TestPeerEvents(t *testing.T) {
}
func TestPeerEventsTimeout(t *testing.T) {
sim := New(noopServiceFuncMap)
sim := NewInProc(noopServiceFuncMap)
defer sim.Close()
_, err := sim.AddNodes(2)

View File

@ -34,7 +34,7 @@ import (
// all nodes have the their Kademlias healthy.
func ExampleSimulation_WaitTillHealthy() {
sim := simulation.New(map[string]simulation.ServiceFunc{
sim := simulation.NewInProc(map[string]simulation.ServiceFunc{
"bzz": func(ctx *adapters.ServiceContext, b *sync.Map) (node.Service, func(), error) {
addr := network.NewAddr(ctx.Config.Node())
hp := network.NewHiveParams()
@ -77,7 +77,7 @@ func ExampleSimulation_WaitTillHealthy() {
// Watch all peer events in the simulation network, buy receiving from a channel.
func ExampleSimulation_PeerEvents() {
sim := simulation.New(nil)
sim := simulation.NewInProc(nil)
defer sim.Close()
events := sim.PeerEvents(context.Background(), sim.NodeIDs())
@ -95,7 +95,7 @@ func ExampleSimulation_PeerEvents() {
// Detect when a nodes drop a peer.
func ExampleSimulation_PeerEvents_disconnections() {
sim := simulation.New(nil)
sim := simulation.NewInProc(nil)
defer sim.Close()
disconnections := sim.PeerEvents(
@ -118,7 +118,7 @@ func ExampleSimulation_PeerEvents_disconnections() {
// Watch multiple types of events or messages. In this case, they differ only
// by MsgCode, but filters can be set for different types or protocols, too.
func ExampleSimulation_PeerEvents_multipleFilters() {
sim := simulation.New(nil)
sim := simulation.NewInProc(nil)
defer sim.Close()
msgs := sim.PeerEvents(

View File

@ -35,7 +35,7 @@ func TestSimulationWithHTTPServer(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
defer cancel()
sim := New(
sim := NewInProc(
map[string]ServiceFunc{
"noop": func(_ *adapters.ServiceContext, b *sync.Map) (node.Service, func(), error) {
return newNoopService(), nil, nil

View File

@ -46,7 +46,7 @@ func TestWaitTillHealthy(t *testing.T) {
testNodesNum := 10
// create the first simulation
sim := New(createSimServiceMap(true))
sim := NewInProc(createSimServiceMap(true))
// connect and...
nodeIDs, err := sim.AddNodesAndConnectRing(testNodesNum)
@ -88,7 +88,7 @@ func TestWaitTillHealthy(t *testing.T) {
// close the initial simulation
sim.Close()
// create a control simulation
controlSim := New(createSimServiceMap(false))
controlSim := NewInProc(createSimServiceMap(false))
defer controlSim.Close()
// load the snapshot into this control simulation
@ -158,7 +158,7 @@ func createSimServiceMap(discovery bool) map[string]ServiceFunc {
func TestWaitTillSnapshotRecreated(t *testing.T) {
t.Skip("test is flaky. disabling until underlying problem is addressed")
var err error
sim := New(createSimServiceMap(true))
sim := NewInProc(createSimServiceMap(true))
_, err = sim.AddNodesAndConnectRing(16)
if err != nil {
t.Fatal(err)
@ -177,7 +177,7 @@ func TestWaitTillSnapshotRecreated(t *testing.T) {
t.Fatal(err)
}
controlSim := New(createSimServiceMap(false))
controlSim := NewInProc(createSimServiceMap(false))
defer controlSim.Close()
err = controlSim.Net.Load(snap)
if err != nil {

View File

@ -32,7 +32,7 @@ import (
)
func TestUpDownNodeIDs(t *testing.T) {
sim := New(noopServiceFuncMap)
sim := NewInProc(noopServiceFuncMap)
defer sim.Close()
ids, err := sim.AddNodes(10)
@ -99,7 +99,7 @@ func equalNodeIDs(one, other []enode.ID) bool {
}
func TestAddNode(t *testing.T) {
sim := New(noopServiceFuncMap)
sim := NewInProc(noopServiceFuncMap)
defer sim.Close()
id, err := sim.AddNode()
@ -118,7 +118,7 @@ func TestAddNode(t *testing.T) {
}
func TestAddNodeWithMsgEvents(t *testing.T) {
sim := New(noopServiceFuncMap)
sim := NewInProc(noopServiceFuncMap)
defer sim.Close()
id, err := sim.AddNode(AddNodeWithMsgEvents(true))
@ -141,7 +141,7 @@ func TestAddNodeWithMsgEvents(t *testing.T) {
}
func TestAddNodeWithService(t *testing.T) {
sim := New(map[string]ServiceFunc{
sim := NewInProc(map[string]ServiceFunc{
"noop1": noopServiceFunc,
"noop2": noopServiceFunc,
})
@ -162,7 +162,7 @@ func TestAddNodeWithService(t *testing.T) {
}
func TestAddNodeMultipleServices(t *testing.T) {
sim := New(map[string]ServiceFunc{
sim := NewInProc(map[string]ServiceFunc{
"noop1": noopServiceFunc,
"noop2": noopService2Func,
})
@ -183,7 +183,7 @@ func TestAddNodeMultipleServices(t *testing.T) {
}
func TestAddNodeDuplicateServiceError(t *testing.T) {
sim := New(map[string]ServiceFunc{
sim := NewInProc(map[string]ServiceFunc{
"noop1": noopServiceFunc,
"noop2": noopServiceFunc,
})
@ -197,7 +197,7 @@ func TestAddNodeDuplicateServiceError(t *testing.T) {
}
func TestAddNodes(t *testing.T) {
sim := New(noopServiceFuncMap)
sim := NewInProc(noopServiceFuncMap)
defer sim.Close()
nodesCount := 12
@ -219,7 +219,7 @@ func TestAddNodes(t *testing.T) {
}
func TestAddNodesAndConnectFull(t *testing.T) {
sim := New(noopServiceFuncMap)
sim := NewInProc(noopServiceFuncMap)
defer sim.Close()
n := 12
@ -233,7 +233,7 @@ func TestAddNodesAndConnectFull(t *testing.T) {
}
func TestAddNodesAndConnectChain(t *testing.T) {
sim := New(noopServiceFuncMap)
sim := NewInProc(noopServiceFuncMap)
defer sim.Close()
_, err := sim.AddNodesAndConnectChain(12)
@ -252,7 +252,7 @@ func TestAddNodesAndConnectChain(t *testing.T) {
}
func TestAddNodesAndConnectRing(t *testing.T) {
sim := New(noopServiceFuncMap)
sim := NewInProc(noopServiceFuncMap)
defer sim.Close()
ids, err := sim.AddNodesAndConnectRing(12)
@ -264,7 +264,7 @@ func TestAddNodesAndConnectRing(t *testing.T) {
}
func TestAddNodesAndConnectStar(t *testing.T) {
sim := New(noopServiceFuncMap)
sim := NewInProc(noopServiceFuncMap)
defer sim.Close()
ids, err := sim.AddNodesAndConnectStar(12)
@ -278,7 +278,7 @@ func TestAddNodesAndConnectStar(t *testing.T) {
//To test that uploading a snapshot works
func TestUploadSnapshot(t *testing.T) {
log.Debug("Creating simulation")
s := New(map[string]ServiceFunc{
s := NewInProc(map[string]ServiceFunc{
"bzz": func(ctx *adapters.ServiceContext, b *sync.Map) (node.Service, func(), error) {
addr := network.NewAddr(ctx.Config.Node())
hp := network.NewHiveParams()
@ -317,7 +317,7 @@ func TestUploadSnapshot(t *testing.T) {
}
func TestStartStopNode(t *testing.T) {
sim := New(noopServiceFuncMap)
sim := NewInProc(noopServiceFuncMap)
defer sim.Close()
id, err := sim.AddNode()
@ -353,7 +353,7 @@ func TestStartStopNode(t *testing.T) {
}
func TestStartStopRandomNode(t *testing.T) {
sim := New(noopServiceFuncMap)
sim := NewInProc(noopServiceFuncMap)
defer sim.Close()
_, err := sim.AddNodes(3)
@ -392,7 +392,7 @@ func TestStartStopRandomNode(t *testing.T) {
}
func TestStartStopRandomNodes(t *testing.T) {
sim := New(noopServiceFuncMap)
sim := NewInProc(noopServiceFuncMap)
defer sim.Close()
_, err := sim.AddNodes(10)

View File

@ -21,7 +21,7 @@ import (
)
func TestService(t *testing.T) {
sim := New(noopServiceFuncMap)
sim := NewInProc(noopServiceFuncMap)
defer sim.Close()
id, err := sim.AddNode()

View File

@ -19,7 +19,9 @@ package simulation
import (
"context"
"errors"
"io/ioutil"
"net/http"
"os"
"sync"
"time"
@ -31,6 +33,11 @@ import (
"github.com/ethersphere/swarm/network"
)
const (
SimulationTypeInproc = iota
SimulationTypeExec
)
// Common errors that are returned by functions in this package.
var (
ErrNodeNotFound = errors.New("node not found")
@ -50,6 +57,8 @@ type Simulation struct {
done chan struct{}
mu sync.RWMutex
neighbourhoodSize int
baseDir string
typ int
httpSrv *http.Server //attach a HTTP server via SimulationOptions
handler *simulations.Server //HTTP handler for the server
@ -71,19 +80,66 @@ type ServiceFunc func(ctx *adapters.ServiceContext, bucket *sync.Map) (s node.Se
// every ServiceFunc must return a node.Service of the unique type.
// This restriction is required by node.Node.Start() function
// which is used to start node.Service returned by ServiceFunc.
func New(services map[string]ServiceFunc) (s *Simulation) {
func NewInProc(services map[string]ServiceFunc) (s *Simulation) {
s = &Simulation{
buckets: make(map[enode.ID]*sync.Map),
done: make(chan struct{}),
neighbourhoodSize: network.NewKadParams().NeighbourhoodSize,
typ: SimulationTypeInproc,
}
s.addServices(services)
adapterServices := s.toAdapterServices(services)
s.Net = simulations.NewNetwork(
adapters.NewTCPAdapter(adapterServices),
&simulations.NetworkConfig{ID: "0"},
)
return s
}
// NewExec does the same as New but lets the caller specify the adapter to use
func NewExec(services map[string]ServiceFunc) (s *Simulation, err error) {
s = &Simulation{
buckets: make(map[enode.ID]*sync.Map),
done: make(chan struct{}),
neighbourhoodSize: network.NewKadParams().NeighbourhoodSize,
typ: SimulationTypeExec,
}
s.addServices(services)
adapterServices := s.toAdapterServices(services)
// exec adapters register services up front, not at node creation time
adapters.RegisterServices(adapterServices)
s.baseDir, err = ioutil.TempDir("", "swarm-sim")
if err != nil {
return nil, err
}
s.Net = simulations.NewNetwork(
adapters.NewExecAdapter(s.baseDir),
&simulations.NetworkConfig{ID: "0"},
)
return s, nil
}
// add names of available services to simulation
func (s *Simulation) addServices(services map[string]ServiceFunc) {
for name := range services {
s.serviceNames = append(s.serviceNames, name)
}
}
// convert services array for use with adapters.RegisterServices
func (s *Simulation) toAdapterServices(services map[string]ServiceFunc) map[string]adapters.ServiceFunc {
adapterServices := make(map[string]adapters.ServiceFunc, len(services))
for name, serviceFunc := range services {
// Scope this variables correctly
// as they will be in the adapterServices[name] function accessed later.
name, serviceFunc := name, serviceFunc
s.serviceNames = append(s.serviceNames, name)
adapterServices[name] = func(ctx *adapters.ServiceContext) (node.Service, error) {
s.mu.Lock()
defer s.mu.Unlock()
@ -102,13 +158,7 @@ func New(services map[string]ServiceFunc) (s *Simulation) {
return service, nil
}
}
s.Net = simulations.NewNetwork(
adapters.NewTCPAdapter(adapterServices),
&simulations.NetworkConfig{ID: "0"},
)
return s
return adapterServices
}
// RunFunc is the function that will be called
@ -208,6 +258,9 @@ func (s *Simulation) Close() {
s.shutdownWG.Wait()
s.Net.Shutdown()
if s.baseDir != "" {
os.RemoveAll(s.baseDir)
}
}
// Done returns a channel that is closed when the simulation

View File

@ -43,7 +43,7 @@ func init() {
// TestRun tests if Run method calls RunFunc and if it handles context properly.
func TestRun(t *testing.T) {
sim := New(noopServiceFuncMap)
sim := NewInProc(noopServiceFuncMap)
defer sim.Close()
t.Run("call", func(t *testing.T) {
@ -104,7 +104,7 @@ func TestClose(t *testing.T) {
sleep := 50 * time.Millisecond
sim := New(map[string]ServiceFunc{
sim := NewInProc(map[string]ServiceFunc{
"noop": func(ctx *adapters.ServiceContext, b *sync.Map) (node.Service, func(), error) {
return newNoopService(), func() {
time.Sleep(sleep)
@ -151,7 +151,7 @@ func TestClose(t *testing.T) {
// TestDone checks if Close method triggers the closing of done channel.
func TestDone(t *testing.T) {
sim := New(noopServiceFuncMap)
sim := NewInProc(noopServiceFuncMap)
sleep := 50 * time.Millisecond
timeout := 2 * time.Second