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