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  }