github.com/neatlab/neatio@v1.7.3-0.20220425043230-d903e92fcc75/network/node/node_test.go (about)

     1  package node
     2  
     3  import (
     4  	"errors"
     5  	"io/ioutil"
     6  	"os"
     7  	"reflect"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/neatlab/neatio/network/p2p"
    12  	"github.com/neatlab/neatio/network/rpc"
    13  	"github.com/neatlab/neatio/utilities/crypto"
    14  )
    15  
    16  var (
    17  	testNodeKey, _ = crypto.GenerateKey()
    18  )
    19  
    20  func testNodeConfig() *Config {
    21  	return &Config{
    22  		Name: "test node",
    23  		P2P:  p2p.Config{PrivateKey: testNodeKey},
    24  	}
    25  }
    26  
    27  func TestNodeLifeCycle(t *testing.T) {
    28  	stack, err := New(testNodeConfig())
    29  	if err != nil {
    30  		t.Fatalf("failed to create protocol stack: %v", err)
    31  	}
    32  
    33  	for i := 0; i < 3; i++ {
    34  		if err := stack.Stop(); err != ErrNodeStopped {
    35  			t.Fatalf("iter %d: stop failure mismatch: have %v, want %v", i, err, ErrNodeStopped)
    36  		}
    37  	}
    38  
    39  	if err := stack.Start(); err != nil {
    40  		t.Fatalf("failed to start node: %v", err)
    41  	}
    42  	if err := stack.Start(); err != ErrNodeRunning {
    43  		t.Fatalf("start failure mismatch: have %v, want %v ", err, ErrNodeRunning)
    44  	}
    45  
    46  	for i := 0; i < 3; i++ {
    47  		if err := stack.Restart(); err != nil {
    48  			t.Fatalf("iter %d: failed to restart node: %v", i, err)
    49  		}
    50  	}
    51  
    52  	if err := stack.Stop(); err != nil {
    53  		t.Fatalf("failed to stop node: %v", err)
    54  	}
    55  	if err := stack.Stop(); err != ErrNodeStopped {
    56  		t.Fatalf("stop failure mismatch: have %v, want %v ", err, ErrNodeStopped)
    57  	}
    58  }
    59  
    60  func TestNodeUsedDataDir(t *testing.T) {
    61  
    62  	dir, err := ioutil.TempDir("", "")
    63  	if err != nil {
    64  		t.Fatalf("failed to create temporary data directory: %v", err)
    65  	}
    66  	defer os.RemoveAll(dir)
    67  
    68  	original, err := New(&Config{DataDir: dir})
    69  	if err != nil {
    70  		t.Fatalf("failed to create original protocol stack: %v", err)
    71  	}
    72  	if err := original.Start(); err != nil {
    73  		t.Fatalf("failed to start original protocol stack: %v", err)
    74  	}
    75  	defer original.Stop()
    76  
    77  	duplicate, err := New(&Config{DataDir: dir})
    78  	if err != nil {
    79  		t.Fatalf("failed to create duplicate protocol stack: %v", err)
    80  	}
    81  	if err := duplicate.Start(); err != ErrDatadirUsed {
    82  		t.Fatalf("duplicate datadir failure mismatch: have %v, want %v", err, ErrDatadirUsed)
    83  	}
    84  }
    85  
    86  func TestServiceRegistry(t *testing.T) {
    87  	stack, err := New(testNodeConfig())
    88  	if err != nil {
    89  		t.Fatalf("failed to create protocol stack: %v", err)
    90  	}
    91  
    92  	services := []ServiceConstructor{NewNoopServiceA, NewNoopServiceB, NewNoopServiceC}
    93  	for i, constructor := range services {
    94  		if err := stack.Register(constructor); err != nil {
    95  			t.Fatalf("service #%d: registration failed: %v", i, err)
    96  		}
    97  	}
    98  	if err := stack.Start(); err != nil {
    99  		t.Fatalf("failed to start original service stack: %v", err)
   100  	}
   101  	if err := stack.Stop(); err != nil {
   102  		t.Fatalf("failed to stop original service stack: %v", err)
   103  	}
   104  
   105  	if err := stack.Register(NewNoopServiceB); err != nil {
   106  		t.Fatalf("duplicate registration failed: %v", err)
   107  	}
   108  	if err := stack.Start(); err == nil {
   109  		t.Fatalf("duplicate service started")
   110  	} else {
   111  		if _, ok := err.(*DuplicateServiceError); !ok {
   112  			t.Fatalf("duplicate error mismatch: have %v, want %v", err, DuplicateServiceError{})
   113  		}
   114  	}
   115  }
   116  
   117  func TestServiceLifeCycle(t *testing.T) {
   118  	stack, err := New(testNodeConfig())
   119  	if err != nil {
   120  		t.Fatalf("failed to create protocol stack: %v", err)
   121  	}
   122  
   123  	services := map[string]InstrumentingWrapper{
   124  		"A": InstrumentedServiceMakerA,
   125  		"B": InstrumentedServiceMakerB,
   126  		"C": InstrumentedServiceMakerC,
   127  	}
   128  	started := make(map[string]bool)
   129  	stopped := make(map[string]bool)
   130  
   131  	for id, maker := range services {
   132  		id := id
   133  		constructor := func(*ServiceContext) (Service, error) {
   134  			return &InstrumentedService{
   135  				startHook: func(*p2p.Server) { started[id] = true },
   136  				stopHook:  func() { stopped[id] = true },
   137  			}, nil
   138  		}
   139  		if err := stack.Register(maker(constructor)); err != nil {
   140  			t.Fatalf("service %s: registration failed: %v", id, err)
   141  		}
   142  	}
   143  
   144  	if err := stack.Start(); err != nil {
   145  		t.Fatalf("failed to start protocol stack: %v", err)
   146  	}
   147  	for id := range services {
   148  		if !started[id] {
   149  			t.Fatalf("service %s: freshly started service not running", id)
   150  		}
   151  		if stopped[id] {
   152  			t.Fatalf("service %s: freshly started service already stopped", id)
   153  		}
   154  	}
   155  
   156  	if err := stack.Stop(); err != nil {
   157  		t.Fatalf("failed to stop protocol stack: %v", err)
   158  	}
   159  	for id := range services {
   160  		if !stopped[id] {
   161  			t.Fatalf("service %s: freshly terminated service still running", id)
   162  		}
   163  	}
   164  }
   165  
   166  func TestServiceRestarts(t *testing.T) {
   167  	stack, err := New(testNodeConfig())
   168  	if err != nil {
   169  		t.Fatalf("failed to create protocol stack: %v", err)
   170  	}
   171  
   172  	var (
   173  		running bool
   174  		started int
   175  	)
   176  	constructor := func(*ServiceContext) (Service, error) {
   177  		running = false
   178  
   179  		return &InstrumentedService{
   180  			startHook: func(*p2p.Server) {
   181  				if running {
   182  					panic("already running")
   183  				}
   184  				running = true
   185  				started++
   186  			},
   187  		}, nil
   188  	}
   189  
   190  	if err := stack.Register(constructor); err != nil {
   191  		t.Fatalf("failed to register the service: %v", err)
   192  	}
   193  	if err := stack.Start(); err != nil {
   194  		t.Fatalf("failed to start protocol stack: %v", err)
   195  	}
   196  	defer stack.Stop()
   197  
   198  	if !running || started != 1 {
   199  		t.Fatalf("running/started mismatch: have %v/%d, want true/1", running, started)
   200  	}
   201  
   202  	for i := 0; i < 3; i++ {
   203  		if err := stack.Restart(); err != nil {
   204  			t.Fatalf("iter %d: failed to restart stack: %v", i, err)
   205  		}
   206  	}
   207  	if !running || started != 4 {
   208  		t.Fatalf("running/started mismatch: have %v/%d, want true/4", running, started)
   209  	}
   210  }
   211  
   212  func TestServiceConstructionAbortion(t *testing.T) {
   213  	stack, err := New(testNodeConfig())
   214  	if err != nil {
   215  		t.Fatalf("failed to create protocol stack: %v", err)
   216  	}
   217  
   218  	services := map[string]InstrumentingWrapper{
   219  		"A": InstrumentedServiceMakerA,
   220  		"B": InstrumentedServiceMakerB,
   221  		"C": InstrumentedServiceMakerC,
   222  	}
   223  	started := make(map[string]bool)
   224  	for id, maker := range services {
   225  		id := id
   226  		constructor := func(*ServiceContext) (Service, error) {
   227  			return &InstrumentedService{
   228  				startHook: func(*p2p.Server) { started[id] = true },
   229  			}, nil
   230  		}
   231  		if err := stack.Register(maker(constructor)); err != nil {
   232  			t.Fatalf("service %s: registration failed: %v", id, err)
   233  		}
   234  	}
   235  
   236  	failure := errors.New("fail")
   237  	failer := func(*ServiceContext) (Service, error) {
   238  		return nil, failure
   239  	}
   240  	if err := stack.Register(failer); err != nil {
   241  		t.Fatalf("failer registration failed: %v", err)
   242  	}
   243  
   244  	for i := 0; i < 100; i++ {
   245  		if err := stack.Start(); err != failure {
   246  			t.Fatalf("iter %d: stack startup failure mismatch: have %v, want %v", i, err, failure)
   247  		}
   248  		for id := range services {
   249  			if started[id] {
   250  				t.Fatalf("service %s: started should not have", id)
   251  			}
   252  			delete(started, id)
   253  		}
   254  	}
   255  }
   256  
   257  func TestServiceStartupAbortion(t *testing.T) {
   258  	stack, err := New(testNodeConfig())
   259  	if err != nil {
   260  		t.Fatalf("failed to create protocol stack: %v", err)
   261  	}
   262  
   263  	services := map[string]InstrumentingWrapper{
   264  		"A": InstrumentedServiceMakerA,
   265  		"B": InstrumentedServiceMakerB,
   266  		"C": InstrumentedServiceMakerC,
   267  	}
   268  	started := make(map[string]bool)
   269  	stopped := make(map[string]bool)
   270  
   271  	for id, maker := range services {
   272  		id := id
   273  		constructor := func(*ServiceContext) (Service, error) {
   274  			return &InstrumentedService{
   275  				startHook: func(*p2p.Server) { started[id] = true },
   276  				stopHook:  func() { stopped[id] = true },
   277  			}, nil
   278  		}
   279  		if err := stack.Register(maker(constructor)); err != nil {
   280  			t.Fatalf("service %s: registration failed: %v", id, err)
   281  		}
   282  	}
   283  
   284  	failure := errors.New("fail")
   285  	failer := func(*ServiceContext) (Service, error) {
   286  		return &InstrumentedService{
   287  			start: failure,
   288  		}, nil
   289  	}
   290  	if err := stack.Register(failer); err != nil {
   291  		t.Fatalf("failer registration failed: %v", err)
   292  	}
   293  
   294  	for i := 0; i < 100; i++ {
   295  		if err := stack.Start(); err != failure {
   296  			t.Fatalf("iter %d: stack startup failure mismatch: have %v, want %v", i, err, failure)
   297  		}
   298  		for id := range services {
   299  			if started[id] && !stopped[id] {
   300  				t.Fatalf("service %s: started but not stopped", id)
   301  			}
   302  			delete(started, id)
   303  			delete(stopped, id)
   304  		}
   305  	}
   306  }
   307  
   308  func TestServiceTerminationGuarantee(t *testing.T) {
   309  	stack, err := New(testNodeConfig())
   310  	if err != nil {
   311  		t.Fatalf("failed to create protocol stack: %v", err)
   312  	}
   313  
   314  	services := map[string]InstrumentingWrapper{
   315  		"A": InstrumentedServiceMakerA,
   316  		"B": InstrumentedServiceMakerB,
   317  		"C": InstrumentedServiceMakerC,
   318  	}
   319  	started := make(map[string]bool)
   320  	stopped := make(map[string]bool)
   321  
   322  	for id, maker := range services {
   323  		id := id
   324  		constructor := func(*ServiceContext) (Service, error) {
   325  			return &InstrumentedService{
   326  				startHook: func(*p2p.Server) { started[id] = true },
   327  				stopHook:  func() { stopped[id] = true },
   328  			}, nil
   329  		}
   330  		if err := stack.Register(maker(constructor)); err != nil {
   331  			t.Fatalf("service %s: registration failed: %v", id, err)
   332  		}
   333  	}
   334  
   335  	failure := errors.New("fail")
   336  	failer := func(*ServiceContext) (Service, error) {
   337  		return &InstrumentedService{
   338  			stop: failure,
   339  		}, nil
   340  	}
   341  	if err := stack.Register(failer); err != nil {
   342  		t.Fatalf("failer registration failed: %v", err)
   343  	}
   344  
   345  	for i := 0; i < 100; i++ {
   346  
   347  		if err := stack.Start(); err != nil {
   348  			t.Fatalf("iter %d: failed to start protocol stack: %v", i, err)
   349  		}
   350  		for id := range services {
   351  			if !started[id] {
   352  				t.Fatalf("iter %d, service %s: service not running", i, id)
   353  			}
   354  			if stopped[id] {
   355  				t.Fatalf("iter %d, service %s: service already stopped", i, id)
   356  			}
   357  		}
   358  
   359  		err := stack.Stop()
   360  		if err, ok := err.(*StopError); !ok {
   361  			t.Fatalf("iter %d: termination failure mismatch: have %v, want StopError", i, err)
   362  		} else {
   363  			failer := reflect.TypeOf(&InstrumentedService{})
   364  			if err.Services[failer] != failure {
   365  				t.Fatalf("iter %d: failer termination failure mismatch: have %v, want %v", i, err.Services[failer], failure)
   366  			}
   367  			if len(err.Services) != 1 {
   368  				t.Fatalf("iter %d: failure count mismatch: have %d, want %d", i, len(err.Services), 1)
   369  			}
   370  		}
   371  		for id := range services {
   372  			if !stopped[id] {
   373  				t.Fatalf("iter %d, service %s: service not terminated", i, id)
   374  			}
   375  			delete(started, id)
   376  			delete(stopped, id)
   377  		}
   378  	}
   379  }
   380  
   381  func TestServiceRetrieval(t *testing.T) {
   382  
   383  	stack, err := New(testNodeConfig())
   384  	if err != nil {
   385  		t.Fatalf("failed to create protocol stack: %v", err)
   386  	}
   387  	if err := stack.Register(NewNoopService); err != nil {
   388  		t.Fatalf("noop service registration failed: %v", err)
   389  	}
   390  	if err := stack.Register(NewInstrumentedService); err != nil {
   391  		t.Fatalf("instrumented service registration failed: %v", err)
   392  	}
   393  
   394  	var noopServ *NoopService
   395  	if err := stack.Service(&noopServ); err != ErrNodeStopped {
   396  		t.Fatalf("noop service retrieval mismatch: have %v, want %v", err, ErrNodeStopped)
   397  	}
   398  	var instServ *InstrumentedService
   399  	if err := stack.Service(&instServ); err != ErrNodeStopped {
   400  		t.Fatalf("instrumented service retrieval mismatch: have %v, want %v", err, ErrNodeStopped)
   401  	}
   402  
   403  	if err := stack.Start(); err != nil {
   404  		t.Fatalf("failed to start stack: %v", err)
   405  	}
   406  	defer stack.Stop()
   407  
   408  	if err := stack.Service(&noopServ); err != nil {
   409  		t.Fatalf("noop service retrieval mismatch: have %v, want %v", err, nil)
   410  	}
   411  	if err := stack.Service(&instServ); err != nil {
   412  		t.Fatalf("instrumented service retrieval mismatch: have %v, want %v", err, nil)
   413  	}
   414  }
   415  
   416  func TestProtocolGather(t *testing.T) {
   417  	stack, err := New(testNodeConfig())
   418  	if err != nil {
   419  		t.Fatalf("failed to create protocol stack: %v", err)
   420  	}
   421  
   422  	services := map[string]struct {
   423  		Count int
   424  		Maker InstrumentingWrapper
   425  	}{
   426  		"Zero Protocols":  {0, InstrumentedServiceMakerA},
   427  		"Single Protocol": {1, InstrumentedServiceMakerB},
   428  		"Many Protocols":  {25, InstrumentedServiceMakerC},
   429  	}
   430  	for id, config := range services {
   431  		protocols := make([]p2p.Protocol, config.Count)
   432  		for i := 0; i < len(protocols); i++ {
   433  			protocols[i].Name = id
   434  			protocols[i].Version = uint(i)
   435  		}
   436  		constructor := func(*ServiceContext) (Service, error) {
   437  			return &InstrumentedService{
   438  				protocols: protocols,
   439  			}, nil
   440  		}
   441  		if err := stack.Register(config.Maker(constructor)); err != nil {
   442  			t.Fatalf("service %s: registration failed: %v", id, err)
   443  		}
   444  	}
   445  
   446  	if err := stack.Start(); err != nil {
   447  		t.Fatalf("failed to start protocol stack: %v", err)
   448  	}
   449  	defer stack.Stop()
   450  
   451  	protocols := stack.Server().Protocols
   452  	if len(protocols) != 26 {
   453  		t.Fatalf("mismatching number of protocols launched: have %d, want %d", len(protocols), 26)
   454  	}
   455  	for id, config := range services {
   456  		for ver := 0; ver < config.Count; ver++ {
   457  			launched := false
   458  			for i := 0; i < len(protocols); i++ {
   459  				if protocols[i].Name == id && protocols[i].Version == uint(ver) {
   460  					launched = true
   461  					break
   462  				}
   463  			}
   464  			if !launched {
   465  				t.Errorf("configured protocol not launched: %s v%d", id, ver)
   466  			}
   467  		}
   468  	}
   469  }
   470  
   471  func TestAPIGather(t *testing.T) {
   472  	stack, err := New(testNodeConfig())
   473  	if err != nil {
   474  		t.Fatalf("failed to create protocol stack: %v", err)
   475  	}
   476  
   477  	calls := make(chan string, 1)
   478  	makeAPI := func(result string) *OneMethodApi {
   479  		return &OneMethodApi{fun: func() { calls <- result }}
   480  	}
   481  	services := map[string]struct {
   482  		APIs  []rpc.API
   483  		Maker InstrumentingWrapper
   484  	}{
   485  		"Zero APIs": {
   486  			[]rpc.API{}, InstrumentedServiceMakerA},
   487  		"Single API": {
   488  			[]rpc.API{
   489  				{Namespace: "single", Version: "1", Service: makeAPI("single.v1"), Public: true},
   490  			}, InstrumentedServiceMakerB},
   491  		"Many APIs": {
   492  			[]rpc.API{
   493  				{Namespace: "multi", Version: "1", Service: makeAPI("multi.v1"), Public: true},
   494  				{Namespace: "multi.v2", Version: "2", Service: makeAPI("multi.v2"), Public: true},
   495  				{Namespace: "multi.v2.nested", Version: "2", Service: makeAPI("multi.v2.nested"), Public: true},
   496  			}, InstrumentedServiceMakerC},
   497  	}
   498  
   499  	for id, config := range services {
   500  		config := config
   501  		constructor := func(*ServiceContext) (Service, error) {
   502  			return &InstrumentedService{apis: config.APIs}, nil
   503  		}
   504  		if err := stack.Register(config.Maker(constructor)); err != nil {
   505  			t.Fatalf("service %s: registration failed: %v", id, err)
   506  		}
   507  	}
   508  
   509  	if err := stack.Start(); err != nil {
   510  		t.Fatalf("failed to start protocol stack: %v", err)
   511  	}
   512  	defer stack.Stop()
   513  
   514  	client, err := stack.Attach()
   515  	if err != nil {
   516  		t.Fatalf("failed to connect to the inproc API server: %v", err)
   517  	}
   518  	defer client.Close()
   519  
   520  	tests := []struct {
   521  		Method string
   522  		Result string
   523  	}{
   524  		{"single_theOneMethod", "single.v1"},
   525  		{"multi_theOneMethod", "multi.v1"},
   526  		{"multi.v2_theOneMethod", "multi.v2"},
   527  		{"multi.v2.nested_theOneMethod", "multi.v2.nested"},
   528  	}
   529  	for i, test := range tests {
   530  		if err := client.Call(nil, test.Method); err != nil {
   531  			t.Errorf("test %d: API request failed: %v", i, err)
   532  		}
   533  		select {
   534  		case result := <-calls:
   535  			if result != test.Result {
   536  				t.Errorf("test %d: result mismatch: have %s, want %s", i, result, test.Result)
   537  			}
   538  		case <-time.After(time.Second):
   539  			t.Fatalf("test %d: rpc execution timeout", i)
   540  		}
   541  	}
   542  }