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 }