github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/core/discovery/brokerdiscovery/repository_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 brokerdiscovery
    19  
    20  import (
    21  	"encoding/json"
    22  	"testing"
    23  	"time"
    24  
    25  	"github.com/mysteriumnetwork/node/communication/nats"
    26  	"github.com/mysteriumnetwork/node/eventbus"
    27  	"github.com/mysteriumnetwork/node/market"
    28  	"github.com/stretchr/testify/assert"
    29  )
    30  
    31  func init() {
    32  	market.RegisterServiceType("mock_service")
    33  	market.RegisterContactUnserializer("mock_contact",
    34  		func(rawMessage *json.RawMessage) (market.ContactDefinition, error) {
    35  			return mockContact{}, nil
    36  		},
    37  	)
    38  }
    39  
    40  var (
    41  	proposalFirst = func() market.ServiceProposal {
    42  		return market.NewProposal("0x1", "mock_service", market.NewProposalOpts{
    43  			Contacts: []market.Contact{{Type: "mock_contact", Definition: mockContact{}}},
    44  		})
    45  	}
    46  	proposalSecond = func() market.ServiceProposal {
    47  		return market.NewProposal("0x2", "mock_service", market.NewProposalOpts{
    48  			Contacts: []market.Contact{{Type: "mock_contact", Definition: mockContact{}}},
    49  		})
    50  	}
    51  )
    52  
    53  func Test_Subscriber_StartSyncsNewProposals(t *testing.T) {
    54  	connection := nats.StartConnectionMock()
    55  	defer connection.Close()
    56  
    57  	repo := NewRepository(connection, NewStorage(eventbus.New()), 500*time.Millisecond, 1*time.Second)
    58  	err := repo.Start()
    59  	defer repo.Stop()
    60  	assert.NoError(t, err)
    61  
    62  	proposalRegister(connection, `
    63  		{
    64  		  "proposal": {
    65  			"format": "service-proposal/v3",
    66  			"compatibility": 2,
    67  			"provider_id": "0x1",
    68  			"service_type": "mock_service",
    69  			"contacts": [
    70  			  {
    71  				"type": "mock_contact"
    72  			  }
    73  			]
    74  		  }
    75  		}
    76  	`)
    77  
    78  	assert.Eventually(t, proposalCountEquals(repo, 1), 2*time.Second, 10*time.Millisecond)
    79  	assert.Exactly(t, []market.ServiceProposal{proposalFirst()}, repo.storage.Proposals())
    80  }
    81  
    82  func Test_Subscriber_SkipUnsupportedProposal(t *testing.T) {
    83  	connection := nats.StartConnectionMock()
    84  	defer connection.Close()
    85  
    86  	repo := NewRepository(connection, NewStorage(eventbus.New()), 500*time.Millisecond, 10*time.Millisecond)
    87  	err := repo.Start()
    88  	defer repo.Stop()
    89  	assert.NoError(t, err)
    90  
    91  	proposalRegister(connection, `{
    92  		"proposal": {"provider_id": "0x1", "service_type": "unknown"}
    93  	}`)
    94  
    95  	time.Sleep(10 * time.Millisecond)
    96  	assert.Len(t, repo.storage.Proposals(), 0)
    97  	assert.Exactly(t, []market.ServiceProposal{}, repo.storage.Proposals())
    98  }
    99  
   100  func Test_Subscriber_StartSyncsIdleProposals(t *testing.T) {
   101  	connection := nats.StartConnectionMock()
   102  	defer connection.Close()
   103  
   104  	repo := NewRepository(connection, NewStorage(eventbus.New()), 10*time.Millisecond, 10*time.Millisecond)
   105  	err := repo.Start()
   106  	defer repo.Stop()
   107  	assert.NoError(t, err)
   108  
   109  	proposalRegister(connection, `{
   110  	  "proposal": {
   111  		"format": "service-proposal/v2",
   112  		"provider_id": "0x1",
   113  		"service_type": "mock_service",
   114  		"contacts": [
   115  		  {
   116  			"type": "mock_contact"
   117  		  }
   118  		]
   119  	  }
   120  	}`)
   121  	assert.Eventually(t, proposalCountEquals(repo, 0), 2*time.Second, 10*time.Millisecond)
   122  }
   123  
   124  func Test_Subscriber_StartSyncsHealthyProposals(t *testing.T) {
   125  	connection := nats.StartConnectionMock()
   126  	defer connection.Close()
   127  
   128  	repo := NewRepository(connection, NewStorage(eventbus.New()), 100*time.Millisecond, 10*time.Millisecond)
   129  	err := repo.Start()
   130  	defer repo.Stop()
   131  	assert.NoError(t, err)
   132  
   133  	proposalRegister(connection, `{
   134  	  "proposal": {
   135  		"format": "service-proposal/v3",
   136  		"compatibility": 2,
   137  		"provider_id": "0x1",
   138  		"service_type": "mock_service",
   139  		"contacts": [
   140  		  {
   141  			"type": "mock_contact"
   142  		  }
   143  		]
   144  	  }
   145  	}`)
   146  
   147  	proposalPing(connection, `{
   148  	  "proposal": {
   149          "format": "service-proposal/v3",
   150  		"compatibility": 2,
   151  		"provider_id": "0x1",
   152  		"service_type": "mock_service",
   153  		"contacts": [
   154  		  {
   155  			"type": "mock_contact"
   156  		  }
   157  		]
   158  	  }
   159  	}`)
   160  
   161  	assert.Eventually(t, proposalCountEquals(repo, 1), 2*time.Second, 10*time.Millisecond)
   162  	expected := []market.ServiceProposal{proposalFirst()}
   163  	actual := repo.storage.Proposals()
   164  	assert.Exactly(t, expected, actual)
   165  }
   166  
   167  func Test_Subscriber_StartSyncsStoppedProposals(t *testing.T) {
   168  	connection := nats.StartConnectionMock()
   169  	defer connection.Close()
   170  
   171  	repo := NewRepository(connection, NewStorage(eventbus.New()), 500*time.Millisecond, 10*time.Millisecond)
   172  	repo.storage.AddProposal(proposalFirst(), proposalSecond())
   173  	err := repo.Start()
   174  	defer repo.Stop()
   175  	assert.NoError(t, err)
   176  
   177  	proposalUnregister(connection, `{
   178  	  "proposal": {
   179  		"format": "service-proposal/v2",
   180  		"provider_id": "0x1",
   181  		"service_type": "mock_service",
   182  		"contacts": [
   183  		  {
   184  			"type": "mock_contact"
   185  		  }
   186  		]
   187  	  }
   188  }`)
   189  }
   190  
   191  func proposalRegister(connection nats.Connection, payload string) {
   192  	err := connection.Publish("*.proposal-register.v3", []byte(payload))
   193  	if err != nil {
   194  		panic(err)
   195  	}
   196  }
   197  
   198  func proposalUnregister(connection nats.Connection, payload string) {
   199  	err := connection.Publish("*.proposal-unregister.v3", []byte(payload))
   200  	if err != nil {
   201  		panic(err)
   202  	}
   203  }
   204  
   205  func proposalPing(connection nats.Connection, payload string) {
   206  	err := connection.Publish("*.proposal-ping.v3", []byte(payload))
   207  	if err != nil {
   208  		panic(err)
   209  	}
   210  }
   211  
   212  func proposalCountEquals(subscriber *Repository, count int) func() bool {
   213  	return func() bool {
   214  		return len(subscriber.storage.Proposals()) == count
   215  	}
   216  }
   217  
   218  type mockContact struct{}