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