github.com/braveheart12/insolar-09-08-19@v0.8.7/network/servicenetwork/suite_test.go (about)

     1  /*
     2   * The Clear BSD License
     3   *
     4   * Copyright (c) 2019 Insolar Technologies
     5   *
     6   * All rights reserved.
     7   *
     8   * Redistribution and use in source and binary forms, with or without modification, are permitted (subject to the limitations in the disclaimer below) provided that the following conditions are met:
     9   *
    10   *  Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
    11   *  Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
    12   *  Neither the name of Insolar Technologies nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
    13   *
    14   * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    15   *
    16   */
    17  
    18  package servicenetwork
    19  
    20  import (
    21  	"context"
    22  	"crypto"
    23  	"fmt"
    24  	"math/rand"
    25  	"strconv"
    26  	"strings"
    27  	"sync"
    28  	"time"
    29  
    30  	"github.com/insolar/insolar/certificate"
    31  	"github.com/insolar/insolar/component"
    32  	"github.com/insolar/insolar/configuration"
    33  	"github.com/insolar/insolar/consensus/packets"
    34  	"github.com/insolar/insolar/core"
    35  	"github.com/insolar/insolar/cryptography"
    36  	"github.com/insolar/insolar/log"
    37  	"github.com/insolar/insolar/network"
    38  	"github.com/insolar/insolar/network/nodenetwork"
    39  	"github.com/insolar/insolar/network/utils"
    40  	"github.com/insolar/insolar/platformpolicy"
    41  	"github.com/insolar/insolar/testutils"
    42  	"github.com/stretchr/testify/require"
    43  	"github.com/stretchr/testify/suite"
    44  )
    45  
    46  var (
    47  	testNetworkPort       = 10010
    48  	pulseTimeMs     int32 = 5000
    49  	reqTimeoutMs    int32 = 2000
    50  	pulseDelta      int32 = 5
    51  )
    52  
    53  type fixture struct {
    54  	ctx            context.Context
    55  	bootstrapNodes []*networkNode
    56  	networkNodes   []*networkNode
    57  	pulsar         TestPulsar
    58  }
    59  
    60  func newFixture() *fixture {
    61  	return &fixture{
    62  		ctx:            context.Background(),
    63  		bootstrapNodes: make([]*networkNode, 0),
    64  		networkNodes:   make([]*networkNode, 0),
    65  	}
    66  }
    67  
    68  type testSuite struct {
    69  	suite.Suite
    70  	fixtureMap     map[string]*fixture
    71  	bootstrapCount int
    72  	nodesCount     int
    73  }
    74  
    75  func NewTestSuite(bootstrapCount, nodesCount int) *testSuite {
    76  	return &testSuite{
    77  		Suite:          suite.Suite{},
    78  		fixtureMap:     make(map[string]*fixture, 0),
    79  		bootstrapCount: bootstrapCount,
    80  		nodesCount:     nodesCount,
    81  	}
    82  }
    83  
    84  func (s *testSuite) fixture() *fixture {
    85  	return s.fixtureMap[s.T().Name()]
    86  }
    87  
    88  // SetupSuite creates and run network with bootstrap and common nodes once before run all tests in the suite
    89  func (s *testSuite) SetupTest() {
    90  	s.fixtureMap[s.T().Name()] = newFixture()
    91  	var err error
    92  	s.fixture().pulsar, err = NewTestPulsar(pulseTimeMs, reqTimeoutMs, pulseDelta)
    93  	require.NoError(s.T(), err)
    94  
    95  	log.Info("SetupTest")
    96  
    97  	for i := 0; i < s.bootstrapCount; i++ {
    98  		s.fixture().bootstrapNodes = append(s.fixture().bootstrapNodes, newNetworkNode())
    99  	}
   100  
   101  	for i := 0; i < s.nodesCount; i++ {
   102  		s.fixture().networkNodes = append(s.fixture().networkNodes, newNetworkNode())
   103  	}
   104  
   105  	pulseReceivers := make([]string, 0)
   106  	for _, node := range s.fixture().bootstrapNodes {
   107  		pulseReceivers = append(pulseReceivers, node.host)
   108  	}
   109  
   110  	log.Info("Start test pulsar")
   111  	err = s.fixture().pulsar.Start(s.fixture().ctx, pulseReceivers)
   112  	require.NoError(s.T(), err)
   113  
   114  	log.Info("Setup bootstrap nodes")
   115  	s.SetupNodesNetwork(s.fixture().bootstrapNodes)
   116  
   117  	<-time.After(time.Second * 2)
   118  	activeNodes := s.fixture().bootstrapNodes[0].serviceNetwork.NodeKeeper.GetActiveNodes()
   119  	require.Equal(s.T(), len(s.fixture().bootstrapNodes), len(activeNodes))
   120  
   121  	if len(s.fixture().networkNodes) > 0 {
   122  		log.Info("Setup network nodes")
   123  		s.SetupNodesNetwork(s.fixture().networkNodes)
   124  		s.waitForConsensus(2)
   125  
   126  		// active nodes count verification
   127  		activeNodes1 := s.fixture().networkNodes[0].serviceNetwork.NodeKeeper.GetActiveNodes()
   128  		activeNodes2 := s.fixture().networkNodes[0].serviceNetwork.NodeKeeper.GetActiveNodes()
   129  
   130  		require.Equal(s.T(), s.getNodesCount(), len(activeNodes1))
   131  		require.Equal(s.T(), s.getNodesCount(), len(activeNodes2))
   132  	}
   133  	fmt.Println("=================== SetupTest() Done")
   134  }
   135  
   136  func (s *testSuite) SetupNodesNetwork(nodes []*networkNode) {
   137  	for _, node := range nodes {
   138  		s.preInitNode(node)
   139  	}
   140  
   141  	results := make(chan error, len(nodes))
   142  	initNode := func(node *networkNode) {
   143  		err := node.init(s.fixture().ctx)
   144  		results <- err
   145  	}
   146  	startNode := func(node *networkNode) {
   147  		err := node.componentManager.Start(s.fixture().ctx)
   148  		results <- err
   149  	}
   150  
   151  	waitResults := func(results chan error, expected int) {
   152  		count := 0
   153  		for count < expected {
   154  			err := <-results
   155  			s.Require().NoError(err)
   156  			count++
   157  		}
   158  	}
   159  
   160  	log.Info("Init nodes")
   161  	for _, node := range nodes {
   162  		go initNode(node)
   163  	}
   164  	waitResults(results, len(nodes))
   165  
   166  	log.Info("Start nodes")
   167  	for _, node := range nodes {
   168  		go startNode(node)
   169  	}
   170  	waitResults(results, len(nodes))
   171  }
   172  
   173  // TearDownSuite shutdowns all nodes in network, calls once after all tests in suite finished
   174  func (s *testSuite) TearDownTest() {
   175  	log.Info("=================== TearDownTest()")
   176  	log.Info("Stop network nodes")
   177  	for _, n := range s.fixture().networkNodes {
   178  		err := n.componentManager.Stop(s.fixture().ctx)
   179  		s.NoError(err)
   180  	}
   181  	log.Info("Stop bootstrap nodes")
   182  	for _, n := range s.fixture().bootstrapNodes {
   183  		err := n.componentManager.Stop(s.fixture().ctx)
   184  		s.NoError(err)
   185  	}
   186  	log.Info("Stop test pulsar")
   187  	s.fixture().pulsar.Stop(s.fixture().ctx)
   188  }
   189  
   190  func (s *testSuite) waitForConsensus(consensusCount int) {
   191  	for i := 0; i < consensusCount; i++ {
   192  		for _, n := range s.fixture().bootstrapNodes {
   193  			err := <-n.consensusResult
   194  			s.NoError(err)
   195  		}
   196  
   197  		for _, n := range s.fixture().networkNodes {
   198  			err := <-n.consensusResult
   199  			s.NoError(err)
   200  		}
   201  	}
   202  }
   203  
   204  func (s *testSuite) waitForConsensusExcept(consensusCount int, exception core.RecordRef) {
   205  	for i := 0; i < consensusCount; i++ {
   206  		for _, n := range s.fixture().bootstrapNodes {
   207  			if n.id.Equal(exception) {
   208  				continue
   209  			}
   210  			err := <-n.consensusResult
   211  			s.NoError(err)
   212  		}
   213  
   214  		for _, n := range s.fixture().networkNodes {
   215  			if n.id.Equal(exception) {
   216  				continue
   217  			}
   218  			err := <-n.consensusResult
   219  			s.NoError(err)
   220  		}
   221  	}
   222  }
   223  
   224  // nodesCount returns count of nodes in network without testNode
   225  func (s *testSuite) getNodesCount() int {
   226  	return len(s.fixture().bootstrapNodes) + len(s.fixture().networkNodes)
   227  }
   228  
   229  func (s *testSuite) InitNode(node *networkNode) {
   230  	if node.componentManager != nil {
   231  		err := node.init(s.fixture().ctx)
   232  		s.NoError(err)
   233  	}
   234  }
   235  
   236  func (s *testSuite) StartNode(node *networkNode) {
   237  	if node.componentManager != nil {
   238  		err := node.componentManager.Start(s.fixture().ctx)
   239  		s.NoError(err)
   240  	}
   241  }
   242  
   243  func (s *testSuite) StopNode(node *networkNode) {
   244  	if node.componentManager != nil {
   245  		err := node.componentManager.Stop(s.fixture().ctx)
   246  		s.NoError(err)
   247  	}
   248  }
   249  
   250  type networkNode struct {
   251  	id                  core.RecordRef
   252  	role                core.StaticRole
   253  	privateKey          crypto.PrivateKey
   254  	cryptographyService core.CryptographyService
   255  	host                string
   256  
   257  	componentManager *component.Manager
   258  	serviceNetwork   *ServiceNetwork
   259  	consensusResult  chan error
   260  }
   261  
   262  // newNetworkNode returns networkNode initialized only with id, host address and key pair
   263  func newNetworkNode() *networkNode {
   264  	key, err := platformpolicy.NewKeyProcessor().GeneratePrivateKey()
   265  	if err != nil {
   266  		panic(err.Error())
   267  	}
   268  	address := "127.0.0.1:" + strconv.Itoa(testNetworkPort)
   269  	testNetworkPort += 2 // coz consensus transport port+=1
   270  
   271  	return &networkNode{
   272  		id:                  testutils.RandomRef(),
   273  		role:                RandomRole(),
   274  		privateKey:          key,
   275  		cryptographyService: cryptography.NewKeyBoundCryptographyService(key),
   276  		host:                address,
   277  		consensusResult:     make(chan error, 30),
   278  	}
   279  }
   280  
   281  // init calls Init for node component manager and wraps PhaseManager
   282  func (n *networkNode) init(ctx context.Context) error {
   283  	err := n.componentManager.Init(ctx)
   284  	n.serviceNetwork.PhaseManager = &phaseManagerWrapper{original: n.serviceNetwork.PhaseManager, result: n.consensusResult}
   285  	n.serviceNetwork.NodeKeeper = &nodeKeeperWrapper{original: n.serviceNetwork.NodeKeeper}
   286  	return err
   287  }
   288  
   289  func (s *testSuite) initCrypto(node *networkNode) (*certificate.CertificateManager, core.CryptographyService) {
   290  	pubKey, err := node.cryptographyService.GetPublicKey()
   291  	s.NoError(err)
   292  
   293  	// init certificate
   294  
   295  	proc := platformpolicy.NewKeyProcessor()
   296  	publicKey, err := proc.ExportPublicKeyPEM(pubKey)
   297  	s.NoError(err)
   298  
   299  	cert := &certificate.Certificate{}
   300  	cert.PublicKey = string(publicKey[:])
   301  	cert.Reference = node.id.String()
   302  	cert.Role = node.role.String()
   303  	cert.BootstrapNodes = make([]certificate.BootstrapNode, 0)
   304  
   305  	for _, b := range s.fixture().bootstrapNodes {
   306  		pubKey, _ := b.cryptographyService.GetPublicKey()
   307  		pubKeyBuf, err := proc.ExportPublicKeyPEM(pubKey)
   308  		s.NoError(err)
   309  
   310  		bootstrapNode := certificate.NewBootstrapNode(
   311  			pubKey,
   312  			string(pubKeyBuf[:]),
   313  			b.host,
   314  			b.id.String())
   315  
   316  		cert.BootstrapNodes = append(cert.BootstrapNodes, *bootstrapNode)
   317  	}
   318  
   319  	// dump cert and read it again from json for correct private files initialization
   320  	jsonCert, err := cert.Dump()
   321  	s.NoError(err)
   322  	log.Infof("cert: %s", jsonCert)
   323  
   324  	cert, err = certificate.ReadCertificateFromReader(pubKey, proc, strings.NewReader(jsonCert))
   325  	s.NoError(err)
   326  	return certificate.NewCertificateManager(cert), node.cryptographyService
   327  }
   328  
   329  func RandomRole() core.StaticRole {
   330  	i := rand.Int()%3 + 1
   331  	return core.StaticRole(i)
   332  }
   333  
   334  type terminationHandler struct {
   335  	NodeID core.RecordRef
   336  }
   337  
   338  func (t *terminationHandler) Abort(reason string) {
   339  	log.Errorf("Abort node %s: %s", t.NodeID, reason)
   340  }
   341  
   342  type pulseManagerMock struct {
   343  	pulse core.Pulse
   344  	lock  sync.Mutex
   345  
   346  	keeper network.NodeKeeper
   347  }
   348  
   349  func newPulseManagerMock(keeper network.NodeKeeper) *pulseManagerMock {
   350  	return &pulseManagerMock{pulse: *core.GenesisPulse, keeper: keeper}
   351  }
   352  
   353  func (p *pulseManagerMock) Current(ctx context.Context) (*core.Pulse, error) {
   354  	p.lock.Lock()
   355  	defer p.lock.Unlock()
   356  	return &p.pulse, nil
   357  }
   358  
   359  func (p *pulseManagerMock) Set(ctx context.Context, pulse core.Pulse, persist bool) error {
   360  	p.lock.Lock()
   361  	p.pulse = pulse
   362  	p.lock.Unlock()
   363  
   364  	return p.keeper.MoveSyncToActive(ctx)
   365  }
   366  
   367  // preInitNode inits previously created node with mocks and external dependencies
   368  func (s *testSuite) preInitNode(node *networkNode) {
   369  	cfg := configuration.NewConfiguration()
   370  	cfg.Pulsar.PulseTime = pulseTimeMs // pulse 5 sec for faster tests
   371  	cfg.Host.Transport.Address = node.host
   372  	cfg.Service.Skip = 5
   373  
   374  	node.componentManager = &component.Manager{}
   375  	node.componentManager.Register(platformpolicy.NewPlatformCryptographyScheme())
   376  	serviceNetwork, err := NewServiceNetwork(cfg, node.componentManager, false)
   377  	s.NoError(err)
   378  
   379  	netCoordinator := testutils.NewNetworkCoordinatorMock(s.T())
   380  	netCoordinator.ValidateCertMock.Set(func(p context.Context, p1 core.AuthorizationCertificate) (bool, error) {
   381  		return true, nil
   382  	})
   383  
   384  	netCoordinator.IsStartedMock.Set(func() (r bool) {
   385  		return true
   386  	})
   387  
   388  	amMock := testutils.NewArtifactManagerMock(s.T())
   389  	amMock.StateMock.Set(func() (r []byte, r1 error) {
   390  		return make([]byte, packets.HashLength), nil
   391  	})
   392  
   393  	pubKey, _ := node.cryptographyService.GetPublicKey()
   394  
   395  	origin := nodenetwork.NewNode(node.id, node.role, pubKey, node.host, "")
   396  	certManager, cryptographyService := s.initCrypto(node)
   397  
   398  	realKeeper := nodenetwork.NewNodeKeeper(origin)
   399  	terminationHandler := &terminationHandler{NodeID: origin.ID()}
   400  
   401  	realKeeper.SetState(core.WaitingNodeNetworkState)
   402  	if len(certManager.GetCertificate().GetDiscoveryNodes()) == 0 || utils.OriginIsDiscovery(certManager.GetCertificate()) {
   403  		realKeeper.SetState(core.ReadyNodeNetworkState)
   404  		realKeeper.AddActiveNodes([]core.Node{origin})
   405  	}
   406  
   407  	node.componentManager.Register(terminationHandler, realKeeper, newPulseManagerMock(realKeeper), netCoordinator, amMock)
   408  	node.componentManager.Register(certManager, cryptographyService)
   409  	node.componentManager.Inject(serviceNetwork, NewTestNetworkSwitcher())
   410  	node.serviceNetwork = serviceNetwork
   411  }