github.com/p202io/bor@v0.1.4/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 "io/ioutil" 22 "os" 23 "reflect" 24 "testing" 25 "time" 26 27 "github.com/maticnetwork/bor/crypto" 28 "github.com/maticnetwork/bor/p2p" 29 "github.com/maticnetwork/bor/rpc" 30 ) 31 32 var ( 33 testNodeKey, _ = crypto.GenerateKey() 34 ) 35 36 func testNodeConfig() *Config { 37 return &Config{ 38 Name: "test node", 39 P2P: p2p.Config{PrivateKey: testNodeKey}, 40 } 41 } 42 43 // Tests that an empty protocol stack can be started, restarted and stopped. 44 func TestNodeLifeCycle(t *testing.T) { 45 stack, err := New(testNodeConfig()) 46 if err != nil { 47 t.Fatalf("failed to create protocol stack: %v", err) 48 } 49 defer stack.Close() 50 51 // Ensure that a stopped node can be stopped again 52 for i := 0; i < 3; i++ { 53 if err := stack.Stop(); err != ErrNodeStopped { 54 t.Fatalf("iter %d: stop failure mismatch: have %v, want %v", i, err, ErrNodeStopped) 55 } 56 } 57 // Ensure that a node can be successfully started, but only once 58 if err := stack.Start(); err != nil { 59 t.Fatalf("failed to start node: %v", err) 60 } 61 if err := stack.Start(); err != ErrNodeRunning { 62 t.Fatalf("start failure mismatch: have %v, want %v ", err, ErrNodeRunning) 63 } 64 // Ensure that a node can be restarted arbitrarily many times 65 for i := 0; i < 3; i++ { 66 if err := stack.Restart(); err != nil { 67 t.Fatalf("iter %d: failed to restart node: %v", i, err) 68 } 69 } 70 // Ensure that a node can be stopped, but only once 71 if err := stack.Stop(); err != nil { 72 t.Fatalf("failed to stop node: %v", err) 73 } 74 if err := stack.Stop(); err != ErrNodeStopped { 75 t.Fatalf("stop failure mismatch: have %v, want %v ", err, ErrNodeStopped) 76 } 77 } 78 79 // Tests that if the data dir is already in use, an appropriate error is returned. 80 func TestNodeUsedDataDir(t *testing.T) { 81 // Create a temporary folder to use as the data directory 82 dir, err := ioutil.TempDir("", "") 83 if err != nil { 84 t.Fatalf("failed to create temporary data directory: %v", err) 85 } 86 defer os.RemoveAll(dir) 87 88 // Create a new node based on the data directory 89 original, err := New(&Config{DataDir: dir}) 90 if err != nil { 91 t.Fatalf("failed to create original protocol stack: %v", err) 92 } 93 defer original.Close() 94 95 if err := original.Start(); err != nil { 96 t.Fatalf("failed to start original protocol stack: %v", err) 97 } 98 defer original.Stop() 99 100 // Create a second node based on the same data directory and ensure failure 101 duplicate, err := New(&Config{DataDir: dir}) 102 if err != nil { 103 t.Fatalf("failed to create duplicate protocol stack: %v", err) 104 } 105 defer duplicate.Close() 106 107 if err := duplicate.Start(); err != ErrDatadirUsed { 108 t.Fatalf("duplicate datadir failure mismatch: have %v, want %v", err, ErrDatadirUsed) 109 } 110 } 111 112 // Tests whether services can be registered and duplicates caught. 113 func TestServiceRegistry(t *testing.T) { 114 stack, err := New(testNodeConfig()) 115 if err != nil { 116 t.Fatalf("failed to create protocol stack: %v", err) 117 } 118 defer stack.Close() 119 120 // Register a batch of unique services and ensure they start successfully 121 services := []ServiceConstructor{NewNoopServiceA, NewNoopServiceB, NewNoopServiceC} 122 for i, constructor := range services { 123 if err := stack.Register(constructor); err != nil { 124 t.Fatalf("service #%d: registration failed: %v", i, err) 125 } 126 } 127 if err := stack.Start(); err != nil { 128 t.Fatalf("failed to start original service stack: %v", err) 129 } 130 if err := stack.Stop(); err != nil { 131 t.Fatalf("failed to stop original service stack: %v", err) 132 } 133 // Duplicate one of the services and retry starting the node 134 if err := stack.Register(NewNoopServiceB); err != nil { 135 t.Fatalf("duplicate registration failed: %v", err) 136 } 137 if err := stack.Start(); err == nil { 138 t.Fatalf("duplicate service started") 139 } else { 140 if _, ok := err.(*DuplicateServiceError); !ok { 141 t.Fatalf("duplicate error mismatch: have %v, want %v", err, DuplicateServiceError{}) 142 } 143 } 144 } 145 146 // Tests that registered services get started and stopped correctly. 147 func TestServiceLifeCycle(t *testing.T) { 148 stack, err := New(testNodeConfig()) 149 if err != nil { 150 t.Fatalf("failed to create protocol stack: %v", err) 151 } 152 defer stack.Close() 153 154 // Register a batch of life-cycle instrumented services 155 services := map[string]InstrumentingWrapper{ 156 "A": InstrumentedServiceMakerA, 157 "B": InstrumentedServiceMakerB, 158 "C": InstrumentedServiceMakerC, 159 } 160 started := make(map[string]bool) 161 stopped := make(map[string]bool) 162 163 for id, maker := range services { 164 id := id // Closure for the constructor 165 constructor := func(*ServiceContext) (Service, error) { 166 return &InstrumentedService{ 167 startHook: func(*p2p.Server) { started[id] = true }, 168 stopHook: func() { stopped[id] = true }, 169 }, nil 170 } 171 if err := stack.Register(maker(constructor)); err != nil { 172 t.Fatalf("service %s: registration failed: %v", id, err) 173 } 174 } 175 // Start the node and check that all services are running 176 if err := stack.Start(); err != nil { 177 t.Fatalf("failed to start protocol stack: %v", err) 178 } 179 for id := range services { 180 if !started[id] { 181 t.Fatalf("service %s: freshly started service not running", id) 182 } 183 if stopped[id] { 184 t.Fatalf("service %s: freshly started service already stopped", id) 185 } 186 } 187 // Stop the node and check that all services have been stopped 188 if err := stack.Stop(); err != nil { 189 t.Fatalf("failed to stop protocol stack: %v", err) 190 } 191 for id := range services { 192 if !stopped[id] { 193 t.Fatalf("service %s: freshly terminated service still running", id) 194 } 195 } 196 } 197 198 // Tests that services are restarted cleanly as new instances. 199 func TestServiceRestarts(t *testing.T) { 200 stack, err := New(testNodeConfig()) 201 if err != nil { 202 t.Fatalf("failed to create protocol stack: %v", err) 203 } 204 defer stack.Close() 205 206 // Define a service that does not support restarts 207 var ( 208 running bool 209 started int 210 ) 211 constructor := func(*ServiceContext) (Service, error) { 212 running = false 213 214 return &InstrumentedService{ 215 startHook: func(*p2p.Server) { 216 if running { 217 panic("already running") 218 } 219 running = true 220 started++ 221 }, 222 }, nil 223 } 224 // Register the service and start the protocol stack 225 if err := stack.Register(constructor); err != nil { 226 t.Fatalf("failed to register the service: %v", err) 227 } 228 if err := stack.Start(); err != nil { 229 t.Fatalf("failed to start protocol stack: %v", err) 230 } 231 defer stack.Stop() 232 233 if !running || started != 1 { 234 t.Fatalf("running/started mismatch: have %v/%d, want true/1", running, started) 235 } 236 // Restart the stack a few times and check successful service restarts 237 for i := 0; i < 3; i++ { 238 if err := stack.Restart(); err != nil { 239 t.Fatalf("iter %d: failed to restart stack: %v", i, err) 240 } 241 } 242 if !running || started != 4 { 243 t.Fatalf("running/started mismatch: have %v/%d, want true/4", running, started) 244 } 245 } 246 247 // Tests that if a service fails to initialize itself, none of the other services 248 // will be allowed to even start. 249 func TestServiceConstructionAbortion(t *testing.T) { 250 stack, err := New(testNodeConfig()) 251 if err != nil { 252 t.Fatalf("failed to create protocol stack: %v", err) 253 } 254 defer stack.Close() 255 256 // Define a batch of good services 257 services := map[string]InstrumentingWrapper{ 258 "A": InstrumentedServiceMakerA, 259 "B": InstrumentedServiceMakerB, 260 "C": InstrumentedServiceMakerC, 261 } 262 started := make(map[string]bool) 263 for id, maker := range services { 264 id := id // Closure for the constructor 265 constructor := func(*ServiceContext) (Service, error) { 266 return &InstrumentedService{ 267 startHook: func(*p2p.Server) { started[id] = true }, 268 }, nil 269 } 270 if err := stack.Register(maker(constructor)); err != nil { 271 t.Fatalf("service %s: registration failed: %v", id, err) 272 } 273 } 274 // Register a service that fails to construct itself 275 failure := errors.New("fail") 276 failer := func(*ServiceContext) (Service, error) { 277 return nil, failure 278 } 279 if err := stack.Register(failer); err != nil { 280 t.Fatalf("failer registration failed: %v", err) 281 } 282 // Start the protocol stack and ensure none of the services get started 283 for i := 0; i < 100; i++ { 284 if err := stack.Start(); err != failure { 285 t.Fatalf("iter %d: stack startup failure mismatch: have %v, want %v", i, err, failure) 286 } 287 for id := range services { 288 if started[id] { 289 t.Fatalf("service %s: started should not have", id) 290 } 291 delete(started, id) 292 } 293 } 294 } 295 296 // Tests that if a service fails to start, all others started before it will be 297 // shut down. 298 func TestServiceStartupAbortion(t *testing.T) { 299 stack, err := New(testNodeConfig()) 300 if err != nil { 301 t.Fatalf("failed to create protocol stack: %v", err) 302 } 303 defer stack.Close() 304 305 // Register a batch of good services 306 services := map[string]InstrumentingWrapper{ 307 "A": InstrumentedServiceMakerA, 308 "B": InstrumentedServiceMakerB, 309 "C": InstrumentedServiceMakerC, 310 } 311 started := make(map[string]bool) 312 stopped := make(map[string]bool) 313 314 for id, maker := range services { 315 id := id // Closure for the constructor 316 constructor := func(*ServiceContext) (Service, error) { 317 return &InstrumentedService{ 318 startHook: func(*p2p.Server) { started[id] = true }, 319 stopHook: func() { stopped[id] = true }, 320 }, nil 321 } 322 if err := stack.Register(maker(constructor)); err != nil { 323 t.Fatalf("service %s: registration failed: %v", id, err) 324 } 325 } 326 // Register a service that fails to start 327 failure := errors.New("fail") 328 failer := func(*ServiceContext) (Service, error) { 329 return &InstrumentedService{ 330 start: failure, 331 }, nil 332 } 333 if err := stack.Register(failer); err != nil { 334 t.Fatalf("failer registration failed: %v", err) 335 } 336 // Start the protocol stack and ensure all started services stop 337 for i := 0; i < 100; i++ { 338 if err := stack.Start(); err != failure { 339 t.Fatalf("iter %d: stack startup failure mismatch: have %v, want %v", i, err, failure) 340 } 341 for id := range services { 342 if started[id] && !stopped[id] { 343 t.Fatalf("service %s: started but not stopped", id) 344 } 345 delete(started, id) 346 delete(stopped, id) 347 } 348 } 349 } 350 351 // Tests that even if a registered service fails to shut down cleanly, it does 352 // not influece the rest of the shutdown invocations. 353 func TestServiceTerminationGuarantee(t *testing.T) { 354 stack, err := New(testNodeConfig()) 355 if err != nil { 356 t.Fatalf("failed to create protocol stack: %v", err) 357 } 358 defer stack.Close() 359 360 // Register a batch of good services 361 services := map[string]InstrumentingWrapper{ 362 "A": InstrumentedServiceMakerA, 363 "B": InstrumentedServiceMakerB, 364 "C": InstrumentedServiceMakerC, 365 } 366 started := make(map[string]bool) 367 stopped := make(map[string]bool) 368 369 for id, maker := range services { 370 id := id // Closure for the constructor 371 constructor := func(*ServiceContext) (Service, error) { 372 return &InstrumentedService{ 373 startHook: func(*p2p.Server) { started[id] = true }, 374 stopHook: func() { stopped[id] = true }, 375 }, nil 376 } 377 if err := stack.Register(maker(constructor)); err != nil { 378 t.Fatalf("service %s: registration failed: %v", id, err) 379 } 380 } 381 // Register a service that fails to shot down cleanly 382 failure := errors.New("fail") 383 failer := func(*ServiceContext) (Service, error) { 384 return &InstrumentedService{ 385 stop: failure, 386 }, nil 387 } 388 if err := stack.Register(failer); err != nil { 389 t.Fatalf("failer registration failed: %v", err) 390 } 391 // Start the protocol stack, and ensure that a failing shut down terminates all 392 for i := 0; i < 100; i++ { 393 // Start the stack and make sure all is online 394 if err := stack.Start(); err != nil { 395 t.Fatalf("iter %d: failed to start protocol stack: %v", i, err) 396 } 397 for id := range services { 398 if !started[id] { 399 t.Fatalf("iter %d, service %s: service not running", i, id) 400 } 401 if stopped[id] { 402 t.Fatalf("iter %d, service %s: service already stopped", i, id) 403 } 404 } 405 // Stop the stack, verify failure and check all terminations 406 err := stack.Stop() 407 if err, ok := err.(*StopError); !ok { 408 t.Fatalf("iter %d: termination failure mismatch: have %v, want StopError", i, err) 409 } else { 410 failer := reflect.TypeOf(&InstrumentedService{}) 411 if err.Services[failer] != failure { 412 t.Fatalf("iter %d: failer termination failure mismatch: have %v, want %v", i, err.Services[failer], failure) 413 } 414 if len(err.Services) != 1 { 415 t.Fatalf("iter %d: failure count mismatch: have %d, want %d", i, len(err.Services), 1) 416 } 417 } 418 for id := range services { 419 if !stopped[id] { 420 t.Fatalf("iter %d, service %s: service not terminated", i, id) 421 } 422 delete(started, id) 423 delete(stopped, id) 424 } 425 } 426 } 427 428 // TestServiceRetrieval tests that individual services can be retrieved. 429 func TestServiceRetrieval(t *testing.T) { 430 // Create a simple stack and register two service types 431 stack, err := New(testNodeConfig()) 432 if err != nil { 433 t.Fatalf("failed to create protocol stack: %v", err) 434 } 435 defer stack.Close() 436 437 if err := stack.Register(NewNoopService); err != nil { 438 t.Fatalf("noop service registration failed: %v", err) 439 } 440 if err := stack.Register(NewInstrumentedService); err != nil { 441 t.Fatalf("instrumented service registration failed: %v", err) 442 } 443 // Make sure none of the services can be retrieved until started 444 var noopServ *NoopService 445 if err := stack.Service(&noopServ); err != ErrNodeStopped { 446 t.Fatalf("noop service retrieval mismatch: have %v, want %v", err, ErrNodeStopped) 447 } 448 var instServ *InstrumentedService 449 if err := stack.Service(&instServ); err != ErrNodeStopped { 450 t.Fatalf("instrumented service retrieval mismatch: have %v, want %v", err, ErrNodeStopped) 451 } 452 // Start the stack and ensure everything is retrievable now 453 if err := stack.Start(); err != nil { 454 t.Fatalf("failed to start stack: %v", err) 455 } 456 defer stack.Stop() 457 458 if err := stack.Service(&noopServ); err != nil { 459 t.Fatalf("noop service retrieval mismatch: have %v, want %v", err, nil) 460 } 461 if err := stack.Service(&instServ); err != nil { 462 t.Fatalf("instrumented service retrieval mismatch: have %v, want %v", err, nil) 463 } 464 } 465 466 // Tests that all protocols defined by individual services get launched. 467 func TestProtocolGather(t *testing.T) { 468 stack, err := New(testNodeConfig()) 469 if err != nil { 470 t.Fatalf("failed to create protocol stack: %v", err) 471 } 472 defer stack.Close() 473 474 // Register a batch of services with some configured number of protocols 475 services := map[string]struct { 476 Count int 477 Maker InstrumentingWrapper 478 }{ 479 "zero": {0, InstrumentedServiceMakerA}, 480 "one": {1, InstrumentedServiceMakerB}, 481 "many": {10, InstrumentedServiceMakerC}, 482 } 483 for id, config := range services { 484 protocols := make([]p2p.Protocol, config.Count) 485 for i := 0; i < len(protocols); i++ { 486 protocols[i].Name = id 487 protocols[i].Version = uint(i) 488 } 489 constructor := func(*ServiceContext) (Service, error) { 490 return &InstrumentedService{ 491 protocols: protocols, 492 }, nil 493 } 494 if err := stack.Register(config.Maker(constructor)); err != nil { 495 t.Fatalf("service %s: registration failed: %v", id, err) 496 } 497 } 498 // Start the services and ensure all protocols start successfully 499 if err := stack.Start(); err != nil { 500 t.Fatalf("failed to start protocol stack: %v", err) 501 } 502 defer stack.Stop() 503 504 protocols := stack.Server().Protocols 505 if len(protocols) != 11 { 506 t.Fatalf("mismatching number of protocols launched: have %d, want %d", len(protocols), 26) 507 } 508 for id, config := range services { 509 for ver := 0; ver < config.Count; ver++ { 510 launched := false 511 for i := 0; i < len(protocols); i++ { 512 if protocols[i].Name == id && protocols[i].Version == uint(ver) { 513 launched = true 514 break 515 } 516 } 517 if !launched { 518 t.Errorf("configured protocol not launched: %s v%d", id, ver) 519 } 520 } 521 } 522 } 523 524 // Tests that all APIs defined by individual services get exposed. 525 func TestAPIGather(t *testing.T) { 526 stack, err := New(testNodeConfig()) 527 if err != nil { 528 t.Fatalf("failed to create protocol stack: %v", err) 529 } 530 defer stack.Close() 531 532 // Register a batch of services with some configured APIs 533 calls := make(chan string, 1) 534 makeAPI := func(result string) *OneMethodAPI { 535 return &OneMethodAPI{fun: func() { calls <- result }} 536 } 537 services := map[string]struct { 538 APIs []rpc.API 539 Maker InstrumentingWrapper 540 }{ 541 "Zero APIs": { 542 []rpc.API{}, InstrumentedServiceMakerA}, 543 "Single API": { 544 []rpc.API{ 545 {Namespace: "single", Version: "1", Service: makeAPI("single.v1"), Public: true}, 546 }, InstrumentedServiceMakerB}, 547 "Many APIs": { 548 []rpc.API{ 549 {Namespace: "multi", Version: "1", Service: makeAPI("multi.v1"), Public: true}, 550 {Namespace: "multi.v2", Version: "2", Service: makeAPI("multi.v2"), Public: true}, 551 {Namespace: "multi.v2.nested", Version: "2", Service: makeAPI("multi.v2.nested"), Public: true}, 552 }, InstrumentedServiceMakerC}, 553 } 554 555 for id, config := range services { 556 config := config 557 constructor := func(*ServiceContext) (Service, error) { 558 return &InstrumentedService{apis: config.APIs}, nil 559 } 560 if err := stack.Register(config.Maker(constructor)); err != nil { 561 t.Fatalf("service %s: registration failed: %v", id, err) 562 } 563 } 564 // Start the services and ensure all API start successfully 565 if err := stack.Start(); err != nil { 566 t.Fatalf("failed to start protocol stack: %v", err) 567 } 568 defer stack.Stop() 569 570 // Connect to the RPC server and verify the various registered endpoints 571 client, err := stack.Attach() 572 if err != nil { 573 t.Fatalf("failed to connect to the inproc API server: %v", err) 574 } 575 defer client.Close() 576 577 tests := []struct { 578 Method string 579 Result string 580 }{ 581 {"single_theOneMethod", "single.v1"}, 582 {"multi_theOneMethod", "multi.v1"}, 583 {"multi.v2_theOneMethod", "multi.v2"}, 584 {"multi.v2.nested_theOneMethod", "multi.v2.nested"}, 585 } 586 for i, test := range tests { 587 if err := client.Call(nil, test.Method); err != nil { 588 t.Errorf("test %d: API request failed: %v", i, err) 589 } 590 select { 591 case result := <-calls: 592 if result != test.Result { 593 t.Errorf("test %d: result mismatch: have %s, want %s", i, result, test.Result) 594 } 595 case <-time.After(time.Second): 596 t.Fatalf("test %d: rpc execution timeout", i) 597 } 598 } 599 }