github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/core/state/state_test.go (about)

     1  /*
     2   * Copyright (C) 2019 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 state
    19  
    20  import (
    21  	"math/big"
    22  	"reflect"
    23  	"sync"
    24  	"testing"
    25  	"time"
    26  
    27  	"github.com/ethereum/go-ethereum/common"
    28  	"github.com/stretchr/testify/assert"
    29  
    30  	"github.com/mysteriumnetwork/node/consumer/session"
    31  	"github.com/mysteriumnetwork/node/core/connection/connectionstate"
    32  	"github.com/mysteriumnetwork/node/core/discovery/proposal"
    33  	"github.com/mysteriumnetwork/node/core/service"
    34  	"github.com/mysteriumnetwork/node/core/service/servicestate"
    35  	"github.com/mysteriumnetwork/node/datasize"
    36  	"github.com/mysteriumnetwork/node/eventbus"
    37  	"github.com/mysteriumnetwork/node/identity"
    38  	"github.com/mysteriumnetwork/node/identity/registry"
    39  	"github.com/mysteriumnetwork/node/market"
    40  	"github.com/mysteriumnetwork/node/mocks"
    41  	nodeSession "github.com/mysteriumnetwork/node/session"
    42  	sessionEvent "github.com/mysteriumnetwork/node/session/event"
    43  	"github.com/mysteriumnetwork/node/session/pingpong"
    44  	pingpongEvent "github.com/mysteriumnetwork/node/session/pingpong/event"
    45  	"github.com/mysteriumnetwork/node/tequilapi/contract"
    46  	"github.com/mysteriumnetwork/payments/crypto"
    47  )
    48  
    49  type debounceTester struct {
    50  	numInteractions int
    51  	lock            sync.Mutex
    52  }
    53  
    54  type interactionCounter interface {
    55  	interactions() int
    56  }
    57  
    58  func (dt *debounceTester) do(interface{}) {
    59  	dt.lock.Lock()
    60  	dt.numInteractions++
    61  	dt.lock.Unlock()
    62  }
    63  
    64  func (dt *debounceTester) interactions() int {
    65  	dt.lock.Lock()
    66  	defer dt.lock.Unlock()
    67  	return dt.numInteractions
    68  }
    69  
    70  func Test_Debounce_CallsOnceInInterval(t *testing.T) {
    71  	dt := &debounceTester{}
    72  	duration := time.Millisecond * 10
    73  	f := debounce(dt.do, duration)
    74  	for i := 1; i < 10; i++ {
    75  		f(struct{}{})
    76  	}
    77  	assert.Eventually(t, interacted(dt, 1), 2*time.Second, 10*time.Millisecond)
    78  }
    79  
    80  type mockPublisher struct {
    81  	lock           sync.Mutex
    82  	publishedTopic string
    83  	publishedData  interface{}
    84  }
    85  
    86  func (mp *mockPublisher) Publish(topic string, data interface{}) {
    87  	mp.lock.Lock()
    88  	defer mp.lock.Unlock()
    89  	mp.publishedData = data
    90  	mp.publishedTopic = topic
    91  }
    92  
    93  type serviceListerMock struct {
    94  	lock             sync.Mutex
    95  	numInteractions  int
    96  	servicesToReturn map[service.ID]*service.Instance
    97  }
    98  
    99  func (slm *serviceListerMock) interactions() int {
   100  	slm.lock.Lock()
   101  	defer slm.lock.Unlock()
   102  	return slm.numInteractions
   103  }
   104  
   105  func (slm *serviceListerMock) List(includeAll bool) []*service.Instance {
   106  	slm.lock.Lock()
   107  	defer slm.lock.Unlock()
   108  	slm.numInteractions++
   109  	list := make([]*service.Instance, 0, len(slm.servicesToReturn))
   110  	for _, instance := range slm.servicesToReturn {
   111  		list = append(list, instance)
   112  	}
   113  	return list
   114  }
   115  
   116  func Test_ConsumesSessionEvents(t *testing.T) {
   117  	// given
   118  	expected := sessionEvent.SessionContext{
   119  		ID:         "1",
   120  		StartedAt:  time.Now(),
   121  		ConsumerID: identity.FromAddress("0x0000000000000000000000000000000000000001"),
   122  		HermesID:   common.HexToAddress("0x000000000000000000000000000000000000000a"),
   123  		Proposal: market.ServiceProposal{
   124  			Location: stubLocation,
   125  		},
   126  	}
   127  
   128  	eventBus := eventbus.New()
   129  	deps := KeeperDeps{
   130  		Publisher:        eventBus,
   131  		IdentityProvider: &mocks.IdentityProvider{},
   132  		EarningsProvider: &mockEarningsProvider{},
   133  	}
   134  	keeper := NewKeeper(deps, time.Millisecond)
   135  	keeper.Subscribe(eventBus)
   136  
   137  	// when
   138  	eventBus.Publish(sessionEvent.AppTopicSession, sessionEvent.AppEventSession{
   139  		Status:  sessionEvent.CreatedStatus,
   140  		Session: expected,
   141  	})
   142  
   143  	// then
   144  	assert.Eventually(t, func() bool {
   145  		return len(keeper.GetState().Sessions) == 1
   146  	}, 2*time.Second, 10*time.Millisecond)
   147  	assert.Equal(
   148  		t,
   149  		[]session.History{
   150  			{
   151  				SessionID:       nodeSession.ID(expected.ID),
   152  				Direction:       session.DirectionProvided,
   153  				ConsumerID:      expected.ConsumerID,
   154  				HermesID:        expected.HermesID.Hex(),
   155  				ProviderCountry: "MU",
   156  				Started:         expected.StartedAt,
   157  				Status:          session.StatusNew,
   158  				Tokens:          new(big.Int),
   159  			},
   160  		},
   161  		keeper.GetState().Sessions,
   162  	)
   163  
   164  	// when
   165  	eventBus.Publish(sessionEvent.AppTopicSession, sessionEvent.AppEventSession{
   166  		Status:  sessionEvent.RemovedStatus,
   167  		Session: expected,
   168  	})
   169  
   170  	// then
   171  	assert.Eventually(t, func() bool {
   172  		return len(keeper.GetState().Sessions) == 0
   173  	}, 2*time.Second, 10*time.Millisecond)
   174  }
   175  
   176  func Test_ConsumesSessionAcknowledgeEvents(t *testing.T) {
   177  	// given
   178  	myID := "test"
   179  	expected := session.History{
   180  		SessionID: nodeSession.ID("1"),
   181  	}
   182  
   183  	eventBus := eventbus.New()
   184  	deps := KeeperDeps{
   185  		Publisher:        eventBus,
   186  		IdentityProvider: &mocks.IdentityProvider{},
   187  		EarningsProvider: &mockEarningsProvider{},
   188  	}
   189  	keeper := NewKeeper(deps, time.Millisecond)
   190  	keeper.Subscribe(eventBus)
   191  	keeper.state.Services = []contract.ServiceInfoDTO{
   192  		{ID: myID, ConnectionStatistics: &contract.ServiceStatisticsDTO{}},
   193  	}
   194  	keeper.state.Sessions = []session.History{
   195  		expected,
   196  	}
   197  
   198  	// when
   199  	eventBus.Publish(sessionEvent.AppTopicSession, sessionEvent.AppEventSession{
   200  		Status: sessionEvent.AcknowledgedStatus,
   201  		Service: sessionEvent.ServiceContext{
   202  			ID: myID,
   203  		},
   204  		Session: sessionEvent.SessionContext{
   205  			ID: string(expected.SessionID),
   206  		},
   207  	})
   208  
   209  	// then
   210  	assert.Eventually(t, func() bool {
   211  		return keeper.GetState().Services[0].ConnectionStatistics.Successful == 1
   212  	}, 2*time.Second, 10*time.Millisecond)
   213  }
   214  
   215  func Test_consumeServiceSessionEarningsEvent(t *testing.T) {
   216  	// given
   217  	eventBus := eventbus.New()
   218  	deps := KeeperDeps{
   219  		Publisher:        eventBus,
   220  		IdentityProvider: &mocks.IdentityProvider{},
   221  		EarningsProvider: &mockEarningsProvider{},
   222  	}
   223  	keeper := NewKeeper(deps, time.Millisecond)
   224  	keeper.Subscribe(eventBus)
   225  	keeper.state.Sessions = []session.History{
   226  		{SessionID: nodeSession.ID("1")},
   227  	}
   228  
   229  	// when
   230  	eventBus.Publish(sessionEvent.AppTopicTokensEarned, sessionEvent.AppEventTokensEarned{
   231  		SessionID: "1",
   232  		Total:     big.NewInt(500),
   233  	})
   234  
   235  	// then
   236  	assert.Eventually(t, func() bool {
   237  		return keeper.GetState().Sessions[0].Tokens.Cmp(big.NewInt(0)) != 0
   238  	}, 2*time.Second, 10*time.Millisecond)
   239  	assert.Equal(
   240  		t,
   241  		[]session.History{
   242  			{SessionID: nodeSession.ID("1"), Tokens: big.NewInt(500)},
   243  		},
   244  		keeper.GetState().Sessions,
   245  	)
   246  }
   247  
   248  func Test_consumeServiceSessionStatisticsEvent(t *testing.T) {
   249  	// given
   250  	eventBus := eventbus.New()
   251  	deps := KeeperDeps{
   252  		Publisher:        eventBus,
   253  		IdentityProvider: &mocks.IdentityProvider{},
   254  		EarningsProvider: &mockEarningsProvider{},
   255  	}
   256  	keeper := NewKeeper(deps, time.Millisecond)
   257  	keeper.Subscribe(eventBus)
   258  	keeper.state.Sessions = []session.History{
   259  		{SessionID: nodeSession.ID("1")},
   260  	}
   261  
   262  	// when
   263  	eventBus.Publish(sessionEvent.AppTopicDataTransferred, sessionEvent.AppEventDataTransferred{
   264  		ID:   "1",
   265  		Up:   1,
   266  		Down: 2,
   267  	})
   268  
   269  	// then
   270  	assert.Eventually(t, func() bool {
   271  		return keeper.GetState().Sessions[0].DataReceived != 0
   272  	}, 2*time.Second, 10*time.Millisecond)
   273  	assert.Equal(
   274  		t,
   275  		[]session.History{
   276  			{SessionID: "1", DataSent: 2, DataReceived: 1},
   277  		},
   278  		keeper.GetState().Sessions,
   279  	)
   280  }
   281  
   282  func Test_ConsumesServiceEvents(t *testing.T) {
   283  	mpr := mockProposalRepository{
   284  		priceToAdd: market.Price{
   285  			PricePerHour: big.NewInt(1),
   286  			PricePerGiB:  big.NewInt(2),
   287  		},
   288  	}
   289  
   290  	expected := service.Instance{
   291  		Proposal: market.NewProposal("0xbeef", "wireguard", market.NewProposalOpts{}),
   292  	}
   293  	var id service.ID
   294  
   295  	publisher := &mockPublisher{}
   296  	sl := &serviceListerMock{
   297  		servicesToReturn: map[service.ID]*service.Instance{
   298  			id: &expected,
   299  		},
   300  	}
   301  
   302  	duration := time.Millisecond * 3
   303  	deps := KeeperDeps{
   304  		Publisher:        publisher,
   305  		ServiceLister:    sl,
   306  		IdentityProvider: &mocks.IdentityProvider{},
   307  		EarningsProvider: &mockEarningsProvider{},
   308  		ProposalPricer:   &mpr,
   309  	}
   310  	keeper := NewKeeper(deps, duration)
   311  
   312  	for i := 0; i < 5; i++ {
   313  		// shoot a few events to see if we'll debounce
   314  		keeper.consumeServiceStateEvent(servicestate.AppEventServiceStatus{})
   315  	}
   316  
   317  	assert.Eventually(t, interacted(sl, 1), 2*time.Second, 10*time.Millisecond)
   318  
   319  	actual := keeper.GetState().Services[0]
   320  	assert.Equal(t, string(id), actual.ID)
   321  	assert.Equal(t, expected.Type, actual.Type)
   322  	assert.Equal(t, expected.ProviderID.Address, actual.ProviderID)
   323  	assert.Equal(t, expected.Options, actual.Options)
   324  	assert.Equal(t, string(expected.State()), actual.Status)
   325  	expt, _ := mpr.EnrichProposalWithPrice(expected.Proposal)
   326  	assert.EqualValues(t, contract.NewProposalDTO(expt), *actual.Proposal)
   327  }
   328  
   329  func Test_ConsumesConnectionStateEvents(t *testing.T) {
   330  	// given
   331  	expected := connectionstate.Status{
   332  		State:     connectionstate.Connected,
   333  		SessionID: "1",
   334  		Proposal: proposal.PricedServiceProposal{
   335  			ServiceProposal: market.ServiceProposal{
   336  				Contacts: market.ContactList{},
   337  			},
   338  		},
   339  	}
   340  	eventBus := eventbus.New()
   341  	deps := KeeperDeps{
   342  		Publisher:        eventBus,
   343  		ServiceLister:    &serviceListerMock{},
   344  		IdentityProvider: &mocks.IdentityProvider{},
   345  		EarningsProvider: &mockEarningsProvider{},
   346  	}
   347  	keeper := NewKeeper(deps, time.Millisecond)
   348  	err := keeper.Subscribe(eventBus)
   349  	assert.NoError(t, err)
   350  	assert.Equal(t, connectionstate.NotConnected, keeper.GetConnection("1").Session.State)
   351  
   352  	// when
   353  	eventBus.Publish(connectionstate.AppTopicConnectionState, connectionstate.AppEventConnectionState{
   354  		State:       expected.State,
   355  		SessionInfo: expected,
   356  	})
   357  
   358  	// then
   359  	assert.Eventually(t, func() bool {
   360  		return keeper.GetConnection("1").Session.State == connectionstate.Connected
   361  	}, 2*time.Second, 10*time.Millisecond)
   362  	assert.Equal(t, expected, keeper.GetConnection("1").Session)
   363  }
   364  
   365  func Test_ConsumesConnectionStatisticsEvents(t *testing.T) {
   366  	// given
   367  	expected := connectionstate.Statistics{
   368  		At:            time.Now(),
   369  		BytesReceived: 10 * datasize.MiB.Bytes(),
   370  		BytesSent:     500 * datasize.KiB.Bytes(),
   371  	}
   372  	eventBus := eventbus.New()
   373  	deps := KeeperDeps{
   374  		Publisher:        eventBus,
   375  		ServiceLister:    &serviceListerMock{},
   376  		IdentityProvider: &mocks.IdentityProvider{},
   377  		EarningsProvider: &mockEarningsProvider{},
   378  	}
   379  	keeper := NewKeeper(deps, time.Millisecond)
   380  	err := keeper.Subscribe(eventBus)
   381  	assert.NoError(t, err)
   382  	assert.True(t, keeper.GetConnection("").Statistics.At.IsZero())
   383  
   384  	// when
   385  	eventBus.Publish(connectionstate.AppTopicConnectionStatistics, connectionstate.AppEventConnectionStatistics{
   386  		Stats: expected,
   387  	})
   388  
   389  	// then
   390  	assert.Eventually(t, func() bool {
   391  		return expected == keeper.GetConnection("").Statistics
   392  	}, 2*time.Second, 10*time.Millisecond)
   393  }
   394  
   395  func Test_ConsumesConnectionInvoiceEvents(t *testing.T) {
   396  	// given
   397  	expected := crypto.Invoice{
   398  		AgreementID:    big.NewInt(1),
   399  		AgreementTotal: big.NewInt(1001),
   400  		TransactorFee:  big.NewInt(10),
   401  	}
   402  	eventBus := eventbus.New()
   403  	deps := KeeperDeps{
   404  		Publisher:        eventBus,
   405  		ServiceLister:    &serviceListerMock{},
   406  		IdentityProvider: &mocks.IdentityProvider{},
   407  		EarningsProvider: &mockEarningsProvider{},
   408  	}
   409  	keeper := NewKeeper(deps, time.Millisecond)
   410  	err := keeper.Subscribe(eventBus)
   411  	assert.NoError(t, err)
   412  	assert.True(t, keeper.GetConnection("").Statistics.At.IsZero())
   413  
   414  	// when
   415  	eventBus.Publish(pingpongEvent.AppTopicInvoicePaid, pingpongEvent.AppEventInvoicePaid{
   416  		Invoice: expected,
   417  	})
   418  
   419  	// then
   420  	assert.Eventually(t, func() bool {
   421  		return reflect.DeepEqual(expected, keeper.GetConnection("").Invoice)
   422  	}, 2*time.Second, 10*time.Millisecond)
   423  }
   424  
   425  func Test_ConsumesBalanceChangeEvent(t *testing.T) {
   426  	// given
   427  	eventBus := eventbus.New()
   428  	deps := KeeperDeps{
   429  		Publisher:     eventBus,
   430  		ServiceLister: &serviceListerMock{},
   431  		IdentityProvider: &mocks.IdentityProvider{
   432  			Identities: []identity.Identity{
   433  				{Address: "0x000000000000000000000000000000000000000a"},
   434  			},
   435  		},
   436  		IdentityRegistry:          &mocks.IdentityRegistry{Status: registry.Registered},
   437  		IdentityChannelCalculator: &mockChannelAddressCalculator{},
   438  		BalanceProvider:           &mockBalanceProvider{Balance: big.NewInt(0)},
   439  		EarningsProvider:          &mockEarningsProvider{},
   440  	}
   441  	keeper := NewKeeper(deps, time.Millisecond)
   442  	err := keeper.Subscribe(eventBus)
   443  	assert.NoError(t, err)
   444  	assert.Zero(t, keeper.GetState().Identities[0].Balance.Uint64())
   445  
   446  	// when
   447  	eventBus.Publish(pingpongEvent.AppTopicBalanceChanged, pingpongEvent.AppEventBalanceChanged{
   448  		Identity: identity.Identity{Address: "0x000000000000000000000000000000000000000a"},
   449  		Previous: big.NewInt(0),
   450  		Current:  big.NewInt(999),
   451  	})
   452  
   453  	// then
   454  	assert.Eventually(t, func() bool {
   455  		return keeper.GetState().Identities[0].Balance.Cmp(big.NewInt(999)) == 0
   456  	}, 2*time.Second, 10*time.Millisecond)
   457  }
   458  
   459  func Test_ConsumesEarningsChangeEvent(t *testing.T) {
   460  	// given
   461  	eventBus := eventbus.New()
   462  	channelsProvider := &mockEarningsProvider{
   463  		Channels: []pingpong.HermesChannel{
   464  			{ChannelID: "1"},
   465  		},
   466  	}
   467  
   468  	deps := KeeperDeps{
   469  		Publisher:     eventBus,
   470  		ServiceLister: &serviceListerMock{},
   471  		IdentityProvider: &mocks.IdentityProvider{
   472  			Identities: []identity.Identity{
   473  				{Address: "0x000000000000000000000000000000000000000a"},
   474  			},
   475  		},
   476  		IdentityRegistry:          &mocks.IdentityRegistry{Status: registry.Registered},
   477  		IdentityChannelCalculator: &mockChannelAddressCalculator{},
   478  		BalanceProvider:           &mockBalanceProvider{Balance: big.NewInt(0)},
   479  		EarningsProvider:          channelsProvider,
   480  	}
   481  	keeper := NewKeeper(deps, time.Millisecond)
   482  	err := keeper.Subscribe(eventBus)
   483  	assert.NoError(t, err)
   484  	assert.Zero(t, keeper.GetState().Identities[0].Balance.Uint64())
   485  	assert.Len(t, keeper.GetState().ProviderChannels, 1)
   486  	assert.Equal(t, channelsProvider.Channels, keeper.GetState().ProviderChannels)
   487  
   488  	// when
   489  	channelsProvider.Channels = []pingpong.HermesChannel{
   490  		{ChannelID: "1"},
   491  		{ChannelID: "2"},
   492  	}
   493  	eventBus.Publish(pingpongEvent.AppTopicEarningsChanged, pingpongEvent.AppEventEarningsChanged{
   494  		Identity: identity.Identity{Address: "0x000000000000000000000000000000000000000a"},
   495  		Previous: pingpongEvent.EarningsDetailed{},
   496  		Current: pingpongEvent.EarningsDetailed{
   497  			Total: pingpongEvent.Earnings{
   498  				LifetimeBalance:  big.NewInt(100),
   499  				UnsettledBalance: big.NewInt(10),
   500  			},
   501  		},
   502  	})
   503  
   504  	// then
   505  	assert.Eventually(t, func() bool {
   506  		return keeper.GetState().Identities[0].Earnings.Cmp(big.NewInt(10)) == 0 && keeper.GetState().Identities[0].EarningsTotal.Cmp(big.NewInt(100)) == 0
   507  	}, 2*time.Second, 10*time.Millisecond)
   508  	assert.Len(t, keeper.GetState().ProviderChannels, 2)
   509  	assert.Equal(t, channelsProvider.Channels, keeper.GetState().ProviderChannels)
   510  }
   511  
   512  func Test_ConsumesIdentityRegistrationEvent(t *testing.T) {
   513  	// given
   514  	eventBus := eventbus.New()
   515  	deps := KeeperDeps{
   516  		Publisher:     eventBus,
   517  		ServiceLister: &serviceListerMock{},
   518  		IdentityProvider: &mocks.IdentityProvider{
   519  			Identities: []identity.Identity{
   520  				{Address: "0x000000000000000000000000000000000000000a"},
   521  			},
   522  		},
   523  		IdentityRegistry:          &mocks.IdentityRegistry{Status: registry.Unregistered},
   524  		IdentityChannelCalculator: &mockChannelAddressCalculator{},
   525  		BalanceProvider:           &mockBalanceProvider{Balance: big.NewInt(0)},
   526  		EarningsProvider:          &mockEarningsProvider{},
   527  	}
   528  	keeper := NewKeeper(deps, time.Millisecond)
   529  	err := keeper.Subscribe(eventBus)
   530  	assert.NoError(t, err)
   531  	assert.Equal(t, registry.Unregistered, keeper.GetState().Identities[0].RegistrationStatus)
   532  
   533  	// when
   534  	eventBus.Publish(registry.AppTopicIdentityRegistration, registry.AppEventIdentityRegistration{
   535  		ID:     identity.Identity{Address: "0x000000000000000000000000000000000000000a"},
   536  		Status: registry.Registered,
   537  	})
   538  
   539  	// then
   540  	assert.Eventually(t, func() bool {
   541  		return keeper.GetState().Identities[0].RegistrationStatus == registry.Registered
   542  	}, 2*time.Second, 10*time.Millisecond)
   543  }
   544  
   545  func Test_getServiceByID(t *testing.T) {
   546  	publisher := &mockPublisher{}
   547  	sl := &serviceListerMock{
   548  		servicesToReturn: map[service.ID]*service.Instance{},
   549  	}
   550  
   551  	duration := time.Millisecond * 3
   552  	deps := KeeperDeps{
   553  		Publisher:        publisher,
   554  		ServiceLister:    sl,
   555  		IdentityProvider: &mocks.IdentityProvider{},
   556  		EarningsProvider: &mockEarningsProvider{},
   557  	}
   558  	keeper := NewKeeper(deps, duration)
   559  	myID := "test"
   560  	keeper.state.Services = []contract.ServiceInfoDTO{
   561  		{ID: myID},
   562  		{ID: "mock"},
   563  	}
   564  
   565  	s, found := keeper.getServiceByID(myID)
   566  	assert.True(t, found)
   567  
   568  	assert.EqualValues(t, keeper.state.Services[0], s)
   569  
   570  	_, found = keeper.getServiceByID("something else")
   571  	assert.False(t, found)
   572  }
   573  
   574  func Test_incrementConnectionCount(t *testing.T) {
   575  	expected := service.Instance{}
   576  	var id service.ID
   577  
   578  	publisher := &mockPublisher{}
   579  	sl := &serviceListerMock{
   580  		servicesToReturn: map[service.ID]*service.Instance{
   581  			id: &expected,
   582  		},
   583  	}
   584  
   585  	duration := time.Millisecond * 3
   586  	deps := KeeperDeps{
   587  		Publisher:        publisher,
   588  		ServiceLister:    sl,
   589  		IdentityProvider: &mocks.IdentityProvider{},
   590  		EarningsProvider: &mockEarningsProvider{},
   591  	}
   592  	keeper := NewKeeper(deps, duration)
   593  	myID := "test"
   594  	keeper.state.Services = []contract.ServiceInfoDTO{
   595  		{ID: myID, ConnectionStatistics: &contract.ServiceStatisticsDTO{}},
   596  		{ID: "mock", ConnectionStatistics: &contract.ServiceStatisticsDTO{}},
   597  	}
   598  
   599  	keeper.incrementConnectCount(myID, false)
   600  	s, found := serviceByID(keeper.GetState().Services, myID)
   601  	assert.True(t, found)
   602  
   603  	assert.Equal(t, 1, s.ConnectionStatistics.Attempted)
   604  	assert.Equal(t, 0, s.ConnectionStatistics.Successful)
   605  
   606  	keeper.incrementConnectCount(myID, true)
   607  	s, found = serviceByID(keeper.GetState().Services, myID)
   608  	assert.True(t, found)
   609  
   610  	assert.Equal(t, 1, s.ConnectionStatistics.Successful)
   611  	assert.Equal(t, 1, s.ConnectionStatistics.Attempted)
   612  }
   613  
   614  func interacted(c interactionCounter, times int) func() bool {
   615  	return func() bool {
   616  		return c.interactions() == times
   617  	}
   618  }
   619  
   620  type mockBalanceProvider struct {
   621  	Balance *big.Int
   622  }
   623  
   624  // GetBalance returns a pre-defined balance.
   625  func (mbp *mockBalanceProvider) GetBalance(_ int64, _ identity.Identity) *big.Int {
   626  	return mbp.Balance
   627  }
   628  
   629  type mockEarningsProvider struct {
   630  	Earnings pingpongEvent.EarningsDetailed
   631  	Channels []pingpong.HermesChannel
   632  }
   633  
   634  // List retrieves identity's channels with all known hermeses.
   635  func (mep *mockEarningsProvider) List(chainID int64) []pingpong.HermesChannel {
   636  	return mep.Channels
   637  }
   638  
   639  // GetEarnings returns a pre-defined settlement state.
   640  func (mep *mockEarningsProvider) GetEarningsDetailed(chainID int64, _ identity.Identity) *pingpongEvent.EarningsDetailed {
   641  	return &mep.Earnings
   642  }
   643  
   644  func serviceByID(services []contract.ServiceInfoDTO, id string) (se contract.ServiceInfoDTO, found bool) {
   645  	for i := range services {
   646  		if services[i].ID == id {
   647  			se = services[i]
   648  			found = true
   649  			return
   650  		}
   651  	}
   652  	return
   653  }
   654  
   655  var stubLocation = market.Location{Country: "MU"}
   656  
   657  type mockChannelAddressCalculator struct{}
   658  
   659  func (mcac *mockChannelAddressCalculator) GetActiveChannelAddress(chainID int64, id common.Address) (common.Address, error) {
   660  	return common.Address{}, nil
   661  }
   662  
   663  func (mcac *mockChannelAddressCalculator) GetActiveHermes(chainID int64) (common.Address, error) {
   664  	return common.Address{}, nil
   665  }
   666  
   667  type mockProposalRepository struct {
   668  	priceToAdd market.Price
   669  }
   670  
   671  func (m *mockProposalRepository) EnrichProposalWithPrice(in market.ServiceProposal) (proposal.PricedServiceProposal, error) {
   672  	return proposal.PricedServiceProposal{
   673  		Price:           m.priceToAdd,
   674  		ServiceProposal: in,
   675  	}, nil
   676  }