status-im/status-go

View on GitHub
protocol/messenger_delete_messages_test.go

Summary

Maintainability
A
0 mins
Test Coverage
package protocol

import (
    "context"
    "testing"

    "github.com/stretchr/testify/suite"

    "github.com/status-im/status-go/protocol/common"
    "github.com/status-im/status-go/protocol/communities"
    "github.com/status-im/status-go/protocol/protobuf"
    "github.com/status-im/status-go/protocol/requests"
)

func TestMessengerDeleteMessagesSuite(t *testing.T) {
    suite.Run(t, new(MessengerDeleteMessagesSuite))
}

type MessengerDeleteMessagesSuite struct {
    CommunitiesMessengerTestSuiteBase
    owner *Messenger
    admin *Messenger
    bob   *Messenger
}

func (s *MessengerDeleteMessagesSuite) SetupTest() {
    s.CommunitiesMessengerTestSuiteBase.SetupTest()

    s.owner = s.newMessenger("", []string{})
    s.bob = s.newMessenger(bobPassword, []string{bobAddress})
    s.admin = s.newMessenger(alicePassword, []string{aliceAddress1})

    _, err := s.owner.Start()
    s.Require().NoError(err)
    _, err = s.bob.Start()
    s.Require().NoError(err)
    _, err = s.admin.Start()
    s.Require().NoError(err)
}

func (s *MessengerDeleteMessagesSuite) TearDownTest() {
    TearDownMessenger(&s.Suite, s.owner)
    TearDownMessenger(&s.Suite, s.bob)
    TearDownMessenger(&s.Suite, s.admin)
    s.CommunitiesMessengerTestSuiteBase.TearDownTest()
}

func (s *MessengerDeleteMessagesSuite) sendMessageAndCheckDelivery(sender *Messenger, text string, chatID string) *common.Message {
    ctx := context.Background()
    messageToSend := common.NewMessage()
    messageToSend.ChatId = chatID
    messageToSend.ContentType = protobuf.ChatMessage_TEXT_PLAIN
    messageToSend.Text = text
    response, err := sender.SendChatMessage(ctx, messageToSend)
    s.Require().NoError(err)
    s.Require().Len(response.Messages(), 1)

    var message *common.Message
    if sender.identity != s.admin.identity {
        response, err := WaitOnMessengerResponse(s.admin, func(response *MessengerResponse) bool {
            return len(response.Messages()) == 1
        }, "admin did not receive message")
        s.Require().NoError(err)
        message = response.Messages()[0]
        s.Require().Equal(messageToSend.Text, message.Text)
    }

    if sender.identity != s.owner.identity {
        response, err = WaitOnMessengerResponse(s.owner, func(response *MessengerResponse) bool {
            return len(response.Messages()) == 1
        }, "owner did not receive message")
        s.Require().NoError(err)
        message = response.Messages()[0]
        s.Require().Equal(messageToSend.Text, message.Text)
    }

    if sender.identity != s.bob.identity {
        response, err = WaitOnMessengerResponse(s.bob, func(response *MessengerResponse) bool {
            return len(response.Messages()) == 1
        }, "bob did not receive message")
        s.Require().NoError(err)
        message = response.Messages()[0]
        s.Require().Equal(messageToSend.Text, message.Text)
    }

    return message
}

func (s *MessengerDeleteMessagesSuite) checkStoredMemberMessagesAmount(messenger *Messenger, memberPubKey string, expectedAmount int, communityID string) {
    storedMessages, err := messenger.GetCommunityMemberAllMessages(
        &requests.CommunityMemberMessages{
            CommunityID:     communityID,
            MemberPublicKey: memberPubKey})
    s.Require().NoError(err)
    s.Require().Len(storedMessages, expectedAmount)
}

func (s *MessengerDeleteMessagesSuite) checkAllMembersHasMemberMessages(memberPubKey string, expectedAmount int, communityID string) {
    s.checkStoredMemberMessagesAmount(s.bob, memberPubKey, expectedAmount, communityID)
    s.checkStoredMemberMessagesAmount(s.owner, memberPubKey, expectedAmount, communityID)
    s.checkStoredMemberMessagesAmount(s.admin, memberPubKey, expectedAmount, communityID)
}

