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