github.com/n1ghtfa1l/go-vnt@v0.6.4-alpha.6/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/vntchain/go-vnt/crypto"
    28  	"github.com/vntchain/go-vnt/rpc"
    29  	p2p "github.com/vntchain/go-vnt/vntp2p"
    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, ListenAddr: "0030304"},
    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  	p2pCfg := p2p.Config{PrivateKey: testNodeKey, ListenAddr: "0030304"}
    87  
    88  	// Create a new node based on the data directory
    89  	original, err := New(&Config{DataDir: dir, P2P: p2pCfg})
    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, P2P: p2pCfg})
   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().Protocols
   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  		"Single API": {
   522  			[]rpc.API{
   523  				{Namespace: "single", Version: "1", Service: makeAPI("single.v1"), Public: true},
   524  			}, InstrumentedServiceMakerB},
   525  		"Many APIs": {
   526  			[]rpc.API{
   527  				{Namespace: "multi", Version: "1", Service: makeAPI("multi.v1"), Public: true},
   528  				{Namespace: "multi.v2", Version: "2", Service: makeAPI("multi.v2"), Public: true},
   529  				{Namespace: "multi.v2.nested", Version: "2", Service: makeAPI("multi.v2.nested"), Public: true},
   530  			}, InstrumentedServiceMakerC},
   531  	}
   532  
   533  	for id, config := range services {
   534  		config := config
   535  		constructor := func(*ServiceContext) (Service, error) {
   536  			return &InstrumentedService{apis: config.APIs}, nil
   537  		}
   538  		if err := stack.Register(config.Maker(constructor)); err != nil {
   539  			t.Fatalf("service %s: registration failed: %v", id, err)
   540  		}
   541  	}
   542  	// Start the services and ensure all API start successfully
   543  	if err := stack.Start(); err != nil {
   544  		t.Fatalf("failed to start protocol stack: %v", err)
   545  	}
   546  	defer stack.Stop()
   547  
   548  	// Connect to the RPC server and verify the various registered endpoints
   549  	client, err := stack.Attach()
   550  	if err != nil {
   551  		t.Fatalf("failed to connect to the inproc API server: %v", err)
   552  	}
   553  	defer client.Close()
   554  
   555  	tests := []struct {
   556  		Method string
   557  		Result string
   558  	}{
   559  		{"single_theOneMethod", "single.v1"},
   560  		{"multi_theOneMethod", "multi.v1"},
   561  		{"multi.v2_theOneMethod", "multi.v2"},
   562  		{"multi.v2.nested_theOneMethod", "multi.v2.nested"},
   563  	}
   564  	for i, test := range tests {
   565  		if err := client.Call(nil, test.Method); err != nil {
   566  			t.Errorf("test %d: API request failed: %v", i, err)
   567  		}
   568  		select {
   569  		case result := <-calls:
   570  			if result != test.Result {
   571  				t.Errorf("test %d: result mismatch: have %s, want %s", i, result, test.Result)
   572  			}
   573  		case <-time.After(time.Second):
   574  			t.Fatalf("test %d: rpc execution timeout", i)
   575  		}
   576  	}
   577  }