436 lines
17 KiB
Go
436 lines
17 KiB
Go
package protocol
|
|
|
|
import (
|
|
"math/big"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/suite"
|
|
"go.uber.org/zap"
|
|
|
|
gethcommon "github.com/ethereum/go-ethereum/common"
|
|
hexutil "github.com/ethereum/go-ethereum/common/hexutil"
|
|
|
|
gethbridge "github.com/status-im/status-go/eth-node/bridge/geth"
|
|
"github.com/status-im/status-go/eth-node/types"
|
|
"github.com/status-im/status-go/protocol/common"
|
|
"github.com/status-im/status-go/protocol/communities"
|
|
"github.com/status-im/status-go/protocol/communities/token"
|
|
"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/services/wallet/bigint"
|
|
"github.com/status-im/status-go/waku"
|
|
)
|
|
|
|
func TestAdminCommunityEventsSuite(t *testing.T) {
|
|
suite.Run(t, new(AdminCommunityEventsSuite))
|
|
}
|
|
|
|
type AdminCommunityEventsSuite struct {
|
|
suite.Suite
|
|
owner *Messenger
|
|
admin *Messenger
|
|
alice *Messenger
|
|
// If one wants to send messages between different instances of Messenger,
|
|
// a single Waku service should be shared.
|
|
shh types.Waku
|
|
logger *zap.Logger
|
|
mockedBalances map[uint64]map[gethcommon.Address]map[gethcommon.Address]*hexutil.Big // chainID, account, token, balance
|
|
collectiblesServiceMock *CollectiblesServiceMock
|
|
}
|
|
|
|
func (s *AdminCommunityEventsSuite) GetControlNode() *Messenger {
|
|
return s.owner
|
|
}
|
|
|
|
func (s *AdminCommunityEventsSuite) GetEventSender() *Messenger {
|
|
return s.admin
|
|
}
|
|
|
|
func (s *AdminCommunityEventsSuite) GetMember() *Messenger {
|
|
return s.alice
|
|
}
|
|
|
|
func (s *AdminCommunityEventsSuite) GetSuite() *suite.Suite {
|
|
return &s.Suite
|
|
}
|
|
|
|
func (s *AdminCommunityEventsSuite) GetCollectiblesServiceMock() *CollectiblesServiceMock {
|
|
return s.collectiblesServiceMock
|
|
}
|
|
|
|
func (s *AdminCommunityEventsSuite) SetupTest() {
|
|
s.logger = tt.MustCreateTestLogger()
|
|
s.collectiblesServiceMock = &CollectiblesServiceMock{}
|
|
|
|
config := waku.DefaultConfig
|
|
config.MinimumAcceptedPoW = 0
|
|
shh := waku.New(&config, s.logger)
|
|
s.shh = gethbridge.NewGethWakuWrapper(shh)
|
|
s.Require().NoError(shh.Start())
|
|
|
|
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 *AdminCommunityEventsSuite) TearDownTest() {
|
|
TearDownMessenger(&s.Suite, s.owner)
|
|
TearDownMessenger(&s.Suite, s.admin)
|
|
TearDownMessenger(&s.Suite, s.alice)
|
|
_ = s.logger.Sync()
|
|
}
|
|
|
|
func (s *AdminCommunityEventsSuite) newMessenger(password string, walletAddresses []string) *Messenger {
|
|
return newMessenger(&s.Suite, s.shh, s.logger, password, walletAddresses, &s.mockedBalances, s.collectiblesServiceMock)
|
|
}
|
|
|
|
func (s *AdminCommunityEventsSuite) TestAdminEditCommunityDescription() {
|
|
// TODO admin test: update to include edit tags, logo, banner, request to join required setting, pin setting, etc...
|
|
community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN)
|
|
editCommunityDescription(s, community)
|
|
}
|
|
|
|
func (s *AdminCommunityEventsSuite) TestAdminCreateEditDeleteChannels() {
|
|
community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN)
|
|
testCreateEditDeleteChannels(s, community)
|
|
}
|
|
|
|
func (s *AdminCommunityEventsSuite) TestAdminCreateEditDeleteBecomeMemberPermission() {
|
|
community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN)
|
|
testCreateEditDeleteBecomeMemberPermission(s, community, protobuf.CommunityTokenPermission_BECOME_MEMBER)
|
|
}
|
|
|
|
func (s *AdminCommunityEventsSuite) TestAdminCannotCreateBecomeAdminPermission() {
|
|
community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN)
|
|
testEventSenderCannotCreatePrivilegedCommunityPermission(s, community, protobuf.CommunityTokenPermission_BECOME_ADMIN)
|
|
}
|
|
|
|
func (s *AdminCommunityEventsSuite) TestAdminCannotCreateBecomeTokenMasterPermission() {
|
|
community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN)
|
|
testEventSenderCannotCreatePrivilegedCommunityPermission(s, community, protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER)
|
|
}
|
|
|
|
func (s *AdminCommunityEventsSuite) TestAdminCannotEditBecomeAdminPermission() {
|
|
community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN)
|
|
testEventSenderCannotEditPrivilegedCommunityPermission(
|
|
s, community, protobuf.CommunityTokenPermission_BECOME_ADMIN, protobuf.CommunityTokenPermission_BECOME_ADMIN)
|
|
}
|
|
|
|
func (s *AdminCommunityEventsSuite) TestAdminCannotEditBecomeTokenMasterPermission() {
|
|
community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN)
|
|
testEventSenderCannotEditPrivilegedCommunityPermission(
|
|
s, community, protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER, protobuf.CommunityTokenPermission_BECOME_ADMIN)
|
|
}
|
|
|
|
func (s *AdminCommunityEventsSuite) TestAdminCannotDeleteBecomeAdminPermission() {
|
|
community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN)
|
|
testEventSenderCannotDeletePrivilegedCommunityPermission(
|
|
s, community, protobuf.CommunityTokenPermission_BECOME_ADMIN, protobuf.CommunityTokenPermission_BECOME_ADMIN)
|
|
}
|
|
|
|
func (s *AdminCommunityEventsSuite) TestAdminCannotDeleteBecomeTokenMasterPermission() {
|
|
community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN)
|
|
testEventSenderCannotDeletePrivilegedCommunityPermission(
|
|
s, community, protobuf.CommunityTokenPermission_BECOME_TOKEN_MASTER, protobuf.CommunityTokenPermission_BECOME_ADMIN)
|
|
}
|
|
|
|
func (s *AdminCommunityEventsSuite) TestAdminAcceptMemberRequestToJoinResponseSharedWithOtherEventSenders() {
|
|
additionalAdmin := s.newMessenger("qwerty", []string{eventsSenderAccountAddress})
|
|
community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN, []*Messenger{additionalAdmin})
|
|
// set up additional user that will send request to join
|
|
user := s.newMessenger("", []string{})
|
|
testAcceptMemberRequestToJoinResponseSharedWithOtherEventSenders(s, community, user, additionalAdmin)
|
|
}
|
|
|
|
func (s *AdminCommunityEventsSuite) TestAdminAcceptMemberRequestToJoin() {
|
|
community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN, []*Messenger{})
|
|
|
|
// set up additional user that will send request to join
|
|
user := s.newMessenger("", []string{})
|
|
testAcceptMemberRequestToJoin(s, community, user)
|
|
}
|
|
|
|
func (s *AdminCommunityEventsSuite) TestAdminRejectMemberRequestToJoinResponseSharedWithOtherEventSenders() {
|
|
additionalAdmin := s.newMessenger("qwerty", []string{eventsSenderAccountAddress})
|
|
community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN, []*Messenger{additionalAdmin})
|
|
// set up additional user that will send request to join
|
|
user := s.newMessenger("", []string{})
|
|
testRejectMemberRequestToJoinResponseSharedWithOtherEventSenders(s, community, user, additionalAdmin)
|
|
}
|
|
|
|
func (s *AdminCommunityEventsSuite) TestAdminRejectMemberRequestToJoin() {
|
|
community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN, []*Messenger{})
|
|
|
|
// set up additional user that will send request to join
|
|
user := s.newMessenger("", []string{})
|
|
testRejectMemberRequestToJoin(s, community, user)
|
|
}
|
|
|
|
func (s *AdminCommunityEventsSuite) TestAdminControlNodeHandlesMultipleEventSenderRequestToJoinDecisions() {
|
|
additionalAdmin := s.newMessenger("qwerty", []string{eventsSenderAccountAddress})
|
|
community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN, []*Messenger{additionalAdmin})
|
|
|
|
// set up additional user that will send request to join
|
|
user := s.newMessenger("", []string{})
|
|
testControlNodeHandlesMultipleEventSenderRequestToJoinDecisions(s, community, user, additionalAdmin)
|
|
}
|
|
|
|
func (s *AdminCommunityEventsSuite) TestAdminCreateEditDeleteCategories() {
|
|
community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN)
|
|
testCreateEditDeleteCategories(s, community)
|
|
}
|
|
|
|
func (s *AdminCommunityEventsSuite) TestAdminReorderChannelsAndCategories() {
|
|
community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN)
|
|
testReorderChannelsAndCategories(s, community)
|
|
}
|
|
|
|
func (s *AdminCommunityEventsSuite) TestAdminKickAdmin() {
|
|
community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN)
|
|
testEventSenderKickTheSameRole(s, community)
|
|
}
|
|
|
|
func (s *AdminCommunityEventsSuite) TestOwnerKickControlNode() {
|
|
community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN)
|
|
testEventSenderKickControlNode(s, community)
|
|
}
|
|
|
|
func (s *AdminCommunityEventsSuite) TestAdminKickMember() {
|
|
community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN)
|
|
kickMember(s, community.ID(), common.PubkeyToHex(&s.alice.identity.PublicKey))
|
|
}
|
|
|
|
func (s *AdminCommunityEventsSuite) TestAdminBanAdmin() {
|
|
community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN)
|
|
testOwnerBanTheSameRole(s, community)
|
|
}
|
|
|
|
func (s *AdminCommunityEventsSuite) TestAdminBanControlNode() {
|
|
community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN)
|
|
testOwnerBanControlNode(s, community)
|
|
}
|
|
|
|
func (s *AdminCommunityEventsSuite) TestAdminBanUnbanMember() {
|
|
community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN)
|
|
testBanUnbanMember(s, community)
|
|
}
|
|
|
|
func (s *AdminCommunityEventsSuite) TestAdminDeleteAnyMessageInTheCommunity() {
|
|
community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN)
|
|
testDeleteAnyMessageInTheCommunity(s, community)
|
|
}
|
|
|
|
func (s *AdminCommunityEventsSuite) TestAdminPinMessage() {
|
|
community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN)
|
|
testEventSenderPinMessage(s, community)
|
|
}
|
|
|
|
func (s *AdminCommunityEventsSuite) TestAdminAddCommunityToken() {
|
|
community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN)
|
|
|
|
tokenERC721 := &token.CommunityToken{
|
|
CommunityID: community.IDString(),
|
|
TokenType: protobuf.CommunityTokenType_ERC721,
|
|
Address: "0x123",
|
|
Name: "StatusToken",
|
|
Symbol: "STT",
|
|
Description: "desc",
|
|
Supply: &bigint.BigInt{Int: big.NewInt(123)},
|
|
InfiniteSupply: false,
|
|
Transferable: true,
|
|
RemoteSelfDestruct: true,
|
|
ChainID: 1,
|
|
DeployState: token.Deployed,
|
|
Base64Image: "ABCD",
|
|
}
|
|
|
|
_, err := s.admin.SaveCommunityToken(tokenERC721, nil)
|
|
s.Require().NoError(err)
|
|
|
|
err = s.admin.AddCommunityToken(tokenERC721.CommunityID, tokenERC721.ChainID, tokenERC721.Address)
|
|
s.Require().Error(err)
|
|
}
|
|
|
|
func (s *AdminCommunityEventsSuite) TestAdminAddTokenMasterAndOwnerToken() {
|
|
community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN)
|
|
testEventSenderAddTokenMasterAndOwnerToken(s, community)
|
|
}
|
|
|
|
func (s *AdminCommunityEventsSuite) TestAdminReceiveOwnerTokenFromControlNode() {
|
|
community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN)
|
|
|
|
testAddAndSyncOwnerTokenFromControlNode(s, community, token.OwnerLevel)
|
|
|
|
}
|
|
|
|
func (s *AdminCommunityEventsSuite) TestAdminReceiveTokenMasterTokenFromControlNode() {
|
|
community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN)
|
|
testAddAndSyncTokenFromControlNode(s, community, token.MasterLevel)
|
|
}
|
|
|
|
func (s *AdminCommunityEventsSuite) TestAdminReceiveCommunityTokenFromControlNode() {
|
|
community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN)
|
|
testAddAndSyncTokenFromControlNode(s, community, token.CommunityLevel)
|
|
}
|
|
|
|
func (s *AdminCommunityEventsSuite) TestMemberReceiveOwnerEventsWhenControlNodeOffline() {
|
|
community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN)
|
|
testMemberReceiveEventsWhenControlNodeOffline(s, community)
|
|
}
|
|
|
|
func (s *AdminCommunityEventsSuite) TestAdminResendRejectedEvents() {
|
|
community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN)
|
|
|
|
// admin modifies community description
|
|
adminEditRequest := &requests.EditCommunity{
|
|
CommunityID: community.ID(),
|
|
CreateCommunity: requests.CreateCommunity{
|
|
Name: "admin name",
|
|
Description: "admin description",
|
|
Color: "#FFFFFF",
|
|
Membership: protobuf.CommunityPermissions_MANUAL_ACCEPT,
|
|
},
|
|
}
|
|
_, err := s.admin.EditCommunity(adminEditRequest)
|
|
s.Require().NoError(err)
|
|
|
|
// in the meantime, control node updates community description as well
|
|
ownerEditRequest := &requests.EditCommunity{
|
|
CommunityID: community.ID(),
|
|
CreateCommunity: requests.CreateCommunity{
|
|
Name: "control node name",
|
|
Description: "control node description",
|
|
Color: "#FFFFFF",
|
|
Membership: protobuf.CommunityPermissions_MANUAL_ACCEPT,
|
|
},
|
|
}
|
|
_, err = s.owner.EditCommunity(ownerEditRequest)
|
|
s.Require().NoError(err)
|
|
|
|
waitOnAdminEventsRejection := waitOnCommunitiesEvent(s.owner, func(s *communities.Subscription) bool {
|
|
return s.CommunityEventsMessageInvalidClock != nil
|
|
})
|
|
|
|
// control node receives admin event and rejects it
|
|
_, err = WaitOnMessengerResponse(s.owner, func(response *MessengerResponse) bool {
|
|
select {
|
|
case err := <-waitOnAdminEventsRejection:
|
|
s.Require().NoError(err)
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}, "")
|
|
s.Require().NoError(err)
|
|
|
|
community, err = s.owner.communitiesManager.GetByID(community.ID())
|
|
s.Require().NoError(err)
|
|
s.Require().Equal(ownerEditRequest.Description, community.DescriptionText())
|
|
|
|
// admin receives rejected events and re-applies them
|
|
// there is no signal whatsoever, we just wait for admin to process all incoming messages
|
|
_, _ = WaitOnMessengerResponse(s.admin, func(response *MessengerResponse) bool {
|
|
return false
|
|
}, "")
|
|
|
|
// control node receives re-applied admin event and accepts it
|
|
response, err := WaitOnMessengerResponse(s.owner, func(response *MessengerResponse) bool {
|
|
return len(response.Communities()) > 0
|
|
}, "no communities in response")
|
|
s.Require().NoError(err)
|
|
s.Require().Equal(adminEditRequest.Description, response.Communities()[0].DescriptionText())
|
|
|
|
// admin receives updated community description
|
|
response, err = WaitOnMessengerResponse(s.admin, func(response *MessengerResponse) bool {
|
|
return len(response.Communities()) > 0
|
|
}, "no communities in response")
|
|
s.Require().NoError(err)
|
|
s.Require().Equal(adminEditRequest.Description, response.Communities()[0].DescriptionText())
|
|
}
|
|
|
|
func (s *AdminCommunityEventsSuite) TestJoinedAdminReceiveRequestsToJoinWithoutRevealedAccounts() {
|
|
community := setUpOnRequestCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN, []*Messenger{})
|
|
|
|
// set up additional user (bob) that will send request to join
|
|
bob := s.newMessenger(accountPassword, []string{bobAccountAddress})
|
|
|
|
// set up additional user that will join to the community as TokenMaster
|
|
newPrivilegedUser := s.newMessenger(accountPassword, []string{eventsSenderAccountAddress})
|
|
|
|
testJoinedPrivilegedMemberReceiveRequestsToJoin(s, community, bob, newPrivilegedUser, protobuf.CommunityTokenPermission_BECOME_ADMIN)
|
|
}
|
|
|
|
func (s *AdminCommunityEventsSuite) TestReceiveRequestsToJoinWithRevealedAccountsAfterGettingAdminRole() {
|
|
// set up additional user (bob) that will send request to join
|
|
bob := s.newMessenger(accountPassword, []string{bobAccountAddress})
|
|
testMemberReceiveRequestsToJoinAfterGettingNewRole(s, bob, protobuf.CommunityTokenPermission_BECOME_ADMIN)
|
|
}
|
|
|
|
func (s *AdminCommunityEventsSuite) TestAdminDoesNotHaveRejectedEventsLoop() {
|
|
community := setUpCommunityAndRoles(s, protobuf.CommunityMember_ROLE_ADMIN)
|
|
|
|
// admin modifies community description
|
|
adminEditRequest := &requests.EditCommunity{
|
|
CommunityID: community.ID(),
|
|
CreateCommunity: requests.CreateCommunity{
|
|
Name: "admin name",
|
|
Description: "admin description",
|
|
Color: "#FFFFFF",
|
|
Membership: protobuf.CommunityPermissions_MANUAL_ACCEPT,
|
|
},
|
|
}
|
|
_, err := s.admin.EditCommunity(adminEditRequest)
|
|
s.Require().NoError(err)
|
|
|
|
community, err = s.owner.communitiesManager.GetByID(community.ID())
|
|
s.Require().NoError(err)
|
|
|
|
// Update community clock without publishing new CommunityDescription
|
|
_, err = community.DeclineRequestToJoin(nil)
|
|
s.Require().NoError(err)
|
|
|
|
err = s.owner.communitiesManager.SaveCommunity(community)
|
|
s.Require().NoError(err)
|
|
|
|
waitOnAdminEventsRejection := waitOnCommunitiesEvent(s.owner, func(s *communities.Subscription) bool {
|
|
return s.CommunityEventsMessageInvalidClock != nil
|
|
})
|
|
|
|
// control node receives admin event and rejects it
|
|
_, err = WaitOnMessengerResponse(s.owner, func(response *MessengerResponse) bool {
|
|
select {
|
|
case err := <-waitOnAdminEventsRejection:
|
|
s.Require().NoError(err)
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}, "")
|
|
s.Require().NoError(err)
|
|
|
|
community, err = s.owner.communitiesManager.GetByID(community.ID())
|
|
s.Require().NoError(err)
|
|
s.Require().NotEqual(adminEditRequest.Description, community.DescriptionText())
|
|
|
|
// admin receives rejected events and re-applies them
|
|
// there is no signal whatsoever, we just wait for admin to process all incoming messages
|
|
_, _ = WaitOnMessengerResponse(s.admin, func(response *MessengerResponse) bool {
|
|
return false
|
|
}, "")
|
|
|
|
// control node does not receives admin event
|
|
_, err = WaitOnMessengerResponse(s.owner, func(response *MessengerResponse) bool {
|
|
return len(response.Communities()) > 0
|
|
}, "no communities in response")
|
|
s.Require().Error(err)
|
|
}
|