func (s *MessengerDeleteMessagesSuite) TestDeleteMessageErrors() {
    community, communityChat := createCommunity(&s.Suite, s.owner)

    advertiseCommunityTo(&s.Suite, community, s.owner, s.admin)
    joinCommunity(&s.Suite, community.ID(), s.owner, s.admin, alicePassword, []string{aliceAddress1})

    community, err := s.owner.GetCommunityByID(community.ID())
    s.Require().NoError(err)

    advertiseCommunityTo(&s.Suite, community, s.owner, s.bob)
    joinCommunity(&s.Suite, community.ID(), s.owner, s.bob, bobPassword, []string{bobAddress})

    grantPermission(&s.Suite, community, s.owner, s.admin, protobuf.CommunityMember_ROLE_ADMIN)

    bobMessage := s.sendMessageAndCheckDelivery(s.bob, "bob message", communityChat.ID)

    expectedMsgsToRemove := 1
    communityID := community.IDString()
    s.checkAllMembersHasMemberMessages(s.bob.IdentityPublicKeyString(), expectedMsgsToRemove, communityID)

    // empty request
    deleteMessagesRequest := &requests.DeleteCommunityMemberMessages{}
    _, err = s.owner.DeleteCommunityMemberMessages(deleteMessagesRequest)
    s.Require().ErrorIs(err, requests.ErrDeleteCommunityMemberMessagesInvalidCommunityID)

    // only community ID provided
    deleteMessagesRequest.CommunityID = community.ID()
    _, err = s.owner.DeleteCommunityMemberMessages(deleteMessagesRequest)
    s.Require().ErrorIs(err, requests.ErrDeleteCommunityMemberMessagesInvalidMemberID)

    // only community ID and member ID provided, but delete flag false and no messages IDs
    deleteMessagesRequest.MemberPubKey = s.bob.IdentityPublicKeyString()
    _, err = s.owner.DeleteCommunityMemberMessages(deleteMessagesRequest)
    s.Require().ErrorIs(err, requests.ErrDeleteCommunityMemberMessagesInvalidDeleteMessagesByID)

    // message provided without id
    deleteMessagesRequest.Messages = []*protobuf.DeleteCommunityMemberMessage{&protobuf.DeleteCommunityMemberMessage{
        ChatId: bobMessage.ChatId,
    }}

    _, err = s.owner.DeleteCommunityMemberMessages(deleteMessagesRequest)
    s.Require().ErrorIs(err, requests.ErrDeleteCommunityMemberMessagesInvalidMsgID)

    // message provided without chatId
    deleteMessagesRequest.Messages = []*protobuf.DeleteCommunityMemberMessage{&protobuf.DeleteCommunityMemberMessage{
        Id: bobMessage.ID,
    }}
    _, err = s.owner.DeleteCommunityMemberMessages(deleteMessagesRequest)
    s.Require().ErrorIs(err, requests.ErrDeleteCommunityMemberMessagesInvalidMsgChatID)

    // messages id provided but with flag deleteAll
    deleteMessagesRequest.CommunityID = community.ID()
    deleteMessagesRequest.Messages = []*protobuf.DeleteCommunityMemberMessage{&protobuf.DeleteCommunityMemberMessage{
        Id:     bobMessage.ID,
        ChatId: bobMessage.ChatId,
    }}
    deleteMessagesRequest.DeleteAll = true
    _, err = s.owner.DeleteCommunityMemberMessages(deleteMessagesRequest)
    s.Require().ErrorIs(err, requests.ErrDeleteCommunityMemberMessagesInvalidDeleteAll)

    // bob tries to delete his own message
    deleteMessagesRequest.DeleteAll = false
    _, err = s.bob.DeleteCommunityMemberMessages(deleteMessagesRequest)
    s.Require().ErrorIs(err, communities.ErrNotEnoughPermissions)

    // admin tries to delete owner message
    deleteMessagesRequest.MemberPubKey = s.owner.IdentityPublicKeyString()
    _, err = s.admin.DeleteCommunityMemberMessages(deleteMessagesRequest)
    s.Require().ErrorIs(err, communities.ErrNotOwner)
}

