github.com/shyftnetwork/go-empyrean@v1.8.3-0.20191127201940-fbfca9338f04/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/ShyftNetwork/go-empyrean/log" 28 "github.com/ShyftNetwork/go-empyrean/node" 29 "github.com/ShyftNetwork/go-empyrean/p2p/simulations" 30 "github.com/ShyftNetwork/go-empyrean/p2p/simulations/adapters" 31 colorable "github.com/mattn/go-colorable" 32 ) 33 34 var ( 35 loglevel = flag.Int("loglevel", 2, "verbosity of logs") 36 ) 37 38 func init() { 39 flag.Parse() 40 log.PrintOrigins(true) 41 log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(colorable.NewColorableStderr(), log.TerminalFormat(true)))) 42 } 43 44 // TestRun tests if Run method calls RunFunc and if it handles context properly. 45 func TestRun(t *testing.T) { 46 sim := New(noopServiceFuncMap) 47 defer sim.Close() 48 49 t.Run("call", func(t *testing.T) { 50 expect := "something" 51 var got string 52 r := sim.Run(context.Background(), func(ctx context.Context, sim *Simulation) error { 53 got = expect 54 return nil 55 }) 56 57 if r.Error != nil { 58 t.Errorf("unexpected error: %v", r.Error) 59 } 60 if got != expect { 61 t.Errorf("expected %q, got %q", expect, got) 62 } 63 }) 64 65 t.Run("cancellation", func(t *testing.T) { 66 ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond) 67 defer cancel() 68 69 r := sim.Run(ctx, func(ctx context.Context, sim *Simulation) error { 70 time.Sleep(time.Second) 71 return nil 72 }) 73 74 if r.Error != context.DeadlineExceeded { 75 t.Errorf("unexpected error: %v", r.Error) 76 } 77 }) 78 79 t.Run("context value and duration", func(t *testing.T) { 80 ctx := context.WithValue(context.Background(), "hey", "there") 81 sleep := 50 * time.Millisecond 82 83 r := sim.Run(ctx, func(ctx context.Context, sim *Simulation) error { 84 if ctx.Value("hey") != "there" { 85 return errors.New("expected context value not passed") 86 } 87 time.Sleep(sleep) 88 return nil 89 }) 90 91 if r.Error != nil { 92 t.Errorf("unexpected error: %v", r.Error) 93 } 94 if r.Duration < sleep { 95 t.Errorf("reported run duration less then expected: %s", r.Duration) 96 } 97 }) 98 } 99 100 // TestClose tests are Close method triggers all close functions and are all nodes not up anymore. 101 func TestClose(t *testing.T) { 102 var mu sync.Mutex 103 var cleanupCount int 104 105 sleep := 50 * time.Millisecond 106 107 sim := New(map[string]ServiceFunc{ 108 "noop": func(ctx *adapters.ServiceContext, b *sync.Map) (node.Service, func(), error) { 109 return newNoopService(), func() { 110 time.Sleep(sleep) 111 mu.Lock() 112 defer mu.Unlock() 113 cleanupCount++ 114 }, nil 115 }, 116 }) 117 118 nodeCount := 30 119 120 _, err := sim.AddNodes(nodeCount) 121 if err != nil { 122 t.Fatal(err) 123 } 124 125 var upNodeCount int 126 for _, n := range sim.Net.GetNodes() { 127 if n.Up { 128 upNodeCount++ 129 } 130 } 131 if upNodeCount != nodeCount { 132 t.Errorf("all nodes should be up, insted only %v are up", upNodeCount) 133 } 134 135 sim.Close() 136 137 if cleanupCount != nodeCount { 138 t.Errorf("number of cleanups expected %v, got %v", nodeCount, cleanupCount) 139 } 140 141 upNodeCount = 0 142 for _, n := range sim.Net.GetNodes() { 143 if n.Up { 144 upNodeCount++ 145 } 146 } 147 if upNodeCount != 0 { 148 t.Errorf("all nodes should be down, insted %v are up", upNodeCount) 149 } 150 } 151 152 // TestDone checks if Close method triggers the closing of done channel. 153 func TestDone(t *testing.T) { 154 sim := New(noopServiceFuncMap) 155 sleep := 50 * time.Millisecond 156 timeout := 2 * time.Second 157 158 start := time.Now() 159 go func() { 160 time.Sleep(sleep) 161 sim.Close() 162 }() 163 164 select { 165 case <-time.After(timeout): 166 t.Error("done channel closing timed out") 167 case <-sim.Done(): 168 if d := time.Since(start); d < sleep { 169 t.Errorf("done channel closed sooner then expected: %s", d) 170 } 171 } 172 } 173 174 // a helper map for usual services that do not do anything 175 var noopServiceFuncMap = map[string]ServiceFunc{ 176 "noop": noopServiceFunc, 177 } 178 179 // a helper function for most basic noop service 180 func noopServiceFunc(_ *adapters.ServiceContext, _ *sync.Map) (node.Service, func(), error) { 181 return newNoopService(), nil, nil 182 } 183 184 func newNoopService() node.Service { 185 return &noopService{} 186 } 187 188 // a helper function for most basic Noop service 189 // of a different type then NoopService to test 190 // multiple services on one node. 191 func noopService2Func(_ *adapters.ServiceContext, _ *sync.Map) (node.Service, func(), error) { 192 return new(noopService2), nil, nil 193 } 194 195 // NoopService2 is the service that does not do anything 196 // but implements node.Service interface. 197 type noopService2 struct { 198 simulations.NoopService 199 } 200 201 type noopService struct { 202 simulations.NoopService 203 }