github.com/phillinzzz/newBsc@v1.1.6/node/api_test.go (about) 1 // Copyright 2020 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 node 18 19 import ( 20 "bytes" 21 "io" 22 "net" 23 "net/http" 24 "net/url" 25 "strings" 26 "testing" 27 28 "github.com/phillinzzz/newBsc/rpc" 29 "github.com/stretchr/testify/assert" 30 ) 31 32 // This test uses the admin_startRPC and admin_startWS APIs, 33 // checking whether the HTTP server is started correctly. 34 func TestStartRPC(t *testing.T) { 35 type test struct { 36 name string 37 cfg Config 38 fn func(*testing.T, *Node, *privateAdminAPI) 39 40 // Checks. These run after the node is configured and all API calls have been made. 41 wantReachable bool // whether the HTTP server should be reachable at all 42 wantHandlers bool // whether RegisterHandler handlers should be accessible 43 wantRPC bool // whether JSON-RPC/HTTP should be accessible 44 wantWS bool // whether JSON-RPC/WS should be accessible 45 } 46 47 tests := []test{ 48 { 49 name: "all off", 50 cfg: Config{}, 51 fn: func(t *testing.T, n *Node, api *privateAdminAPI) { 52 }, 53 wantReachable: false, 54 wantHandlers: false, 55 wantRPC: false, 56 wantWS: false, 57 }, 58 { 59 name: "rpc enabled through config", 60 cfg: Config{HTTPHost: "127.0.0.1"}, 61 fn: func(t *testing.T, n *Node, api *privateAdminAPI) { 62 }, 63 wantReachable: true, 64 wantHandlers: true, 65 wantRPC: true, 66 wantWS: false, 67 }, 68 { 69 name: "rpc enabled through API", 70 cfg: Config{}, 71 fn: func(t *testing.T, n *Node, api *privateAdminAPI) { 72 _, err := api.StartHTTP(sp("127.0.0.1"), ip(0), nil, nil, nil) 73 assert.NoError(t, err) 74 }, 75 wantReachable: true, 76 wantHandlers: true, 77 wantRPC: true, 78 wantWS: false, 79 }, 80 { 81 name: "rpc start again after failure", 82 cfg: Config{}, 83 fn: func(t *testing.T, n *Node, api *privateAdminAPI) { 84 // Listen on a random port. 85 listener, err := net.Listen("tcp", "127.0.0.1:0") 86 if err != nil { 87 t.Fatal("can't listen:", err) 88 } 89 defer listener.Close() 90 port := listener.Addr().(*net.TCPAddr).Port 91 92 // Now try to start RPC on that port. This should fail. 93 _, err = api.StartHTTP(sp("127.0.0.1"), ip(port), nil, nil, nil) 94 if err == nil { 95 t.Fatal("StartHTTP should have failed on port", port) 96 } 97 98 // Try again after unblocking the port. It should work this time. 99 listener.Close() 100 _, err = api.StartHTTP(sp("127.0.0.1"), ip(port), nil, nil, nil) 101 assert.NoError(t, err) 102 }, 103 wantReachable: true, 104 wantHandlers: true, 105 wantRPC: true, 106 wantWS: false, 107 }, 108 { 109 name: "rpc stopped through API", 110 cfg: Config{HTTPHost: "127.0.0.1"}, 111 fn: func(t *testing.T, n *Node, api *privateAdminAPI) { 112 _, err := api.StopHTTP() 113 assert.NoError(t, err) 114 }, 115 wantReachable: false, 116 wantHandlers: false, 117 wantRPC: false, 118 wantWS: false, 119 }, 120 { 121 name: "rpc stopped twice", 122 cfg: Config{HTTPHost: "127.0.0.1"}, 123 fn: func(t *testing.T, n *Node, api *privateAdminAPI) { 124 _, err := api.StopHTTP() 125 assert.NoError(t, err) 126 127 _, err = api.StopHTTP() 128 assert.NoError(t, err) 129 }, 130 wantReachable: false, 131 wantHandlers: false, 132 wantRPC: false, 133 wantWS: false, 134 }, 135 { 136 name: "ws enabled through config", 137 cfg: Config{WSHost: "127.0.0.1"}, 138 wantReachable: true, 139 wantHandlers: false, 140 wantRPC: false, 141 wantWS: true, 142 }, 143 { 144 name: "ws enabled through API", 145 cfg: Config{}, 146 fn: func(t *testing.T, n *Node, api *privateAdminAPI) { 147 _, err := api.StartWS(sp("127.0.0.1"), ip(0), nil, nil) 148 assert.NoError(t, err) 149 }, 150 wantReachable: true, 151 wantHandlers: false, 152 wantRPC: false, 153 wantWS: true, 154 }, 155 { 156 name: "ws stopped through API", 157 cfg: Config{WSHost: "127.0.0.1"}, 158 fn: func(t *testing.T, n *Node, api *privateAdminAPI) { 159 _, err := api.StopWS() 160 assert.NoError(t, err) 161 }, 162 wantReachable: false, 163 wantHandlers: false, 164 wantRPC: false, 165 wantWS: false, 166 }, 167 { 168 name: "ws stopped twice", 169 cfg: Config{WSHost: "127.0.0.1"}, 170 fn: func(t *testing.T, n *Node, api *privateAdminAPI) { 171 _, err := api.StopWS() 172 assert.NoError(t, err) 173 174 _, err = api.StopWS() 175 assert.NoError(t, err) 176 }, 177 wantReachable: false, 178 wantHandlers: false, 179 wantRPC: false, 180 wantWS: false, 181 }, 182 { 183 name: "ws enabled after RPC", 184 cfg: Config{HTTPHost: "127.0.0.1"}, 185 fn: func(t *testing.T, n *Node, api *privateAdminAPI) { 186 wsport := n.http.port 187 _, err := api.StartWS(sp("127.0.0.1"), ip(wsport), nil, nil) 188 assert.NoError(t, err) 189 }, 190 wantReachable: true, 191 wantHandlers: true, 192 wantRPC: true, 193 wantWS: true, 194 }, 195 { 196 name: "ws enabled after RPC then stopped", 197 cfg: Config{HTTPHost: "127.0.0.1"}, 198 fn: func(t *testing.T, n *Node, api *privateAdminAPI) { 199 wsport := n.http.port 200 _, err := api.StartWS(sp("127.0.0.1"), ip(wsport), nil, nil) 201 assert.NoError(t, err) 202 203 _, err = api.StopWS() 204 assert.NoError(t, err) 205 }, 206 wantReachable: true, 207 wantHandlers: true, 208 wantRPC: true, 209 wantWS: false, 210 }, 211 { 212 name: "rpc stopped with ws enabled", 213 fn: func(t *testing.T, n *Node, api *privateAdminAPI) { 214 _, err := api.StartHTTP(sp("127.0.0.1"), ip(0), nil, nil, nil) 215 assert.NoError(t, err) 216 217 wsport := n.http.port 218 _, err = api.StartWS(sp("127.0.0.1"), ip(wsport), nil, nil) 219 assert.NoError(t, err) 220 221 _, err = api.StopHTTP() 222 assert.NoError(t, err) 223 }, 224 wantReachable: false, 225 wantHandlers: false, 226 wantRPC: false, 227 wantWS: false, 228 }, 229 { 230 name: "rpc enabled after ws", 231 fn: func(t *testing.T, n *Node, api *privateAdminAPI) { 232 _, err := api.StartWS(sp("127.0.0.1"), ip(0), nil, nil) 233 assert.NoError(t, err) 234 235 wsport := n.http.port 236 _, err = api.StartHTTP(sp("127.0.0.1"), ip(wsport), nil, nil, nil) 237 assert.NoError(t, err) 238 }, 239 wantReachable: true, 240 wantHandlers: true, 241 wantRPC: true, 242 wantWS: true, 243 }, 244 } 245 246 for _, test := range tests { 247 test := test 248 t.Run(test.name, func(t *testing.T) { 249 t.Parallel() 250 251 // Apply some sane defaults. 252 config := test.cfg 253 // config.Logger = testlog.Logger(t, log.LvlDebug) 254 config.P2P.NoDiscovery = true 255 256 // Create Node. 257 stack, err := New(&config) 258 if err != nil { 259 t.Fatal("can't create node:", err) 260 } 261 defer stack.Close() 262 263 // Register the test handler. 264 stack.RegisterHandler("test", "/test", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 265 w.Write([]byte("OK")) 266 })) 267 268 if err := stack.Start(); err != nil { 269 t.Fatal("can't start node:", err) 270 } 271 272 // Run the API call hook. 273 if test.fn != nil { 274 test.fn(t, stack, &privateAdminAPI{stack}) 275 } 276 277 // Check if the HTTP endpoints are available. 278 baseURL := stack.HTTPEndpoint() 279 reachable := checkReachable(baseURL) 280 handlersAvailable := checkBodyOK(baseURL + "/test") 281 rpcAvailable := checkRPC(baseURL) 282 wsAvailable := checkRPC(strings.Replace(baseURL, "http://", "ws://", 1)) 283 if reachable != test.wantReachable { 284 t.Errorf("HTTP server is %sreachable, want it %sreachable", not(reachable), not(test.wantReachable)) 285 } 286 if handlersAvailable != test.wantHandlers { 287 t.Errorf("RegisterHandler handlers %savailable, want them %savailable", not(handlersAvailable), not(test.wantHandlers)) 288 } 289 if rpcAvailable != test.wantRPC { 290 t.Errorf("HTTP RPC %savailable, want it %savailable", not(rpcAvailable), not(test.wantRPC)) 291 } 292 if wsAvailable != test.wantWS { 293 t.Errorf("WS RPC %savailable, want it %savailable", not(wsAvailable), not(test.wantWS)) 294 } 295 }) 296 } 297 } 298 299 // checkReachable checks if the TCP endpoint in rawurl is open. 300 func checkReachable(rawurl string) bool { 301 u, err := url.Parse(rawurl) 302 if err != nil { 303 panic(err) 304 } 305 conn, err := net.Dial("tcp", u.Host) 306 if err != nil { 307 return false 308 } 309 conn.Close() 310 return true 311 } 312 313 // checkBodyOK checks whether the given HTTP URL responds with 200 OK and body "OK". 314 func checkBodyOK(url string) bool { 315 resp, err := http.Get(url) 316 if err != nil { 317 return false 318 } 319 defer resp.Body.Close() 320 321 if resp.StatusCode != 200 { 322 return false 323 } 324 buf := make([]byte, 2) 325 if _, err = io.ReadFull(resp.Body, buf); err != nil { 326 return false 327 } 328 return bytes.Equal(buf, []byte("OK")) 329 } 330 331 // checkRPC checks whether JSON-RPC works against the given URL. 332 func checkRPC(url string) bool { 333 c, err := rpc.Dial(url) 334 if err != nil { 335 return false 336 } 337 defer c.Close() 338 339 _, err = c.SupportedModules() 340 return err == nil 341 } 342 343 // string/int pointer helpers. 344 func sp(s string) *string { return &s } 345 func ip(i int) *int { return &i } 346 347 func not(ok bool) string { 348 if ok { 349 return "" 350 } 351 return "not " 352 }