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