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 }