github.com/aigarnetwork/aigar@v0.0.0-20191115204914-d59a6eb70f8e/node/node_test.go (about)

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