github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/core/connection/manager_test.go (about) 1 /* 2 * Copyright (C) 2017 The "MysteriumNetwork/node" Authors. 3 * 4 * This program is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU 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 * This program 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 General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 package connection 19 20 import ( 21 "context" 22 "errors" 23 "fmt" 24 "math/big" 25 "net" 26 "sync" 27 "testing" 28 "time" 29 30 "github.com/ethereum/go-ethereum/common" 31 "github.com/stretchr/testify/assert" 32 "github.com/stretchr/testify/suite" 33 "google.golang.org/protobuf/proto" 34 35 "github.com/mysteriumnetwork/node/communication/nats" 36 "github.com/mysteriumnetwork/node/core/connection/connectionstate" 37 "github.com/mysteriumnetwork/node/core/discovery/proposal" 38 "github.com/mysteriumnetwork/node/core/ip" 39 "github.com/mysteriumnetwork/node/core/location" 40 "github.com/mysteriumnetwork/node/core/location/locationstate" 41 "github.com/mysteriumnetwork/node/identity" 42 "github.com/mysteriumnetwork/node/market" 43 "github.com/mysteriumnetwork/node/mocks" 44 "github.com/mysteriumnetwork/node/p2p" 45 "github.com/mysteriumnetwork/node/pb" 46 "github.com/mysteriumnetwork/node/session" 47 "github.com/mysteriumnetwork/node/session/connectivity" 48 "github.com/mysteriumnetwork/node/trace" 49 ) 50 51 type testContext struct { 52 suite.Suite 53 fakeConnectionFactory *connectionFactoryFake 54 connManager *connectionManager 55 MockPaymentIssuer *MockPaymentIssuer 56 stubPublisher *mocks.EventBus 57 mockStatistics connectionstate.Statistics 58 fakeIPResolver ip.Resolver 59 fakeLocationResolver location.OriginResolver 60 config Config 61 statsReportInterval time.Duration 62 mockP2P *mockP2PDialer 63 mockTime time.Time 64 sync.RWMutex 65 } 66 67 var ( 68 consumerID = identity.FromAddress("identity-1") 69 consumerLocation = locationstate.Location{Country: "CH"} 70 activeProviderID = identity.FromAddress("fake-node-1") 71 hermesID = common.HexToAddress("hermes") 72 activeProviderContact = market.Contact{ 73 Type: p2p.ContactTypeV1, 74 Definition: p2p.ContactDefinition{}, 75 } 76 activeServiceType = "fake-service" 77 activeProposal = proposal.PricedServiceProposal{ 78 ServiceProposal: market.ServiceProposal{ 79 ProviderID: activeProviderID.Address, 80 Contacts: []market.Contact{activeProviderContact}, 81 ServiceType: activeServiceType, 82 Location: market.Location{}, 83 }, 84 Price: market.Price{ 85 PricePerHour: big.NewInt(1), 86 PricePerGiB: big.NewInt(2), 87 }, 88 } 89 activeProposalLookup = func() (proposal *proposal.PricedServiceProposal, err error) { 90 return &activeProposal, nil 91 } 92 establishedSessionID = session.ID("session-100") 93 ) 94 95 func (tc *testContext) SetupTest() { 96 tc.Lock() 97 defer tc.Unlock() 98 99 tc.stubPublisher = mocks.NewEventBus() 100 tc.mockStatistics = connectionstate.Statistics{ 101 BytesReceived: 10, 102 BytesSent: 20, 103 } 104 tc.fakeConnectionFactory = &connectionFactoryFake{ 105 mockError: nil, 106 mockConnection: &connectionMock{ 107 onStartReportStates: []fakeState{ 108 processStarted, 109 connectingState, 110 waitState, 111 authenticatingState, 112 getConfigState, 113 assignIPState, 114 connectedState, 115 }, 116 onStopReportStates: []fakeState{ 117 exitingState, 118 processExited, 119 }, 120 onStartReportStats: tc.mockStatistics, 121 }, 122 } 123 124 tc.config = Config{ 125 IPCheck: IPCheckConfig{ 126 MaxAttempts: 3, 127 SleepDurationAfterCheck: 1 * time.Millisecond, 128 }, 129 KeepAlive: KeepAliveConfig{ 130 SendInterval: 100 * time.Millisecond, 131 MaxSendErrCount: 5, 132 }, 133 } 134 tc.fakeIPResolver = ip.NewResolverMock("ip") 135 tc.fakeLocationResolver = &mockLocationResolver{} 136 tc.statsReportInterval = 1 * time.Millisecond 137 138 brokerConn := nats.StartConnectionMock() 139 brokerConn.MockResponse("fake-node-1.p2p-config-exchange", []byte("123")) 140 141 tc.mockP2P = &mockP2PDialer{&mockP2PChannel{}} 142 tc.mockTime = time.Date(2000, time.January, 0, 10, 12, 3, 0, time.UTC) 143 144 tc.connManager = NewManager( 145 func(senderUUID string, channel p2p.Channel, 146 consumer, provider identity.Identity, hermes common.Address, proposal proposal.PricedServiceProposal, price market.Price, 147 ) (PaymentIssuer, error) { 148 tc.MockPaymentIssuer = &MockPaymentIssuer{ 149 stopChan: make(chan struct{}), 150 } 151 return tc.MockPaymentIssuer, nil 152 }, 153 tc.fakeConnectionFactory.CreateConnection, 154 tc.stubPublisher, 155 tc.fakeIPResolver, 156 tc.fakeLocationResolver, 157 tc.config, 158 tc.statsReportInterval, 159 &mockValidator{}, 160 tc.mockP2P, 161 func() {}, func() {}, 162 ) 163 tc.connManager.timeGetter = func() time.Time { 164 return tc.mockTime 165 } 166 } 167 168 func (tc *testContext) TestWhenNoConnectionIsMadeStatusIsNotConnected() { 169 assert.Exactly(tc.T(), connectionstate.Status{State: connectionstate.NotConnected}, tc.connManager.Status()) 170 } 171 172 func (tc *testContext) TestOnConnectErrorStatusIsNotConnected() { 173 tc.fakeConnectionFactory.mockError = errors.New("fatal connection error") 174 175 assert.Error(tc.T(), tc.connManager.Connect(consumerID, hermesID, activeProposalLookup, ConnectParams{})) 176 assert.Equal( 177 tc.T(), 178 connectionstate.Status{ 179 StartedAt: tc.mockTime, 180 ConsumerID: consumerID, 181 ConsumerLocation: consumerLocation, 182 HermesID: hermesID, 183 State: connectionstate.NotConnected, 184 Proposal: activeProposal, 185 }, 186 tc.connManager.Status(), 187 ) 188 } 189 190 func (tc *testContext) TestWhenManagerMadeConnectionStatusReturnsConnectedStateAndSessionId() { 191 err := tc.connManager.Connect(consumerID, hermesID, activeProposalLookup, ConnectParams{}) 192 assert.NoError(tc.T(), err) 193 assert.Equal( 194 tc.T(), 195 connectionstate.Status{ 196 StartedAt: tc.mockTime, 197 ConsumerID: consumerID, 198 ConsumerLocation: consumerLocation, 199 HermesID: hermesID, 200 State: connectionstate.Connected, 201 SessionID: establishedSessionID, 202 Proposal: activeProposal, 203 }, 204 tc.connManager.Status(), 205 ) 206 } 207 208 func (tc *testContext) TestStatusReportsConnectingWhenConnectionIsInProgress() { 209 tc.fakeConnectionFactory.mockConnection.onStartReportStates = []fakeState{} 210 211 go func() { 212 tc.connManager.Connect(consumerID, hermesID, activeProposalLookup, ConnectParams{}) 213 }() 214 215 waitABit() 216 217 assert.Equal( 218 tc.T(), 219 connectionstate.Status{ 220 StartedAt: tc.mockTime, 221 ConsumerID: consumerID, 222 ConsumerLocation: consumerLocation, 223 HermesID: hermesID, 224 State: connectionstate.Connecting, 225 SessionID: establishedSessionID, 226 Proposal: activeProposal, 227 }, 228 tc.connManager.Status(), 229 ) 230 tc.connManager.Disconnect() 231 } 232 233 func (tc *testContext) TestStatusReportsNotConnected() { 234 tc.fakeConnectionFactory.mockConnection.onStopReportStates = []fakeState{} 235 tc.fakeConnectionFactory.mockConnection.stopBlock = make(chan struct{}) 236 defer func() { 237 tc.fakeConnectionFactory.mockConnection.stopBlock = nil 238 }() 239 240 err := tc.connManager.Connect(consumerID, hermesID, activeProposalLookup, ConnectParams{}) 241 assert.NoError(tc.T(), err) 242 assert.Equal(tc.T(), connectionstate.Connected, tc.connManager.Status().State) 243 244 go func() { 245 assert.NoError(tc.T(), tc.connManager.Disconnect()) 246 }() 247 248 waitABit() 249 assert.Equal( 250 tc.T(), 251 connectionstate.Status{ 252 StartedAt: tc.mockTime, 253 ConsumerID: consumerID, 254 ConsumerLocation: consumerLocation, 255 HermesID: hermesID, 256 State: connectionstate.Disconnecting, 257 SessionID: establishedSessionID, 258 Proposal: activeProposal, 259 }, 260 tc.connManager.Status(), 261 ) 262 263 tc.fakeConnectionFactory.mockConnection.stopBlock <- struct{}{} 264 265 tc.fakeConnectionFactory.mockConnection.reportState(exitingState) 266 tc.fakeConnectionFactory.mockConnection.reportState(processExited) 267 268 waitABit() 269 assert.Equal( 270 tc.T(), 271 connectionstate.Status{ 272 StartedAt: tc.mockTime, 273 ConsumerID: consumerID, 274 ConsumerLocation: consumerLocation, 275 HermesID: hermesID, 276 State: connectionstate.NotConnected, 277 SessionID: establishedSessionID, 278 Proposal: activeProposal, 279 }, 280 tc.connManager.Status(), 281 ) 282 } 283 284 func (tc *testContext) TestConnectResultsInAlreadyConnectedErrorWhenConnectionExists() { 285 assert.NoError(tc.T(), tc.connManager.Connect(consumerID, hermesID, activeProposalLookup, ConnectParams{})) 286 assert.Equal(tc.T(), ErrAlreadyExists, tc.connManager.Connect(consumerID, hermesID, activeProposalLookup, ConnectParams{})) 287 } 288 289 func (tc *testContext) TestDisconnectReturnsErrorWhenNoConnectionExists() { 290 assert.Equal(tc.T(), ErrNoConnection, tc.connManager.Disconnect()) 291 } 292 293 func (tc *testContext) TestReconnectingStatusIsReportedWhenOpenVpnGoesIntoReconnectingState() { 294 assert.NoError(tc.T(), tc.connManager.Connect(consumerID, hermesID, activeProposalLookup, ConnectParams{})) 295 tc.fakeConnectionFactory.mockConnection.reportState(reconnectingState) 296 waitABit() 297 assert.Equal( 298 tc.T(), 299 connectionstate.Status{ 300 StartedAt: tc.mockTime, 301 ConsumerID: consumerID, 302 ConsumerLocation: consumerLocation, 303 HermesID: hermesID, 304 State: connectionstate.Reconnecting, 305 SessionID: establishedSessionID, 306 Proposal: activeProposal, 307 }, 308 tc.connManager.Status(), 309 ) 310 } 311 312 func (tc *testContext) TestDoubleDisconnectResultsInError() { 313 assert.NoError(tc.T(), tc.connManager.Connect(consumerID, hermesID, activeProposalLookup, ConnectParams{})) 314 assert.Equal(tc.T(), connectionstate.Connected, tc.connManager.Status().State) 315 assert.NoError(tc.T(), tc.connManager.Disconnect()) 316 waitABit() 317 assert.Equal(tc.T(), connectionstate.NotConnected, tc.connManager.Status().State) 318 assert.Equal(tc.T(), ErrNoConnection, tc.connManager.Disconnect()) 319 } 320 321 func (tc *testContext) TestTwoConnectDisconnectCyclesReturnNoError() { 322 assert.NoError(tc.T(), tc.connManager.Connect(consumerID, hermesID, activeProposalLookup, ConnectParams{})) 323 assert.Equal(tc.T(), connectionstate.Connected, tc.connManager.Status().State) 324 assert.NoError(tc.T(), tc.connManager.Disconnect()) 325 waitABit() 326 assert.Equal(tc.T(), connectionstate.NotConnected, tc.connManager.Status().State) 327 328 assert.NoError(tc.T(), tc.connManager.Connect(consumerID, hermesID, activeProposalLookup, ConnectParams{})) 329 assert.Equal(tc.T(), connectionstate.Connected, tc.connManager.Status().State) 330 assert.NoError(tc.T(), tc.connManager.Disconnect()) 331 waitABit() 332 assert.Equal(tc.T(), connectionstate.NotConnected, tc.connManager.Status().State) 333 } 334 335 func (tc *testContext) TestConnectFailsIfConnectionFactoryReturnsError() { 336 tc.fakeConnectionFactory.mockError = errors.New("failed to create connection instance") 337 assert.Error(tc.T(), tc.connManager.Connect(consumerID, hermesID, activeProposalLookup, ConnectParams{})) 338 } 339 340 func (tc *testContext) TestStatusIsConnectedWhenConnectCommandReturnsWithoutError() { 341 tc.connManager.Connect(consumerID, hermesID, activeProposalLookup, ConnectParams{}) 342 assert.Equal( 343 tc.T(), 344 connectionstate.Status{ 345 StartedAt: tc.mockTime, 346 ConsumerID: consumerID, 347 ConsumerLocation: consumerLocation, 348 HermesID: hermesID, 349 State: connectionstate.Connected, 350 SessionID: establishedSessionID, 351 Proposal: activeProposal, 352 }, 353 tc.connManager.Status(), 354 ) 355 } 356 357 func (tc *testContext) TestConnectingInProgressCanBeCanceled() { 358 tc.fakeConnectionFactory.mockConnection.onStartReportStates = []fakeState{} 359 tc.fakeConnectionFactory.mockConnection.onStopReportStates = []fakeState{} 360 361 connectWaiter := &sync.WaitGroup{} 362 connectWaiter.Add(1) 363 var err error 364 go func() { 365 defer connectWaiter.Done() 366 err = tc.connManager.Connect(consumerID, hermesID, activeProposalLookup, ConnectParams{}) 367 }() 368 369 waitABit() 370 assert.Equal(tc.T(), connectionstate.Connecting, tc.connManager.Status().State) 371 assert.NoError(tc.T(), tc.connManager.Disconnect()) 372 373 connectWaiter.Wait() 374 375 assert.Equal(tc.T(), ErrConnectionCancelled, err) 376 } 377 378 func (tc *testContext) TestConnectMethodReturnsErrorIfConnectionExitsDuringConnect() { 379 tc.fakeConnectionFactory.mockConnection.onStartReportStates = []fakeState{} 380 tc.fakeConnectionFactory.mockConnection.onStopReportStates = []fakeState{} 381 connectWaiter := sync.WaitGroup{} 382 connectWaiter.Add(1) 383 384 var err error 385 go func() { 386 defer connectWaiter.Done() 387 err = tc.connManager.Connect(consumerID, hermesID, activeProposalLookup, ConnectParams{}) 388 }() 389 waitABit() 390 tc.fakeConnectionFactory.mockConnection.reportState(processExited) 391 connectWaiter.Wait() 392 assert.Equal(tc.T(), ErrConnectionFailed, err) 393 } 394 395 func (tc *testContext) Test_PaymentManager_WhenManagerMadeConnectionIsStarted() { 396 err := tc.connManager.Connect(consumerID, hermesID, activeProposalLookup, ConnectParams{}) 397 waitABit() 398 assert.NoError(tc.T(), err) 399 assert.True(tc.T(), tc.MockPaymentIssuer.StartCalled()) 400 } 401 402 func (tc *testContext) Test_PaymentManager_OnConnectErrorIsStopped() { 403 tc.fakeConnectionFactory.mockConnection.onStartReturnError = errors.New("fatal connection error") 404 err := tc.connManager.Connect(consumerID, hermesID, activeProposalLookup, ConnectParams{}) 405 assert.Error(tc.T(), err) 406 assert.True(tc.T(), tc.MockPaymentIssuer.StopCalled()) 407 } 408 409 func (tc *testContext) Test_SessionEndPublished_OnConnectError() { 410 tc.stubPublisher.Clear() 411 412 tc.fakeConnectionFactory.mockConnection.onStartReturnError = errors.New("fatal connection error") 413 err := tc.connManager.Connect(consumerID, hermesID, activeProposalLookup, ConnectParams{}) 414 assert.Error(tc.T(), err) 415 416 history := tc.stubPublisher.GetEventHistory() 417 418 found := false 419 420 for _, v := range history { 421 if v.Topic == connectionstate.AppTopicConnectionSession { 422 event := v.Event.(connectionstate.AppEventConnectionSession) 423 if event.Status == connectionstate.SessionEndedStatus { 424 found = true 425 426 assert.Equal(tc.T(), connectionstate.SessionEndedStatus, event.Status) 427 assert.Equal(tc.T(), consumerID, event.SessionInfo.ConsumerID) 428 assert.Equal(tc.T(), establishedSessionID, event.SessionInfo.SessionID) 429 assert.Equal(tc.T(), activeProposal.ProviderID, event.SessionInfo.Proposal.ProviderID) 430 assert.Equal(tc.T(), activeProposal.ServiceType, event.SessionInfo.Proposal.ServiceType) 431 } 432 } 433 } 434 435 assert.True(tc.T(), found) 436 } 437 438 func (tc *testContext) Test_ManagerPublishesEvents() { 439 tc.stubPublisher.Clear() 440 441 tc.fakeConnectionFactory.mockConnection.onStartReportStates = []fakeState{ 442 connectedState, 443 } 444 445 err := tc.connManager.Connect(consumerID, hermesID, activeProposalLookup, ConnectParams{}) 446 assert.NoError(tc.T(), err) 447 448 waitABit() 449 450 history := tc.stubPublisher.GetEventHistory() 451 assert.True(tc.T(), len(history) >= 4) 452 453 // Check if published to all expected topics. 454 expectedTopics := [...]string{connectionstate.AppTopicConnectionStatistics, connectionstate.AppTopicConnectionState, connectionstate.AppTopicConnectionSession} 455 for _, v := range expectedTopics { 456 var published bool 457 for _, h := range history { 458 if v == h.Topic { 459 published = true 460 } 461 } 462 tc.Assert().Truef(published, "expected publish event to %s", v) 463 } 464 465 // Check received events data. 466 for _, v := range history { 467 if v.Topic == connectionstate.AppTopicConnectionStatistics { 468 event := v.Event.(connectionstate.AppEventConnectionStatistics) 469 assert.True(tc.T(), event.Stats.BytesReceived == tc.mockStatistics.BytesReceived) 470 assert.True(tc.T(), event.Stats.BytesSent == tc.mockStatistics.BytesSent) 471 } 472 if v.Topic == connectionstate.AppTopicConnectionState && v.Event.(connectionstate.AppEventConnectionState).State == connectionstate.Connected { 473 event := v.Event.(connectionstate.AppEventConnectionState) 474 assert.Equal(tc.T(), connectionstate.Connected, event.State) 475 assert.Equal(tc.T(), consumerID, event.SessionInfo.ConsumerID) 476 assert.Equal(tc.T(), establishedSessionID, event.SessionInfo.SessionID) 477 assert.Equal(tc.T(), activeProposal.ProviderID, event.SessionInfo.Proposal.ProviderID) 478 assert.Equal(tc.T(), activeProposal.ServiceType, event.SessionInfo.Proposal.ServiceType) 479 } 480 if v.Topic == connectionstate.AppTopicConnectionState && v.Event.(connectionstate.AppEventConnectionState).State == connectionstate.StateIPNotChanged { 481 event := v.Event.(connectionstate.AppEventConnectionState) 482 assert.Equal(tc.T(), connectionstate.StateIPNotChanged, event.State) 483 assert.Equal(tc.T(), consumerID, event.SessionInfo.ConsumerID) 484 assert.Equal(tc.T(), establishedSessionID, event.SessionInfo.SessionID) 485 assert.Equal(tc.T(), activeProposal.ProviderID, event.SessionInfo.Proposal.ProviderID) 486 assert.Equal(tc.T(), activeProposal.ServiceType, event.SessionInfo.Proposal.ServiceType) 487 } 488 if v.Topic == connectionstate.AppTopicConnectionSession { 489 event := v.Event.(connectionstate.AppEventConnectionSession) 490 assert.Equal(tc.T(), connectionstate.SessionCreatedStatus, event.Status) 491 assert.Equal(tc.T(), consumerID, event.SessionInfo.ConsumerID) 492 assert.Equal(tc.T(), establishedSessionID, event.SessionInfo.SessionID) 493 assert.Equal(tc.T(), activeProposal.ProviderID, event.SessionInfo.Proposal.ProviderID) 494 assert.Equal(tc.T(), activeProposal.ServiceType, event.SessionInfo.Proposal.ServiceType) 495 } 496 } 497 } 498 499 func (tc *testContext) Test_ManagerNotifiesAboutSessionIPNotChanged() { 500 tc.stubPublisher.Clear() 501 502 tc.fakeConnectionFactory.mockConnection.onStartReportStates = []fakeState{ 503 connectedState, 504 } 505 506 err := tc.connManager.Connect(consumerID, hermesID, activeProposalLookup, ConnectParams{}) 507 assert.NoError(tc.T(), err) 508 509 assert.Eventually(tc.T(), func() bool { 510 // Check that state event with StateIPNotChanged status was called. 511 history := tc.stubPublisher.GetEventHistory() 512 for _, v := range history { 513 if v.Topic == connectionstate.AppTopicConnectionState && v.Event.(connectionstate.AppEventConnectionState).State == connectionstate.StateIPNotChanged { 514 return true 515 } 516 } 517 return false 518 }, 2*time.Second, 10*time.Millisecond) 519 520 // Check that status sender was called with status code. 521 expectedStatusMsg := &pb.SessionStatus{ 522 ConsumerID: consumerID.Address, 523 SessionID: string(establishedSessionID), 524 Code: uint32(connectivity.StatusSessionIPNotChanged), 525 Message: "", 526 } 527 assert.True( 528 tc.T(), 529 proto.Equal(expectedStatusMsg, tc.mockP2P.ch.getSentMsg()), 530 fmt.Sprintf("Session status are not equal:\nexpected: %v\nactual: %v", expectedStatusMsg, tc.mockP2P.ch.getSentMsg()), 531 ) 532 } 533 534 func (tc *testContext) Test_ManagerNotifiesAboutSuccessfulConnection() { 535 tc.stubPublisher.Clear() 536 537 tc.fakeConnectionFactory.mockConnection.onStartReportStates = []fakeState{ 538 connectedState, 539 } 540 541 // Simulate IP change. 542 tc.connManager.ipResolver = ip.NewResolverMockMultiple("127.0.0.1", "10.0.0.4", "10.0.5") 543 544 err := tc.connManager.Connect(consumerID, hermesID, activeProposalLookup, ConnectParams{}) 545 assert.NoError(tc.T(), err) 546 547 waitABit() 548 549 // Check that state event with StateIPNotChanged status was not called. 550 history := tc.stubPublisher.GetEventHistory() 551 var ipNotChangedEvent *mocks.EventBusEntry 552 for _, v := range history { 553 if v.Topic == connectionstate.AppTopicConnectionState && v.Event.(connectionstate.AppEventConnectionState).State == connectionstate.StateIPNotChanged { 554 ipNotChangedEvent = &v 555 } 556 } 557 assert.Nil(tc.T(), ipNotChangedEvent) 558 559 // Check that status sender was called with status code. 560 expectedStatusMsg := &pb.SessionStatus{ 561 ConsumerID: consumerID.Address, 562 SessionID: string(establishedSessionID), 563 Code: uint32(connectivity.StatusConnectionOk), 564 Message: "", 565 } 566 assert.True( 567 tc.T(), 568 proto.Equal(expectedStatusMsg, tc.mockP2P.ch.getSentMsg()), 569 fmt.Sprintf("Session status are not equal:\nexpected: %v\nactual: %v", expectedStatusMsg, tc.mockP2P.ch.getSentMsg()), 570 ) 571 } 572 573 func TestConnectionManagerSuite(t *testing.T) { 574 suite.Run(t, new(testContext)) 575 } 576 577 func waitABit() { 578 // usually time.Sleep call gives a chance for other goroutines to kick in 579 // important when testing async code 580 time.Sleep(10 * time.Millisecond) 581 } 582 583 type MockPaymentIssuer struct { 584 startCalled bool 585 stopCalled bool 586 MockError error 587 stopChan chan struct{} 588 sync.Mutex 589 } 590 591 func (mpm *MockPaymentIssuer) Start() error { 592 mpm.Lock() 593 mpm.startCalled = true 594 mpm.Unlock() 595 <-mpm.stopChan 596 return mpm.MockError 597 } 598 599 func (mpm *MockPaymentIssuer) StartCalled() bool { 600 mpm.Lock() 601 defer mpm.Unlock() 602 return mpm.startCalled 603 } 604 605 func (mpm *MockPaymentIssuer) StopCalled() bool { 606 mpm.Lock() 607 defer mpm.Unlock() 608 return mpm.stopCalled 609 } 610 611 func (mpm *MockPaymentIssuer) Stop() { 612 mpm.Lock() 613 defer mpm.Unlock() 614 mpm.stopCalled = true 615 close(mpm.stopChan) 616 } 617 618 func (mpm *MockPaymentIssuer) SetSessionID(string) { 619 } 620 621 type mockP2PDialer struct { 622 ch *mockP2PChannel 623 } 624 625 func (m mockP2PDialer) Dial(ctx context.Context, consumerID identity.Identity, providerID identity.Identity, serviceType string, contactDef p2p.ContactDefinition, tracer *trace.Tracer) (p2p.Channel, error) { 626 return m.ch, nil 627 } 628 629 type mockP2PChannel struct { 630 status proto.Message 631 lock sync.Mutex 632 } 633 634 func (m *mockP2PChannel) Conn() *net.UDPConn { 635 return &net.UDPConn{} 636 } 637 638 func (m *mockP2PChannel) getSentMsg() proto.Message { 639 m.lock.Lock() 640 defer m.lock.Unlock() 641 return m.status 642 } 643 644 func (m *mockP2PChannel) Send(_ context.Context, topic string, msg *p2p.Message) (*p2p.Message, error) { 645 switch topic { 646 case p2p.TopicSessionCreate: 647 res := &pb.SessionResponse{ 648 ID: string(establishedSessionID), 649 } 650 return p2p.ProtoMessage(res), nil 651 case p2p.TopicSessionStatus: 652 m.lock.Lock() 653 m.status = &pb.SessionStatus{} 654 msg.UnmarshalProto(m.status) 655 m.lock.Unlock() 656 657 return nil, nil 658 case p2p.TopicSessionAcknowledge: 659 return nil, nil 660 } 661 662 return nil, errors.New("unexpected error") 663 } 664 665 func (m *mockP2PChannel) Handle(topic string, handler p2p.HandlerFunc) { 666 } 667 668 func (m *mockP2PChannel) Tracer() *trace.Tracer { 669 return nil 670 } 671 672 func (m *mockP2PChannel) ServiceConn() *net.UDPConn { 673 raddr, _ := net.ResolveUDPAddr("udp", "127.0.0.1:12345") 674 conn, _ := net.DialUDP("udp", nil, raddr) 675 return conn 676 } 677 678 func (m *mockP2PChannel) Close() error { 679 return nil 680 } 681 682 func (m *mockP2PChannel) ID() string { 683 return fmt.Sprintf("%p", m) 684 } 685 686 type mockValidator struct { 687 errorToReturn error 688 } 689 690 func (mv *mockValidator) Validate(chainID int64, consumerID identity.Identity, price market.Price) error { 691 return mv.errorToReturn 692 } 693 694 type mockLocationResolver struct{} 695 696 func (mlr *mockLocationResolver) GetOrigin() locationstate.Location { 697 return consumerLocation 698 }