github.com/status-im/status-go@v1.1.0/protocol/persistence_test.go (about) 1 package protocol 2 3 import ( 4 "bytes" 5 "database/sql" 6 "fmt" 7 "math" 8 "sort" 9 "strconv" 10 "strings" 11 "testing" 12 "time" 13 14 "github.com/stretchr/testify/require" 15 16 "github.com/status-im/status-go/appdatabase" 17 "github.com/status-im/status-go/eth-node/crypto" 18 "github.com/status-im/status-go/eth-node/types" 19 "github.com/status-im/status-go/protocol/common" 20 "github.com/status-im/status-go/protocol/protobuf" 21 "github.com/status-im/status-go/protocol/sqlite" 22 "github.com/status-im/status-go/t/helpers" 23 ) 24 25 func TestTableUserMessagesAllFieldsCount(t *testing.T) { 26 db := sqlitePersistence{} 27 expected := len(strings.Split(db.tableUserMessagesAllFields(), ",")) 28 require.Equal(t, expected, db.tableUserMessagesAllFieldsCount()) 29 } 30 31 func TestSaveMessages(t *testing.T) { 32 db, err := openTestDB() 33 require.NoError(t, err) 34 p := newSQLitePersistence(db) 35 36 for i := 0; i < 10; i++ { 37 id := strconv.Itoa(i) 38 err := insertMinimalMessage(p, id) 39 require.NoError(t, err) 40 41 m, err := p.MessageByID(id) 42 require.NoError(t, err) 43 require.EqualValues(t, id, m.ID) 44 } 45 } 46 47 func TestMessagesByIDs(t *testing.T) { 48 db, err := openTestDB() 49 require.NoError(t, err) 50 p := newSQLitePersistence(db) 51 52 var ids []string 53 for i := 0; i < 10; i++ { 54 id := strconv.Itoa(i) 55 err := insertMinimalMessage(p, id) 56 require.NoError(t, err) 57 ids = append(ids, id) 58 59 } 60 m, err := p.MessagesByIDs(ids) 61 require.NoError(t, err) 62 require.Len(t, m, 10) 63 } 64 65 func TestMessagesByIDs_WithDiscordMessagesPayload(t *testing.T) { 66 db, err := openTestDB() 67 require.NoError(t, err) 68 p := newSQLitePersistence(db) 69 70 var ids []string 71 for i := 0; i < 10; i++ { 72 id := strconv.Itoa(i) 73 err := insertMinimalMessage(p, id) 74 require.NoError(t, err) 75 err = insertMinimalDiscordMessage(p, id, id) 76 require.NoError(t, err) 77 ids = append(ids, id) 78 } 79 80 m, err := p.MessagesByIDs(ids) 81 require.NoError(t, err) 82 require.Len(t, m, 10) 83 84 for _, _m := range m { 85 require.NotNil(t, _m.GetDiscordMessage()) 86 } 87 } 88 89 func TestMessageByID(t *testing.T) { 90 db, err := openTestDB() 91 require.NoError(t, err) 92 p := newSQLitePersistence(db) 93 id := "1" 94 95 err = insertMinimalMessage(p, id) 96 require.NoError(t, err) 97 98 m, err := p.MessageByID(id) 99 require.NoError(t, err) 100 require.EqualValues(t, id, m.ID) 101 } 102 103 func TestMessageByID_WithDiscordMessagePayload(t *testing.T) { 104 105 db, err := openTestDB() 106 require.NoError(t, err) 107 p := newSQLitePersistence(db) 108 id := "1" 109 discordMessageID := "2" 110 111 err = insertMinimalDiscordMessage(p, id, discordMessageID) 112 require.NoError(t, err) 113 114 m, err := p.MessageByID(id) 115 require.NoError(t, err) 116 require.EqualValues(t, id, m.ID) 117 require.NotNil(t, m.GetDiscordMessage()) 118 require.EqualValues(t, discordMessageID, m.GetDiscordMessage().Id) 119 require.EqualValues(t, "2", m.GetDiscordMessage().Author.Id) 120 } 121 122 func TestMessageByID_WithDiscordMessageAttachmentPayload(t *testing.T) { 123 124 db, err := openTestDB() 125 require.NoError(t, err) 126 p := newSQLitePersistence(db) 127 id := "1" 128 discordMessageID := "2" 129 130 err = insertDiscordMessageWithAttachments(p, id, discordMessageID) 131 require.NoError(t, err) 132 133 m, err := p.MessageByID(id) 134 require.NoError(t, err) 135 require.EqualValues(t, id, m.ID) 136 137 dm := m.GetDiscordMessage() 138 require.NotNil(t, dm) 139 require.EqualValues(t, discordMessageID, dm.Id) 140 141 require.NotNil(t, dm.Attachments) 142 require.Len(t, dm.Attachments, 2) 143 } 144 145 func TestMessagesExist(t *testing.T) { 146 db, err := openTestDB() 147 require.NoError(t, err) 148 p := newSQLitePersistence(db) 149 150 err = insertMinimalMessage(p, "1") 151 require.NoError(t, err) 152 153 result, err := p.MessagesExist([]string{"1"}) 154 require.NoError(t, err) 155 156 require.True(t, result["1"]) 157 158 err = insertMinimalMessage(p, "2") 159 require.NoError(t, err) 160 161 result, err = p.MessagesExist([]string{"1", "2", "3"}) 162 require.NoError(t, err) 163 164 require.True(t, result["1"]) 165 require.True(t, result["2"]) 166 require.False(t, result["3"]) 167 } 168 169 func TestMessageByChatID(t *testing.T) { 170 db, err := openTestDB() 171 require.NoError(t, err) 172 p := newSQLitePersistence(db) 173 chatID := testPublicChatID 174 count := 1000 175 pageSize := 50 176 177 var messages []*common.Message 178 for i := 0; i < count; i++ { 179 messages = append(messages, &common.Message{ 180 ID: strconv.Itoa(i), 181 LocalChatID: chatID, 182 ChatMessage: &protobuf.ChatMessage{ 183 Clock: uint64(i), 184 }, 185 From: testPK, 186 }) 187 188 // Add some other chats. 189 if count%5 == 0 { 190 messages = append(messages, &common.Message{ 191 ID: strconv.Itoa(count + i), 192 LocalChatID: "other-chat", 193 ChatMessage: &protobuf.ChatMessage{ 194 Clock: uint64(i), 195 }, 196 197 From: testPK, 198 }) 199 } 200 } 201 202 // Add some out-of-order message. Add more than page size. 203 outOfOrderCount := pageSize + 1 204 allCount := count + outOfOrderCount 205 for i := 0; i < pageSize+1; i++ { 206 messages = append(messages, &common.Message{ 207 ID: strconv.Itoa(count*2 + i), 208 LocalChatID: chatID, 209 ChatMessage: &protobuf.ChatMessage{ 210 Clock: uint64(i), 211 }, 212 213 From: testPK, 214 }) 215 } 216 217 err = p.SaveMessages(messages) 218 require.NoError(t, err) 219 220 var ( 221 result []*common.Message 222 cursor string 223 iter int 224 ) 225 for { 226 var ( 227 items []*common.Message 228 err error 229 ) 230 231 items, cursor, err = p.MessageByChatID(chatID, cursor, pageSize) 232 require.NoError(t, err) 233 result = append(result, items...) 234 235 iter++ 236 if len(cursor) == 0 || iter > count { 237 break 238 } 239 } 240 require.Equal(t, "", cursor) // for loop should exit because of cursor being empty 241 require.EqualValues(t, math.Ceil(float64(allCount)/float64(pageSize)), iter) 242 require.Equal(t, len(result), allCount) 243 require.True( 244 t, 245 // Verify descending order. 246 sort.SliceIsSorted(result, func(i, j int) bool { 247 return result[i].Clock > result[j].Clock 248 }), 249 ) 250 } 251 252 func TestFirstUnseenMessageIDByChatID(t *testing.T) { 253 db, err := openTestDB() 254 require.NoError(t, err) 255 p := newSQLitePersistence(db) 256 257 messageID, err := p.FirstUnseenMessageID(testPublicChatID) 258 require.NoError(t, err) 259 require.Equal(t, "", messageID) 260 261 err = p.SaveMessages([]*common.Message{ 262 { 263 ID: "1", 264 LocalChatID: testPublicChatID, 265 ChatMessage: &protobuf.ChatMessage{ 266 Clock: 1, 267 Text: "some-text"}, 268 From: testPK, 269 Seen: true, 270 }, 271 { 272 ID: "2", 273 LocalChatID: testPublicChatID, 274 ChatMessage: &protobuf.ChatMessage{ 275 Clock: 2, 276 Text: "some-text"}, 277 From: testPK, 278 Seen: false, 279 }, 280 { 281 ID: "3", 282 LocalChatID: testPublicChatID, 283 ChatMessage: &protobuf.ChatMessage{ 284 Clock: 3, 285 Text: "some-text"}, 286 From: testPK, 287 Seen: false, 288 }, 289 }) 290 require.NoError(t, err) 291 292 messageID, err = p.FirstUnseenMessageID(testPublicChatID) 293 require.NoError(t, err) 294 require.Equal(t, "2", messageID) 295 } 296 297 func TestLatestMessageByChatID(t *testing.T) { 298 db, err := openTestDB() 299 require.NoError(t, err) 300 p := newSQLitePersistence(db) 301 302 var ids []string 303 for i := 0; i < 10; i++ { 304 id := strconv.Itoa(i) 305 err := insertMinimalMessage(p, id) 306 require.NoError(t, err) 307 ids = append(ids, id) 308 } 309 310 id := strconv.Itoa(10) 311 err = insertMinimalDeletedMessage(p, id) 312 require.NoError(t, err) 313 ids = append(ids, id) 314 315 id = strconv.Itoa(11) 316 err = insertMinimalDeletedForMeMessage(p, id) 317 require.NoError(t, err) 318 ids = append(ids, id) 319 320 m, err := p.LatestMessageByChatID(testPublicChatID) 321 require.NoError(t, err) 322 require.Equal(t, m[0].ID, ids[9]) 323 } 324 325 func TestOldestMessageWhisperTimestampByChatID(t *testing.T) { 326 db, err := openTestDB() 327 require.NoError(t, err) 328 p := newSQLitePersistence(db) 329 chatID := testPublicChatID 330 331 _, hasMessage, err := p.OldestMessageWhisperTimestampByChatID(chatID) 332 require.NoError(t, err) 333 require.False(t, hasMessage) 334 335 var messages []*common.Message 336 for i := 0; i < 10; i++ { 337 messages = append(messages, &common.Message{ 338 ID: strconv.Itoa(i), 339 LocalChatID: chatID, 340 ChatMessage: &protobuf.ChatMessage{ 341 Clock: uint64(i), 342 }, 343 WhisperTimestamp: uint64(i + 10), 344 From: testPK, 345 }) 346 } 347 348 err = p.SaveMessages(messages) 349 require.NoError(t, err) 350 351 timestamp, hasMessage, err := p.OldestMessageWhisperTimestampByChatID(chatID) 352 require.NoError(t, err) 353 require.True(t, hasMessage) 354 require.Equal(t, uint64(10), timestamp) 355 } 356 357 func TestPinMessageByChatID(t *testing.T) { 358 db, err := openTestDB() 359 require.NoError(t, err) 360 p := sqlitePersistence{db: db} 361 chatID := "chat-with-pinned-messages" 362 messagesCount := 1000 363 pageSize := 5 364 pinnedMessagesCount := 0 365 366 var messages []*common.Message 367 var pinMessages []*common.PinMessage 368 for i := 0; i < messagesCount; i++ { 369 messages = append(messages, &common.Message{ 370 ID: strconv.Itoa(i), 371 LocalChatID: chatID, 372 ChatMessage: &protobuf.ChatMessage{ 373 Clock: uint64(i), 374 }, 375 From: testPK, 376 }) 377 378 // Pin this message 379 if i%100 == 0 { 380 from := testPK 381 if i == 100 { 382 from = "them" 383 } 384 385 pinMessage := common.NewPinMessage() 386 pinMessage.ID = strconv.Itoa(i) 387 pinMessage.LocalChatID = chatID 388 pinMessage.From = from 389 390 pinMessage.MessageId = strconv.Itoa(i) 391 pinMessage.Clock = 111 392 pinMessage.Pinned = true 393 pinMessages = append(pinMessages, pinMessage) 394 pinnedMessagesCount++ 395 396 if i%200 == 0 { 397 // unpin a message 398 unpinMessage := common.NewPinMessage() 399 400 unpinMessage.ID = strconv.Itoa(i) 401 unpinMessage.LocalChatID = chatID 402 unpinMessage.From = testPK 403 404 pinMessage.MessageId = strconv.Itoa(i) 405 unpinMessage.Clock = 333 406 unpinMessage.Pinned = false 407 pinMessages = append(pinMessages, unpinMessage) 408 pinnedMessagesCount-- 409 410 // pinned before the unpin 411 pinMessage2 := common.NewPinMessage() 412 pinMessage2.ID = strconv.Itoa(i) 413 pinMessage2.LocalChatID = chatID 414 pinMessage2.From = testPK 415 416 pinMessage2.MessageId = strconv.Itoa(i) 417 pinMessage2.Clock = 222 418 pinMessage2.Pinned = true 419 pinMessages = append(pinMessages, pinMessage2) 420 } 421 } 422 423 // Add some other chats. 424 if i%5 == 0 { 425 messages = append(messages, &common.Message{ 426 ID: strconv.Itoa(messagesCount + i), 427 LocalChatID: "chat-without-pinned-messages", 428 ChatMessage: &protobuf.ChatMessage{ 429 Clock: uint64(i), 430 }, 431 432 From: testPK, 433 }) 434 } 435 } 436 437 err = p.SaveMessages(messages) 438 require.NoError(t, err) 439 440 err = p.SavePinMessages(pinMessages) 441 require.NoError(t, err) 442 443 var ( 444 result []*common.PinnedMessage 445 cursor string 446 iter int 447 ) 448 for { 449 var ( 450 items []*common.PinnedMessage 451 err error 452 ) 453 454 items, cursor, err = p.PinnedMessageByChatID(chatID, cursor, pageSize) 455 require.NoError(t, err) 456 result = append(result, items...) 457 458 iter++ 459 if len(cursor) == 0 || iter > messagesCount { 460 break 461 } 462 } 463 464 require.Equal(t, "", cursor) // for loop should exit because of cursor being empty 465 require.EqualValues(t, pinnedMessagesCount, len(result)) 466 require.EqualValues(t, math.Ceil(float64(pinnedMessagesCount)/float64(pageSize)), iter) 467 require.True( 468 t, 469 // Verify descending order. 470 sort.SliceIsSorted(result, func(i, j int) bool { 471 return result[i].Message.Clock > result[j].Message.Clock 472 }), 473 ) 474 475 require.Equal(t, "them", result[len(result)-1].PinnedBy) 476 for i := 0; i < len(result)-1; i++ { 477 require.Equal(t, testPK, result[i].PinnedBy) 478 } 479 } 480 481 func TestMessageReplies(t *testing.T) { 482 db, err := openTestDB() 483 require.NoError(t, err) 484 p := newSQLitePersistence(db) 485 chatID := testPublicChatID 486 message1 := &common.Message{ 487 ID: "id-1", 488 LocalChatID: chatID, 489 ChatMessage: &protobuf.ChatMessage{ 490 Text: "content-1", 491 Clock: uint64(1), 492 }, 493 From: "1", 494 } 495 message2 := &common.Message{ 496 ID: "id-2", 497 LocalChatID: chatID, 498 ChatMessage: &protobuf.ChatMessage{ 499 Text: "content-2", 500 Clock: uint64(2), 501 ResponseTo: "id-1", 502 }, 503 504 From: "2", 505 } 506 507 message3 := &common.Message{ 508 ID: "id-3", 509 LocalChatID: chatID, 510 ChatMessage: &protobuf.ChatMessage{ 511 Text: "content-3", 512 Clock: uint64(3), 513 ResponseTo: "non-existing", 514 }, 515 From: "3", 516 } 517 518 // Message that is deleted 519 message4 := &common.Message{ 520 ID: "id-4", 521 LocalChatID: chatID, 522 Deleted: true, 523 ChatMessage: &protobuf.ChatMessage{ 524 Text: "content-4", 525 Clock: uint64(4), 526 }, 527 From: "2", 528 } 529 530 // Message replied to a deleted message. It will not have QuotedMessage info 531 message5 := &common.Message{ 532 ID: "id-5", 533 LocalChatID: chatID, 534 ChatMessage: &protobuf.ChatMessage{ 535 Text: "content-4", 536 Clock: uint64(5), 537 ResponseTo: "id-4", 538 }, 539 From: "3", 540 } 541 542 // messages := []*common.Message{message1, message2, message3} 543 messages := []*common.Message{message1, message2, message3, message4, message5} 544 545 err = p.SaveMessages(messages) 546 require.NoError(t, err) 547 548 retrievedMessages, _, err := p.MessageByChatID(chatID, "", 10) 549 require.NoError(t, err) 550 551 require.Equal(t, "non-existing", retrievedMessages[2].ResponseTo) 552 require.Nil(t, retrievedMessages[2].QuotedMessage) 553 554 require.Equal(t, "id-1", retrievedMessages[3].ResponseTo) 555 require.Equal(t, &common.QuotedMessage{ID: "id-1", From: "1", Text: "content-1"}, retrievedMessages[3].QuotedMessage) 556 557 require.Equal(t, "", retrievedMessages[4].ResponseTo) 558 require.Nil(t, retrievedMessages[4].QuotedMessage) 559 560 // We have a ResponseTo, but no QuotedMessage only gives the ID, From, and Deleted 561 require.Equal(t, "id-4", retrievedMessages[0].ResponseTo) 562 require.Equal(t, &common.QuotedMessage{ID: "id-4", Deleted: true, From: "2"}, retrievedMessages[0].QuotedMessage) 563 } 564 565 func TestMessageByChatIDWithTheSameClocks(t *testing.T) { 566 db, err := openTestDB() 567 require.NoError(t, err) 568 p := newSQLitePersistence(db) 569 chatID := testPublicChatID 570 clockValues := []uint64{10, 10, 9, 9, 9, 11, 12, 11, 100000, 6, 4, 5, 5, 5, 5} 571 count := len(clockValues) 572 pageSize := 2 573 574 var messages []*common.Message 575 576 for i, clock := range clockValues { 577 messages = append(messages, &common.Message{ 578 ID: strconv.Itoa(i), 579 LocalChatID: chatID, 580 ChatMessage: &protobuf.ChatMessage{ 581 Clock: clock, 582 }, 583 From: testPK, 584 }) 585 } 586 587 err = p.SaveMessages(messages) 588 require.NoError(t, err) 589 590 var ( 591 result []*common.Message 592 cursor string 593 iter int 594 ) 595 for { 596 var ( 597 items []*common.Message 598 err error 599 ) 600 601 items, cursor, err = p.MessageByChatID(chatID, cursor, pageSize) 602 require.NoError(t, err) 603 result = append(result, items...) 604 605 iter++ 606 if cursor == "" || iter > count { 607 break 608 } 609 } 610 require.Empty(t, cursor) // for loop should exit because of cursor being empty 611 require.Len(t, result, count) 612 // Verify the order. 613 expectedClocks := make([]uint64, len(clockValues)) 614 copy(expectedClocks, clockValues) 615 sort.Slice(expectedClocks, func(i, j int) bool { 616 return expectedClocks[i] > expectedClocks[j] 617 }) 618 resultClocks := make([]uint64, 0, len(clockValues)) 619 for _, m := range result { 620 resultClocks = append(resultClocks, m.Clock) 621 } 622 require.EqualValues(t, expectedClocks, resultClocks) 623 } 624 625 func TestDeleteMessageByID(t *testing.T) { 626 db, err := openTestDB() 627 require.NoError(t, err) 628 p := newSQLitePersistence(db) 629 id := "1" 630 631 err = insertMinimalMessage(p, id) 632 require.NoError(t, err) 633 634 m, err := p.MessageByID(id) 635 require.NoError(t, err) 636 require.Equal(t, id, m.ID) 637 638 err = p.DeleteMessage(m.ID) 639 require.NoError(t, err) 640 641 _, err = p.MessageByID(id) 642 require.EqualError(t, err, "record not found") 643 } 644 645 func TestDeleteMessagesByChatID(t *testing.T) { 646 db, err := openTestDB() 647 require.NoError(t, err) 648 p := newSQLitePersistence(db) 649 650 err = insertMinimalMessage(p, "1") 651 require.NoError(t, err) 652 653 err = insertMinimalMessage(p, "2") 654 require.NoError(t, err) 655 656 m, _, err := p.MessageByChatID(testPublicChatID, "", 10) 657 require.NoError(t, err) 658 require.Equal(t, 2, len(m)) 659 660 err = p.DeleteMessagesByChatID(testPublicChatID) 661 require.NoError(t, err) 662 663 m, _, err = p.MessageByChatID(testPublicChatID, "", 10) 664 require.NoError(t, err) 665 require.Equal(t, 0, len(m)) 666 667 } 668 669 func TestMarkMessageSeen(t *testing.T) { 670 chatID := "test-chat" 671 db, err := openTestDB() 672 require.NoError(t, err) 673 p := newSQLitePersistence(db) 674 id := "1" 675 676 err = insertMinimalMessage(p, id) 677 require.NoError(t, err) 678 679 m, err := p.MessageByID(id) 680 require.NoError(t, err) 681 require.False(t, m.Seen) 682 683 count, countWithMention, err := p.MarkMessagesSeen(chatID, []string{m.ID}) 684 require.NoError(t, err) 685 require.Equal(t, uint64(1), count) 686 require.Equal(t, uint64(0), countWithMention) 687 688 m, err = p.MessageByID(id) 689 require.NoError(t, err) 690 require.True(t, m.Seen) 691 } 692 693 func TestUpdateMessageOutgoingStatus(t *testing.T) { 694 db, err := openTestDB() 695 require.NoError(t, err) 696 p := newSQLitePersistence(db) 697 id := "1" 698 699 err = insertMinimalMessage(p, id) 700 require.NoError(t, err) 701 702 err = p.UpdateMessageOutgoingStatus(id, "new-status") 703 require.NoError(t, err) 704 705 m, err := p.MessageByID(id) 706 require.NoError(t, err) 707 require.Equal(t, "new-status", m.OutgoingStatus) 708 } 709 710 func TestMessagesIDsByType(t *testing.T) { 711 db, err := openTestDB() 712 require.NoError(t, err) 713 p := newSQLitePersistence(db) 714 715 ids, err := p.RawMessagesIDsByType(protobuf.ApplicationMetadataMessage_CHAT_MESSAGE) 716 require.NoError(t, err) 717 require.Empty(t, ids) 718 719 err = p.SaveRawMessage(minimalRawMessage("chat-message-id", protobuf.ApplicationMetadataMessage_CHAT_MESSAGE)) 720 require.NoError(t, err) 721 ids, err = p.RawMessagesIDsByType(protobuf.ApplicationMetadataMessage_CHAT_MESSAGE) 722 require.NoError(t, err) 723 require.Equal(t, 1, len(ids)) 724 require.Equal(t, "chat-message-id", ids[0]) 725 726 ids, err = p.RawMessagesIDsByType(protobuf.ApplicationMetadataMessage_EMOJI_REACTION) 727 require.NoError(t, err) 728 require.Empty(t, ids) 729 730 err = p.SaveRawMessage(minimalRawMessage("emoji-message-id", protobuf.ApplicationMetadataMessage_EMOJI_REACTION)) 731 require.NoError(t, err) 732 ids, err = p.RawMessagesIDsByType(protobuf.ApplicationMetadataMessage_EMOJI_REACTION) 733 require.NoError(t, err) 734 require.Equal(t, 1, len(ids)) 735 require.Equal(t, "emoji-message-id", ids[0]) 736 } 737 738 func TestExpiredMessagesIDs(t *testing.T) { 739 messageResendMaxCount := 30 740 db, err := openTestDB() 741 require.NoError(t, err) 742 p := newSQLitePersistence(db) 743 744 ids, err := p.ExpiredMessagesIDs(messageResendMaxCount) 745 require.NoError(t, err) 746 require.Empty(t, ids) 747 748 //save expired emoji message 749 rawEmojiReaction := minimalRawMessage("emoji-message-id", protobuf.ApplicationMetadataMessage_EMOJI_REACTION) 750 rawEmojiReaction.Sent = false 751 err = p.SaveRawMessage(rawEmojiReaction) 752 require.NoError(t, err) 753 754 //make sure it appered in expired emoji reactions list 755 ids, err = p.ExpiredMessagesIDs(messageResendMaxCount) 756 require.NoError(t, err) 757 require.Equal(t, 1, len(ids)) 758 759 //save non-expired emoji reaction 760 rawEmojiReaction2 := minimalRawMessage("emoji-message-id2", protobuf.ApplicationMetadataMessage_EMOJI_REACTION) 761 rawEmojiReaction2.Sent = true 762 err = p.SaveRawMessage(rawEmojiReaction2) 763 require.NoError(t, err) 764 765 //make sure it didn't appear in expired emoji reactions list 766 ids, err = p.ExpiredMessagesIDs(messageResendMaxCount) 767 require.NoError(t, err) 768 require.Equal(t, 1, len(ids)) 769 } 770 771 func TestDontOverwriteSentStatus(t *testing.T) { 772 db, err := openTestDB() 773 require.NoError(t, err) 774 p := newSQLitePersistence(db) 775 776 //save rawMessage 777 rawMessage := minimalRawMessage("chat-message-id", protobuf.ApplicationMetadataMessage_CHAT_MESSAGE) 778 rawMessage.Sent = true 779 err = p.SaveRawMessage(rawMessage) 780 require.NoError(t, err) 781 782 rawMessage.Sent = false 783 err = p.SaveRawMessage(rawMessage) 784 require.NoError(t, err) 785 786 m, err := p.RawMessageByID(rawMessage.ID) 787 require.NoError(t, err) 788 789 require.True(t, m.Sent) 790 } 791 792 func TestPersistenceEmojiReactions(t *testing.T) { 793 db, err := openTestDB() 794 require.NoError(t, err) 795 p := newSQLitePersistence(db) 796 // reverse order as we use DESC 797 id1 := "1" 798 id2 := "2" 799 id3 := "3" 800 801 from1 := "from-1" 802 from2 := "from-2" 803 from3 := "from-3" 804 805 chatID := testPublicChatID 806 807 err = insertMinimalMessage(p, id1) 808 require.NoError(t, err) 809 810 err = insertMinimalMessage(p, id2) 811 require.NoError(t, err) 812 813 err = insertMinimalMessage(p, id3) 814 require.NoError(t, err) 815 816 // Insert normal emoji reaction 817 require.NoError(t, p.SaveEmojiReaction(&EmojiReaction{ 818 EmojiReaction: &protobuf.EmojiReaction{ 819 Clock: 1, 820 MessageId: id3, 821 ChatId: chatID, 822 Type: protobuf.EmojiReaction_SAD, 823 }, 824 LocalChatID: chatID, 825 From: from1, 826 })) 827 828 // Insert retracted emoji reaction 829 require.NoError(t, p.SaveEmojiReaction(&EmojiReaction{ 830 EmojiReaction: &protobuf.EmojiReaction{ 831 Clock: 1, 832 MessageId: id3, 833 ChatId: chatID, 834 Type: protobuf.EmojiReaction_SAD, 835 Retracted: true, 836 }, 837 LocalChatID: chatID, 838 From: from2, 839 })) 840 841 // Insert retracted emoji reaction out of pagination 842 require.NoError(t, p.SaveEmojiReaction(&EmojiReaction{ 843 EmojiReaction: &protobuf.EmojiReaction{ 844 Clock: 1, 845 MessageId: id1, 846 ChatId: chatID, 847 Type: protobuf.EmojiReaction_SAD, 848 }, 849 LocalChatID: chatID, 850 From: from2, 851 })) 852 853 // Insert retracted emoji reaction out of pagination 854 require.NoError(t, p.SaveEmojiReaction(&EmojiReaction{ 855 EmojiReaction: &protobuf.EmojiReaction{ 856 Clock: 1, 857 MessageId: id1, 858 ChatId: chatID, 859 Type: protobuf.EmojiReaction_SAD, 860 }, 861 LocalChatID: chatID, 862 From: from3, 863 })) 864 865 // Wrong local chat id 866 require.NoError(t, p.SaveEmojiReaction(&EmojiReaction{ 867 EmojiReaction: &protobuf.EmojiReaction{ 868 Clock: 1, 869 MessageId: id1, 870 ChatId: chatID, 871 Type: protobuf.EmojiReaction_LOVE, 872 }, 873 LocalChatID: "wrong-chat-id", 874 From: from3, 875 })) 876 877 reactions, err := p.EmojiReactionsByChatID(chatID, "", 1) 878 require.NoError(t, err) 879 require.Len(t, reactions, 1) 880 require.Equal(t, id3, reactions[0].MessageId) 881 882 // Try with a cursor 883 _, cursor, err := p.MessageByChatID(chatID, "", 1) 884 require.NoError(t, err) 885 886 reactions, err = p.EmojiReactionsByChatID(chatID, cursor, 2) 887 require.NoError(t, err) 888 require.Len(t, reactions, 2) 889 require.Equal(t, id1, reactions[0].MessageId) 890 require.Equal(t, id1, reactions[1].MessageId) 891 } 892 893 func openTestDB() (*sql.DB, error) { 894 db, err := helpers.SetupTestMemorySQLDB(appdatabase.DbInitializer{}) 895 if err != nil { 896 return nil, err 897 } 898 899 return db, sqlite.Migrate(db) 900 } 901 902 func insertMinimalMessage(p *sqlitePersistence, id string) error { 903 return p.SaveMessages([]*common.Message{{ 904 ID: id, 905 LocalChatID: testPublicChatID, 906 ChatMessage: &protobuf.ChatMessage{Text: "some-text"}, 907 From: testPK, 908 }}) 909 } 910 911 func insertMinimalDeletedMessage(p *sqlitePersistence, id string) error { 912 return p.SaveMessages([]*common.Message{{ 913 ID: id, 914 Deleted: true, 915 LocalChatID: testPublicChatID, 916 ChatMessage: &protobuf.ChatMessage{Text: "some-text"}, 917 From: testPK, 918 }}) 919 } 920 921 func insertMinimalDeletedForMeMessage(p *sqlitePersistence, id string) error { 922 return p.SaveMessages([]*common.Message{{ 923 ID: id, 924 DeletedForMe: true, 925 LocalChatID: testPublicChatID, 926 ChatMessage: &protobuf.ChatMessage{Text: "some-text"}, 927 From: testPK, 928 }}) 929 } 930 931 func insertDiscordMessageWithAttachments(p *sqlitePersistence, id string, discordMessageID string) error { 932 err := insertMinimalDiscordMessage(p, id, discordMessageID) 933 if err != nil { 934 return err 935 } 936 937 attachment := &protobuf.DiscordMessageAttachment{ 938 Id: "1", 939 MessageId: discordMessageID, 940 Url: "https://does-not-exist.com", 941 Payload: []byte{1, 2, 3, 4}, 942 } 943 944 attachment2 := &protobuf.DiscordMessageAttachment{ 945 Id: "2", 946 MessageId: discordMessageID, 947 Url: "https://does-not-exist.com", 948 Payload: []byte{5, 6, 7, 8}, 949 } 950 951 return p.SaveDiscordMessageAttachments([]*protobuf.DiscordMessageAttachment{ 952 attachment, 953 attachment2, 954 }) 955 } 956 957 func insertMinimalDiscordMessage(p *sqlitePersistence, id string, discordMessageID string) error { 958 discordMessage := &protobuf.DiscordMessage{ 959 Id: discordMessageID, 960 Type: "Default", 961 Timestamp: "123456", 962 Content: "This is the message", 963 Author: &protobuf.DiscordMessageAuthor{ 964 Id: "2", 965 }, 966 Reference: &protobuf.DiscordMessageReference{}, 967 } 968 969 err := p.SaveDiscordMessage(discordMessage) 970 if err != nil { 971 return err 972 } 973 974 return p.SaveMessages([]*common.Message{{ 975 ID: id, 976 LocalChatID: testPublicChatID, 977 From: testPK, 978 ChatMessage: &protobuf.ChatMessage{ 979 Text: "some-text", 980 ContentType: protobuf.ChatMessage_DISCORD_MESSAGE, 981 ChatId: testPublicChatID, 982 Payload: &protobuf.ChatMessage_DiscordMessage{ 983 DiscordMessage: discordMessage, 984 }, 985 }, 986 }}) 987 } 988 989 func minimalRawMessage(id string, messageType protobuf.ApplicationMetadataMessage_Type) *common.RawMessage { 990 return &common.RawMessage{ 991 ID: id, 992 LocalChatID: "test-chat", 993 MessageType: messageType, 994 } 995 } 996 997 // Regression test making sure that if audio_duration_ms is null, no error is thrown 998 func TestMessagesAudioDurationMsNull(t *testing.T) { 999 db, err := openTestDB() 1000 require.NoError(t, err) 1001 p := newSQLitePersistence(db) 1002 id := "message-id-1" 1003 1004 err = insertMinimalMessage(p, id) 1005 require.NoError(t, err) 1006 1007 _, err = p.db.Exec("UPDATE user_messages SET audio_duration_ms = NULL") 1008 require.NoError(t, err) 1009 1010 m, err := p.MessagesByIDs([]string{id}) 1011 require.NoError(t, err) 1012 require.Len(t, m, 1) 1013 1014 m, _, err = p.MessageByChatID(testPublicChatID, "", 10) 1015 require.NoError(t, err) 1016 require.Len(t, m, 1) 1017 } 1018 1019 func TestSaveChat(t *testing.T) { 1020 db, err := openTestDB() 1021 require.NoError(t, err) 1022 p := newSQLitePersistence(db) 1023 1024 chat := CreatePublicChat("test-chat", &testTimeSource{}) 1025 chat.LastMessage = common.NewMessage() 1026 err = p.SaveChat(*chat) 1027 require.NoError(t, err) 1028 1029 retrievedChat, err := p.Chat(chat.ID) 1030 require.NoError(t, err) 1031 require.Equal(t, chat, retrievedChat) 1032 } 1033 1034 func TestSaveMentions(t *testing.T) { 1035 chatID := testPublicChatID 1036 db, err := openTestDB() 1037 require.NoError(t, err) 1038 p := newSQLitePersistence(db) 1039 1040 key, err := crypto.GenerateKey() 1041 require.NoError(t, err) 1042 1043 pkString := types.EncodeHex(crypto.FromECDSAPub(&key.PublicKey)) 1044 1045 message := common.Message{ 1046 ID: "1", 1047 LocalChatID: chatID, 1048 ChatMessage: &protobuf.ChatMessage{Text: "some-text"}, 1049 From: testPK, 1050 Mentions: []string{pkString}, 1051 } 1052 1053 err = p.SaveMessages([]*common.Message{&message}) 1054 require.NoError(t, err) 1055 1056 retrievedMessages, _, err := p.MessageByChatID(chatID, "", 10) 1057 require.NoError(t, err) 1058 require.Len(t, retrievedMessages, 1) 1059 require.Len(t, retrievedMessages[0].Mentions, 1) 1060 require.Equal(t, retrievedMessages[0].Mentions, message.Mentions) 1061 } 1062 1063 func TestSqlitePersistence_GetWhenChatIdentityLastPublished(t *testing.T) { 1064 db, err := openTestDB() 1065 require.NoError(t, err) 1066 p := newSQLitePersistence(db) 1067 1068 chatID := "0xabcd1234" 1069 hash := []byte{0x1} 1070 now := time.Now().Unix() 1071 1072 err = p.SaveWhenChatIdentityLastPublished(chatID, hash) 1073 require.NoError(t, err) 1074 1075 ts, actualHash, err := p.GetWhenChatIdentityLastPublished(chatID) 1076 require.NoError(t, err) 1077 1078 // Check that the save happened in the last 2 seconds 1079 diff := ts - now 1080 require.LessOrEqual(t, diff, int64(2)) 1081 1082 require.True(t, bytes.Equal(hash, actualHash)) 1083 1084 // Require unsaved values to be zero 1085 ts2, actualHash2, err := p.GetWhenChatIdentityLastPublished("0xdeadbeef") 1086 require.NoError(t, err) 1087 require.Exactly(t, int64(0), ts2) 1088 require.Nil(t, actualHash2) 1089 } 1090 1091 func TestContactBioPersistence(t *testing.T) { 1092 db, err := openTestDB() 1093 require.NoError(t, err) 1094 p := newSQLitePersistence(db) 1095 1096 key, err := crypto.GenerateKey() 1097 require.NoError(t, err) 1098 1099 contactID := types.EncodeHex(crypto.FromECDSAPub(&key.PublicKey)) 1100 contactBio := "A contact bio description" 1101 1102 err = p.SaveContact(&Contact{ID: contactID, Bio: contactBio}, nil) 1103 require.NoError(t, err) 1104 1105 contacts, err := p.Contacts() 1106 require.NoError(t, err) 1107 require.Len(t, contacts, 1) 1108 require.Equal(t, contactBio, contacts[0].Bio) 1109 } 1110 1111 func TestContactBioPersistenceDefaults(t *testing.T) { 1112 db, err := openTestDB() 1113 require.NoError(t, err) 1114 p := newSQLitePersistence(db) 1115 1116 key, err := crypto.GenerateKey() 1117 require.NoError(t, err) 1118 1119 contactID := types.EncodeHex(crypto.FromECDSAPub(&key.PublicKey)) 1120 1121 err = p.SaveContact(&Contact{ID: contactID}, nil) 1122 require.NoError(t, err) 1123 1124 contacts, err := p.Contacts() 1125 require.NoError(t, err) 1126 require.Len(t, contacts, 1) 1127 require.Equal(t, "", contacts[0].Bio) 1128 } 1129 1130 func TestUpdateContactChatIdentity(t *testing.T) { 1131 db, err := openTestDB() 1132 require.NoError(t, err) 1133 p := newSQLitePersistence(db) 1134 1135 key, err := crypto.GenerateKey() 1136 require.NoError(t, err) 1137 1138 contactID := types.EncodeHex(crypto.FromECDSAPub(&key.PublicKey)) 1139 1140 err = p.SaveContact(&Contact{ID: contactID}, nil) 1141 require.NoError(t, err) 1142 1143 jpegType := []byte{0xff, 0xd8, 0xff, 0x1} 1144 identityImages := make(map[string]*protobuf.IdentityImage) 1145 identityImages["large"] = &protobuf.IdentityImage{ 1146 Payload: jpegType, 1147 SourceType: protobuf.IdentityImage_RAW_PAYLOAD, 1148 ImageFormat: protobuf.ImageFormat_PNG, 1149 } 1150 1151 identityImages["small"] = &protobuf.IdentityImage{ 1152 Payload: jpegType, 1153 SourceType: protobuf.IdentityImage_RAW_PAYLOAD, 1154 ImageFormat: protobuf.ImageFormat_PNG, 1155 } 1156 1157 toArrayOfPointers := func(array []protobuf.SocialLink) (result []*protobuf.SocialLink) { 1158 result = make([]*protobuf.SocialLink, len(array)) 1159 for i := range array { 1160 result[i] = &array[i] 1161 } 1162 return 1163 } 1164 1165 chatIdentity := &protobuf.ChatIdentity{ 1166 Clock: 1, 1167 Images: identityImages, 1168 SocialLinks: toArrayOfPointers([]protobuf.SocialLink{ 1169 { 1170 Text: "Personal Site", 1171 Url: "status.im", 1172 }, 1173 { 1174 Text: "Twitter", 1175 Url: "Status_ico", 1176 }, 1177 }), 1178 } 1179 1180 clockUpdated, imagesUpdated, err := p.UpdateContactChatIdentity(contactID, chatIdentity) 1181 require.NoError(t, err) 1182 require.True(t, clockUpdated) 1183 require.True(t, imagesUpdated) 1184 1185 // Save again same clock and data 1186 clockUpdated, imagesUpdated, err = p.UpdateContactChatIdentity(contactID, chatIdentity) 1187 require.NoError(t, err) 1188 require.False(t, clockUpdated) 1189 require.False(t, imagesUpdated) 1190 1191 // Save again newer clock and no images 1192 chatIdentity.Clock = 2 1193 chatIdentity.Images = make(map[string]*protobuf.IdentityImage) 1194 clockUpdated, imagesUpdated, err = p.UpdateContactChatIdentity(contactID, chatIdentity) 1195 require.NoError(t, err) 1196 require.True(t, clockUpdated) 1197 require.True(t, imagesUpdated) 1198 1199 contacts, err := p.Contacts() 1200 require.NoError(t, err) 1201 require.Len(t, contacts, 1) 1202 1203 require.Len(t, contacts[0].Images, 0) 1204 } 1205 1206 func TestRemovedProfileImage(t *testing.T) { 1207 db, err := openTestDB() 1208 require.NoError(t, err) 1209 p := newSQLitePersistence(db) 1210 1211 key, err := crypto.GenerateKey() 1212 require.NoError(t, err) 1213 1214 contactID := types.EncodeHex(crypto.FromECDSAPub(&key.PublicKey)) 1215 1216 err = p.SaveContact(&Contact{ID: contactID}, nil) 1217 require.NoError(t, err) 1218 1219 jpegType := []byte{0xff, 0xd8, 0xff, 0x1} 1220 identityImages := make(map[string]*protobuf.IdentityImage) 1221 identityImages["large"] = &protobuf.IdentityImage{ 1222 Payload: jpegType, 1223 SourceType: protobuf.IdentityImage_RAW_PAYLOAD, 1224 ImageFormat: protobuf.ImageFormat_PNG, 1225 } 1226 1227 identityImages["small"] = &protobuf.IdentityImage{ 1228 Payload: jpegType, 1229 SourceType: protobuf.IdentityImage_RAW_PAYLOAD, 1230 ImageFormat: protobuf.ImageFormat_PNG, 1231 } 1232 1233 chatIdentity := &protobuf.ChatIdentity{ 1234 Clock: 1, 1235 Images: identityImages, 1236 } 1237 1238 clockUpdated, imagesUpdated, err := p.UpdateContactChatIdentity(contactID, chatIdentity) 1239 require.NoError(t, err) 1240 require.True(t, clockUpdated) 1241 require.True(t, imagesUpdated) 1242 1243 contacts, err := p.Contacts() 1244 require.NoError(t, err) 1245 require.Len(t, contacts, 1) 1246 require.Len(t, contacts[0].Images, 2) 1247 1248 emptyChatIdentity := &protobuf.ChatIdentity{ 1249 Clock: 1, 1250 Images: nil, 1251 } 1252 1253 clockUpdated, imagesUpdated, err = p.UpdateContactChatIdentity(contactID, emptyChatIdentity) 1254 require.NoError(t, err) 1255 require.False(t, clockUpdated) 1256 require.True(t, imagesUpdated) 1257 1258 contacts, err = p.Contacts() 1259 require.NoError(t, err) 1260 require.Len(t, contacts, 1) 1261 require.Len(t, contacts[0].Images, 0) 1262 } 1263 1264 func TestSaveLinks(t *testing.T) { 1265 chatID := testPublicChatID 1266 db, err := openTestDB() 1267 require.NoError(t, err) 1268 p := newSQLitePersistence(db) 1269 1270 require.NoError(t, err) 1271 1272 message := common.Message{ 1273 ID: "1", 1274 LocalChatID: chatID, 1275 ChatMessage: &protobuf.ChatMessage{Text: "some-text"}, 1276 From: testPK, 1277 Links: []string{"https://github.com/status-im/status-mobile"}, 1278 } 1279 1280 err = p.SaveMessages([]*common.Message{&message}) 1281 require.NoError(t, err) 1282 1283 retrievedMessages, _, err := p.MessageByChatID(chatID, "", 10) 1284 require.NoError(t, err) 1285 require.Len(t, retrievedMessages, 1) 1286 require.Len(t, retrievedMessages[0].Links, 1) 1287 require.Equal(t, retrievedMessages[0].Links, message.Links) 1288 } 1289 1290 func TestSaveWithUnfurledLinks(t *testing.T) { 1291 db, err := openTestDB() 1292 require.NoError(t, err) 1293 p := newSQLitePersistence(db) 1294 require.NoError(t, err) 1295 1296 chatID := testPublicChatID 1297 message := common.Message{ 1298 ID: "1", 1299 LocalChatID: chatID, 1300 From: testPK, 1301 ChatMessage: &protobuf.ChatMessage{ 1302 Text: "some-text", 1303 UnfurledLinks: []*protobuf.UnfurledLink{ 1304 { 1305 Type: protobuf.UnfurledLink_LINK, 1306 Url: "https://github.com", 1307 Title: "Build software better, together", 1308 Description: "GitHub is where people build software.", 1309 ThumbnailPayload: []byte("abc"), 1310 }, 1311 { 1312 Type: protobuf.UnfurledLink_LINK, 1313 Url: "https://www.youtube.com/watch?v=mzOyYtfXkb0", 1314 Title: "Status Town Hall #67 - 12 October 2020", 1315 Description: "", 1316 ThumbnailPayload: []byte("def"), 1317 }, 1318 }, 1319 }, 1320 } 1321 1322 err = p.SaveMessages([]*common.Message{&message}) 1323 require.NoError(t, err) 1324 1325 mgs, _, err := p.MessageByChatID(chatID, "", 10) 1326 require.NoError(t, err) 1327 require.Len(t, mgs, 1) 1328 require.Len(t, mgs[0].UnfurledLinks, 2) 1329 require.Equal(t, mgs[0].UnfurledLinks, message.UnfurledLinks) 1330 } 1331 1332 func TestHideMessage(t *testing.T) { 1333 db, err := openTestDB() 1334 require.NoError(t, err) 1335 p := newSQLitePersistence(db) 1336 chatID := testPublicChatID 1337 message := &common.Message{ 1338 ID: "id-1", 1339 LocalChatID: chatID, 1340 ChatMessage: &protobuf.ChatMessage{ 1341 Text: "content-1", 1342 Clock: uint64(1), 1343 }, 1344 From: "1", 1345 } 1346 1347 messages := []*common.Message{message} 1348 1349 err = p.SaveMessages(messages) 1350 require.NoError(t, err) 1351 1352 err = p.HideMessage(message.ID) 1353 require.NoError(t, err) 1354 1355 var actualHidden, actualSeen bool 1356 err = p.db.QueryRow("SELECT hide, seen FROM user_messages WHERE id = ?", message.ID).Scan(&actualHidden, &actualSeen) 1357 1358 require.NoError(t, err) 1359 require.True(t, actualHidden) 1360 require.True(t, actualSeen) 1361 } 1362 1363 func TestDeactivatePublicChat(t *testing.T) { 1364 db, err := openTestDB() 1365 require.NoError(t, err) 1366 p := newSQLitePersistence(db) 1367 publicChatID := "public-chat-id" 1368 var currentClockValue uint64 = 10 1369 1370 timesource := &testTimeSource{} 1371 lastMessage := common.Message{ 1372 ID: "0x01", 1373 LocalChatID: publicChatID, 1374 ChatMessage: &protobuf.ChatMessage{Text: "some-text"}, 1375 From: testPK, 1376 } 1377 lastMessage.Clock = 20 1378 1379 require.NoError(t, p.SaveMessages([]*common.Message{&lastMessage})) 1380 1381 publicChat := CreatePublicChat(publicChatID, timesource) 1382 publicChat.LastMessage = &lastMessage 1383 publicChat.UnviewedMessagesCount = 1 1384 1385 err = p.DeactivateChat(publicChat, currentClockValue, true) 1386 1387 // It does not set deleted at for a public chat 1388 require.NoError(t, err) 1389 require.Equal(t, uint64(0), publicChat.DeletedAtClockValue) 1390 1391 // It sets the lastMessage to nil 1392 require.Nil(t, publicChat.LastMessage) 1393 1394 // It sets unviewed messages count 1395 require.Equal(t, uint(0), publicChat.UnviewedMessagesCount) 1396 1397 // It sets active as false 1398 require.False(t, publicChat.Active) 1399 1400 // It deletes messages 1401 messages, _, err := p.MessageByChatID(publicChatID, "", 10) 1402 require.NoError(t, err) 1403 require.Len(t, messages, 0) 1404 1405 // Reload chat to make sure it has been save 1406 dbChat, err := p.Chat(publicChatID) 1407 1408 require.NoError(t, err) 1409 require.NotNil(t, dbChat) 1410 1411 // Same checks on the chat pulled from the db 1412 // It does not set deleted at for a public chat 1413 require.NoError(t, err) 1414 require.Equal(t, uint64(0), dbChat.DeletedAtClockValue) 1415 1416 // It sets the lastMessage to nil 1417 require.Nil(t, dbChat.LastMessage) 1418 1419 // It sets unviewed messages count 1420 require.Equal(t, uint(0), dbChat.UnviewedMessagesCount) 1421 1422 // It sets active as false 1423 require.False(t, dbChat.Active) 1424 } 1425 1426 func TestDeactivateOneToOneChat(t *testing.T) { 1427 key, err := crypto.GenerateKey() 1428 require.NoError(t, err) 1429 1430 pkString := types.EncodeHex(crypto.FromECDSAPub(&key.PublicKey)) 1431 1432 db, err := openTestDB() 1433 require.NoError(t, err) 1434 p := newSQLitePersistence(db) 1435 var currentClockValue uint64 = 10 1436 1437 timesource := &testTimeSource{} 1438 1439 chat := CreateOneToOneChat(pkString, &key.PublicKey, timesource) 1440 1441 lastMessage := common.Message{ 1442 ID: "0x01", 1443 LocalChatID: chat.ID, 1444 ChatMessage: &protobuf.ChatMessage{Text: "some-text"}, 1445 From: testPK, 1446 } 1447 lastMessage.Clock = 20 1448 1449 require.NoError(t, p.SaveMessages([]*common.Message{&lastMessage})) 1450 1451 chat.LastMessage = &lastMessage 1452 chat.UnviewedMessagesCount = 1 1453 1454 err = p.DeactivateChat(chat, currentClockValue, true) 1455 1456 // It does set deleted at for a public chat 1457 require.NoError(t, err) 1458 require.NotEqual(t, uint64(0), chat.DeletedAtClockValue) 1459 1460 // It sets the lastMessage to nil 1461 require.Nil(t, chat.LastMessage) 1462 1463 // It sets unviewed messages count 1464 require.Equal(t, uint(0), chat.UnviewedMessagesCount) 1465 1466 // It sets active as false 1467 require.False(t, chat.Active) 1468 1469 // It deletes messages 1470 messages, _, err := p.MessageByChatID(chat.ID, "", 10) 1471 require.NoError(t, err) 1472 require.Len(t, messages, 0) 1473 1474 // Reload chat to make sure it has been save 1475 dbChat, err := p.Chat(chat.ID) 1476 1477 require.NoError(t, err) 1478 require.NotNil(t, dbChat) 1479 1480 // Same checks on the chat pulled from the db 1481 // It does set deleted at for a public chat 1482 require.NoError(t, err) 1483 require.NotEqual(t, uint64(0), dbChat.DeletedAtClockValue) 1484 1485 // It sets the lastMessage to nil 1486 require.Nil(t, dbChat.LastMessage) 1487 1488 // It sets unviewed messages count 1489 require.Equal(t, uint(0), dbChat.UnviewedMessagesCount) 1490 1491 // It sets active as false 1492 require.False(t, dbChat.Active) 1493 } 1494 1495 func TestConfirmations(t *testing.T) { 1496 dataSyncID1 := []byte("datsync-id-1") 1497 dataSyncID2 := []byte("datsync-id-2") 1498 dataSyncID3 := []byte("datsync-id-3") 1499 dataSyncID4 := []byte("datsync-id-3") 1500 1501 messageID1 := []byte("message-id-1") 1502 messageID2 := []byte("message-id-2") 1503 1504 publicKey1 := []byte("pk-1") 1505 publicKey2 := []byte("pk-2") 1506 publicKey3 := []byte("pk-3") 1507 1508 db, err := openTestDB() 1509 require.NoError(t, err) 1510 p := newSQLitePersistence(db) 1511 1512 confirmation1 := &common.RawMessageConfirmation{ 1513 DataSyncID: dataSyncID1, 1514 MessageID: messageID1, 1515 PublicKey: publicKey1, 1516 } 1517 1518 // Same datasyncID and same messageID, different pubkey 1519 confirmation2 := &common.RawMessageConfirmation{ 1520 DataSyncID: dataSyncID2, 1521 MessageID: messageID1, 1522 PublicKey: publicKey2, 1523 } 1524 1525 // Different datasyncID and same messageID, different pubkey 1526 confirmation3 := &common.RawMessageConfirmation{ 1527 DataSyncID: dataSyncID3, 1528 MessageID: messageID1, 1529 PublicKey: publicKey3, 1530 } 1531 1532 // Same dataSyncID, different messageID 1533 confirmation4 := &common.RawMessageConfirmation{ 1534 DataSyncID: dataSyncID4, 1535 MessageID: messageID2, 1536 PublicKey: publicKey1, 1537 } 1538 1539 require.NoError(t, p.InsertPendingConfirmation(confirmation1)) 1540 require.NoError(t, p.InsertPendingConfirmation(confirmation2)) 1541 require.NoError(t, p.InsertPendingConfirmation(confirmation3)) 1542 require.NoError(t, p.InsertPendingConfirmation(confirmation4)) 1543 1544 // We confirm the first datasync message, no confirmations 1545 messageID, err := p.MarkAsConfirmed(dataSyncID1, false) 1546 require.NoError(t, err) 1547 require.Nil(t, messageID) 1548 1549 // We confirm the second datasync message, no confirmations 1550 messageID, err = p.MarkAsConfirmed(dataSyncID2, false) 1551 require.NoError(t, err) 1552 require.Nil(t, messageID) 1553 1554 // We confirm the third datasync message, messageID1 should be confirmed 1555 messageID, err = p.MarkAsConfirmed(dataSyncID3, false) 1556 require.NoError(t, err) 1557 require.Equal(t, messageID, types.HexBytes(messageID1)) 1558 } 1559 1560 func TestConfirmationsAtLeastOne(t *testing.T) { 1561 dataSyncID1 := []byte("datsync-id-1") 1562 dataSyncID2 := []byte("datsync-id-2") 1563 dataSyncID3 := []byte("datsync-id-3") 1564 1565 messageID1 := []byte("message-id-1") 1566 1567 publicKey1 := []byte("pk-1") 1568 publicKey2 := []byte("pk-2") 1569 publicKey3 := []byte("pk-3") 1570 1571 db, err := openTestDB() 1572 require.NoError(t, err) 1573 p := newSQLitePersistence(db) 1574 1575 confirmation1 := &common.RawMessageConfirmation{ 1576 DataSyncID: dataSyncID1, 1577 MessageID: messageID1, 1578 PublicKey: publicKey1, 1579 } 1580 1581 // Same datasyncID and same messageID, different pubkey 1582 confirmation2 := &common.RawMessageConfirmation{ 1583 DataSyncID: dataSyncID2, 1584 MessageID: messageID1, 1585 PublicKey: publicKey2, 1586 } 1587 1588 // Different datasyncID and same messageID, different pubkey 1589 confirmation3 := &common.RawMessageConfirmation{ 1590 DataSyncID: dataSyncID3, 1591 MessageID: messageID1, 1592 PublicKey: publicKey3, 1593 } 1594 1595 require.NoError(t, p.InsertPendingConfirmation(confirmation1)) 1596 require.NoError(t, p.InsertPendingConfirmation(confirmation2)) 1597 require.NoError(t, p.InsertPendingConfirmation(confirmation3)) 1598 1599 // We confirm the first datasync message, messageID1 and 3 should be confirmed 1600 messageID, err := p.MarkAsConfirmed(dataSyncID1, true) 1601 require.NoError(t, err) 1602 require.NotNil(t, messageID) 1603 require.Equal(t, types.HexBytes(messageID1), messageID) 1604 } 1605 1606 func TestSaveCommunityChat(t *testing.T) { 1607 db, err := openTestDB() 1608 require.NoError(t, err) 1609 p := newSQLitePersistence(db) 1610 1611 identity := &protobuf.ChatIdentity{ 1612 DisplayName: "community-chat-name", 1613 Description: "community-chat-name-description", 1614 FirstMessageTimestamp: 1, 1615 } 1616 permissions := &protobuf.CommunityPermissions{ 1617 Access: protobuf.CommunityPermissions_AUTO_ACCEPT, 1618 } 1619 1620 communityChat := &protobuf.CommunityChat{ 1621 Identity: identity, 1622 Permissions: permissions, 1623 } 1624 1625 chat := CreateCommunityChat("test-or-gid", "test-chat-id", communityChat, &testTimeSource{}) 1626 chat.LastMessage = common.NewMessage() 1627 err = p.SaveChat(*chat) 1628 require.NoError(t, err) 1629 1630 retrievedChat, err := p.Chat(chat.ID) 1631 require.NoError(t, err) 1632 require.Equal(t, chat, retrievedChat) 1633 } 1634 1635 func TestSaveDiscordMessageAuthor(t *testing.T) { 1636 1637 db, err := openTestDB() 1638 require.NoError(t, err) 1639 p := newSQLitePersistence(db) 1640 1641 testAuthor := &protobuf.DiscordMessageAuthor{ 1642 Id: "1", 1643 Name: "Testuser", 1644 Discriminator: "1234", 1645 Nickname: "User", 1646 AvatarUrl: "http://example.com/profile.jpg", 1647 AvatarImagePayload: []byte{1, 2, 3}, 1648 } 1649 1650 require.NoError(t, p.SaveDiscordMessageAuthor(testAuthor)) 1651 1652 exists, err := p.HasDiscordMessageAuthor("1") 1653 require.NoError(t, err) 1654 require.True(t, exists) 1655 author, err := p.GetDiscordMessageAuthorByID("1") 1656 require.NoError(t, err) 1657 require.Equal(t, author.Id, testAuthor.Id) 1658 require.Equal(t, author.Name, testAuthor.Name) 1659 } 1660 1661 func TestGetDiscordMessageAuthorImagePayloadByID(t *testing.T) { 1662 db, err := openTestDB() 1663 require.NoError(t, err) 1664 p := newSQLitePersistence(db) 1665 1666 testAuthor := &protobuf.DiscordMessageAuthor{ 1667 Id: "1", 1668 Name: "Testuser", 1669 Discriminator: "1234", 1670 Nickname: "User", 1671 AvatarUrl: "http://example.com/profile.jpg", 1672 AvatarImagePayload: []byte{1, 2, 3}, 1673 } 1674 1675 require.NoError(t, p.SaveDiscordMessageAuthor(testAuthor)) 1676 1677 payload, err := p.GetDiscordMessageAuthorImagePayloadByID("1") 1678 require.NoError(t, err) 1679 1680 require.Equal(t, testAuthor.AvatarImagePayload, payload) 1681 } 1682 1683 func TestSaveDiscordMessage(t *testing.T) { 1684 1685 db, err := openTestDB() 1686 require.NoError(t, err) 1687 p := newSQLitePersistence(db) 1688 1689 require.NoError(t, p.SaveDiscordMessage(&protobuf.DiscordMessage{ 1690 Id: "1", 1691 Type: "Default", 1692 Timestamp: "123456", 1693 Content: "This is the message", 1694 Author: &protobuf.DiscordMessageAuthor{ 1695 Id: "2", 1696 }, 1697 Reference: &protobuf.DiscordMessageReference{}, 1698 })) 1699 1700 require.NoError(t, err) 1701 } 1702 1703 func TestSaveDiscordMessages(t *testing.T) { 1704 db, err := openTestDB() 1705 require.NoError(t, err) 1706 p := newSQLitePersistence(db) 1707 1708 for i := 0; i < 10; i++ { 1709 id := strconv.Itoa(i) 1710 err := insertMinimalDiscordMessage(p, id, id) 1711 require.NoError(t, err) 1712 1713 m, err := p.MessageByID(id) 1714 require.NoError(t, err) 1715 dm := m.GetDiscordMessage() 1716 require.NotNil(t, dm) 1717 require.EqualValues(t, id, dm.Id) 1718 require.EqualValues(t, "2", dm.Author.Id) 1719 } 1720 } 1721 1722 func TestUpdateDiscordMessageAuthorImage(t *testing.T) { 1723 1724 db, err := openTestDB() 1725 require.NoError(t, err) 1726 p := newSQLitePersistence(db) 1727 1728 require.NoError(t, p.SaveDiscordMessageAuthor(&protobuf.DiscordMessageAuthor{ 1729 Id: "1", 1730 Name: "Testuser", 1731 Discriminator: "1234", 1732 Nickname: "User", 1733 AvatarUrl: "http://example.com/profile.jpg", 1734 })) 1735 1736 exists, err := p.HasDiscordMessageAuthor("1") 1737 require.NoError(t, err) 1738 require.True(t, exists) 1739 1740 err = p.UpdateDiscordMessageAuthorImage("1", []byte{0, 1, 2, 3}) 1741 require.NoError(t, err) 1742 payload, err := p.GetDiscordMessageAuthorImagePayloadByID("1") 1743 require.NoError(t, err) 1744 require.Equal(t, []byte{0, 1, 2, 3}, payload) 1745 } 1746 1747 func TestSaveHashRatchetMessage(t *testing.T) { 1748 db, err := openTestDB() 1749 require.NoError(t, err) 1750 p := newSQLitePersistence(db) 1751 1752 groupID1 := []byte("group-id-1") 1753 groupID2 := []byte("group-id-2") 1754 keyID := []byte("key-id") 1755 1756 message1 := &types.Message{ 1757 Hash: []byte{1}, 1758 Sig: []byte{2}, 1759 TTL: 1, 1760 Timestamp: 2, 1761 Payload: []byte{3}, 1762 } 1763 1764 require.NoError(t, p.SaveHashRatchetMessage(groupID1, keyID, message1)) 1765 1766 message2 := &types.Message{ 1767 Hash: []byte{2}, 1768 Sig: []byte{2}, 1769 TTL: 1, 1770 Topic: types.BytesToTopic([]byte{5}), 1771 Timestamp: 2, 1772 Payload: []byte{3}, 1773 Dst: []byte{4}, 1774 P2P: true, 1775 } 1776 1777 require.NoError(t, p.SaveHashRatchetMessage(groupID2, keyID, message2)) 1778 1779 fetchedMessages, err := p.GetHashRatchetMessages(keyID) 1780 require.NoError(t, err) 1781 require.NotNil(t, fetchedMessages) 1782 require.Len(t, fetchedMessages, 2) 1783 } 1784 1785 func TestCountActiveChattersInCommunity(t *testing.T) { 1786 db, err := openTestDB() 1787 require.NoError(t, err) 1788 p := newSQLitePersistence(db) 1789 1790 channel1 := Chat{ 1791 ID: "channel1", 1792 Name: "channel1", 1793 CommunityID: "testCommunity", 1794 } 1795 1796 channel2 := Chat{ 1797 ID: "channel2", 1798 Name: "channel2", 1799 CommunityID: "testCommunity", 1800 } 1801 1802 require.NoError(t, p.SaveChat(channel1)) 1803 require.NoError(t, p.SaveChat(channel2)) 1804 1805 fillChatWithMessages := func(chat *Chat, offset int) { 1806 count := 5 1807 var messages []*common.Message 1808 for i := 0; i < count; i++ { 1809 messages = append(messages, &common.Message{ 1810 ID: fmt.Sprintf("%smsg%d", chat.Name, i), 1811 LocalChatID: chat.ID, 1812 ChatMessage: &protobuf.ChatMessage{ 1813 Clock: uint64(i), 1814 Timestamp: uint64(i + offset), 1815 }, 1816 From: fmt.Sprintf("user%d", i), 1817 }) 1818 } 1819 require.NoError(t, p.SaveMessages(messages)) 1820 } 1821 1822 // timestamp/user/msgID 1823 // channel1: 0/user0/channel1msg0 1/user1/channel1msg1 2/user2/channel1msg2 3/user3/channel1msg3 4/user4/channel1msg4 1824 // channel2: 3/user0/channel2msg0 4/user1/channel2msg1 5/user2/channel2msg2 6/user3/channel2msg3 7/user4/channel2msg4 1825 fillChatWithMessages(&channel1, 0) 1826 fillChatWithMessages(&channel2, 3) 1827 1828 checker := func(activeAfterTimestamp int64, expected uint) { 1829 result, err := p.CountActiveChattersInCommunity("testCommunity", activeAfterTimestamp) 1830 require.NoError(t, err) 1831 require.Equal(t, expected, result) 1832 } 1833 checker(0, 5) 1834 checker(3, 5) 1835 checker(4, 4) 1836 checker(5, 3) 1837 checker(6, 2) 1838 checker(7, 1) 1839 checker(8, 0) 1840 } 1841 1842 func TestDeleteHashRatchetMessage(t *testing.T) { 1843 db, err := openTestDB() 1844 require.NoError(t, err) 1845 p := newSQLitePersistence(db) 1846 1847 groupID := []byte("group-id") 1848 keyID := []byte("key-id") 1849 1850 message1 := &types.Message{ 1851 Hash: []byte{1}, 1852 Sig: []byte{2}, 1853 TTL: 1, 1854 Timestamp: 2, 1855 Payload: []byte{3}, 1856 } 1857 1858 require.NoError(t, p.SaveHashRatchetMessage(groupID, keyID, message1)) 1859 1860 message2 := &types.Message{ 1861 Hash: []byte{2}, 1862 Sig: []byte{2}, 1863 TTL: 1, 1864 Topic: types.BytesToTopic([]byte{5}), 1865 Timestamp: 2, 1866 Payload: []byte{3}, 1867 Dst: []byte{4}, 1868 P2P: true, 1869 } 1870 1871 require.NoError(t, p.SaveHashRatchetMessage(groupID, keyID, message2)) 1872 1873 message3 := &types.Message{ 1874 Hash: []byte{3}, 1875 Sig: []byte{2}, 1876 TTL: 1, 1877 Topic: types.BytesToTopic([]byte{5}), 1878 Timestamp: 2, 1879 Payload: []byte{3}, 1880 Dst: []byte{4}, 1881 P2P: true, 1882 } 1883 1884 require.NoError(t, p.SaveHashRatchetMessage(groupID, keyID, message3)) 1885 1886 fetchedMessages, err := p.GetHashRatchetMessages(keyID) 1887 require.NoError(t, err) 1888 require.NotNil(t, fetchedMessages) 1889 require.Len(t, fetchedMessages, 3) 1890 1891 require.NoError(t, p.DeleteHashRatchetMessages([][]byte{[]byte{1}, []byte{2}})) 1892 1893 fetchedMessages, err = p.GetHashRatchetMessages(keyID) 1894 require.NoError(t, err) 1895 require.NotNil(t, fetchedMessages) 1896 require.Len(t, fetchedMessages, 1) 1897 1898 } 1899 1900 func TestSaveBridgeMessage(t *testing.T) { 1901 db, err := openTestDB() 1902 require.NoError(t, err) 1903 p := newSQLitePersistence(db) 1904 1905 require.NoError(t, err) 1906 1907 bridgeMessage := &protobuf.BridgeMessage{ 1908 BridgeName: "discord", 1909 UserName: "joe", 1910 Content: "abc", 1911 UserAvatar: "data:image/png;base64,iVBO...", 1912 UserID: "123", 1913 MessageID: "456", 1914 ParentMessageID: "789", 1915 } 1916 1917 const msgID = "123" 1918 err = p.SaveMessages([]*common.Message{{ 1919 ID: msgID, 1920 LocalChatID: testPublicChatID, 1921 From: testPK, 1922 ChatMessage: &protobuf.ChatMessage{ 1923 Text: "some-text", 1924 ContentType: protobuf.ChatMessage_BRIDGE_MESSAGE, 1925 ChatId: testPublicChatID, 1926 Payload: &protobuf.ChatMessage_BridgeMessage{ 1927 BridgeMessage: bridgeMessage, 1928 }, 1929 }, 1930 }}) 1931 1932 require.NoError(t, err) 1933 1934 retrievedMessages, _, err := p.MessageByChatID(testPublicChatID, "", 10) 1935 require.NoError(t, err) 1936 require.Len(t, retrievedMessages, 1) 1937 require.Equal(t, "discord", retrievedMessages[0].GetBridgeMessage().BridgeName) 1938 require.Equal(t, "joe", retrievedMessages[0].GetBridgeMessage().UserName) 1939 require.Equal(t, "abc", retrievedMessages[0].GetBridgeMessage().Content) 1940 require.Equal(t, "data:image/png;base64,iVBO...", retrievedMessages[0].GetBridgeMessage().UserAvatar) 1941 require.Equal(t, "123", retrievedMessages[0].GetBridgeMessage().UserID) 1942 require.Equal(t, "456", retrievedMessages[0].GetBridgeMessage().MessageID) 1943 require.Equal(t, "789", retrievedMessages[0].GetBridgeMessage().ParentMessageID) 1944 } 1945 1946 func insertMinimalBridgeMessage(p *sqlitePersistence, messageID string, bridgeMessageID string, bridgeMessageParentID string) error { 1947 1948 bridgeMessage := &protobuf.BridgeMessage{ 1949 BridgeName: "discord", 1950 UserName: "joe", 1951 Content: "abc", 1952 UserAvatar: "data:image/png;base64,iVBO...", 1953 UserID: "123", 1954 MessageID: bridgeMessageID, 1955 ParentMessageID: bridgeMessageParentID, 1956 } 1957 1958 return p.SaveMessages([]*common.Message{{ 1959 ID: messageID, 1960 LocalChatID: testPublicChatID, 1961 From: testPK, 1962 ChatMessage: &protobuf.ChatMessage{ 1963 Text: "some-text", 1964 ContentType: protobuf.ChatMessage_BRIDGE_MESSAGE, 1965 ChatId: testPublicChatID, 1966 Payload: &protobuf.ChatMessage_BridgeMessage{ 1967 BridgeMessage: bridgeMessage, 1968 }, 1969 }, 1970 }}) 1971 } 1972 1973 func messageResponseTo(p *sqlitePersistence, messageID string) (string, error) { 1974 var responseTo string 1975 err := p.db.QueryRow("SELECT response_to FROM user_messages WHERE id = ?", messageID).Scan(&responseTo) 1976 return responseTo, err 1977 } 1978 1979 func TestBridgeMessageReplies(t *testing.T) { 1980 db, err := openTestDB() 1981 require.NoError(t, err) 1982 p := newSQLitePersistence(db) 1983 1984 require.NoError(t, err) 1985 1986 err = insertMinimalBridgeMessage(p, "111", "1", "") 1987 require.NoError(t, err) 1988 1989 err = insertMinimalBridgeMessage(p, "222", "2", "1") 1990 require.NoError(t, err) 1991 1992 // "333 is not delivered yet" 1993 1994 // this is a reply to a message which was not delivered yet 1995 err = insertMinimalBridgeMessage(p, "444", "4", "3") 1996 require.NoError(t, err) 1997 1998 // status message "222" should have reply_to = "111" 1999 responseTo, err := messageResponseTo(p, "222") 2000 require.NoError(t, err) 2001 require.Equal(t, "111", responseTo) 2002 2003 responseTo, err = messageResponseTo(p, "111") 2004 require.NoError(t, err) 2005 require.Equal(t, "", responseTo) 2006 2007 responseTo, err = messageResponseTo(p, "444") 2008 require.NoError(t, err) 2009 require.Equal(t, "", responseTo) 2010 2011 // receiving message for which "444" is replied to 2012 err = insertMinimalBridgeMessage(p, "333", "3", "") 2013 require.NoError(t, err) 2014 2015 responseTo, err = messageResponseTo(p, "333") 2016 require.NoError(t, err) 2017 require.Equal(t, "", responseTo) 2018 2019 // now 444 is replied to 333 2020 responseTo, err = messageResponseTo(p, "444") 2021 require.NoError(t, err) 2022 require.Equal(t, "333", responseTo) 2023 } 2024 2025 func createAndSaveMessage(p *sqlitePersistence, id string, from string, deleted bool, communityID string) error { 2026 return p.SaveMessages([]*common.Message{{ 2027 ID: id, 2028 From: from, 2029 CommunityID: communityID, 2030 ChatMessage: &protobuf.ChatMessage{ 2031 Timestamp: uint64(time.Now().Unix()), 2032 Text: "some-text", 2033 ChatId: testPublicChatID, 2034 }, 2035 Deleted: deleted, 2036 }}) 2037 } 2038 2039 func TestGetCommunityMemberMessagesID(t *testing.T) { 2040 db, err := openTestDB() 2041 require.NoError(t, err) 2042 p := newSQLitePersistence(db) 2043 testCommunity := "test-community" 2044 2045 chat := &Chat{ 2046 ID: testPublicChatID, 2047 CommunityID: testCommunity, 2048 } 2049 2050 err = p.SaveChats([]*Chat{chat}) 2051 require.NoError(t, err) 2052 2053 messages, err := p.GetCommunityMemberMessagesToDelete(testPK, testCommunity) 2054 require.NoError(t, err) 2055 require.Len(t, messages, 0) 2056 2057 require.NoError(t, createAndSaveMessage(p, "1", testPK, false, testCommunity)) 2058 2059 messages, err = p.GetCommunityMemberMessagesToDelete(testPK, "wrong community") 2060 require.NoError(t, err) 2061 require.Len(t, messages, 0) 2062 2063 messages, err = p.GetCommunityMemberMessagesToDelete("wrong user name", testCommunity) 2064 require.NoError(t, err) 2065 require.Len(t, messages, 0) 2066 2067 messages, err = p.GetCommunityMemberMessagesToDelete(testPK, testCommunity) 2068 require.NoError(t, err) 2069 require.Len(t, messages, 1) 2070 require.Exactly(t, "1", messages[0].Id) 2071 require.Exactly(t, testPublicChatID, messages[0].ChatId) 2072 2073 require.NoError(t, createAndSaveMessage(p, "2", "another user", false, testCommunity)) 2074 2075 messages, err = p.GetCommunityMemberMessagesToDelete(testPK, testCommunity) 2076 require.NoError(t, err) 2077 require.Len(t, messages, 1) 2078 2079 require.NoError(t, createAndSaveMessage(p, "3", testPK, true, testCommunity)) 2080 2081 messages, err = p.GetCommunityMemberMessagesToDelete(testPK, testCommunity) 2082 require.NoError(t, err) 2083 require.Len(t, messages, 2) 2084 } 2085 2086 func TestGetCommunityMemberMessages(t *testing.T) { 2087 db, err := openTestDB() 2088 require.NoError(t, err) 2089 p := newSQLitePersistence(db) 2090 testCommunity := "test-community" 2091 2092 chat := &Chat{ 2093 ID: testPublicChatID, 2094 CommunityID: testCommunity, 2095 } 2096 2097 err = p.SaveChats([]*Chat{chat}) 2098 require.NoError(t, err) 2099 2100 messages, err := p.GetCommunityMemberAllMessages(testPK, testCommunity) 2101 require.NoError(t, err) 2102 require.Len(t, messages, 0) 2103 2104 require.NoError(t, createAndSaveMessage(p, "1", testPK, false, testCommunity)) 2105 2106 messages, err = p.GetCommunityMemberAllMessages(testPK, "wrong community") 2107 require.NoError(t, err) 2108 require.Len(t, messages, 0) 2109 2110 messages, err = p.GetCommunityMemberAllMessages("wrong user name", testCommunity) 2111 require.NoError(t, err) 2112 require.Len(t, messages, 0) 2113 2114 messages, err = p.GetCommunityMemberAllMessages(testPK, testCommunity) 2115 require.NoError(t, err) 2116 require.Len(t, messages, 1) 2117 require.Exactly(t, "1", messages[0].ID) 2118 2119 require.NoError(t, createAndSaveMessage(p, "2", "another user", false, testCommunity)) 2120 2121 messages, err = p.GetCommunityMemberAllMessages(testPK, testCommunity) 2122 require.NoError(t, err) 2123 require.Len(t, messages, 1) 2124 2125 require.NoError(t, createAndSaveMessage(p, "3", testPK, true, testCommunity)) 2126 2127 messages, err = p.GetCommunityMemberAllMessages(testPK, testCommunity) 2128 require.NoError(t, err) 2129 require.Len(t, messages, 2) 2130 }