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