github.com/codingfuture/orig-energi3@v0.8.4/swarm/network/simulation/simulation_test.go (about)

     1  // Copyright 2018 The Energi Core Authors
     2  // Copyright 2018 The go-ethereum Authors
     3  // This file is part of the Energi Core library.
     4  //
     5  // The Energi Core library is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Lesser General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // The Energi Core library is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    13  // GNU Lesser General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Lesser General Public License
    16  // along with the Energi Core library. If not, see <http://www.gnu.org/licenses/>.
    17  
    18  package simulation
    19  
    20  import (
    21  	"context"
    22  	"errors"
    23  	"flag"
    24  	"sync"
    25  	"testing"
    26  	"time"
    27  
    28  	"github.com/ethereum/go-ethereum/log"
    29  	"github.com/ethereum/go-ethereum/node"
    30  	"github.com/ethereum/go-ethereum/p2p/simulations"
    31  	"github.com/ethereum/go-ethereum/p2p/simulations/adapters"
    32  	"github.com/mattn/go-colorable"
    33  )
    34  
    35  var (
    36  	loglevel = flag.Int("loglevel", 2, "verbosity of logs")
    37  )
    38  
    39  func init() {
    40  	testing.Init()
    41  	flag.Parse()
    42  	log.PrintOrigins(true)
    43  	log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(colorable.NewColorableStderr(), log.TerminalFormat(true))))
    44  }
    45  
    46  // TestRun tests if Run method calls RunFunc and if it handles context properly.
    47  func TestRun(t *testing.T) {
    48  	sim := New(noopServiceFuncMap)
    49  	defer sim.Close()
    50  
    51  	t.Run("call", func(t *testing.T) {
    52  		expect := "something"
    53  		var got string
    54  		r := sim.Run(context.Background(), func(ctx context.Context, sim *Simulation) error {
    55  			got = expect
    56  			return nil
    57  		})
    58  
    59  		if r.Error != nil {
    60  			t.Errorf("unexpected error: %v", r.Error)
    61  		}
    62  		if got != expect {
    63  			t.Errorf("expected %q, got %q", expect, got)
    64  		}
    65  	})
    66  
    67  	t.Run("cancellation", func(t *testing.T) {
    68  		ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)
    69  		defer cancel()
    70  
    71  		r := sim.Run(ctx, func(ctx context.Context, sim *Simulation) error {
    72  			time.Sleep(time.Second)
    73  			return nil
    74  		})
    75  
    76  		if r.Error != context.DeadlineExceeded {
    77  			t.Errorf("unexpected error: %v", r.Error)
    78  		}
    79  	})
    80  
    81  	t.Run("context value and duration", func(t *testing.T) {
    82  		ctx := context.WithValue(context.Background(), "hey", "there")
    83  		sleep := 50 * time.Millisecond
    84  
    85  		r := sim.Run(ctx, func(ctx context.Context, sim *Simulation) error {
    86  			if ctx.Value("hey") != "there" {
    87  				return errors.New("expected context value not passed")
    88  			}
    89  			time.Sleep(sleep)
    90  			return nil
    91  		})
    92  
    93  		if r.Error != nil {
    94  			t.Errorf("unexpected error: %v", r.Error)
    95  		}
    96  		if r.Duration < sleep {
    97  			t.Errorf("reported run duration less then expected: %s", r.Duration)
    98  		}
    99  	})
   100  }
   101  
   102  // TestClose tests are Close method triggers all close functions and are all nodes not up anymore.
   103  func TestClose(t *testing.T) {
   104  	var mu sync.Mutex
   105  	var cleanupCount int
   106  
   107  	sleep := 50 * time.Millisecond
   108  
   109  	sim := New(map[string]ServiceFunc{
   110  		"noop": func(ctx *adapters.ServiceContext, b *sync.Map) (node.Service, func(), error) {
   111  			return newNoopService(), func() {
   112  				time.Sleep(sleep)
   113  				mu.Lock()
   114  				defer mu.Unlock()
   115  				cleanupCount++
   116  			}, nil
   117  		},
   118  	})
   119  
   120  	nodeCount := 30
   121  
   122  	_, err := sim.AddNodes(nodeCount)
   123  	if err != nil {
   124  		t.Fatal(err)
   125  	}
   126  
   127  	var upNodeCount int
   128  	for _, n := range sim.Net.GetNodes() {
   129  		if n.Up() {
   130  			upNodeCount++
   131  		}
   132  	}
   133  	if upNodeCount != nodeCount {
   134  		t.Errorf("all nodes should be up, insted only %v are up", upNodeCount)
   135  	}
   136  
   137  	sim.Close()
   138  
   139  	if cleanupCount != nodeCount {
   140  		t.Errorf("number of cleanups expected %v, got %v", nodeCount, cleanupCount)
   141  	}
   142  
   143  	upNodeCount = 0
   144  	for _, n := range sim.Net.GetNodes() {
   145  		if n.Up() {
   146  			upNodeCount++
   147  		}
   148  	}
   149  	if upNodeCount != 0 {
   150  		t.Errorf("all nodes should be down, insted %v are up", upNodeCount)
   151  	}
   152  }
   153  
   154  // TestDone checks if Close method triggers the closing of done channel.
   155  func TestDone(t *testing.T) {
   156  	sim := New(noopServiceFuncMap)
   157  	sleep := 50 * time.Millisecond
   158  	timeout := 2 * time.Second
   159  
   160  	start := time.Now()
   161  	go func() {
   162  		time.Sleep(sleep)
   163  		sim.Close()
   164  	}()
   165  
   166  	select {
   167  	case <-time.After(timeout):
   168  		t.Error("done channel closing timed out")
   169  	case <-sim.Done():
   170  		if d := time.Since(start); d < sleep {
   171  			t.Errorf("done channel closed sooner then expected: %s", d)
   172  		}
   173  	}
   174  }
   175  
   176  // a helper map for usual services that do not do anything
   177  var noopServiceFuncMap = map[string]ServiceFunc{
   178  	"noop": noopServiceFunc,
   179  }
   180  
   181  // a helper function for most basic noop service
   182  func noopServiceFunc(_ *adapters.ServiceContext, _ *sync.Map) (node.Service, func(), error) {
   183  	return newNoopService(), nil, nil
   184  }
   185  
   186  func newNoopService() node.Service {
   187  	return &noopService{}
   188  }
   189  
   190  // a helper function for most basic Noop service
   191  // of a different type then NoopService to test
   192  // multiple services on one node.
   193  func noopService2Func(_ *adapters.ServiceContext, _ *sync.Map) (node.Service, func(), error) {
   194  	return new(noopService2), nil, nil
   195  }
   196  
   197  // NoopService2 is the service that does not do anything
   198  // but implements node.Service interface.
   199  type noopService2 struct {
   200  	simulations.NoopService
   201  }
   202  
   203  type noopService struct {
   204  	simulations.NoopService
   205  }