func (s *MessengerDeleteMessagesSuite) TestDeleteMessage() {
    community, communityChat := createCommunity(&s.Suite, s.owner)

    advertiseCommunityTo(&s.Suite, community, s.owner, s.admin)
    joinCommunity(&s.Suite, community.ID(), s.owner, s.admin, alicePassword, []string{aliceAddress1})

    advertiseCommunityTo(&s.Suite, community, s.owner, s.bob)
    joinCommunity(&s.Suite, community.ID(), s.owner, s.bob, bobPassword, []string{bobAddress})

    grantPermission(&s.Suite, community, s.owner, s.admin, protobuf.CommunityMember_ROLE_ADMIN)

    bobMessage := s.sendMessageAndCheckDelivery(s.bob, "bob message", communityChat.ID)
    bobMessage2 := s.sendMessageAndCheckDelivery(s.bob, "bob message2", communityChat.ID)
    ownerMessage := s.sendMessageAndCheckDelivery(s.owner, "owner message", communityChat.ID)
    adminMessage := s.sendMessageAndCheckDelivery(s.admin, "admin message", communityChat.ID)

    identityString := s.bob.IdentityPublicKeyString()
    expectedMsgsToRemove := 2
    communityID := community.IDString()
    s.checkAllMembersHasMemberMessages(identityString, expectedMsgsToRemove, communityID)
    s.checkAllMembersHasMemberMessages(s.admin.IdentityPublicKeyString(), 1, communityID)
    s.checkAllMembersHasMemberMessages(s.owner.IdentityPublicKeyString(), 1, communityID)

    // delete bob message
    deleteMessagesRequest := &requests.DeleteCommunityMemberMessages{
        CommunityID:  community.ID(),
        MemberPubKey: identityString,
        Messages: []*protobuf.DeleteCommunityMemberMessage{&protobuf.DeleteCommunityMemberMessage{
            Id:     bobMessage.ID,
            ChatId: bobMessage.ChatId,
        }},
    }
    response, err := s.owner.DeleteCommunityMemberMessages(deleteMessagesRequest)
    s.Require().NoError(err)

    checkMessageDeleted := func(response *MessengerResponse) bool {
        if len(response.DeletedMessages()) == 0 {
            return false
        }

        if _, exists := response.DeletedMessages()[deleteMessagesRequest.Messages[0].Id]; !exists {
            return false
        }
        return true
    }

    s.Require().True(checkMessageDeleted(response))

    _, err = WaitOnMessengerResponse(s.bob, checkMessageDeleted, "message was not deleted for bob")
    s.Require().NoError(err)
    _, err = WaitOnMessengerResponse(s.admin, checkMessageDeleted, "message was not deleted for admin")
    s.Require().NoError(err)

    expectedMsgsToRemove = 1
    s.checkAllMembersHasMemberMessages(s.bob.IdentityPublicKeyString(), expectedMsgsToRemove, communityID)

    // check that other users messages were not removed
    s.checkAllMembersHasMemberMessages(s.admin.IdentityPublicKeyString(), expectedMsgsToRemove, communityID)
    s.checkAllMembersHasMemberMessages(s.owner.IdentityPublicKeyString(), expectedMsgsToRemove, communityID)

    // check that admin can delete member message
    deleteMessagesRequest.Messages = []*protobuf.DeleteCommunityMemberMessage{&protobuf.DeleteCommunityMemberMessage{
        Id:     bobMessage2.ID,
        ChatId: bobMessage2.ChatId,
    }}
    response, err = s.admin.DeleteCommunityMemberMessages(deleteMessagesRequest)
    s.Require().NoError(err)
    s.Require().True(checkMessageDeleted(response))

    _, err = WaitOnMessengerResponse(s.bob, checkMessageDeleted, "message2 was not deleted for bob")
    s.Require().NoError(err)
    _, err = WaitOnMessengerResponse(s.owner, checkMessageDeleted, "message2 was not deleted for owner")
    s.Require().NoError(err)

    expectedMsgsToRemove = 0
    s.checkAllMembersHasMemberMessages(s.bob.IdentityPublicKeyString(), expectedMsgsToRemove, communityID)

    // check that other users messages were not removed
    expectedMsgsToRemove = 1
    s.checkAllMembersHasMemberMessages(s.admin.IdentityPublicKeyString(), expectedMsgsToRemove, communityID)
    s.checkAllMembersHasMemberMessages(s.owner.IdentityPublicKeyString(), expectedMsgsToRemove, communityID)

    // check that owner can delete member message
    deleteMessagesRequest.Messages = []*protobuf.DeleteCommunityMemberMessage{&protobuf.DeleteCommunityMemberMessage{
        Id:     adminMessage.ID,
        ChatId: adminMessage.ChatId,
    }}
    response, err = s.owner.DeleteCommunityMemberMessages(deleteMessagesRequest)
    s.Require().NoError(err)
    s.Require().True(checkMessageDeleted(response))

    _, err = WaitOnMessengerResponse(s.bob, checkMessageDeleted, "adminMessage was not deleted for bob")
    s.Require().NoError(err)
    _, err = WaitOnMessengerResponse(s.admin, checkMessageDeleted, "adminMessage was not deleted for admin")
    s.Require().NoError(err)

    s.checkAllMembersHasMemberMessages(s.admin.IdentityPublicKeyString(), 0, communityID)
    s.checkAllMembersHasMemberMessages(s.owner.IdentityPublicKeyString(), 1, communityID)

    // check that owner can delete his own message
    deleteMessagesRequest.Messages = []*protobuf.DeleteCommunityMemberMessage{&protobuf.DeleteCommunityMemberMessage{
        Id:     ownerMessage.ID,
        ChatId: ownerMessage.ChatId,
    }}
    response, err = s.owner.DeleteCommunityMemberMessages(deleteMessagesRequest)
    s.Require().NoError(err)
    s.Require().True(checkMessageDeleted(response))

    _, err = WaitOnMessengerResponse(s.bob, checkMessageDeleted, "ownerMessage was not deleted for bob")
    s.Require().NoError(err)
    _, err = WaitOnMessengerResponse(s.admin, checkMessageDeleted, "ownerMessage was not deleted for admin")
    s.Require().NoError(err)

    s.checkAllMembersHasMemberMessages(s.owner.IdentityPublicKeyString(), 0, communityID)
}

