MCPcopy Create free account
hub / github.com/CPChain/chain / TestServiceTerminationGuarantee

Function TestServiceTerminationGuarantee

node/node_test.go:323–394  ·  view source on GitHub ↗

Tests that even if a registered service fails to shut down cleanly, it does not influece the rest of the shutdown invocations.

(t *testing.T)

Source from the content-addressed store, hash-verified

321// Tests that even if a registered service fails to shut down cleanly, it does
322// not influece the rest of the shutdown invocations.
323func TestServiceTerminationGuarantee(t *testing.T) {
324 stack, err := New(testNodeConfig())
325 if err != nil {
326 t.Fatalf("failed to create protocol stack: %v", err)
327 }
328 // Register a batch of good services
329 services := map[string]InstrumentingWrapper{
330 "A": InstrumentedServiceMakerA,
331 "B": InstrumentedServiceMakerB,
332 "C": InstrumentedServiceMakerC,
333 }
334 started := make(map[string]bool)
335 stopped := make(map[string]bool)
336
337 for id, maker := range services {
338 id := id // Closure for the constructor
339 constructor := func(*ServiceContext) (Service, error) {
340 return &InstrumentedService{
341 startHook: func(*p2p.Server) { started[id] = true },
342 stopHook: func() { stopped[id] = true },
343 }, nil
344 }
345 if err := stack.Register(maker(constructor)); err != nil {
346 t.Fatalf("service %s: registration failed: %v", id, err)
347 }
348 }
349 // Register a service that fails to shot down cleanly
350 failure := errors.New("fail")
351 failer := func(*ServiceContext) (Service, error) {
352 return &InstrumentedService{
353 stop: failure,
354 }, nil
355 }
356 if err := stack.Register(failer); err != nil {
357 t.Fatalf("failer registration failed: %v", err)
358 }
359 // Start the protocol stack, and ensure that a failing shut down terminates all
360 for i := 0; i < 100; i++ {
361 // Start the stack and make sure all is online
362 if err := stack.Start(); err != nil {
363 t.Fatalf("iter %d: failed to start protocol stack: %v", i, err)
364 }
365 for id := range services {
366 if !started[id] {
367 t.Fatalf("iter %d, service %s: service not running", i, id)
368 }
369 if stopped[id] {
370 t.Fatalf("iter %d, service %s: service already stopped", i, id)
371 }
372 }
373 // Stop the stack, verify failure and check all terminations
374 err := stack.Stop()
375 if err, ok := err.(*StopError); !ok {
376 t.Fatalf("iter %d: termination failure mismatch: have %v, want StopError", i, err)
377 } else {
378 failer := reflect.TypeOf(&InstrumentedService{})
379 if err.Services[failer] != failure {
380 t.Fatalf("iter %d: failer termination failure mismatch: have %v, want %v", i, err.Services[failer], failure)

Callers

nothing calls this directly

Calls 5

testNodeConfigFunction · 0.85
NewFunction · 0.70
StartMethod · 0.65
StopMethod · 0.65
RegisterMethod · 0.45

Tested by

no test coverage detected