status-go/protocol/communities_events_eventual...

179 lines
5.8 KiB
Go

package protocol
import (
"testing"
"time"
"github.com/stretchr/testify/suite"
"github.com/status-im/status-go/protocol/communities"
"github.com/status-im/status-go/protocol/protobuf"
"github.com/status-im/status-go/protocol/requests"
"github.com/status-im/status-go/protocol/tt"
"github.com/status-im/status-go/waku"
)
func TestCommunityEventsEventualConsistencySuite(t *testing.T) {
suite.Run(t, new(CommunityEventsEventualConsistencySuite))
}
type CommunityEventsEventualConsistencySuite struct {
AdminCommunityEventsSuite
messagesOrderController *MessagesOrderController
}
func (s *CommunityEventsEventualConsistencySuite) SetupTest() {
s.logger = tt.MustCreateTestLogger()
s.collectiblesServiceMock = &CollectiblesServiceMock{}
config := waku.DefaultConfig
config.MinimumAcceptedPoW = 0
shh := waku.New(&config, s.logger)
wakuWrapper, err := newTestWakuWrapper(&config, s.logger)
s.Require().NoError(err)
s.Require().NoError(shh.Start())
s.shh = wakuWrapper
s.messagesOrderController = NewMessagesOrderController(messagesOrderRandom)
s.messagesOrderController.Start(wakuWrapper.SubscribePostEvents())
s.owner = s.newMessenger("", []string{})
s.admin = s.newMessenger(accountPassword, []string{eventsSenderAccountAddress})
s.alice = s.newMessenger(accountPassword, []string{aliceAccountAddress})
_, err = s.owner.Start()
s.Require().NoError(err)
_, err = s.admin.Start()
s.Require().NoError(err)
_, err = s.alice.Start()
s.Require().NoError(err)
s.mockedBalances = createMockedWalletBalance(&s.Suite)
}
func (s *CommunityEventsEventualConsistencySuite) TearDownTest() {
s.AdminCommunityEventsSuite.TearDownTest()
s.messagesOrderController.Stop()
}
func (s *CommunityEventsEventualConsistencySuite) newMessenger(password string, walletAddresses []string) *Messenger {
return newTestCommunitiesMessenger(&s.Suite, s.shh, testCommunitiesMessengerConfig{
testMessengerConfig: testMessengerConfig{
logger: s.logger,
messagesOrderController: s.messagesOrderController,
},
password: password,
walletAddresses: walletAddresses,
mockedBalances: &s.mockedBalances,
collectiblesService: s.collectiblesServiceMock,
})
}
// TODO: remove once eventual consistency is implemented
var communityRequestsEventualConsistencyFixed = false
func (s *CommunityEventsEventualConsistencySuite) TestAdminAcceptRejectRequestToJoin() {
community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN, []*Messenger{})
// set up additional user that will send request to join
user := s.newMessenger("", []string{})
s.SetupAdditionalMessengers([]*Messenger{user})
advertiseCommunityToUserOldWay(&s.Suite, community, s.owner, user)
// user sends request to join
requestToJoin := &requests.RequestToJoinCommunity{CommunityID: community.ID(), ENSName: "testName"}
response, err := user.RequestToJoinCommunity(requestToJoin)
s.Require().NoError(err)
s.Require().NotNil(response)
s.Require().Len(response.RequestsToJoinCommunity(), 1)
sentRequest := response.RequestsToJoinCommunity()[0]
checkRequestToJoin := func(r *MessengerResponse) bool {
for _, request := range r.RequestsToJoinCommunity() {
if request.ENSName == requestToJoin.ENSName {
return true
}
}
return false
}
// admin receives request to join
response, err = WaitOnMessengerResponse(
s.admin,
checkRequestToJoin,
"event sender did not receive community request to join",
)
s.Require().NoError(err)
s.Require().Len(response.RequestsToJoinCommunity(), 1)
// accept request to join
acceptRequestToJoin := &requests.AcceptRequestToJoinCommunity{ID: sentRequest.ID}
_, err = s.admin.AcceptRequestToJoinCommunity(acceptRequestToJoin)
s.Require().NoError(err)
// then reject request to join
rejectRequestToJoin := &requests.DeclineRequestToJoinCommunity{ID: sentRequest.ID}
_, err = s.admin.DeclineRequestToJoinCommunity(rejectRequestToJoin)
s.Require().NoError(err)
// ensure both messages are pushed to waku
/*
FIXME: we should do it smarter, as follows:
```
hashes1, err := admin.SendEvent()
hashes2, err := admin.SendEvent()
WaitForHashes([][]byte{hashes1, hashes2}, admin.waku)
s.messagesOrderController.setCustomOrder([][]{hashes1, hashes2})
```
*/
time.Sleep(1 * time.Second)
// ensure events are received in order
s.messagesOrderController.order = messagesOrderAsPosted
waitForAcceptedRequestToJoin := waitOnCommunitiesEvent(s.owner, func(sub *communities.Subscription) bool {
return len(sub.AcceptedRequestsToJoin) == 1
})
waitOnAdminEventsRejection := waitOnCommunitiesEvent(s.owner, func(s *communities.Subscription) bool {
return s.CommunityEventsMessageInvalidClock != nil
})
_, err = s.owner.RetrieveAll()
s.Require().NoError(err)
// first owner handles AcceptRequestToJoinCommunity event
err = <-waitForAcceptedRequestToJoin
s.Require().NoError(err)
// then owner rejects DeclineRequestToJoinCommunity event due to invalid clock
err = <-waitOnAdminEventsRejection
s.Require().NoError(err)
if communityRequestsEventualConsistencyFixed {
// admin receives rejected DeclineRequestToJoinCommunity event and re-applies it,
// there is no signal whatsoever, we just wait for admin to process all incoming messages
_, _ = WaitOnMessengerResponse(s.admin, func(response *MessengerResponse) bool {
return false
}, "")
waitForRejectedRequestToJoin := waitOnCommunitiesEvent(s.owner, func(sub *communities.Subscription) bool {
return len(sub.RejectedRequestsToJoin) == 1
})
_, err = s.owner.RetrieveAll()
s.Require().NoError(err)
// owner handles DeclineRequestToJoinCommunity event eventually
err = <-waitForRejectedRequestToJoin
s.Require().NoError(err)
// user should be removed from community
community, err = s.owner.GetCommunityByID(community.ID())
s.Require().NoError(err)
s.Require().False(community.HasMember(&user.identity.PublicKey))
}
}