func (s *MessengerDeleteMessagesSuite) TestDeleteAllMemberMessage() {
    community, communityChat := createCommunity(&s.Suite, s.owner)

    advertiseCommunityTo(&s.Suite, community, s.owner, s.admin)
    joinCommunity(&s.Suite, community.ID(), s.owner, s.admin, aliceAccountAddress, []string{aliceAddress1})

    advertiseCommunityTo(&s.Suite, community, s.owner, s.bob)
    joinCommunity(&s.Suite, community.ID(), s.owner, s.bob, bobPassword, []string{bobAddress})

    grantPermission(&s.Suite, community, s.owner, s.admin, protobuf.CommunityMember_ROLE_ADMIN)

    _ = s.sendMessageAndCheckDelivery(s.bob, "bob message", communityChat.ID)
    _ = s.sendMessageAndCheckDelivery(s.bob, "bob message2", communityChat.ID)
    _ = s.sendMessageAndCheckDelivery(s.owner, "owner message", communityChat.ID)
    _ = s.sendMessageAndCheckDelivery(s.admin, "admin message", communityChat.ID)

    identityString := s.bob.IdentityPublicKeyString()
    expectedMsgsToRemove := 2
    communityID := community.IDString()
    s.checkAllMembersHasMemberMessages(identityString, expectedMsgsToRemove, communityID)
    s.checkAllMembersHasMemberMessages(s.admin.IdentityPublicKeyString(), 1, communityID)
    s.checkAllMembersHasMemberMessages(s.owner.IdentityPublicKeyString(), 1, communityID)

    // delete all bob message
    deleteMessagesRequest := &requests.DeleteCommunityMemberMessages{
        CommunityID:  community.ID(),
        MemberPubKey: identityString,
        DeleteAll:    true,
    }
    response, err := s.owner.DeleteCommunityMemberMessages(deleteMessagesRequest)
    s.Require().NoError(err)

    checkMessageDeleted := func(response *MessengerResponse) bool {
        return len(response.DeletedMessages()) == 2
    }

    s.Require().True(checkMessageDeleted(response))

    _, err = WaitOnMessengerResponse(s.bob, checkMessageDeleted, "messages were not deleted for bob")
    s.Require().NoError(err)
    _, err = WaitOnMessengerResponse(s.admin, checkMessageDeleted, "messages were not deleted for admin")
    s.Require().NoError(err)

    expectedMsgsToRemove = 0
    s.checkAllMembersHasMemberMessages(s.bob.IdentityPublicKeyString(), expectedMsgsToRemove, communityID)

    // check that other users messages were not removed
    expectedMsgsToRemove = 1
    s.checkAllMembersHasMemberMessages(s.admin.IdentityPublicKeyString(), expectedMsgsToRemove, communityID)
    s.checkAllMembersHasMemberMessages(s.owner.IdentityPublicKeyString(), expectedMsgsToRemove, communityID)
}