github.com/waltonchain/waltonchain_gwtc_src@v1.1.4-0.20201225072101-8a298c95a819/cmd/swarm/run_test.go (about) 1 // Copyright 2016 The go-ethereum Authors 2 // This file is part of go-wtc. 3 // 4 // go-wtc 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-wtc 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-wtc. 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/wtc/go-wtc/accounts/keystore" 31 "github.com/wtc/go-wtc/internal/cmdtest" 32 "github.com/wtc/go-wtc/node" 33 "github.com/wtc/go-wtc/p2p" 34 "github.com/wtc/go-wtc/rpc" 35 "github.com/wtc/go-wtc/swarm" 36 ) 37 38 func init() { 39 // Run the app if we've been exec'd as "swarm-test" in runSwarm. 40 reexec.Register("swarm-test", func() { 41 if err := app.Run(os.Args); err != nil { 42 fmt.Fprintln(os.Stderr, err) 43 os.Exit(1) 44 } 45 os.Exit(0) 46 }) 47 } 48 49 func TestMain(m *testing.M) { 50 // check if we have been reexec'd 51 if reexec.Init() { 52 return 53 } 54 os.Exit(m.Run()) 55 } 56 57 func runSwarm(t *testing.T, args ...string) *cmdtest.TestCmd { 58 tt := cmdtest.NewTestCmd(t, nil) 59 60 // Boot "swarm". This actually runs the test binary but the TestMain 61 // function will prevent any tests from running. 62 tt.Run("swarm-test", args...) 63 64 return tt 65 } 66 67 type testCluster struct { 68 Nodes []*testNode 69 TmpDir string 70 } 71 72 // newTestCluster starts a test swarm cluster of the given size. 73 // 74 // A temporary directory is created and each node gets a data directory inside 75 // it. 76 // 77 // Each node listens on 127.0.0.1 with random ports for both the HTTP and p2p 78 // ports (assigned by first listening on 127.0.0.1:0 and then passing the ports 79 // as flags). 80 // 81 // When starting more than one node, they are connected together using the 82 // admin SetPeer RPC method. 83 func newTestCluster(t *testing.T, size int) *testCluster { 84 cluster := &testCluster{} 85 defer func() { 86 if t.Failed() { 87 cluster.Shutdown() 88 } 89 }() 90 91 tmpdir, err := ioutil.TempDir("", "swarm-test") 92 if err != nil { 93 t.Fatal(err) 94 } 95 cluster.TmpDir = tmpdir 96 97 // start the nodes 98 cluster.Nodes = make([]*testNode, 0, size) 99 for i := 0; i < size; i++ { 100 dir := filepath.Join(cluster.TmpDir, fmt.Sprintf("swarm%02d", i)) 101 if err := os.Mkdir(dir, 0700); err != nil { 102 t.Fatal(err) 103 } 104 105 node := newTestNode(t, dir) 106 node.Name = fmt.Sprintf("swarm%02d", i) 107 108 cluster.Nodes = append(cluster.Nodes, node) 109 } 110 111 if size == 1 { 112 return cluster 113 } 114 115 // connect the nodes together 116 for _, node := range cluster.Nodes { 117 if err := node.Client.Call(nil, "admin_addPeer", cluster.Nodes[0].Enode); err != nil { 118 t.Fatal(err) 119 } 120 } 121 122 // wait until all nodes have the correct number of peers 123 outer: 124 for _, node := range cluster.Nodes { 125 var peers []*p2p.PeerInfo 126 for start := time.Now(); time.Since(start) < time.Minute; time.Sleep(50 * time.Millisecond) { 127 if err := node.Client.Call(&peers, "admin_peers"); err != nil { 128 t.Fatal(err) 129 } 130 if len(peers) == len(cluster.Nodes)-1 { 131 continue outer 132 } 133 } 134 t.Fatalf("%s only has %d / %d peers", node.Name, len(peers), len(cluster.Nodes)-1) 135 } 136 137 return cluster 138 } 139 140 func (c *testCluster) Shutdown() { 141 for _, node := range c.Nodes { 142 node.Shutdown() 143 } 144 os.RemoveAll(c.TmpDir) 145 } 146 147 type testNode struct { 148 Name string 149 Addr string 150 URL string 151 Enode string 152 Dir string 153 Client *rpc.Client 154 Cmd *cmdtest.TestCmd 155 } 156 157 const testPassphrase = "swarm-test-passphrase" 158 159 func newTestNode(t *testing.T, dir string) *testNode { 160 // create key 161 conf := &node.Config{ 162 DataDir: dir, 163 IPCPath: "bzzd.ipc", 164 NoUSB: true, 165 } 166 n, err := node.New(conf) 167 if err != nil { 168 t.Fatal(err) 169 } 170 account, err := n.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore).NewAccount(testPassphrase) 171 if err != nil { 172 t.Fatal(err) 173 } 174 175 node := &testNode{Dir: dir} 176 177 // use a unique IPCPath when running tests on Windows 178 if runtime.GOOS == "windows" { 179 conf.IPCPath = fmt.Sprintf("bzzd-%s.ipc", account.Address.String()) 180 } 181 182 // assign ports 183 httpPort, err := assignTCPPort() 184 if err != nil { 185 t.Fatal(err) 186 } 187 p2pPort, err := assignTCPPort() 188 if err != nil { 189 t.Fatal(err) 190 } 191 192 // start the node 193 node.Cmd = runSwarm(t, 194 "--port", p2pPort, 195 "--nodiscover", 196 "--datadir", dir, 197 "--ipcpath", conf.IPCPath, 198 "--ens-api", "", 199 "--bzzaccount", account.Address.String(), 200 "--bzznetworkid", "321", 201 "--bzzport", httpPort, 202 "--verbosity", "6", 203 ) 204 node.Cmd.InputLine(testPassphrase) 205 defer func() { 206 if t.Failed() { 207 node.Shutdown() 208 } 209 }() 210 211 // wait for the node to start 212 for start := time.Now(); time.Since(start) < 10*time.Second; time.Sleep(50 * time.Millisecond) { 213 node.Client, err = rpc.Dial(conf.IPCEndpoint()) 214 if err == nil { 215 break 216 } 217 } 218 if node.Client == nil { 219 t.Fatal(err) 220 } 221 222 // load info 223 var info swarm.Info 224 if err := node.Client.Call(&info, "bzz_info"); err != nil { 225 t.Fatal(err) 226 } 227 node.Addr = net.JoinHostPort("127.0.0.1", info.Port) 228 node.URL = "http://" + node.Addr 229 230 var nodeInfo p2p.NodeInfo 231 if err := node.Client.Call(&nodeInfo, "admin_nodeInfo"); err != nil { 232 t.Fatal(err) 233 } 234 node.Enode = fmt.Sprintf("enode://%s@127.0.0.1:%s", nodeInfo.ID, p2pPort) 235 236 return node 237 } 238 239 func (n *testNode) Shutdown() { 240 if n.Cmd != nil { 241 n.Cmd.Kill() 242 } 243 } 244 245 func assignTCPPort() (string, error) { 246 l, err := net.Listen("tcp", "127.0.0.1:0") 247 if err != nil { 248 return "", err 249 } 250 l.Close() 251 _, port, err := net.SplitHostPort(l.Addr().String()) 252 if err != nil { 253 return "", err 254 } 255 return port, nil 256 }