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 }