github.com/aswedchain/aswed@v1.0.1/node/node_test.go (about) 1 // Copyright 2015 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 "errors" 21 "fmt" 22 "io" 23 "io/ioutil" 24 "net" 25 "net/http" 26 "os" 27 "reflect" 28 "strings" 29 "testing" 30 31 "github.com/aswedchain/aswed/crypto" 32 "github.com/aswedchain/aswed/ethdb" 33 "github.com/aswedchain/aswed/p2p" 34 "github.com/aswedchain/aswed/rpc" 35 36 "github.com/stretchr/testify/assert" 37 ) 38 39 var ( 40 testNodeKey, _ = crypto.GenerateKey() 41 ) 42 43 func testNodeConfig() *Config { 44 return &Config{ 45 Name: "test node", 46 P2P: p2p.Config{PrivateKey: testNodeKey}, 47 } 48 } 49 50 // Tests that an empty protocol stack can be closed more than once. 51 func TestNodeCloseMultipleTimes(t *testing.T) { 52 stack, err := New(testNodeConfig()) 53 if err != nil { 54 t.Fatalf("failed to create protocol stack: %v", err) 55 } 56 stack.Close() 57 58 // Ensure that a stopped node can be stopped again 59 for i := 0; i < 3; i++ { 60 if err := stack.Close(); err != ErrNodeStopped { 61 t.Fatalf("iter %d: stop failure mismatch: have %v, want %v", i, err, ErrNodeStopped) 62 } 63 } 64 } 65 66 func TestNodeStartMultipleTimes(t *testing.T) { 67 stack, err := New(testNodeConfig()) 68 if err != nil { 69 t.Fatalf("failed to create protocol stack: %v", err) 70 } 71 72 // Ensure that a node can be successfully started, but only once 73 if err := stack.Start(); err != nil { 74 t.Fatalf("failed to start node: %v", err) 75 } 76 if err := stack.Start(); err != ErrNodeRunning { 77 t.Fatalf("start failure mismatch: have %v, want %v ", err, ErrNodeRunning) 78 } 79 // Ensure that a node can be stopped, but only once 80 if err := stack.Close(); err != nil { 81 t.Fatalf("failed to stop node: %v", err) 82 } 83 if err := stack.Close(); err != ErrNodeStopped { 84 t.Fatalf("stop failure mismatch: have %v, want %v ", err, ErrNodeStopped) 85 } 86 } 87 88 // Tests that if the data dir is already in use, an appropriate error is returned. 89 func TestNodeUsedDataDir(t *testing.T) { 90 // Create a temporary folder to use as the data directory 91 dir, err := ioutil.TempDir("", "") 92 if err != nil { 93 t.Fatalf("failed to create temporary data directory: %v", err) 94 } 95 defer os.RemoveAll(dir) 96 97 // Create a new node based on the data directory 98 original, err := New(&Config{DataDir: dir}) 99 if err != nil { 100 t.Fatalf("failed to create original protocol stack: %v", err) 101 } 102 defer original.Close() 103 if err := original.Start(); err != nil { 104 t.Fatalf("failed to start original protocol stack: %v", err) 105 } 106 107 // Create a second node based on the same data directory and ensure failure 108 _, err = New(&Config{DataDir: dir}) 109 if err != ErrDatadirUsed { 110 t.Fatalf("duplicate datadir failure mismatch: have %v, want %v", err, ErrDatadirUsed) 111 } 112 } 113 114 // Tests whether a Lifecycle can be registered. 115 func TestLifecycleRegistry_Successful(t *testing.T) { 116 stack, err := New(testNodeConfig()) 117 if err != nil { 118 t.Fatalf("failed to create protocol stack: %v", err) 119 } 120 defer stack.Close() 121 122 noop := NewNoop() 123 stack.RegisterLifecycle(noop) 124 125 if !containsLifecycle(stack.lifecycles, noop) { 126 t.Fatalf("lifecycle was not properly registered on the node, %v", err) 127 } 128 } 129 130 // Tests whether a service's protocols can be registered properly on the node's p2p server. 131 func TestRegisterProtocols(t *testing.T) { 132 stack, err := New(testNodeConfig()) 133 if err != nil { 134 t.Fatalf("failed to create protocol stack: %v", err) 135 } 136 defer stack.Close() 137 138 fs, err := NewFullService(stack) 139 if err != nil { 140 t.Fatalf("could not create full service: %v", err) 141 } 142 143 for _, protocol := range fs.Protocols() { 144 if !containsProtocol(stack.server.Protocols, protocol) { 145 t.Fatalf("protocol %v was not successfully registered", protocol) 146 } 147 } 148 149 for _, api := range fs.APIs() { 150 if !containsAPI(stack.rpcAPIs, api) { 151 t.Fatalf("api %v was not successfully registered", api) 152 } 153 } 154 } 155 156 // This test checks that open databases are closed with node. 157 func TestNodeCloseClosesDB(t *testing.T) { 158 stack, _ := New(testNodeConfig()) 159 defer stack.Close() 160 161 db, err := stack.OpenDatabase("mydb", 0, 0, "") 162 if err != nil { 163 t.Fatal("can't open DB:", err) 164 } 165 if err = db.Put([]byte{}, []byte{}); err != nil { 166 t.Fatal("can't Put on open DB:", err) 167 } 168 169 stack.Close() 170 if err = db.Put([]byte{}, []byte{}); err == nil { 171 t.Fatal("Put succeeded after node is closed") 172 } 173 } 174 175 // This test checks that OpenDatabase can be used from within a Lifecycle Start method. 176 func TestNodeOpenDatabaseFromLifecycleStart(t *testing.T) { 177 stack, _ := New(testNodeConfig()) 178 defer stack.Close() 179 180 var db ethdb.Database 181 var err error 182 stack.RegisterLifecycle(&InstrumentedService{ 183 startHook: func() { 184 db, err = stack.OpenDatabase("mydb", 0, 0, "") 185 if err != nil { 186 t.Fatal("can't open DB:", err) 187 } 188 }, 189 stopHook: func() { 190 db.Close() 191 }, 192 }) 193 194 stack.Start() 195 stack.Close() 196 } 197 198 // This test checks that OpenDatabase can be used from within a Lifecycle Stop method. 199 func TestNodeOpenDatabaseFromLifecycleStop(t *testing.T) { 200 stack, _ := New(testNodeConfig()) 201 defer stack.Close() 202 203 stack.RegisterLifecycle(&InstrumentedService{ 204 stopHook: func() { 205 db, err := stack.OpenDatabase("mydb", 0, 0, "") 206 if err != nil { 207 t.Fatal("can't open DB:", err) 208 } 209 db.Close() 210 }, 211 }) 212 213 stack.Start() 214 stack.Close() 215 } 216 217 // Tests that registered Lifecycles get started and stopped correctly. 218 func TestLifecycleLifeCycle(t *testing.T) { 219 stack, _ := New(testNodeConfig()) 220 defer stack.Close() 221 222 started := make(map[string]bool) 223 stopped := make(map[string]bool) 224 225 // Create a batch of instrumented services 226 lifecycles := map[string]Lifecycle{ 227 "A": &InstrumentedService{ 228 startHook: func() { started["A"] = true }, 229 stopHook: func() { stopped["A"] = true }, 230 }, 231 "B": &InstrumentedService{ 232 startHook: func() { started["B"] = true }, 233 stopHook: func() { stopped["B"] = true }, 234 }, 235 "C": &InstrumentedService{ 236 startHook: func() { started["C"] = true }, 237 stopHook: func() { stopped["C"] = true }, 238 }, 239 } 240 // register lifecycles on node 241 for _, lifecycle := range lifecycles { 242 stack.RegisterLifecycle(lifecycle) 243 } 244 // Start the node and check that all services are running 245 if err := stack.Start(); err != nil { 246 t.Fatalf("failed to start protocol stack: %v", err) 247 } 248 for id := range lifecycles { 249 if !started[id] { 250 t.Fatalf("service %s: freshly started service not running", id) 251 } 252 if stopped[id] { 253 t.Fatalf("service %s: freshly started service already stopped", id) 254 } 255 } 256 // Stop the node and check that all services have been stopped 257 if err := stack.Close(); err != nil { 258 t.Fatalf("failed to stop protocol stack: %v", err) 259 } 260 for id := range lifecycles { 261 if !stopped[id] { 262 t.Fatalf("service %s: freshly terminated service still running", id) 263 } 264 } 265 } 266 267 // Tests that if a Lifecycle fails to start, all others started before it will be 268 // shut down. 269 func TestLifecycleStartupError(t *testing.T) { 270 stack, err := New(testNodeConfig()) 271 if err != nil { 272 t.Fatalf("failed to create protocol stack: %v", err) 273 } 274 defer stack.Close() 275 276 started := make(map[string]bool) 277 stopped := make(map[string]bool) 278 279 // Create a batch of instrumented services 280 lifecycles := map[string]Lifecycle{ 281 "A": &InstrumentedService{ 282 startHook: func() { started["A"] = true }, 283 stopHook: func() { stopped["A"] = true }, 284 }, 285 "B": &InstrumentedService{ 286 startHook: func() { started["B"] = true }, 287 stopHook: func() { stopped["B"] = true }, 288 }, 289 "C": &InstrumentedService{ 290 startHook: func() { started["C"] = true }, 291 stopHook: func() { stopped["C"] = true }, 292 }, 293 } 294 // register lifecycles on node 295 for _, lifecycle := range lifecycles { 296 stack.RegisterLifecycle(lifecycle) 297 } 298 299 // Register a service that fails to construct itself 300 failure := errors.New("fail") 301 failer := &InstrumentedService{start: failure} 302 stack.RegisterLifecycle(failer) 303 304 // Start the protocol stack and ensure all started services stop 305 if err := stack.Start(); err != failure { 306 t.Fatalf("stack startup failure mismatch: have %v, want %v", err, failure) 307 } 308 for id := range lifecycles { 309 if started[id] && !stopped[id] { 310 t.Fatalf("service %s: started but not stopped", id) 311 } 312 delete(started, id) 313 delete(stopped, id) 314 } 315 } 316 317 // Tests that even if a registered Lifecycle fails to shut down cleanly, it does 318 // not influence the rest of the shutdown invocations. 319 func TestLifecycleTerminationGuarantee(t *testing.T) { 320 stack, err := New(testNodeConfig()) 321 if err != nil { 322 t.Fatalf("failed to create protocol stack: %v", err) 323 } 324 defer stack.Close() 325 326 started := make(map[string]bool) 327 stopped := make(map[string]bool) 328 329 // Create a batch of instrumented services 330 lifecycles := map[string]Lifecycle{ 331 "A": &InstrumentedService{ 332 startHook: func() { started["A"] = true }, 333 stopHook: func() { stopped["A"] = true }, 334 }, 335 "B": &InstrumentedService{ 336 startHook: func() { started["B"] = true }, 337 stopHook: func() { stopped["B"] = true }, 338 }, 339 "C": &InstrumentedService{ 340 startHook: func() { started["C"] = true }, 341 stopHook: func() { stopped["C"] = true }, 342 }, 343 } 344 // register lifecycles on node 345 for _, lifecycle := range lifecycles { 346 stack.RegisterLifecycle(lifecycle) 347 } 348 349 // Register a service that fails to shot down cleanly 350 failure := errors.New("fail") 351 failer := &InstrumentedService{stop: failure} 352 stack.RegisterLifecycle(failer) 353 354 // Start the protocol stack, and ensure that a failing shut down terminates all 355 // Start the stack and make sure all is online 356 if err := stack.Start(); err != nil { 357 t.Fatalf("failed to start protocol stack: %v", err) 358 } 359 for id := range lifecycles { 360 if !started[id] { 361 t.Fatalf("service %s: service not running", id) 362 } 363 if stopped[id] { 364 t.Fatalf("service %s: service already stopped", id) 365 } 366 } 367 // Stop the stack, verify failure and check all terminations 368 err = stack.Close() 369 if err, ok := err.(*StopError); !ok { 370 t.Fatalf("termination failure mismatch: have %v, want StopError", err) 371 } else { 372 failer := reflect.TypeOf(&InstrumentedService{}) 373 if err.Services[failer] != failure { 374 t.Fatalf("failer termination failure mismatch: have %v, want %v", err.Services[failer], failure) 375 } 376 if len(err.Services) != 1 { 377 t.Fatalf("failure count mismatch: have %d, want %d", len(err.Services), 1) 378 } 379 } 380 for id := range lifecycles { 381 if !stopped[id] { 382 t.Fatalf("service %s: service not terminated", id) 383 } 384 delete(started, id) 385 delete(stopped, id) 386 } 387 388 stack.server = &p2p.Server{} 389 stack.server.PrivateKey = testNodeKey 390 } 391 392 // Tests whether a handler can be successfully mounted on the canonical HTTP server 393 // on the given path 394 func TestRegisterHandler_Successful(t *testing.T) { 395 node := createNode(t, 7878, 7979) 396 397 // create and mount handler 398 handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 399 w.Write([]byte("success")) 400 }) 401 node.RegisterHandler("test", "/test", handler) 402 403 // start node 404 if err := node.Start(); err != nil { 405 t.Fatalf("could not start node: %v", err) 406 } 407 408 // create HTTP request 409 httpReq, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:7878/test", nil) 410 if err != nil { 411 t.Error("could not issue new http request ", err) 412 } 413 414 // check response 415 resp := doHTTPRequest(t, httpReq) 416 buf := make([]byte, 7) 417 _, err = io.ReadFull(resp.Body, buf) 418 if err != nil { 419 t.Fatalf("could not read response: %v", err) 420 } 421 assert.Equal(t, "success", string(buf)) 422 } 423 424 // Tests that the given handler will not be successfully mounted since no HTTP server 425 // is enabled for RPC 426 func TestRegisterHandler_Unsuccessful(t *testing.T) { 427 node, err := New(&DefaultConfig) 428 if err != nil { 429 t.Fatalf("could not create new node: %v", err) 430 } 431 432 // create and mount handler 433 handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 434 w.Write([]byte("success")) 435 }) 436 node.RegisterHandler("test", "/test", handler) 437 } 438 439 // Tests whether websocket requests can be handled on the same port as a regular http server. 440 func TestWebsocketHTTPOnSamePort_WebsocketRequest(t *testing.T) { 441 node := startHTTP(t, 0, 0) 442 defer node.Close() 443 444 ws := strings.Replace(node.HTTPEndpoint(), "http://", "ws://", 1) 445 446 if node.WSEndpoint() != ws { 447 t.Fatalf("endpoints should be the same") 448 } 449 if !checkRPC(ws) { 450 t.Fatalf("ws request failed") 451 } 452 if !checkRPC(node.HTTPEndpoint()) { 453 t.Fatalf("http request failed") 454 } 455 } 456 457 func TestWebsocketHTTPOnSeparatePort_WSRequest(t *testing.T) { 458 // try and get a free port 459 listener, err := net.Listen("tcp", "127.0.0.1:0") 460 if err != nil { 461 t.Fatal("can't listen:", err) 462 } 463 port := listener.Addr().(*net.TCPAddr).Port 464 listener.Close() 465 466 node := startHTTP(t, 0, port) 467 defer node.Close() 468 469 wsOnHTTP := strings.Replace(node.HTTPEndpoint(), "http://", "ws://", 1) 470 ws := fmt.Sprintf("ws://127.0.0.1:%d", port) 471 472 if node.WSEndpoint() == wsOnHTTP { 473 t.Fatalf("endpoints should not be the same") 474 } 475 // ensure ws endpoint matches the expected endpoint 476 if node.WSEndpoint() != ws { 477 t.Fatalf("ws endpoint is incorrect: expected %s, got %s", ws, node.WSEndpoint()) 478 } 479 480 if !checkRPC(ws) { 481 t.Fatalf("ws request failed") 482 } 483 if !checkRPC(node.HTTPEndpoint()) { 484 t.Fatalf("http request failed") 485 } 486 487 } 488 489 func createNode(t *testing.T, httpPort, wsPort int) *Node { 490 conf := &Config{ 491 HTTPHost: "127.0.0.1", 492 HTTPPort: httpPort, 493 WSHost: "127.0.0.1", 494 WSPort: wsPort, 495 } 496 node, err := New(conf) 497 if err != nil { 498 t.Fatalf("could not create a new node: %v", err) 499 } 500 return node 501 } 502 503 func startHTTP(t *testing.T, httpPort, wsPort int) *Node { 504 node := createNode(t, httpPort, wsPort) 505 err := node.Start() 506 if err != nil { 507 t.Fatalf("could not start http service on node: %v", err) 508 } 509 510 return node 511 } 512 513 func doHTTPRequest(t *testing.T, req *http.Request) *http.Response { 514 client := http.DefaultClient 515 resp, err := client.Do(req) 516 if err != nil { 517 t.Fatalf("could not issue a GET request to the given endpoint: %v", err) 518 519 } 520 return resp 521 } 522 523 func containsProtocol(stackProtocols []p2p.Protocol, protocol p2p.Protocol) bool { 524 for _, a := range stackProtocols { 525 if reflect.DeepEqual(a, protocol) { 526 return true 527 } 528 } 529 return false 530 } 531 532 func containsAPI(stackAPIs []rpc.API, api rpc.API) bool { 533 for _, a := range stackAPIs { 534 if reflect.DeepEqual(a, api) { 535 return true 536 } 537 } 538 return false 539 }