github.com/muhammedhassanm/blockchain@v0.0.0-20200120143007-697261defd4d/go-ethereum-master/cmd/swarm/run_test.go (about) 1 // Copyright 2017 The go-ethereum Authors 2 // This file is part of go-ethereum. 3 // 4 // go-ethereum is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU 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 // go-ethereum 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 General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. 16 17 package main 18 19 import ( 20 "fmt" 21 "io/ioutil" 22 "net" 23 "os" 24 "path/filepath" 25 "runtime" 26 "testing" 27 "time" 28 29 "github.com/docker/docker/pkg/reexec" 30 "github.com/ethereum/go-ethereum/accounts" 31 "github.com/ethereum/go-ethereum/accounts/keystore" 32 "github.com/ethereum/go-ethereum/internal/cmdtest" 33 "github.com/ethereum/go-ethereum/node" 34 "github.com/ethereum/go-ethereum/p2p" 35 "github.com/ethereum/go-ethereum/rpc" 36 "github.com/ethereum/go-ethereum/swarm" 37 ) 38 39 func init() { 40 // Run the app if we've been exec'd as "swarm-test" in runSwarm. 41 reexec.Register("swarm-test", func() { 42 if err := app.Run(os.Args); err != nil { 43 fmt.Fprintln(os.Stderr, err) 44 os.Exit(1) 45 } 46 os.Exit(0) 47 }) 48 } 49 50 func TestMain(m *testing.M) { 51 // check if we have been reexec'd 52 if reexec.Init() { 53 return 54 } 55 os.Exit(m.Run()) 56 } 57 58 func runSwarm(t *testing.T, args ...string) *cmdtest.TestCmd { 59 tt := cmdtest.NewTestCmd(t, nil) 60 61 // Boot "swarm". This actually runs the test binary but the TestMain 62 // function will prevent any tests from running. 63 tt.Run("swarm-test", args...) 64 65 return tt 66 } 67 68 type testCluster struct { 69 Nodes []*testNode 70 TmpDir string 71 } 72 73 // newTestCluster starts a test swarm cluster of the given size. 74 // 75 // A temporary directory is created and each node gets a data directory inside 76 // it. 77 // 78 // Each node listens on 127.0.0.1 with random ports for both the HTTP and p2p 79 // ports (assigned by first listening on 127.0.0.1:0 and then passing the ports 80 // as flags). 81 // 82 // When starting more than one node, they are connected together using the 83 // admin SetPeer RPC method. 84 85 func newTestCluster(t *testing.T, size int) *testCluster { 86 cluster := &testCluster{} 87 defer func() { 88 if t.Failed() { 89 cluster.Shutdown() 90 } 91 }() 92 93 tmpdir, err := ioutil.TempDir("", "swarm-test") 94 if err != nil { 95 t.Fatal(err) 96 } 97 cluster.TmpDir = tmpdir 98 99 // start the nodes 100 cluster.StartNewNodes(t, size) 101 102 if size == 1 { 103 return cluster 104 } 105 106 // connect the nodes together 107 for _, node := range cluster.Nodes { 108 if err := node.Client.Call(nil, "admin_addPeer", cluster.Nodes[0].Enode); err != nil { 109 t.Fatal(err) 110 } 111 } 112 113 // wait until all nodes have the correct number of peers 114 outer: 115 for _, node := range cluster.Nodes { 116 var peers []*p2p.PeerInfo 117 for start := time.Now(); time.Since(start) < time.Minute; time.Sleep(50 * time.Millisecond) { 118 if err := node.Client.Call(&peers, "admin_peers"); err != nil { 119 t.Fatal(err) 120 } 121 if len(peers) == len(cluster.Nodes)-1 { 122 continue outer 123 } 124 } 125 t.Fatalf("%s only has %d / %d peers", node.Name, len(peers), len(cluster.Nodes)-1) 126 } 127 128 return cluster 129 } 130 131 func (c *testCluster) Shutdown() { 132 for _, node := range c.Nodes { 133 node.Shutdown() 134 } 135 os.RemoveAll(c.TmpDir) 136 } 137 138 func (c *testCluster) Stop() { 139 for _, node := range c.Nodes { 140 node.Shutdown() 141 } 142 } 143 144 func (c *testCluster) StartNewNodes(t *testing.T, size int) { 145 c.Nodes = make([]*testNode, 0, size) 146 for i := 0; i < size; i++ { 147 dir := filepath.Join(c.TmpDir, fmt.Sprintf("swarm%02d", i)) 148 if err := os.Mkdir(dir, 0700); err != nil { 149 t.Fatal(err) 150 } 151 152 node := newTestNode(t, dir) 153 node.Name = fmt.Sprintf("swarm%02d", i) 154 155 c.Nodes = append(c.Nodes, node) 156 } 157 } 158 159 func (c *testCluster) StartExistingNodes(t *testing.T, size int, bzzaccount string) { 160 c.Nodes = make([]*testNode, 0, size) 161 for i := 0; i < size; i++ { 162 dir := filepath.Join(c.TmpDir, fmt.Sprintf("swarm%02d", i)) 163 node := existingTestNode(t, dir, bzzaccount) 164 node.Name = fmt.Sprintf("swarm%02d", i) 165 166 c.Nodes = append(c.Nodes, node) 167 } 168 } 169 170 func (c *testCluster) Cleanup() { 171 os.RemoveAll(c.TmpDir) 172 } 173 174 type testNode struct { 175 Name string 176 Addr string 177 URL string 178 Enode string 179 Dir string 180 IpcPath string 181 Client *rpc.Client 182 Cmd *cmdtest.TestCmd 183 } 184 185 const testPassphrase = "swarm-test-passphrase" 186 187 func getTestAccount(t *testing.T, dir string) (conf *node.Config, account accounts.Account) { 188 // create key 189 conf = &node.Config{ 190 DataDir: dir, 191 IPCPath: "bzzd.ipc", 192 NoUSB: true, 193 } 194 n, err := node.New(conf) 195 if err != nil { 196 t.Fatal(err) 197 } 198 account, err = n.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore).NewAccount(testPassphrase) 199 if err != nil { 200 t.Fatal(err) 201 } 202 203 // use a unique IPCPath when running tests on Windows 204 if runtime.GOOS == "windows" { 205 conf.IPCPath = fmt.Sprintf("bzzd-%s.ipc", account.Address.String()) 206 } 207 208 return conf, account 209 } 210 211 func existingTestNode(t *testing.T, dir string, bzzaccount string) *testNode { 212 conf, _ := getTestAccount(t, dir) 213 node := &testNode{Dir: dir} 214 215 // use a unique IPCPath when running tests on Windows 216 if runtime.GOOS == "windows" { 217 conf.IPCPath = fmt.Sprintf("bzzd-%s.ipc", bzzaccount) 218 } 219 220 // assign ports 221 httpPort, err := assignTCPPort() 222 if err != nil { 223 t.Fatal(err) 224 } 225 p2pPort, err := assignTCPPort() 226 if err != nil { 227 t.Fatal(err) 228 } 229 230 // start the node 231 node.Cmd = runSwarm(t, 232 "--port", p2pPort, 233 "--nodiscover", 234 "--datadir", dir, 235 "--ipcpath", conf.IPCPath, 236 "--ens-api", "", 237 "--bzzaccount", bzzaccount, 238 "--bzznetworkid", "321", 239 "--bzzport", httpPort, 240 "--verbosity", "6", 241 ) 242 node.Cmd.InputLine(testPassphrase) 243 defer func() { 244 if t.Failed() { 245 node.Shutdown() 246 } 247 }() 248 249 // wait for the node to start 250 for start := time.Now(); time.Since(start) < 10*time.Second; time.Sleep(50 * time.Millisecond) { 251 node.Client, err = rpc.Dial(conf.IPCEndpoint()) 252 if err == nil { 253 break 254 } 255 } 256 if node.Client == nil { 257 t.Fatal(err) 258 } 259 260 // load info 261 var info swarm.Info 262 if err := node.Client.Call(&info, "bzz_info"); err != nil { 263 t.Fatal(err) 264 } 265 node.Addr = net.JoinHostPort("127.0.0.1", info.Port) 266 node.URL = "http://" + node.Addr 267 268 var nodeInfo p2p.NodeInfo 269 if err := node.Client.Call(&nodeInfo, "admin_nodeInfo"); err != nil { 270 t.Fatal(err) 271 } 272 node.Enode = fmt.Sprintf("enode://%s@127.0.0.1:%s", nodeInfo.ID, p2pPort) 273 274 return node 275 } 276 277 func newTestNode(t *testing.T, dir string) *testNode { 278 279 conf, account := getTestAccount(t, dir) 280 node := &testNode{Dir: dir} 281 282 // assign ports 283 httpPort, err := assignTCPPort() 284 if err != nil { 285 t.Fatal(err) 286 } 287 p2pPort, err := assignTCPPort() 288 if err != nil { 289 t.Fatal(err) 290 } 291 292 // start the node 293 node.Cmd = runSwarm(t, 294 "--port", p2pPort, 295 "--nodiscover", 296 "--datadir", dir, 297 "--ipcpath", conf.IPCPath, 298 "--ens-api", "", 299 "--bzzaccount", account.Address.String(), 300 "--bzznetworkid", "321", 301 "--bzzport", httpPort, 302 "--verbosity", "6", 303 ) 304 node.Cmd.InputLine(testPassphrase) 305 defer func() { 306 if t.Failed() { 307 node.Shutdown() 308 } 309 }() 310 311 // wait for the node to start 312 for start := time.Now(); time.Since(start) < 10*time.Second; time.Sleep(50 * time.Millisecond) { 313 node.Client, err = rpc.Dial(conf.IPCEndpoint()) 314 if err == nil { 315 break 316 } 317 } 318 if node.Client == nil { 319 t.Fatal(err) 320 } 321 322 // load info 323 var info swarm.Info 324 if err := node.Client.Call(&info, "bzz_info"); err != nil { 325 t.Fatal(err) 326 } 327 node.Addr = net.JoinHostPort("127.0.0.1", info.Port) 328 node.URL = "http://" + node.Addr 329 330 var nodeInfo p2p.NodeInfo 331 if err := node.Client.Call(&nodeInfo, "admin_nodeInfo"); err != nil { 332 t.Fatal(err) 333 } 334 node.Enode = fmt.Sprintf("enode://%s@127.0.0.1:%s", nodeInfo.ID, p2pPort) 335 node.IpcPath = conf.IPCPath 336 337 return node 338 } 339 340 func (n *testNode) Shutdown() { 341 if n.Cmd != nil { 342 n.Cmd.Kill() 343 } 344 } 345 346 func assignTCPPort() (string, error) { 347 l, err := net.Listen("tcp", "127.0.0.1:0") 348 if err != nil { 349 return "", err 350 } 351 l.Close() 352 _, port, err := net.SplitHostPort(l.Addr().String()) 353 if err != nil { 354 return "", err 355 } 356 return port, nil 357 }