github.com/status-im/status-go@v1.1.0/protocol/communities_events_eventual_consistency_test.go (about)

     1  package protocol
     2  
     3  import (
     4  	"testing"
     5  	"time"
     6  
     7  	"github.com/stretchr/testify/suite"
     8  
     9  	"github.com/status-im/status-go/protocol/communities"
    10  	"github.com/status-im/status-go/protocol/protobuf"
    11  	"github.com/status-im/status-go/protocol/requests"
    12  	"github.com/status-im/status-go/protocol/tt"
    13  	"github.com/status-im/status-go/waku"
    14  )
    15  
    16  func TestCommunityEventsEventualConsistencySuite(t *testing.T) {
    17  	suite.Run(t, new(CommunityEventsEventualConsistencySuite))
    18  }
    19  
    20  type CommunityEventsEventualConsistencySuite struct {
    21  	EventSenderCommunityEventsSuiteBase
    22  
    23  	messagesOrderController *MessagesOrderController
    24  }
    25  
    26  func (s *CommunityEventsEventualConsistencySuite) SetupTest() {
    27  	s.logger = tt.MustCreateTestLogger()
    28  	s.collectiblesServiceMock = &CollectiblesServiceMock{}
    29  	s.accountsTestData = make(map[string][]string)
    30  	s.accountsPasswords = make(map[string]string)
    31  	s.mockedBalances = createMockedWalletBalance(&s.Suite)
    32  
    33  	config := waku.DefaultConfig
    34  	config.MinimumAcceptedPoW = 0
    35  	shh := waku.New(&config, s.logger)
    36  	wakuWrapper, err := newTestWakuWrapper(&config, s.logger)
    37  	s.Require().NoError(err)
    38  	s.Require().NoError(shh.Start())
    39  	s.shh = wakuWrapper
    40  
    41  	s.messagesOrderController = NewMessagesOrderController(messagesOrderRandom)
    42  	s.messagesOrderController.Start(wakuWrapper.SubscribePostEvents())
    43  
    44  	s.owner = s.newMessenger("", []string{})
    45  	s.eventSender = s.newMessenger(accountPassword, []string{eventsSenderAccountAddress})
    46  	s.alice = s.newMessenger(accountPassword, []string{aliceAccountAddress})
    47  	_, err = s.owner.Start()
    48  	s.Require().NoError(err)
    49  	_, err = s.eventSender.Start()
    50  	s.Require().NoError(err)
    51  	_, err = s.alice.Start()
    52  	s.Require().NoError(err)
    53  
    54  }
    55  
    56  func (s *CommunityEventsEventualConsistencySuite) newMessenger(password string, walletAddresses []string) *Messenger {
    57  	messenger := newTestCommunitiesMessenger(&s.Suite, s.shh, testCommunitiesMessengerConfig{
    58  		testMessengerConfig: testMessengerConfig{
    59  			logger:                  s.logger,
    60  			messagesOrderController: s.messagesOrderController,
    61  		},
    62  		password:            password,
    63  		walletAddresses:     walletAddresses,
    64  		mockedBalances:      &s.mockedBalances,
    65  		collectiblesService: s.collectiblesServiceMock,
    66  	})
    67  
    68  	publicKey := messenger.IdentityPublicKeyString()
    69  	s.accountsTestData[publicKey] = walletAddresses
    70  	s.accountsPasswords[publicKey] = password
    71  	return messenger
    72  }
    73  
    74  func (s *CommunityEventsEventualConsistencySuite) TearDownTest() {
    75  	s.EventSenderCommunityEventsSuiteBase.TearDownTest()
    76  	s.messagesOrderController.Stop()
    77  }
    78  
    79  type requestToJoinActionType int
    80  
    81  const (
    82  	requestToJoinAccept requestToJoinActionType = iota
    83  	requestToJoinReject
    84  )
    85  
    86  func (s *CommunityEventsEventualConsistencySuite) testRequestsToJoin(actions []requestToJoinActionType, messagesOrder messagesOrderType) {
    87  	community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN, []*Messenger{})
    88  	s.Require().True(community.IsControlNode())
    89  
    90  	// set up additional user that will send request to join
    91  	user := s.newMessenger("somePassword", []string{"0x0123400000000000000000000000000000000000"})
    92  	s.SetupAdditionalMessengers([]*Messenger{user})
    93  
    94  	advertiseCommunityToUserOldWay(&s.Suite, community, s.owner, user)
    95  
    96  	// user sends request to join
    97  	userPPk := user.IdentityPublicKeyString()
    98  	userPassword, exists := s.accountsPasswords[userPPk]
    99  	s.Require().True(exists)
   100  	userAccounts, exists := s.accountsTestData[userPPk]
   101  	s.Require().True(exists)
   102  	requestToJoin := createRequestToJoinCommunity(&s.Suite, community.ID(), user, userPassword, userAccounts)
   103  	response, err := user.RequestToJoinCommunity(requestToJoin)
   104  	s.Require().NoError(err)
   105  	s.Require().NotNil(response)
   106  	s.Require().Len(response.RequestsToJoinCommunity(), 1)
   107  
   108  	sentRequest := response.RequestsToJoinCommunity()[0]
   109  
   110  	checkRequestToJoin := func(r *MessengerResponse) bool {
   111  		for _, request := range r.RequestsToJoinCommunity() {
   112  			if request.ENSName == requestToJoin.ENSName {
   113  				return true
   114  			}
   115  		}
   116  		return false
   117  	}
   118  
   119  	// admin receives request to join
   120  	response, err = WaitOnMessengerResponse(
   121  		s.eventSender,
   122  		checkRequestToJoin,
   123  		"event sender did not receive community request to join",
   124  	)
   125  	s.Require().NoError(err)
   126  	s.Require().Len(response.RequestsToJoinCommunity(), 1)
   127  
   128  	for _, action := range actions {
   129  		switch action {
   130  		case requestToJoinAccept:
   131  			acceptRequestToJoin := &requests.AcceptRequestToJoinCommunity{ID: sentRequest.ID}
   132  			_, err = s.eventSender.AcceptRequestToJoinCommunity(acceptRequestToJoin)
   133  			s.Require().NoError(err)
   134  
   135  		case requestToJoinReject:
   136  			rejectRequestToJoin := &requests.DeclineRequestToJoinCommunity{ID: sentRequest.ID}
   137  			_, err = s.eventSender.DeclineRequestToJoinCommunity(rejectRequestToJoin)
   138  			s.Require().NoError(err)
   139  		}
   140  	}
   141  
   142  	// ensure all messages are pushed to waku
   143  	/*
   144  		FIXME: we should do it smarter, as follows:
   145  		```
   146  		hashes1, err := admin.SendEvent()
   147  		hashes2, err := admin.SendEvent()
   148  		WaitForHashes([][]byte{hashes1, hashes2}, admin.waku)
   149  		s.messagesOrderController.setCustomOrder([][]{hashes1, hashes2})
   150  		```
   151  	*/
   152  	time.Sleep(1 * time.Second)
   153  
   154  	// ensure events are received in order
   155  	s.messagesOrderController.order = messagesOrder
   156  
   157  	response, err = s.owner.RetrieveAll()
   158  	s.Require().NoError(err)
   159  
   160  	lastAction := actions[len(actions)-1]
   161  	responseChecker := func(mr *MessengerResponse) bool {
   162  		if len(mr.RequestsToJoinCommunity()) == 0 || len(mr.Communities()) == 0 {
   163  			return false
   164  		}
   165  		switch lastAction {
   166  		case requestToJoinAccept:
   167  			return mr.RequestsToJoinCommunity()[0].State == communities.RequestToJoinStateAccepted &&
   168  				mr.Communities()[0].HasMember(&user.identity.PublicKey)
   169  		case requestToJoinReject:
   170  			return mr.RequestsToJoinCommunity()[0].State == communities.RequestToJoinStateDeclined &&
   171  				!mr.Communities()[0].HasMember(&user.identity.PublicKey)
   172  		}
   173  		return false
   174  	}
   175  
   176  	switch messagesOrder {
   177  	case messagesOrderAsPosted:
   178  		_, err = WaitOnSignaledMessengerResponse(s.owner, responseChecker, "lack of eventual consistency")
   179  		s.Require().NoError(err)
   180  	case messagesOrderReversed:
   181  		s.Require().True(responseChecker(response))
   182  	}
   183  }
   184  
   185  func (s *CommunityEventsEventualConsistencySuite) TestAdminAcceptRejectRequestToJoin_InOrder() {
   186  	s.testRequestsToJoin([]requestToJoinActionType{requestToJoinAccept, requestToJoinReject}, messagesOrderAsPosted)
   187  }
   188  
   189  func (s *CommunityEventsEventualConsistencySuite) TestAdminAcceptRejectRequestToJoin_OutOfOrder() {
   190  	s.testRequestsToJoin([]requestToJoinActionType{requestToJoinAccept, requestToJoinReject}, messagesOrderReversed)
   191  }
   192  
   193  func (s *CommunityEventsEventualConsistencySuite) TestAdminRejectAcceptRequestToJoin_InOrder() {
   194  	s.testRequestsToJoin([]requestToJoinActionType{requestToJoinReject, requestToJoinAccept}, messagesOrderAsPosted)
   195  }
   196  
   197  func (s *CommunityEventsEventualConsistencySuite) TestAdminRejectAcceptRequestToJoin_OutOfOrder() {
   198  	s.testRequestsToJoin([]requestToJoinActionType{requestToJoinReject, requestToJoinAccept}, messagesOrderReversed)
   199  }