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