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  }