github.com/status-im/status-go@v1.1.0/protocol/messenger_pin_message_test.go (about) 1 package protocol 2 3 import ( 4 "context" 5 "testing" 6 7 "github.com/stretchr/testify/suite" 8 9 "github.com/status-im/status-go/protocol/common" 10 "github.com/status-im/status-go/protocol/protobuf" 11 ) 12 13 func TestMessengerPinMessageSuite(t *testing.T) { 14 suite.Run(t, new(MessengerPinMessageSuite)) 15 } 16 17 type MessengerPinMessageSuite struct { 18 MessengerBaseTestSuite 19 } 20 21 func (s *MessengerPinMessageSuite) TestPinMessage() { 22 theirMessenger := s.newMessenger() 23 defer TearDownMessenger(&s.Suite, theirMessenger) 24 25 theirChat := CreateOneToOneChat("Their 1TO1", &s.privateKey.PublicKey, s.m.transport) 26 err := theirMessenger.SaveChat(theirChat) 27 s.Require().NoError(err) 28 29 ourChat := CreateOneToOneChat("Our 1TO1", &theirMessenger.identity.PublicKey, s.m.transport) 30 err = s.m.SaveChat(ourChat) 31 s.Require().NoError(err) 32 33 inputMessage := buildTestMessage(*theirChat) 34 sendResponse, err := theirMessenger.SendChatMessage(context.Background(), inputMessage) 35 s.NoError(err) 36 s.Require().Len(sendResponse.Messages(), 1) 37 38 response, err := WaitOnMessengerResponse( 39 s.m, 40 func(r *MessengerResponse) bool { return len(r.Messages()) > 0 }, 41 "no messages", 42 ) 43 s.Require().NoError(err) 44 s.Require().Len(response.Chats(), 1) 45 46 pinMessage := common.NewPinMessage() 47 pinMessage.LocalChatID = theirChat.ID 48 pinMessage.MessageId = inputMessage.ID 49 pinMessage.Pinned = true 50 pinMessage.ChatId = theirChat.ID 51 sendResponse, err = theirMessenger.SendPinMessage(context.Background(), pinMessage) 52 s.NoError(err) 53 s.Require().Len(sendResponse.PinMessages(), 1) 54 55 // Wait for the message to reach its destination 56 response, err = WaitOnMessengerResponse( 57 s.m, 58 func(r *MessengerResponse) bool { 59 // we pull as well the original pinned message 60 return len(r.PinMessages()) == 1 && len(r.Messages()) == 2 61 }, 62 "pin message not received", 63 ) 64 s.Require().NoError(err) 65 66 receivedPinMessage := response.PinMessages()[0] 67 s.Require().True(receivedPinMessage.Pinned) 68 s.Require().NotNil(receivedPinMessage.Message) 69 s.Require().Equal(inputMessage.ID, receivedPinMessage.Message.Message.ID) 70 messages := response.Messages() 71 72 var originalMessage *common.Message 73 var notificationMessage *common.Message 74 75 if messages[0].ID == inputMessage.ID { 76 originalMessage = messages[0] 77 notificationMessage = messages[1] 78 } else { 79 originalMessage = messages[1] 80 notificationMessage = messages[0] 81 } 82 83 s.Require().Equal(theirMessenger.myHexIdentity(), notificationMessage.From) 84 s.Require().Equal(inputMessage.ID, notificationMessage.ResponseTo) 85 s.Require().Equal(protobuf.ChatMessage_SYSTEM_MESSAGE_PINNED_MESSAGE, notificationMessage.ContentType) 86 87 s.Require().Equal(inputMessage.ID, originalMessage.ID) 88 } 89 90 func (s *MessengerPinMessageSuite) TestPinMessageOutOfOrder() { 91 theirMessenger := s.newMessenger() 92 defer TearDownMessenger(&s.Suite, theirMessenger) 93 94 theirChat := CreateOneToOneChat("Their 1TO1", &s.privateKey.PublicKey, s.m.transport) 95 err := theirMessenger.SaveChat(theirChat) 96 s.Require().NoError(err) 97 98 ourChat := CreateOneToOneChat("Our 1TO1", &theirMessenger.identity.PublicKey, s.m.transport) 99 err = s.m.SaveChat(ourChat) 100 s.Require().NoError(err) 101 102 inputMessage := buildTestMessage(*theirChat) 103 sendResponse, err := theirMessenger.SendChatMessage(context.Background(), inputMessage) 104 s.NoError(err) 105 s.Require().Len(sendResponse.Messages(), 1) 106 107 response, err := WaitOnMessengerResponse( 108 s.m, 109 func(r *MessengerResponse) bool { return len(r.Messages()) > 0 }, 110 "no messages", 111 ) 112 s.Require().NoError(err) 113 s.Require().Len(response.Chats(), 1) 114 s.Require().Equal(response.Chats()[0].UnviewedMessagesCount, uint(1)) 115 116 // Unpin with higher clock 117 118 unpinMessage := protobuf.PinMessage{ 119 ChatId: theirChat.ID, 120 MessageId: inputMessage.ID, 121 Pinned: false, 122 Clock: 3, 123 MessageType: protobuf.MessageType_ONE_TO_ONE, 124 } 125 126 handlePinMessageResponse := &MessengerResponse{} 127 err = theirMessenger.handlePinMessage( 128 &Contact{ID: s.m.myHexIdentity()}, 129 1000, 130 handlePinMessageResponse, 131 &unpinMessage, 132 false, 133 ) 134 s.Require().NoError(err) 135 136 s.Require().Len(handlePinMessageResponse.PinMessages(), 1) 137 s.Require().False(handlePinMessageResponse.PinMessages()[0].Pinned) 138 s.Require().Len(handlePinMessageResponse.Chats(), 1) 139 s.Require().Equal(handlePinMessageResponse.Chats()[0].UnviewedMessagesCount, uint(0)) 140 141 // Pin with lower clock in response 142 143 pinMessage := protobuf.PinMessage{ 144 ChatId: theirChat.ID, 145 MessageId: inputMessage.ID, 146 Pinned: true, 147 Clock: 2, 148 MessageType: protobuf.MessageType_ONE_TO_ONE, 149 } 150 151 err = theirMessenger.handlePinMessage( 152 &Contact{ID: s.m.myHexIdentity()}, 153 1000, 154 handlePinMessageResponse, 155 &pinMessage, 156 false, 157 ) 158 s.Require().NoError(err) 159 160 s.Require().Len(handlePinMessageResponse.PinMessages(), 1) 161 s.Require().False(handlePinMessageResponse.PinMessages()[0].Pinned) 162 s.Require().Len(handlePinMessageResponse.Chats(), 1) 163 s.Require().Equal(handlePinMessageResponse.Chats()[0].UnviewedMessagesCount, uint(0)) 164 165 // Pin with lower clock not in response 166 167 handlePinMessageResponse = &MessengerResponse{} 168 pinMessage = protobuf.PinMessage{ 169 ChatId: theirChat.ID, 170 MessageId: inputMessage.ID, 171 Pinned: true, 172 Clock: 1, 173 MessageType: protobuf.MessageType_ONE_TO_ONE, 174 } 175 176 err = theirMessenger.handlePinMessage( 177 &Contact{ID: s.m.myHexIdentity()}, 178 1000, 179 handlePinMessageResponse, 180 &pinMessage, 181 false, 182 ) 183 s.Require().NoError(err) 184 185 s.Require().Len(handlePinMessageResponse.PinMessages(), 0) 186 }