github.com/klaytn/klaytn@v1.10.2/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  	"io/ioutil"
    26  	"os"
    27  	"reflect"
    28  	"testing"
    29  	"time"
    30  
    31  	"github.com/klaytn/klaytn/crypto"
    32  	"github.com/klaytn/klaytn/networks/p2p"
    33  	"github.com/klaytn/klaytn/networks/rpc"
    34  )
    35  
    36  var testNodeKey, _ = crypto.GenerateKey()
    37  
    38  func testNodeConfig() *Config {
    39  	return &Config{
    40  		Name: "test node",
    41  		P2P:  p2p.Config{PrivateKey: testNodeKey},
    42  	}
    43  }
    44  
    45  // Tests that an empty protocol stack can be started, restarted and stopped.
    46  func TestNodeLifeCycle(t *testing.T) {
    47  	stack, err := New(testNodeConfig())
    48  	if err != nil {
    49  		t.Fatalf("failed to create protocol stack: %v", err)
    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  	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})
   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().GetProtocols()
   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  		},
   522  		"Single API": {
   523  			[]rpc.API{
   524  				{Namespace: "single", Version: "1", Service: makeAPI("single.v1"), Public: true},
   525  			}, InstrumentedServiceMakerB,
   526  		},
   527  		"Many APIs": {
   528  			[]rpc.API{
   529  				{Namespace: "multi", Version: "1", Service: makeAPI("multi.v1"), Public: true},
   530  				{Namespace: "multi.v2", Version: "2", Service: makeAPI("multi.v2"), Public: true},
   531  				{Namespace: "multi.v2.nested", Version: "2", Service: makeAPI("multi.v2.nested"), Public: true},
   532  			}, InstrumentedServiceMakerC,
   533  		},
   534  	}
   535  
   536  	for id, config := range services {
   537  		config := config
   538  		constructor := func(*ServiceContext) (Service, error) {
   539  			return &InstrumentedService{apis: config.APIs}, nil
   540  		}
   541  		if err := stack.Register(config.Maker(constructor)); err != nil {
   542  			t.Fatalf("service %s: registration failed: %v", id, err)
   543  		}
   544  	}
   545  	// Start the services and ensure all API start successfully
   546  	if err := stack.Start(); err != nil {
   547  		t.Fatalf("failed to start protocol stack: %v", err)
   548  	}
   549  	defer stack.Stop()
   550  
   551  	// Connect to the RPC server and verify the various registered endpoints
   552  	client, err := stack.Attach()
   553  	if err != nil {
   554  		t.Fatalf("failed to connect to the inproc API server: %v", err)
   555  	}
   556  	defer client.Close()
   557  
   558  	tests := []struct {
   559  		Method string
   560  		Result string
   561  	}{
   562  		{"single_theOneMethod", "single.v1"},
   563  		{"multi_theOneMethod", "multi.v1"},
   564  		{"multi.v2_theOneMethod", "multi.v2"},
   565  		{"multi.v2.nested_theOneMethod", "multi.v2.nested"},
   566  	}
   567  	for i, test := range tests {
   568  		if err := client.Call(nil, test.Method); err != nil {
   569  			t.Errorf("test %d: API request failed: %v", i, err)
   570  		}
   571  		select {
   572  		case result := <-calls:
   573  			if result != test.Result {
   574  				t.Errorf("test %d: result mismatch: have %s, want %s", i, result, test.Result)
   575  			}
   576  		case <-time.After(time.Second):
   577  			t.Fatalf("test %d: rpc execution timeout", i)
   578  		}
   579  	}
   580  }