2021-05-27 17:24:04 +00:00
|
|
|
package protocol
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/stretchr/testify/suite"
|
|
|
|
|
|
|
|
"github.com/status-im/status-go/eth-node/crypto"
|
|
|
|
"github.com/status-im/status-go/eth-node/types"
|
2021-06-08 06:07:45 +00:00
|
|
|
"github.com/status-im/status-go/protocol/common"
|
2021-06-07 11:45:06 +00:00
|
|
|
"github.com/status-im/status-go/protocol/protobuf"
|
2021-06-07 08:31:27 +00:00
|
|
|
"github.com/status-im/status-go/protocol/requests"
|
2021-05-27 17:24:04 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func TestMessengerEditMessageSuite(t *testing.T) {
|
|
|
|
suite.Run(t, new(MessengerEditMessageSuite))
|
|
|
|
}
|
|
|
|
|
|
|
|
type MessengerEditMessageSuite struct {
|
2023-07-13 10:28:34 +00:00
|
|
|
MessengerBaseTestSuite
|
2021-05-27 17:24:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *MessengerEditMessageSuite) TestEditMessage() {
|
|
|
|
theirMessenger := s.newMessenger()
|
2023-11-27 17:01:13 +00:00
|
|
|
defer TearDownMessenger(&s.Suite, theirMessenger)
|
2021-05-27 17:24:04 +00:00
|
|
|
|
|
|
|
theirChat := CreateOneToOneChat("Their 1TO1", &s.privateKey.PublicKey, s.m.transport)
|
2024-02-26 09:12:37 +00:00
|
|
|
err := theirMessenger.SaveChat(theirChat)
|
2021-05-27 17:24:04 +00:00
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
ourChat := CreateOneToOneChat("Our 1TO1", &theirMessenger.identity.PublicKey, s.m.transport)
|
|
|
|
err = s.m.SaveChat(ourChat)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
inputMessage := buildTestMessage(*theirChat)
|
|
|
|
sendResponse, err := theirMessenger.SendChatMessage(context.Background(), inputMessage)
|
|
|
|
s.NoError(err)
|
2021-06-03 13:11:55 +00:00
|
|
|
s.Require().Len(sendResponse.Messages(), 1)
|
2021-05-27 17:24:04 +00:00
|
|
|
|
|
|
|
response, err := WaitOnMessengerResponse(
|
|
|
|
s.m,
|
2021-06-03 13:11:55 +00:00
|
|
|
func(r *MessengerResponse) bool { return len(r.messages) > 0 },
|
2021-05-27 17:24:04 +00:00
|
|
|
"no messages",
|
|
|
|
)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().Len(response.Chats(), 1)
|
2021-06-03 13:11:55 +00:00
|
|
|
s.Require().Len(response.Messages(), 1)
|
2021-05-27 17:24:04 +00:00
|
|
|
|
2021-06-03 13:11:55 +00:00
|
|
|
ogMessage := sendResponse.Messages()[0]
|
2021-05-27 17:24:04 +00:00
|
|
|
|
2021-06-07 08:31:27 +00:00
|
|
|
messageID, err := types.DecodeHex(ogMessage.ID)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
editedText := "edited text"
|
|
|
|
editedMessage := &requests.EditMessage{
|
|
|
|
ID: messageID,
|
|
|
|
Text: editedText,
|
|
|
|
}
|
2021-05-27 17:24:04 +00:00
|
|
|
|
2021-06-07 08:31:27 +00:00
|
|
|
sendResponse, err = theirMessenger.EditMessage(context.Background(), editedMessage)
|
2021-05-27 17:24:04 +00:00
|
|
|
|
2021-06-03 13:11:55 +00:00
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().Len(sendResponse.Messages(), 1)
|
2021-06-07 08:31:27 +00:00
|
|
|
s.Require().NotEmpty(sendResponse.Messages()[0].EditedAt)
|
|
|
|
s.Require().Equal(sendResponse.Messages()[0].Text, editedText)
|
2021-06-23 10:07:26 +00:00
|
|
|
s.Require().Len(sendResponse.Chats(), 1)
|
|
|
|
s.Require().NotNil(sendResponse.Chats()[0].LastMessage)
|
|
|
|
s.Require().NotEmpty(sendResponse.Chats()[0].LastMessage.EditedAt)
|
2021-05-27 17:24:04 +00:00
|
|
|
|
|
|
|
response, err = WaitOnMessengerResponse(
|
|
|
|
s.m,
|
2021-06-03 13:11:55 +00:00
|
|
|
func(r *MessengerResponse) bool { return len(r.messages) > 0 },
|
2021-05-27 17:24:04 +00:00
|
|
|
"no messages",
|
|
|
|
)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
s.Require().Len(response.Chats(), 1)
|
2021-06-03 13:11:55 +00:00
|
|
|
s.Require().Len(response.Messages(), 1)
|
2021-06-07 08:31:27 +00:00
|
|
|
s.Require().NotEmpty(response.Messages()[0].EditedAt)
|
2021-06-25 08:30:18 +00:00
|
|
|
s.Require().False(response.Messages()[0].New)
|
2021-05-27 17:24:04 +00:00
|
|
|
|
|
|
|
// Main instance user attempts to edit the message it received from theirMessenger
|
2021-06-07 08:31:27 +00:00
|
|
|
editedMessage = &requests.EditMessage{
|
|
|
|
ID: messageID,
|
|
|
|
Text: "edited-again text",
|
|
|
|
}
|
|
|
|
_, err = s.m.EditMessage(context.Background(), editedMessage)
|
2021-05-27 17:24:04 +00:00
|
|
|
|
2021-07-26 21:06:32 +00:00
|
|
|
s.Require().Equal(ErrInvalidEditOrDeleteAuthor, err)
|
2021-06-29 08:27:11 +00:00
|
|
|
}
|
|
|
|
|
2024-12-03 15:04:21 +00:00
|
|
|
func (s *MessengerEditMessageSuite) TestEditImageMessage() {
|
|
|
|
theirMessenger := s.newMessenger()
|
|
|
|
defer TearDownMessenger(&s.Suite, theirMessenger)
|
|
|
|
|
|
|
|
theirChat := CreateOneToOneChat("Their 1TO1", &s.privateKey.PublicKey, s.m.transport)
|
|
|
|
err := theirMessenger.SaveChat(theirChat)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
ourChat := CreateOneToOneChat("Our 1TO1", &theirMessenger.identity.PublicKey, s.m.transport)
|
|
|
|
err = s.m.SaveChat(ourChat)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
const messageCount = 1
|
|
|
|
var album []*common.Message
|
|
|
|
|
|
|
|
for i := 0; i < messageCount; i++ {
|
|
|
|
image, err := buildImageWithoutAlbumIDMessage(*ourChat)
|
|
|
|
s.NoError(err)
|
|
|
|
image.Text = "my message"
|
|
|
|
album = append(album, image)
|
|
|
|
}
|
|
|
|
|
|
|
|
sendResponse, err := s.m.SendChatMessages(context.Background(), album)
|
|
|
|
s.NoError(err)
|
|
|
|
s.Require().Len(sendResponse.Messages(), messageCount)
|
|
|
|
|
|
|
|
ogMessage := sendResponse.Messages()[0]
|
|
|
|
|
|
|
|
response, err := WaitOnMessengerResponse(
|
|
|
|
theirMessenger,
|
|
|
|
func(r *MessengerResponse) bool {
|
|
|
|
if len(r.messages) == 0 {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
_, ok := r.messages[ogMessage.ID]
|
|
|
|
return ok
|
|
|
|
},
|
|
|
|
"no messages",
|
|
|
|
)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().Len(response.Chats(), 1)
|
|
|
|
s.Require().Len(response.Messages(), 1)
|
|
|
|
|
|
|
|
messageID, err := types.DecodeHex(ogMessage.ID)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
editedText := "edited text"
|
|
|
|
editedMessage := &requests.EditMessage{
|
|
|
|
ID: messageID,
|
|
|
|
Text: editedText,
|
|
|
|
}
|
|
|
|
|
|
|
|
sendResponse, err = s.m.EditMessage(context.Background(), editedMessage)
|
|
|
|
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().Len(sendResponse.Messages(), 1)
|
|
|
|
s.Require().Equal(editedText, sendResponse.Messages()[0].Text)
|
|
|
|
s.Require().Equal(protobuf.ChatMessage_IMAGE, sendResponse.Messages()[0].ContentType)
|
|
|
|
|
|
|
|
response, err = WaitOnMessengerResponse(
|
|
|
|
theirMessenger,
|
|
|
|
func(r *MessengerResponse) bool {
|
|
|
|
if len(r.messages) == 0 {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
_, ok := r.messages[sendResponse.Messages()[0].ID]
|
|
|
|
return ok
|
|
|
|
},
|
|
|
|
"no messages",
|
|
|
|
)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().Len(response.Messages(), 1)
|
|
|
|
s.Require().NotEmpty(response.Messages()[0].EditedAt)
|
|
|
|
s.Require().False(response.Messages()[0].New)
|
|
|
|
s.Require().Equal(protobuf.ChatMessage_IMAGE, response.Messages()[0].ContentType)
|
|
|
|
|
|
|
|
// Check DB to make sure the message is still an image
|
|
|
|
dbMessage, err := s.m.persistence.MessageByID(ogMessage.ID)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().Equal(protobuf.ChatMessage_IMAGE, dbMessage.ContentType)
|
|
|
|
}
|
|
|
|
|
2024-03-22 12:23:43 +00:00
|
|
|
func (s *MessengerEditMessageSuite) TestEditBridgeMessage() {
|
|
|
|
theirMessenger := s.newMessenger()
|
|
|
|
defer TearDownMessenger(&s.Suite, theirMessenger)
|
|
|
|
|
|
|
|
theirChat := CreateOneToOneChat("Their 1TO1", &s.privateKey.PublicKey, s.m.transport)
|
|
|
|
err := theirMessenger.SaveChat(theirChat)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
ourChat := CreateOneToOneChat("Our 1TO1", &theirMessenger.identity.PublicKey, s.m.transport)
|
|
|
|
err = s.m.SaveChat(ourChat)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
bridgeMessage := buildTestMessage(*theirChat)
|
|
|
|
bridgeMessage.ContentType = protobuf.ChatMessage_BRIDGE_MESSAGE
|
|
|
|
bridgeMessage.Payload = &protobuf.ChatMessage_BridgeMessage{
|
|
|
|
BridgeMessage: &protobuf.BridgeMessage{
|
|
|
|
BridgeName: "discord",
|
|
|
|
UserName: "user1",
|
|
|
|
UserAvatar: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAIAAACRXR/mAAAAjklEQVR4nOzXwQmFMBAAUZXUYh32ZB32ZB02sxYQQSZGsod55/91WFgSS0RM+SyjA56ZRZhFmEWYRRT6h+M6G16zrxv6fdJpmUWYRbxsYr13dKfanpN0WmYRZhGzXz6AWYRZRIfbaX26fT9Jk07LLMIsosPt9I/dTDotswizCG+nhFmEWYRZhFnEHQAA///z1CFkYamgfQAAAABJRU5ErkJggg==",
|
|
|
|
UserID: "123",
|
|
|
|
Content: "text1",
|
|
|
|
MessageID: "456",
|
|
|
|
ParentMessageID: "789",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
sendResponse, err := theirMessenger.SendChatMessage(context.Background(), bridgeMessage)
|
|
|
|
s.NoError(err)
|
|
|
|
s.Require().Len(sendResponse.Messages(), 1)
|
|
|
|
|
|
|
|
response, err := WaitOnMessengerResponse(
|
|
|
|
s.m,
|
|
|
|
func(r *MessengerResponse) bool { return len(r.messages) > 0 },
|
|
|
|
"no messages",
|
|
|
|
)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().Len(response.Chats(), 1)
|
|
|
|
s.Require().Len(response.Messages(), 1)
|
|
|
|
|
|
|
|
messageToEdit := sendResponse.Messages()[0]
|
|
|
|
|
|
|
|
messageID, err := types.DecodeHex(messageToEdit.ID)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
editedText := "edited text"
|
|
|
|
editedMessage := &requests.EditMessage{
|
2024-12-03 15:04:21 +00:00
|
|
|
ID: messageID,
|
|
|
|
Text: editedText,
|
2024-03-22 12:23:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
sendResponse, err = theirMessenger.EditMessage(context.Background(), editedMessage)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().Len(sendResponse.Messages(), 1)
|
|
|
|
s.Require().NotEmpty(sendResponse.Messages()[0].EditedAt)
|
|
|
|
s.Require().Equal(sendResponse.Messages()[0].Text, "text-input-message")
|
|
|
|
s.Require().Equal(sendResponse.Messages()[0].GetBridgeMessage().Content, editedText)
|
|
|
|
s.Require().Len(sendResponse.Chats(), 1)
|
|
|
|
s.Require().NotNil(sendResponse.Chats()[0].LastMessage)
|
|
|
|
s.Require().NotEmpty(sendResponse.Chats()[0].LastMessage.EditedAt)
|
|
|
|
|
|
|
|
response, err = WaitOnMessengerResponse(
|
|
|
|
s.m,
|
|
|
|
func(r *MessengerResponse) bool { return len(r.messages) > 0 },
|
|
|
|
"no messages",
|
|
|
|
)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().Len(response.Chats(), 1)
|
|
|
|
s.Require().Len(response.Messages(), 1)
|
|
|
|
|
|
|
|
s.Require().NotEmpty(response.Chats()[0].LastMessage.EditedAt)
|
|
|
|
s.Require().Equal(response.Messages()[0].GetBridgeMessage().Content, "edited text")
|
|
|
|
}
|
|
|
|
|
2021-06-07 11:45:06 +00:00
|
|
|
func (s *MessengerEditMessageSuite) TestEditMessageEdgeCases() {
|
|
|
|
theirMessenger := s.newMessenger()
|
2023-11-27 17:01:13 +00:00
|
|
|
defer TearDownMessenger(&s.Suite, theirMessenger)
|
2021-06-07 11:45:06 +00:00
|
|
|
|
|
|
|
theirChat := CreateOneToOneChat("Their 1TO1", &s.privateKey.PublicKey, s.m.transport)
|
2024-02-26 09:12:37 +00:00
|
|
|
err := theirMessenger.SaveChat(theirChat)
|
2021-06-07 11:45:06 +00:00
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
ourChat := CreateOneToOneChat("Our 1TO1", &theirMessenger.identity.PublicKey, s.m.transport)
|
|
|
|
err = s.m.SaveChat(ourChat)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
inputMessage := buildTestMessage(*theirChat)
|
|
|
|
sendResponse, err := theirMessenger.SendChatMessage(context.Background(), inputMessage)
|
|
|
|
s.NoError(err)
|
|
|
|
s.Require().Len(sendResponse.Messages(), 1)
|
|
|
|
|
|
|
|
response, err := WaitOnMessengerResponse(
|
|
|
|
s.m,
|
|
|
|
func(r *MessengerResponse) bool { return len(r.messages) > 0 },
|
|
|
|
"no messages",
|
|
|
|
)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().Len(response.Chats(), 1)
|
|
|
|
s.Require().Len(response.Messages(), 1)
|
|
|
|
|
|
|
|
chat := response.Chats()[0]
|
|
|
|
editedMessage := sendResponse.Messages()[0]
|
|
|
|
|
|
|
|
newContactKey, err := crypto.GenerateKey()
|
|
|
|
s.Require().NoError(err)
|
|
|
|
wrongContact, err := BuildContactFromPublicKey(&newContactKey.PublicKey)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
editMessage := EditMessage{
|
2023-08-18 11:39:59 +00:00
|
|
|
EditMessage: &protobuf.EditMessage{
|
2021-06-07 11:45:06 +00:00
|
|
|
Clock: editedMessage.Clock + 1,
|
|
|
|
Text: "some text",
|
|
|
|
MessageId: editedMessage.ID,
|
|
|
|
ChatId: chat.ID,
|
|
|
|
},
|
|
|
|
From: wrongContact.ID,
|
|
|
|
}
|
|
|
|
|
2023-02-06 10:38:37 +00:00
|
|
|
state := &ReceivedMessageState{
|
|
|
|
Response: &MessengerResponse{},
|
|
|
|
AllChats: &chatMap{},
|
|
|
|
}
|
|
|
|
state.AllChats.Store(ourChat.ID, ourChat)
|
2021-06-07 11:45:06 +00:00
|
|
|
|
2023-08-18 11:39:59 +00:00
|
|
|
err = s.m.handleEditMessage(state, editMessage)
|
2021-06-07 11:45:06 +00:00
|
|
|
// It should error as the user can't edit this message
|
|
|
|
s.Require().Error(err)
|
|
|
|
|
|
|
|
// Edit with a newer clock value
|
|
|
|
|
|
|
|
contact, err := BuildContactFromPublicKey(&theirMessenger.identity.PublicKey)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
editMessage = EditMessage{
|
2023-08-18 11:39:59 +00:00
|
|
|
EditMessage: &protobuf.EditMessage{
|
2021-06-29 08:27:11 +00:00
|
|
|
Clock: editedMessage.Clock + 2,
|
|
|
|
Text: "some text",
|
|
|
|
MessageType: protobuf.MessageType_ONE_TO_ONE,
|
|
|
|
MessageId: editedMessage.ID,
|
|
|
|
ChatId: chat.ID,
|
2021-06-07 11:45:06 +00:00
|
|
|
},
|
|
|
|
From: contact.ID,
|
|
|
|
}
|
|
|
|
|
2023-08-18 11:39:59 +00:00
|
|
|
err = s.m.handleEditMessage(state, editMessage)
|
2021-06-07 11:45:06 +00:00
|
|
|
s.Require().NoError(err)
|
|
|
|
// It save the edit
|
2023-02-06 10:38:37 +00:00
|
|
|
s.Require().Len(state.Response.Messages(), 1)
|
|
|
|
s.Require().Len(state.Response.Chats(), 1)
|
|
|
|
s.Require().NotNil(state.Response.Chats()[0].LastMessage)
|
|
|
|
s.Require().NotEmpty(state.Response.Chats()[0].LastMessage.EditedAt)
|
2021-06-07 11:45:06 +00:00
|
|
|
|
2023-02-06 10:38:37 +00:00
|
|
|
editedMessage = state.Response.Messages()[0]
|
2021-06-07 11:45:06 +00:00
|
|
|
|
|
|
|
// In-between edit
|
|
|
|
editMessage = EditMessage{
|
2023-08-18 11:39:59 +00:00
|
|
|
EditMessage: &protobuf.EditMessage{
|
2021-06-29 08:27:11 +00:00
|
|
|
Clock: editedMessage.Clock + 1,
|
|
|
|
Text: "some other text",
|
|
|
|
MessageType: protobuf.MessageType_ONE_TO_ONE,
|
|
|
|
MessageId: editedMessage.ID,
|
|
|
|
ChatId: chat.ID,
|
2021-06-07 11:45:06 +00:00
|
|
|
},
|
|
|
|
From: contact.ID,
|
|
|
|
}
|
|
|
|
|
2023-02-06 10:38:37 +00:00
|
|
|
state.Response = &MessengerResponse{}
|
2021-06-07 11:45:06 +00:00
|
|
|
|
2023-08-18 11:39:59 +00:00
|
|
|
err = s.m.handleEditMessage(state, editMessage)
|
2021-06-07 11:45:06 +00:00
|
|
|
// It should error as the user can't edit this message
|
|
|
|
s.Require().NoError(err)
|
|
|
|
// It discards the edit
|
2023-02-06 10:38:37 +00:00
|
|
|
s.Require().Len(state.Response.Messages(), 0)
|
2021-05-27 17:24:04 +00:00
|
|
|
}
|
2021-06-08 06:07:45 +00:00
|
|
|
|
|
|
|
func (s *MessengerEditMessageSuite) TestEditMessageFirstEditsThenMessage() {
|
|
|
|
theirMessenger := s.newMessenger()
|
2023-11-27 17:01:13 +00:00
|
|
|
defer TearDownMessenger(&s.Suite, theirMessenger)
|
2021-06-08 06:07:45 +00:00
|
|
|
|
|
|
|
theirChat := CreateOneToOneChat("Their 1TO1", &s.privateKey.PublicKey, s.m.transport)
|
2024-02-26 09:12:37 +00:00
|
|
|
err := theirMessenger.SaveChat(theirChat)
|
2021-06-08 06:07:45 +00:00
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
contact, err := BuildContactFromPublicKey(&theirMessenger.identity.PublicKey)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
ourChat := CreateOneToOneChat("Our 1TO1", &theirMessenger.identity.PublicKey, s.m.transport)
|
|
|
|
err = s.m.SaveChat(ourChat)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
messageID := "message-id"
|
|
|
|
|
|
|
|
inputMessage := buildTestMessage(*theirChat)
|
|
|
|
inputMessage.Clock = 1
|
|
|
|
editMessage := EditMessage{
|
2023-08-18 11:39:59 +00:00
|
|
|
EditMessage: &protobuf.EditMessage{
|
2021-06-29 08:27:11 +00:00
|
|
|
Clock: 2,
|
|
|
|
Text: "some text",
|
|
|
|
MessageType: protobuf.MessageType_ONE_TO_ONE,
|
|
|
|
MessageId: messageID,
|
|
|
|
ChatId: theirChat.ID,
|
2021-06-08 06:07:45 +00:00
|
|
|
},
|
|
|
|
From: common.PubkeyToHex(&theirMessenger.identity.PublicKey),
|
|
|
|
}
|
2023-02-06 10:38:37 +00:00
|
|
|
state := &ReceivedMessageState{
|
|
|
|
Response: &MessengerResponse{},
|
|
|
|
}
|
2021-06-08 06:07:45 +00:00
|
|
|
|
|
|
|
// Handle edit first
|
2023-08-18 11:39:59 +00:00
|
|
|
err = s.m.handleEditMessage(state, editMessage)
|
2021-06-08 06:07:45 +00:00
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
// Handle chat message
|
2023-02-06 10:38:37 +00:00
|
|
|
response := &MessengerResponse{}
|
|
|
|
state = &ReceivedMessageState{
|
2021-06-08 06:07:45 +00:00
|
|
|
Response: response,
|
|
|
|
CurrentMessageState: &CurrentMessageState{
|
|
|
|
MessageID: messageID,
|
|
|
|
WhisperTimestamp: s.m.getTimesource().GetCurrentTime(),
|
|
|
|
Contact: contact,
|
|
|
|
PublicKey: &theirMessenger.identity.PublicKey,
|
|
|
|
},
|
|
|
|
}
|
2023-09-07 10:33:20 +00:00
|
|
|
err = s.m.HandleChatMessage(state, inputMessage.ChatMessage, nil, false)
|
2021-06-08 06:07:45 +00:00
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().Len(response.Messages(), 1)
|
|
|
|
|
|
|
|
editedMessage := response.Messages()[0]
|
|
|
|
|
|
|
|
s.Require().Equal(uint64(2), editedMessage.EditedAt)
|
|
|
|
}
|
2021-06-25 10:37:54 +00:00
|
|
|
|
|
|
|
// Test editing a message on an existing private group chat
|
|
|
|
func (s *MessengerEditMessageSuite) TestEditGroupChatMessage() {
|
|
|
|
theirMessenger := s.newMessenger()
|
2023-11-27 17:01:13 +00:00
|
|
|
defer TearDownMessenger(&s.Suite, theirMessenger)
|
2021-06-25 10:37:54 +00:00
|
|
|
|
|
|
|
response, err := s.m.CreateGroupChatWithMembers(context.Background(), "id", []string{})
|
|
|
|
s.NoError(err)
|
|
|
|
s.Require().Len(response.Chats(), 1)
|
|
|
|
|
|
|
|
ourChat := response.Chats()[0]
|
|
|
|
|
|
|
|
err = s.m.SaveChat(ourChat)
|
|
|
|
s.NoError(err)
|
|
|
|
|
2022-08-26 09:25:54 +00:00
|
|
|
s.Require().NoError(makeMutualContact(s.m, &theirMessenger.identity.PublicKey))
|
|
|
|
|
2021-06-25 10:37:54 +00:00
|
|
|
members := []string{common.PubkeyToHex(&theirMessenger.identity.PublicKey)}
|
|
|
|
_, err = s.m.AddMembersToGroupChat(context.Background(), ourChat.ID, members)
|
|
|
|
s.NoError(err)
|
|
|
|
|
|
|
|
// Retrieve their messages so that the chat is created
|
|
|
|
response, err = WaitOnMessengerResponse(
|
|
|
|
theirMessenger,
|
|
|
|
func(r *MessengerResponse) bool { return len(r.Chats()) > 0 },
|
|
|
|
"chat invitation not received",
|
|
|
|
)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().Len(response.Chats(), 1)
|
|
|
|
s.Require().Len(response.ActivityCenterNotifications(), 1)
|
|
|
|
s.Require().False(response.Chats()[0].Active)
|
|
|
|
|
|
|
|
_, err = theirMessenger.ConfirmJoiningGroup(context.Background(), ourChat.ID)
|
|
|
|
s.NoError(err)
|
|
|
|
|
|
|
|
// Wait for the message to reach its destination
|
|
|
|
_, err = WaitOnMessengerResponse(
|
|
|
|
s.m,
|
|
|
|
func(r *MessengerResponse) bool { return len(r.Chats()) > 0 },
|
|
|
|
"no joining group event received",
|
|
|
|
)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
inputMessage := buildTestMessage(*ourChat)
|
|
|
|
|
|
|
|
sendResponse, err := theirMessenger.SendChatMessage(context.Background(), inputMessage)
|
|
|
|
s.NoError(err)
|
|
|
|
s.Require().Len(sendResponse.Messages(), 1)
|
|
|
|
|
|
|
|
sentMessage := sendResponse.Messages()[0]
|
|
|
|
|
|
|
|
_, err = WaitOnMessengerResponse(
|
|
|
|
s.m,
|
|
|
|
func(r *MessengerResponse) bool { return len(r.Messages()) > 0 },
|
|
|
|
"no messages",
|
|
|
|
)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
// Edit message
|
|
|
|
|
|
|
|
messageID, err := types.DecodeHex(sentMessage.ID)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
editedText := "edited text"
|
|
|
|
editedMessage := &requests.EditMessage{
|
|
|
|
ID: messageID,
|
|
|
|
Text: editedText,
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err = theirMessenger.EditMessage(context.Background(), editedMessage)
|
|
|
|
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
response, err = WaitOnMessengerResponse(
|
|
|
|
s.m,
|
|
|
|
func(r *MessengerResponse) bool { return len(r.messages) > 0 },
|
|
|
|
"no messages",
|
|
|
|
)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().Len(response.Chats(), 1)
|
|
|
|
s.Require().Len(response.Messages(), 1)
|
|
|
|
s.Require().NotEmpty(response.Messages()[0].EditedAt)
|
|
|
|
s.Require().False(response.Messages()[0].New)
|
|
|
|
}
|
2023-04-27 14:22:26 +00:00
|
|
|
|
|
|
|
func (s *MessengerEditMessageSuite) TestEditMessageWithMention() {
|
|
|
|
theirMessenger := s.newMessenger()
|
2023-11-27 17:01:13 +00:00
|
|
|
defer TearDownMessenger(&s.Suite, theirMessenger)
|
2023-04-27 14:22:26 +00:00
|
|
|
|
|
|
|
theirChat := CreateOneToOneChat("Their 1TO1", &s.privateKey.PublicKey, s.m.transport)
|
2024-02-26 09:12:37 +00:00
|
|
|
err := theirMessenger.SaveChat(theirChat)
|
2023-04-27 14:22:26 +00:00
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
ourChat := CreateOneToOneChat("Our 1TO1", &theirMessenger.identity.PublicKey, s.m.transport)
|
|
|
|
err = s.m.SaveChat(ourChat)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
inputMessage := buildTestMessage(*theirChat)
|
|
|
|
// Send first message with no mention
|
|
|
|
sendResponse, err := theirMessenger.SendChatMessage(context.Background(), inputMessage)
|
|
|
|
s.NoError(err)
|
|
|
|
s.Require().Len(sendResponse.Messages(), 1)
|
|
|
|
|
|
|
|
response, err := WaitOnMessengerResponse(
|
|
|
|
s.m,
|
|
|
|
func(r *MessengerResponse) bool { return len(r.messages) == 1 },
|
|
|
|
"no messages",
|
|
|
|
)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().Len(response.Chats(), 1)
|
|
|
|
s.Require().Len(response.Messages(), 1)
|
2023-09-25 15:29:36 +00:00
|
|
|
// Make sure the message is not marked as Mentioned (chat still counts it because it's 1-1)
|
2023-04-27 14:22:26 +00:00
|
|
|
s.Require().False(response.Messages()[0].Mentioned)
|
2023-09-25 15:29:36 +00:00
|
|
|
s.Require().Equal(int(response.Chats()[0].UnviewedMessagesCount), 1)
|
|
|
|
s.Require().Equal(int(response.Chats()[0].UnviewedMentionsCount), 1)
|
2023-04-27 14:22:26 +00:00
|
|
|
|
|
|
|
ogMessage := sendResponse.Messages()[0]
|
|
|
|
|
|
|
|
messageID, err := types.DecodeHex(ogMessage.ID)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
// Edit the message and add a mention
|
|
|
|
editedText := "edited text @" + common.PubkeyToHex(&s.privateKey.PublicKey)
|
|
|
|
editedMessage := &requests.EditMessage{
|
|
|
|
ID: messageID,
|
|
|
|
Text: editedText,
|
|
|
|
}
|
|
|
|
|
|
|
|
sendResponse, err = theirMessenger.EditMessage(context.Background(), editedMessage)
|
|
|
|
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().Len(sendResponse.Messages(), 1)
|
|
|
|
s.Require().NotEmpty(sendResponse.Messages()[0].EditedAt)
|
|
|
|
s.Require().Equal(sendResponse.Messages()[0].Text, editedText)
|
|
|
|
s.Require().Len(sendResponse.Chats(), 1)
|
|
|
|
s.Require().NotNil(sendResponse.Chats()[0].LastMessage)
|
|
|
|
s.Require().NotEmpty(sendResponse.Chats()[0].LastMessage.EditedAt)
|
|
|
|
s.Require().False(sendResponse.Messages()[0].Mentioned) // Sender is still not mentioned
|
|
|
|
|
|
|
|
response, err = WaitOnMessengerResponse(
|
|
|
|
s.m,
|
|
|
|
func(r *MessengerResponse) bool { return len(r.messages) == 1 },
|
|
|
|
"no messages",
|
|
|
|
)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
s.Require().Len(response.Chats(), 1)
|
|
|
|
s.Require().Len(response.Messages(), 1)
|
|
|
|
s.Require().NotEmpty(response.Messages()[0].EditedAt)
|
|
|
|
s.Require().False(response.Messages()[0].New)
|
|
|
|
// Receiver (us) is now mentioned
|
2023-09-25 15:29:36 +00:00
|
|
|
s.Require().True(response.Messages()[0].Mentioned)
|
2023-04-27 14:22:26 +00:00
|
|
|
s.Require().Equal(int(response.Chats()[0].UnviewedMessagesCount), 1)
|
|
|
|
s.Require().Equal(int(response.Chats()[0].UnviewedMentionsCount), 1)
|
|
|
|
|
|
|
|
// Edit the message again but remove the mention
|
|
|
|
editedText = "edited text no mention"
|
|
|
|
editedMessage = &requests.EditMessage{
|
|
|
|
ID: messageID,
|
|
|
|
Text: editedText,
|
|
|
|
}
|
|
|
|
|
|
|
|
sendResponse, err = theirMessenger.EditMessage(context.Background(), editedMessage)
|
|
|
|
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().Len(sendResponse.Messages(), 1)
|
|
|
|
s.Require().NotEmpty(sendResponse.Messages()[0].EditedAt)
|
|
|
|
s.Require().Equal(sendResponse.Messages()[0].Text, editedText)
|
|
|
|
s.Require().Len(sendResponse.Chats(), 1)
|
|
|
|
s.Require().NotNil(sendResponse.Chats()[0].LastMessage)
|
|
|
|
s.Require().NotEmpty(sendResponse.Chats()[0].LastMessage.EditedAt)
|
|
|
|
s.Require().False(sendResponse.Messages()[0].Mentioned) // Sender is still not mentioned
|
|
|
|
|
|
|
|
response, err = WaitOnMessengerResponse(
|
|
|
|
s.m,
|
|
|
|
func(r *MessengerResponse) bool { return len(r.messages) == 1 },
|
|
|
|
"no messages",
|
|
|
|
)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
s.Require().Len(response.Chats(), 1)
|
|
|
|
s.Require().Len(response.Messages(), 1)
|
|
|
|
s.Require().NotEmpty(response.Messages()[0].EditedAt)
|
|
|
|
s.Require().False(response.Messages()[0].New)
|
|
|
|
// Receiver (us) is no longer mentioned
|
|
|
|
s.Require().False(response.Messages()[0].Mentioned)
|
2023-09-25 15:29:36 +00:00
|
|
|
s.Require().Equal(int(response.Chats()[0].UnviewedMessagesCount), 1) // We still have an unread message though
|
|
|
|
s.Require().Equal(int(response.Chats()[0].UnviewedMentionsCount), 1)
|
2023-04-27 14:22:26 +00:00
|
|
|
}
|
2023-08-31 07:21:25 +00:00
|
|
|
|
|
|
|
func (s *MessengerEditMessageSuite) TestEditMessageWithLinkPreviews() {
|
|
|
|
theirMessenger := s.newMessenger()
|
2023-11-27 17:01:13 +00:00
|
|
|
defer TearDownMessenger(&s.Suite, theirMessenger)
|
2023-08-31 07:21:25 +00:00
|
|
|
|
|
|
|
theirChat := CreateOneToOneChat("Their 1TO1", &s.privateKey.PublicKey, s.m.transport)
|
2024-02-26 09:12:37 +00:00
|
|
|
err := theirMessenger.SaveChat(theirChat)
|
2023-08-31 07:21:25 +00:00
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
ourChat := CreateOneToOneChat("Our 1TO1", &theirMessenger.identity.PublicKey, s.m.transport)
|
|
|
|
err = s.m.SaveChat(ourChat)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
inputMessage := buildTestMessage(*theirChat)
|
|
|
|
|
|
|
|
sendResponse, err := theirMessenger.SendChatMessage(context.Background(), inputMessage)
|
|
|
|
s.NoError(err)
|
|
|
|
s.Require().Len(sendResponse.Messages(), 1)
|
|
|
|
|
|
|
|
response, err := WaitOnMessengerResponse(
|
|
|
|
s.m,
|
|
|
|
func(r *MessengerResponse) bool { return len(r.messages) > 0 },
|
|
|
|
"no messages",
|
|
|
|
)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().Len(response.Chats(), 1)
|
|
|
|
s.Require().Len(response.Messages(), 1)
|
|
|
|
|
|
|
|
ogMessage := sendResponse.Messages()[0]
|
|
|
|
|
|
|
|
messageID, err := types.DecodeHex(ogMessage.ID)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
2023-11-09 16:24:35 +00:00
|
|
|
contactPublicKey, err := crypto.GenerateKey()
|
|
|
|
s.Require().NoError(err)
|
|
|
|
contactID := types.EncodeHex(crypto.FromECDSAPub(&contactPublicKey.PublicKey))
|
|
|
|
|
2023-08-31 07:21:25 +00:00
|
|
|
editedText := "edited text"
|
|
|
|
editedMessage := &requests.EditMessage{
|
|
|
|
ID: messageID,
|
|
|
|
Text: editedText,
|
|
|
|
LinkPreviews: []common.LinkPreview{
|
|
|
|
{
|
|
|
|
Type: protobuf.UnfurledLink_LINK,
|
|
|
|
Description: "GitHub is where people build software.",
|
|
|
|
Hostname: "github.com",
|
|
|
|
Title: "Build software better, together",
|
|
|
|
URL: "https://github.com",
|
|
|
|
Thumbnail: common.LinkPreviewThumbnail{
|
|
|
|
Width: 100,
|
|
|
|
Height: 200,
|
|
|
|
URL: "http://localhost:9999",
|
|
|
|
DataURI: "data:image/png;base64,iVBORw0KGgoAAAANSUg=",
|
|
|
|
}},
|
|
|
|
},
|
2023-10-13 12:25:34 +00:00
|
|
|
StatusLinkPreviews: []common.StatusLinkPreview{
|
|
|
|
{
|
|
|
|
URL: "https://status.app/u/TestUrl",
|
|
|
|
Contact: &common.StatusContactLinkPreview{
|
2023-11-09 16:24:35 +00:00
|
|
|
PublicKey: contactID,
|
2023-10-13 12:25:34 +00:00
|
|
|
DisplayName: "TestDisplayName",
|
|
|
|
Description: "Test description",
|
|
|
|
Icon: common.LinkPreviewThumbnail{
|
|
|
|
Width: 100,
|
|
|
|
Height: 200,
|
|
|
|
DataURI: "data:image/png;base64,iVBORw0KGgoAAAANSUg=",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2023-08-31 07:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
sendResponse, err = theirMessenger.EditMessage(context.Background(), editedMessage)
|
|
|
|
|
|
|
|
s.Require().NoError(err)
|
|
|
|
s.Require().Len(sendResponse.Messages(), 1)
|
2023-10-13 12:25:34 +00:00
|
|
|
s.Require().Len(sendResponse.Messages()[0].LinkPreviews, 1)
|
|
|
|
s.Require().NotNil(sendResponse.Messages()[0].UnfurledStatusLinks)
|
|
|
|
s.Require().Len(sendResponse.Messages()[0].UnfurledStatusLinks.UnfurledStatusLinks, 1)
|
2023-08-31 07:21:25 +00:00
|
|
|
response, err = WaitOnMessengerResponse(
|
|
|
|
s.m,
|
|
|
|
func(r *MessengerResponse) bool { return len(r.messages) == 1 },
|
|
|
|
"no messages",
|
|
|
|
)
|
|
|
|
s.Require().NoError(err)
|
|
|
|
|
|
|
|
s.Require().Len(response.Chats(), 1)
|
|
|
|
s.Require().Len(response.Messages(), 1)
|
2023-10-13 12:25:34 +00:00
|
|
|
|
|
|
|
responseMessage := response.Messages()[0]
|
|
|
|
s.Require().NotEmpty(responseMessage.EditedAt)
|
|
|
|
s.Require().Len(responseMessage.UnfurledLinks, 1)
|
|
|
|
s.Require().NotNil(responseMessage.UnfurledStatusLinks)
|
|
|
|
s.Require().Len(responseMessage.UnfurledStatusLinks.UnfurledStatusLinks, 1)
|
|
|
|
s.Require().False(responseMessage.New)
|
2023-08-31 07:21:25 +00:00
|
|
|
}
|