2019-11-21 16:19:22 +00:00
|
|
|
package protocol
|
|
|
|
|
|
|
|
import (
|
2020-12-10 10:12:51 +00:00
|
|
|
"bytes"
|
2019-11-21 16:19:22 +00:00
|
|
|
"database/sql"
|
|
|
|
"io/ioutil"
|
|
|
|
"math"
|
|
|
|
"sort"
|
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
"testing"
|
2020-10-28 13:41:22 +00:00
|
|
|
"time"
|
2019-11-21 16:19:22 +00:00
|
|
|
|
2020-01-02 09:10:19 +00:00
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
|
2020-09-01 10:34:28 +00:00
|
|
|
"github.com/status-im/status-go/eth-node/crypto"
|
|
|
|
"github.com/status-im/status-go/eth-node/types"
|
2020-09-01 13:27:01 +00:00
|
|
|
"github.com/status-im/status-go/protocol/common"
|
Move to protobuf for Message type (#1706)
* Use a single Message type `v1/message.go` and `message.go` are the same now, and they embed `protobuf.ChatMessage`
* Use `SendChatMessage` for sending chat messages, this is basically the old `Send` but a bit more flexible so we can send different message types (stickers,commands), and not just text.
* Remove dedup from services/shhext. Because now we process in status-protocol, dedup makes less sense, as those messages are going to be processed anyway, so removing for now, we can re-evaluate if bringing it to status-go or not.
* Change the various retrieveX method to a single one:
`RetrieveAll` will be processing those messages that it can process (Currently only `Message`), and return the rest in `RawMessages` (still transit). The format for the response is:
`Chats`: -> The chats updated by receiving the message
`Messages`: -> The messages retrieved (already matched to a chat)
`Contacts`: -> The contacts updated by the messages
`RawMessages` -> Anything else that can't be parsed, eventually as we move everything to status-protocol-go this will go away.
2019-12-05 16:25:34 +00:00
|
|
|
"github.com/status-im/status-go/protocol/protobuf"
|
2019-11-21 16:19:22 +00:00
|
|
|
"github.com/status-im/status-go/protocol/sqlite"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestTableUserMessagesAllFieldsCount(t *testing.T) {
|
|
|
|
db := sqlitePersistence{}
|
2020-05-20 12:16:12 +00:00
|
|
|
expected := len(strings.Split(db.tableUserMessagesAllFields(), ","))
|
|
|
|
require.Equal(t, expected, db.tableUserMessagesAllFieldsCount())
|
2019-11-21 16:19:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestSaveMessages(t *testing.T) {
|
|
|
|
db, err := openTestDB()
|
|
|
|
require.NoError(t, err)
|
2022-03-28 10:10:40 +00:00
|
|
|
p := newSQLitePersistence(db)
|
2019-11-21 16:19:22 +00:00
|
|
|
|
|
|
|
for i := 0; i < 10; i++ {
|
|
|
|
id := strconv.Itoa(i)
|
|
|
|
err := insertMinimalMessage(p, id)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
m, err := p.MessageByID(id)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.EqualValues(t, id, m.ID)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Add replies to messages
Currently replies to messages are handled in status-react.
This causes some issues with the fact that sometimes replies might come
out of order, they might be offloaded to the database etc.
This commit changes the behavior so that status-go always returns the
replies, and in case a reply comes out of order (first the reply, later
the message being replied to), it will include in the messages the
updated message.
It also adds some fields (RTL,Replace,LineCount) to the database which
were not previously saved, resulting in some potential bugs.
The method that we use to pull replies is currently a bit naive, we just
pull all the message again from the database, but has the advantage of
being simple. It will go through performance testing to make sure
performnace are acceptable, if so I think it's reasonable to avoid some
complexity.
2020-04-08 13:42:02 +00:00
|
|
|
func TestMessagesByIDs(t *testing.T) {
|
|
|
|
db, err := openTestDB()
|
|
|
|
require.NoError(t, err)
|
2022-03-28 10:10:40 +00:00
|
|
|
p := newSQLitePersistence(db)
|
Add replies to messages
Currently replies to messages are handled in status-react.
This causes some issues with the fact that sometimes replies might come
out of order, they might be offloaded to the database etc.
This commit changes the behavior so that status-go always returns the
replies, and in case a reply comes out of order (first the reply, later
the message being replied to), it will include in the messages the
updated message.
It also adds some fields (RTL,Replace,LineCount) to the database which
were not previously saved, resulting in some potential bugs.
The method that we use to pull replies is currently a bit naive, we just
pull all the message again from the database, but has the advantage of
being simple. It will go through performance testing to make sure
performnace are acceptable, if so I think it's reasonable to avoid some
complexity.
2020-04-08 13:42:02 +00:00
|
|
|
|
|
|
|
var ids []string
|
|
|
|
for i := 0; i < 10; i++ {
|
|
|
|
id := strconv.Itoa(i)
|
|
|
|
err := insertMinimalMessage(p, id)
|
|
|
|
require.NoError(t, err)
|
|
|
|
ids = append(ids, id)
|
|
|
|
|
|
|
|
}
|
|
|
|
m, err := p.MessagesByIDs(ids)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, m, 10)
|
|
|
|
}
|
|
|
|
|
2022-09-20 09:13:44 +00:00
|
|
|
func TestMessagesByIDs_WithDiscordMessagesPayload(t *testing.T) {
|
|
|
|
db, err := openTestDB()
|
|
|
|
require.NoError(t, err)
|
|
|
|
p := newSQLitePersistence(db)
|
|
|
|
|
|
|
|
var ids []string
|
|
|
|
for i := 0; i < 10; i++ {
|
|
|
|
id := strconv.Itoa(i)
|
|
|
|
err := insertMinimalMessage(p, id)
|
|
|
|
require.NoError(t, err)
|
|
|
|
err = insertMinimalDiscordMessage(p, id, id)
|
|
|
|
require.NoError(t, err)
|
|
|
|
ids = append(ids, id)
|
|
|
|
}
|
|
|
|
|
|
|
|
m, err := p.MessagesByIDs(ids)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, m, 10)
|
|
|
|
|
|
|
|
for _, _m := range m {
|
|
|
|
require.NotNil(t, _m.GetDiscordMessage())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-21 16:19:22 +00:00
|
|
|
func TestMessageByID(t *testing.T) {
|
|
|
|
db, err := openTestDB()
|
|
|
|
require.NoError(t, err)
|
2022-03-28 10:10:40 +00:00
|
|
|
p := newSQLitePersistence(db)
|
2019-11-21 16:19:22 +00:00
|
|
|
id := "1"
|
|
|
|
|
|
|
|
err = insertMinimalMessage(p, id)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
m, err := p.MessageByID(id)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.EqualValues(t, id, m.ID)
|
|
|
|
}
|
|
|
|
|
2022-08-04 16:16:56 +00:00
|
|
|
func TestMessageByID_WithDiscordMessagePayload(t *testing.T) {
|
|
|
|
|
|
|
|
db, err := openTestDB()
|
|
|
|
require.NoError(t, err)
|
|
|
|
p := newSQLitePersistence(db)
|
|
|
|
id := "1"
|
|
|
|
discordMessageID := "2"
|
|
|
|
|
|
|
|
err = insertMinimalDiscordMessage(p, id, discordMessageID)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
m, err := p.MessageByID(id)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.EqualValues(t, id, m.ID)
|
|
|
|
require.NotNil(t, m.GetDiscordMessage())
|
|
|
|
require.EqualValues(t, discordMessageID, m.GetDiscordMessage().Id)
|
|
|
|
require.EqualValues(t, "2", m.GetDiscordMessage().Author.Id)
|
|
|
|
}
|
|
|
|
|
2022-09-20 09:13:44 +00:00
|
|
|
func TestMessageByID_WithDiscordMessageAttachmentPayload(t *testing.T) {
|
|
|
|
|
|
|
|
db, err := openTestDB()
|
|
|
|
require.NoError(t, err)
|
|
|
|
p := newSQLitePersistence(db)
|
|
|
|
id := "1"
|
|
|
|
discordMessageID := "2"
|
|
|
|
|
|
|
|
err = insertDiscordMessageWithAttachments(p, id, discordMessageID)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
m, err := p.MessageByID(id)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.EqualValues(t, id, m.ID)
|
|
|
|
|
|
|
|
dm := m.GetDiscordMessage()
|
|
|
|
require.NotNil(t, dm)
|
|
|
|
require.EqualValues(t, discordMessageID, dm.Id)
|
|
|
|
|
|
|
|
require.NotNil(t, dm.Attachments)
|
|
|
|
require.Len(t, dm.Attachments, 2)
|
|
|
|
}
|
|
|
|
|
2019-11-21 16:19:22 +00:00
|
|
|
func TestMessagesExist(t *testing.T) {
|
|
|
|
db, err := openTestDB()
|
|
|
|
require.NoError(t, err)
|
2022-03-28 10:10:40 +00:00
|
|
|
p := newSQLitePersistence(db)
|
2019-11-21 16:19:22 +00:00
|
|
|
|
|
|
|
err = insertMinimalMessage(p, "1")
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
result, err := p.MessagesExist([]string{"1"})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
require.True(t, result["1"])
|
|
|
|
|
|
|
|
err = insertMinimalMessage(p, "2")
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
result, err = p.MessagesExist([]string{"1", "2", "3"})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
require.True(t, result["1"])
|
|
|
|
require.True(t, result["2"])
|
|
|
|
require.False(t, result["3"])
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestMessageByChatID(t *testing.T) {
|
|
|
|
db, err := openTestDB()
|
|
|
|
require.NoError(t, err)
|
2022-03-28 10:10:40 +00:00
|
|
|
p := newSQLitePersistence(db)
|
2020-02-21 14:48:53 +00:00
|
|
|
chatID := testPublicChatID
|
2019-11-21 16:19:22 +00:00
|
|
|
count := 1000
|
|
|
|
pageSize := 50
|
|
|
|
|
2020-09-01 13:27:01 +00:00
|
|
|
var messages []*common.Message
|
2019-11-21 16:19:22 +00:00
|
|
|
for i := 0; i < count; i++ {
|
2020-09-01 13:27:01 +00:00
|
|
|
messages = append(messages, &common.Message{
|
Move to protobuf for Message type (#1706)
* Use a single Message type `v1/message.go` and `message.go` are the same now, and they embed `protobuf.ChatMessage`
* Use `SendChatMessage` for sending chat messages, this is basically the old `Send` but a bit more flexible so we can send different message types (stickers,commands), and not just text.
* Remove dedup from services/shhext. Because now we process in status-protocol, dedup makes less sense, as those messages are going to be processed anyway, so removing for now, we can re-evaluate if bringing it to status-go or not.
* Change the various retrieveX method to a single one:
`RetrieveAll` will be processing those messages that it can process (Currently only `Message`), and return the rest in `RawMessages` (still transit). The format for the response is:
`Chats`: -> The chats updated by receiving the message
`Messages`: -> The messages retrieved (already matched to a chat)
`Contacts`: -> The contacts updated by the messages
`RawMessages` -> Anything else that can't be parsed, eventually as we move everything to status-protocol-go this will go away.
2019-12-05 16:25:34 +00:00
|
|
|
ID: strconv.Itoa(i),
|
|
|
|
LocalChatID: chatID,
|
|
|
|
ChatMessage: protobuf.ChatMessage{
|
|
|
|
Clock: uint64(i),
|
|
|
|
},
|
|
|
|
From: "me",
|
2019-11-21 16:19:22 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
// Add some other chats.
|
|
|
|
if count%5 == 0 {
|
2020-09-01 13:27:01 +00:00
|
|
|
messages = append(messages, &common.Message{
|
Move to protobuf for Message type (#1706)
* Use a single Message type `v1/message.go` and `message.go` are the same now, and they embed `protobuf.ChatMessage`
* Use `SendChatMessage` for sending chat messages, this is basically the old `Send` but a bit more flexible so we can send different message types (stickers,commands), and not just text.
* Remove dedup from services/shhext. Because now we process in status-protocol, dedup makes less sense, as those messages are going to be processed anyway, so removing for now, we can re-evaluate if bringing it to status-go or not.
* Change the various retrieveX method to a single one:
`RetrieveAll` will be processing those messages that it can process (Currently only `Message`), and return the rest in `RawMessages` (still transit). The format for the response is:
`Chats`: -> The chats updated by receiving the message
`Messages`: -> The messages retrieved (already matched to a chat)
`Contacts`: -> The contacts updated by the messages
`RawMessages` -> Anything else that can't be parsed, eventually as we move everything to status-protocol-go this will go away.
2019-12-05 16:25:34 +00:00
|
|
|
ID: strconv.Itoa(count + i),
|
|
|
|
LocalChatID: "other-chat",
|
|
|
|
ChatMessage: protobuf.ChatMessage{
|
|
|
|
Clock: uint64(i),
|
|
|
|
},
|
|
|
|
|
|
|
|
From: "me",
|
2019-11-21 16:19:22 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add some out-of-order message. Add more than page size.
|
|
|
|
outOfOrderCount := pageSize + 1
|
|
|
|
allCount := count + outOfOrderCount
|
|
|
|
for i := 0; i < pageSize+1; i++ {
|
2020-09-01 13:27:01 +00:00
|
|
|
messages = append(messages, &common.Message{
|
Move to protobuf for Message type (#1706)
* Use a single Message type `v1/message.go` and `message.go` are the same now, and they embed `protobuf.ChatMessage`
* Use `SendChatMessage` for sending chat messages, this is basically the old `Send` but a bit more flexible so we can send different message types (stickers,commands), and not just text.
* Remove dedup from services/shhext. Because now we process in status-protocol, dedup makes less sense, as those messages are going to be processed anyway, so removing for now, we can re-evaluate if bringing it to status-go or not.
* Change the various retrieveX method to a single one:
`RetrieveAll` will be processing those messages that it can process (Currently only `Message`), and return the rest in `RawMessages` (still transit). The format for the response is:
`Chats`: -> The chats updated by receiving the message
`Messages`: -> The messages retrieved (already matched to a chat)
`Contacts`: -> The contacts updated by the messages
`RawMessages` -> Anything else that can't be parsed, eventually as we move everything to status-protocol-go this will go away.
2019-12-05 16:25:34 +00:00
|
|
|
ID: strconv.Itoa(count*2 + i),
|
|
|
|
LocalChatID: chatID,
|
|
|
|
ChatMessage: protobuf.ChatMessage{
|
|
|
|
Clock: uint64(i),
|
|
|
|
},
|
|
|
|
|
|
|
|
From: "me",
|
2019-11-21 16:19:22 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-05-20 12:16:12 +00:00
|
|
|
err = p.SaveMessages(messages)
|
2019-11-21 16:19:22 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
var (
|
2020-09-01 13:27:01 +00:00
|
|
|
result []*common.Message
|
2019-11-21 16:19:22 +00:00
|
|
|
cursor string
|
|
|
|
iter int
|
|
|
|
)
|
|
|
|
for {
|
|
|
|
var (
|
2020-09-01 13:27:01 +00:00
|
|
|
items []*common.Message
|
2019-11-21 16:19:22 +00:00
|
|
|
err error
|
|
|
|
)
|
|
|
|
|
|
|
|
items, cursor, err = p.MessageByChatID(chatID, cursor, pageSize)
|
|
|
|
require.NoError(t, err)
|
|
|
|
result = append(result, items...)
|
|
|
|
|
|
|
|
iter++
|
|
|
|
if len(cursor) == 0 || iter > count {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
require.Equal(t, "", cursor) // for loop should exit because of cursor being empty
|
|
|
|
require.EqualValues(t, math.Ceil(float64(allCount)/float64(pageSize)), iter)
|
|
|
|
require.Equal(t, len(result), allCount)
|
|
|
|
require.True(
|
|
|
|
t,
|
|
|
|
// Verify descending order.
|
|
|
|
sort.SliceIsSorted(result, func(i, j int) bool {
|
Move to protobuf for Message type (#1706)
* Use a single Message type `v1/message.go` and `message.go` are the same now, and they embed `protobuf.ChatMessage`
* Use `SendChatMessage` for sending chat messages, this is basically the old `Send` but a bit more flexible so we can send different message types (stickers,commands), and not just text.
* Remove dedup from services/shhext. Because now we process in status-protocol, dedup makes less sense, as those messages are going to be processed anyway, so removing for now, we can re-evaluate if bringing it to status-go or not.
* Change the various retrieveX method to a single one:
`RetrieveAll` will be processing those messages that it can process (Currently only `Message`), and return the rest in `RawMessages` (still transit). The format for the response is:
`Chats`: -> The chats updated by receiving the message
`Messages`: -> The messages retrieved (already matched to a chat)
`Contacts`: -> The contacts updated by the messages
`RawMessages` -> Anything else that can't be parsed, eventually as we move everything to status-protocol-go this will go away.
2019-12-05 16:25:34 +00:00
|
|
|
return result[i].Clock > result[j].Clock
|
2019-11-21 16:19:22 +00:00
|
|
|
}),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2022-12-11 19:08:51 +00:00
|
|
|
func TestFirstUnseenMessageIDByChatID(t *testing.T) {
|
|
|
|
db, err := openTestDB()
|
|
|
|
require.NoError(t, err)
|
|
|
|
p := newSQLitePersistence(db)
|
|
|
|
|
|
|
|
messageID, err := p.FirstUnseenMessageID(testPublicChatID)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, "", messageID)
|
|
|
|
|
|
|
|
err = p.SaveMessages([]*common.Message{
|
|
|
|
{
|
|
|
|
ID: "1",
|
|
|
|
LocalChatID: testPublicChatID,
|
|
|
|
ChatMessage: protobuf.ChatMessage{
|
|
|
|
Clock: 1,
|
|
|
|
Text: "some-text"},
|
|
|
|
From: "me",
|
|
|
|
Seen: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
ID: "2",
|
|
|
|
LocalChatID: testPublicChatID,
|
|
|
|
ChatMessage: protobuf.ChatMessage{
|
|
|
|
Clock: 2,
|
|
|
|
Text: "some-text"},
|
|
|
|
From: "me",
|
|
|
|
Seen: false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
ID: "3",
|
|
|
|
LocalChatID: testPublicChatID,
|
|
|
|
ChatMessage: protobuf.ChatMessage{
|
|
|
|
Clock: 3,
|
|
|
|
Text: "some-text"},
|
|
|
|
From: "me",
|
|
|
|
Seen: false,
|
|
|
|
},
|
|
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
messageID, err = p.FirstUnseenMessageID(testPublicChatID)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, "2", messageID)
|
|
|
|
}
|
|
|
|
|
2022-11-17 10:11:58 +00:00
|
|
|
func TestLatestMessageByChatID(t *testing.T) {
|
|
|
|
db, err := openTestDB()
|
|
|
|
require.NoError(t, err)
|
|
|
|
p := newSQLitePersistence(db)
|
|
|
|
|
|
|
|
var ids []string
|
|
|
|
for i := 0; i < 10; i++ {
|
|
|
|
id := strconv.Itoa(i)
|
|
|
|
err := insertMinimalMessage(p, id)
|
|
|
|
require.NoError(t, err)
|
|
|
|
ids = append(ids, id)
|
|
|
|
}
|
|
|
|
|
|
|
|
id := strconv.Itoa(10)
|
|
|
|
err = insertMinimalDeletedMessage(p, id)
|
|
|
|
require.NoError(t, err)
|
|
|
|
ids = append(ids, id)
|
|
|
|
|
|
|
|
id = strconv.Itoa(11)
|
|
|
|
err = insertMinimalDeletedForMeMessage(p, id)
|
|
|
|
require.NoError(t, err)
|
|
|
|
ids = append(ids, id)
|
|
|
|
|
|
|
|
m, err := p.LatestMessageByChatID(testPublicChatID)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, m[0].ID, ids[9])
|
|
|
|
}
|
|
|
|
|
2022-09-02 08:36:07 +00:00
|
|
|
func TestOldestMessageWhisperTimestampByChatID(t *testing.T) {
|
|
|
|
db, err := openTestDB()
|
|
|
|
require.NoError(t, err)
|
|
|
|
p := newSQLitePersistence(db)
|
|
|
|
chatID := testPublicChatID
|
|
|
|
|
|
|
|
_, hasMessage, err := p.OldestMessageWhisperTimestampByChatID(chatID)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.False(t, hasMessage)
|
|
|
|
|
|
|
|
var messages []*common.Message
|
|
|
|
for i := 0; i < 10; i++ {
|
|
|
|
messages = append(messages, &common.Message{
|
|
|
|
ID: strconv.Itoa(i),
|
|
|
|
LocalChatID: chatID,
|
|
|
|
ChatMessage: protobuf.ChatMessage{
|
|
|
|
Clock: uint64(i),
|
|
|
|
},
|
|
|
|
WhisperTimestamp: uint64(i + 10),
|
|
|
|
From: "me",
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
err = p.SaveMessages(messages)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
timestamp, hasMessage, err := p.OldestMessageWhisperTimestampByChatID(chatID)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.True(t, hasMessage)
|
|
|
|
require.Equal(t, uint64(10), timestamp)
|
|
|
|
}
|
|
|
|
|
2021-05-14 21:22:50 +00:00
|
|
|
func TestPinMessageByChatID(t *testing.T) {
|
|
|
|
db, err := openTestDB()
|
|
|
|
require.NoError(t, err)
|
|
|
|
p := sqlitePersistence{db: db}
|
|
|
|
chatID := "chat-with-pinned-messages"
|
|
|
|
messagesCount := 1000
|
|
|
|
pageSize := 5
|
|
|
|
pinnedMessagesCount := 0
|
|
|
|
|
|
|
|
var messages []*common.Message
|
|
|
|
var pinMessages []*common.PinMessage
|
|
|
|
for i := 0; i < messagesCount; i++ {
|
|
|
|
messages = append(messages, &common.Message{
|
|
|
|
ID: strconv.Itoa(i),
|
|
|
|
LocalChatID: chatID,
|
|
|
|
ChatMessage: protobuf.ChatMessage{
|
|
|
|
Clock: uint64(i),
|
|
|
|
},
|
|
|
|
From: "me",
|
|
|
|
})
|
|
|
|
|
|
|
|
// Pin this message
|
|
|
|
if i%100 == 0 {
|
2021-06-08 15:23:32 +00:00
|
|
|
from := "me"
|
|
|
|
if i == 100 {
|
|
|
|
from = "them"
|
|
|
|
}
|
|
|
|
|
2021-05-14 21:22:50 +00:00
|
|
|
pinMessage := &common.PinMessage{
|
|
|
|
ID: strconv.Itoa(i),
|
|
|
|
LocalChatID: chatID,
|
2021-06-08 15:23:32 +00:00
|
|
|
From: from,
|
2021-05-14 21:22:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pinMessage.MessageId = strconv.Itoa(i)
|
|
|
|
pinMessage.Clock = 111
|
|
|
|
pinMessage.Pinned = true
|
|
|
|
pinMessages = append(pinMessages, pinMessage)
|
|
|
|
pinnedMessagesCount++
|
|
|
|
|
|
|
|
if i%200 == 0 {
|
|
|
|
// unpin a message
|
|
|
|
unpinMessage := &common.PinMessage{
|
|
|
|
ID: strconv.Itoa(i),
|
|
|
|
LocalChatID: chatID,
|
|
|
|
From: "me",
|
|
|
|
}
|
|
|
|
pinMessage.MessageId = strconv.Itoa(i)
|
|
|
|
unpinMessage.Clock = 333
|
|
|
|
unpinMessage.Pinned = false
|
|
|
|
pinMessages = append(pinMessages, unpinMessage)
|
|
|
|
pinnedMessagesCount--
|
|
|
|
|
|
|
|
// pinned before the unpin
|
|
|
|
pinMessage2 := &common.PinMessage{
|
|
|
|
ID: strconv.Itoa(i),
|
|
|
|
LocalChatID: chatID,
|
|
|
|
From: "me",
|
|
|
|
}
|
|
|
|
pinMessage2.MessageId = strconv.Itoa(i)
|
|
|
|
pinMessage2.Clock = 222
|
|
|
|
pinMessage2.Pinned = true
|
|
|
|
pinMessages = append(pinMessages, pinMessage2)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add some other chats.
|
|
|
|
if i%5 == 0 {
|
|
|
|
messages = append(messages, &common.Message{
|
|
|
|
ID: strconv.Itoa(messagesCount + i),
|
|
|
|
LocalChatID: "chat-without-pinned-messages",
|
|
|
|
ChatMessage: protobuf.ChatMessage{
|
|
|
|
Clock: uint64(i),
|
|
|
|
},
|
|
|
|
|
|
|
|
From: "me",
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
err = p.SaveMessages(messages)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
err = p.SavePinMessages(pinMessages)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
var (
|
|
|
|
result []*common.PinnedMessage
|
|
|
|
cursor string
|
|
|
|
iter int
|
|
|
|
)
|
|
|
|
for {
|
|
|
|
var (
|
|
|
|
items []*common.PinnedMessage
|
|
|
|
err error
|
|
|
|
)
|
|
|
|
|
|
|
|
items, cursor, err = p.PinnedMessageByChatID(chatID, cursor, pageSize)
|
|
|
|
require.NoError(t, err)
|
|
|
|
result = append(result, items...)
|
|
|
|
|
|
|
|
iter++
|
|
|
|
if len(cursor) == 0 || iter > messagesCount {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
2021-06-08 15:23:32 +00:00
|
|
|
|
2021-05-14 21:22:50 +00:00
|
|
|
require.Equal(t, "", cursor) // for loop should exit because of cursor being empty
|
|
|
|
require.EqualValues(t, pinnedMessagesCount, len(result))
|
|
|
|
require.EqualValues(t, math.Ceil(float64(pinnedMessagesCount)/float64(pageSize)), iter)
|
|
|
|
require.True(
|
|
|
|
t,
|
|
|
|
// Verify descending order.
|
|
|
|
sort.SliceIsSorted(result, func(i, j int) bool {
|
2021-06-08 15:23:32 +00:00
|
|
|
return result[i].Message.Clock > result[j].Message.Clock
|
2021-05-14 21:22:50 +00:00
|
|
|
}),
|
|
|
|
)
|
2021-06-08 15:23:32 +00:00
|
|
|
|
|
|
|
require.Equal(t, "them", result[len(result)-1].PinnedBy)
|
|
|
|
for i := 0; i < len(result)-1; i++ {
|
|
|
|
require.Equal(t, "me", result[i].PinnedBy)
|
|
|
|
}
|
2021-05-14 21:22:50 +00:00
|
|
|
}
|
|
|
|
|
2019-11-21 16:19:22 +00:00
|
|
|
func TestMessageReplies(t *testing.T) {
|
|
|
|
db, err := openTestDB()
|
|
|
|
require.NoError(t, err)
|
2022-03-28 10:10:40 +00:00
|
|
|
p := newSQLitePersistence(db)
|
2020-02-21 14:48:53 +00:00
|
|
|
chatID := testPublicChatID
|
2020-09-01 13:27:01 +00:00
|
|
|
message1 := &common.Message{
|
Move to protobuf for Message type (#1706)
* Use a single Message type `v1/message.go` and `message.go` are the same now, and they embed `protobuf.ChatMessage`
* Use `SendChatMessage` for sending chat messages, this is basically the old `Send` but a bit more flexible so we can send different message types (stickers,commands), and not just text.
* Remove dedup from services/shhext. Because now we process in status-protocol, dedup makes less sense, as those messages are going to be processed anyway, so removing for now, we can re-evaluate if bringing it to status-go or not.
* Change the various retrieveX method to a single one:
`RetrieveAll` will be processing those messages that it can process (Currently only `Message`), and return the rest in `RawMessages` (still transit). The format for the response is:
`Chats`: -> The chats updated by receiving the message
`Messages`: -> The messages retrieved (already matched to a chat)
`Contacts`: -> The contacts updated by the messages
`RawMessages` -> Anything else that can't be parsed, eventually as we move everything to status-protocol-go this will go away.
2019-12-05 16:25:34 +00:00
|
|
|
ID: "id-1",
|
|
|
|
LocalChatID: chatID,
|
|
|
|
ChatMessage: protobuf.ChatMessage{
|
|
|
|
Text: "content-1",
|
|
|
|
Clock: uint64(1),
|
|
|
|
},
|
|
|
|
From: "1",
|
2019-11-21 16:19:22 +00:00
|
|
|
}
|
2020-09-01 13:27:01 +00:00
|
|
|
message2 := &common.Message{
|
Move to protobuf for Message type (#1706)
* Use a single Message type `v1/message.go` and `message.go` are the same now, and they embed `protobuf.ChatMessage`
* Use `SendChatMessage` for sending chat messages, this is basically the old `Send` but a bit more flexible so we can send different message types (stickers,commands), and not just text.
* Remove dedup from services/shhext. Because now we process in status-protocol, dedup makes less sense, as those messages are going to be processed anyway, so removing for now, we can re-evaluate if bringing it to status-go or not.
* Change the various retrieveX method to a single one:
`RetrieveAll` will be processing those messages that it can process (Currently only `Message`), and return the rest in `RawMessages` (still transit). The format for the response is:
`Chats`: -> The chats updated by receiving the message
`Messages`: -> The messages retrieved (already matched to a chat)
`Contacts`: -> The contacts updated by the messages
`RawMessages` -> Anything else that can't be parsed, eventually as we move everything to status-protocol-go this will go away.
2019-12-05 16:25:34 +00:00
|
|
|
ID: "id-2",
|
|
|
|
LocalChatID: chatID,
|
|
|
|
ChatMessage: protobuf.ChatMessage{
|
|
|
|
Text: "content-2",
|
|
|
|
Clock: uint64(2),
|
|
|
|
ResponseTo: "id-1",
|
|
|
|
},
|
|
|
|
|
|
|
|
From: "2",
|
2019-11-21 16:19:22 +00:00
|
|
|
}
|
|
|
|
|
2020-09-01 13:27:01 +00:00
|
|
|
message3 := &common.Message{
|
Move to protobuf for Message type (#1706)
* Use a single Message type `v1/message.go` and `message.go` are the same now, and they embed `protobuf.ChatMessage`
* Use `SendChatMessage` for sending chat messages, this is basically the old `Send` but a bit more flexible so we can send different message types (stickers,commands), and not just text.
* Remove dedup from services/shhext. Because now we process in status-protocol, dedup makes less sense, as those messages are going to be processed anyway, so removing for now, we can re-evaluate if bringing it to status-go or not.
* Change the various retrieveX method to a single one:
`RetrieveAll` will be processing those messages that it can process (Currently only `Message`), and return the rest in `RawMessages` (still transit). The format for the response is:
`Chats`: -> The chats updated by receiving the message
`Messages`: -> The messages retrieved (already matched to a chat)
`Contacts`: -> The contacts updated by the messages
`RawMessages` -> Anything else that can't be parsed, eventually as we move everything to status-protocol-go this will go away.
2019-12-05 16:25:34 +00:00
|
|
|
ID: "id-3",
|
|
|
|
LocalChatID: chatID,
|
|
|
|
ChatMessage: protobuf.ChatMessage{
|
|
|
|
Text: "content-3",
|
|
|
|
Clock: uint64(3),
|
|
|
|
ResponseTo: "non-existing",
|
|
|
|
},
|
|
|
|
From: "3",
|
2019-11-21 16:19:22 +00:00
|
|
|
}
|
|
|
|
|
2023-01-09 16:38:24 +00:00
|
|
|
// Message that is deleted
|
|
|
|
message4 := &common.Message{
|
|
|
|
ID: "id-4",
|
|
|
|
LocalChatID: chatID,
|
|
|
|
Deleted: true,
|
|
|
|
ChatMessage: protobuf.ChatMessage{
|
|
|
|
Text: "content-4",
|
|
|
|
Clock: uint64(4),
|
|
|
|
},
|
|
|
|
From: "2",
|
|
|
|
}
|
|
|
|
|
|
|
|
// Message replied to a deleted message. It will not have QuotedMessage info
|
|
|
|
message5 := &common.Message{
|
|
|
|
ID: "id-5",
|
|
|
|
LocalChatID: chatID,
|
|
|
|
ChatMessage: protobuf.ChatMessage{
|
|
|
|
Text: "content-4",
|
|
|
|
Clock: uint64(5),
|
|
|
|
ResponseTo: "id-4",
|
|
|
|
},
|
|
|
|
From: "3",
|
|
|
|
}
|
|
|
|
|
|
|
|
// messages := []*common.Message{message1, message2, message3}
|
|
|
|
messages := []*common.Message{message1, message2, message3, message4, message5}
|
2019-11-21 16:19:22 +00:00
|
|
|
|
2020-05-20 12:16:12 +00:00
|
|
|
err = p.SaveMessages(messages)
|
2019-11-21 16:19:22 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
retrievedMessages, _, err := p.MessageByChatID(chatID, "", 10)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
2023-01-09 16:38:24 +00:00
|
|
|
require.Equal(t, "non-existing", retrievedMessages[2].ResponseTo)
|
|
|
|
require.Nil(t, retrievedMessages[2].QuotedMessage)
|
2019-11-21 16:19:22 +00:00
|
|
|
|
2023-01-09 16:38:24 +00:00
|
|
|
require.Equal(t, "id-1", retrievedMessages[3].ResponseTo)
|
|
|
|
require.Equal(t, &common.QuotedMessage{ID: "id-1", From: "1", Text: "content-1"}, retrievedMessages[3].QuotedMessage)
|
2019-11-21 16:19:22 +00:00
|
|
|
|
2023-01-09 16:38:24 +00:00
|
|
|
require.Equal(t, "", retrievedMessages[4].ResponseTo)
|
|
|
|
require.Nil(t, retrievedMessages[4].QuotedMessage)
|
|
|
|
|
|
|
|
// We have a ResponseTo, but no QuotedMessage, since the message was deleted
|
|
|
|
require.Equal(t, "id-4", retrievedMessages[0].ResponseTo)
|
|
|
|
require.Nil(t, retrievedMessages[0].QuotedMessage)
|
2019-11-21 16:19:22 +00:00
|
|
|
}
|
|
|
|
|
Move to protobuf for Message type (#1706)
* Use a single Message type `v1/message.go` and `message.go` are the same now, and they embed `protobuf.ChatMessage`
* Use `SendChatMessage` for sending chat messages, this is basically the old `Send` but a bit more flexible so we can send different message types (stickers,commands), and not just text.
* Remove dedup from services/shhext. Because now we process in status-protocol, dedup makes less sense, as those messages are going to be processed anyway, so removing for now, we can re-evaluate if bringing it to status-go or not.
* Change the various retrieveX method to a single one:
`RetrieveAll` will be processing those messages that it can process (Currently only `Message`), and return the rest in `RawMessages` (still transit). The format for the response is:
`Chats`: -> The chats updated by receiving the message
`Messages`: -> The messages retrieved (already matched to a chat)
`Contacts`: -> The contacts updated by the messages
`RawMessages` -> Anything else that can't be parsed, eventually as we move everything to status-protocol-go this will go away.
2019-12-05 16:25:34 +00:00
|
|
|
func TestMessageByChatIDWithTheSameClocks(t *testing.T) {
|
2019-11-21 16:19:22 +00:00
|
|
|
db, err := openTestDB()
|
|
|
|
require.NoError(t, err)
|
2022-03-28 10:10:40 +00:00
|
|
|
p := newSQLitePersistence(db)
|
2020-02-21 14:48:53 +00:00
|
|
|
chatID := testPublicChatID
|
Move to protobuf for Message type (#1706)
* Use a single Message type `v1/message.go` and `message.go` are the same now, and they embed `protobuf.ChatMessage`
* Use `SendChatMessage` for sending chat messages, this is basically the old `Send` but a bit more flexible so we can send different message types (stickers,commands), and not just text.
* Remove dedup from services/shhext. Because now we process in status-protocol, dedup makes less sense, as those messages are going to be processed anyway, so removing for now, we can re-evaluate if bringing it to status-go or not.
* Change the various retrieveX method to a single one:
`RetrieveAll` will be processing those messages that it can process (Currently only `Message`), and return the rest in `RawMessages` (still transit). The format for the response is:
`Chats`: -> The chats updated by receiving the message
`Messages`: -> The messages retrieved (already matched to a chat)
`Contacts`: -> The contacts updated by the messages
`RawMessages` -> Anything else that can't be parsed, eventually as we move everything to status-protocol-go this will go away.
2019-12-05 16:25:34 +00:00
|
|
|
clockValues := []uint64{10, 10, 9, 9, 9, 11, 12, 11, 100000, 6, 4, 5, 5, 5, 5}
|
2019-11-21 16:19:22 +00:00
|
|
|
count := len(clockValues)
|
|
|
|
pageSize := 2
|
|
|
|
|
2020-09-01 13:27:01 +00:00
|
|
|
var messages []*common.Message
|
2019-11-21 16:19:22 +00:00
|
|
|
|
|
|
|
for i, clock := range clockValues {
|
2020-09-01 13:27:01 +00:00
|
|
|
messages = append(messages, &common.Message{
|
Move to protobuf for Message type (#1706)
* Use a single Message type `v1/message.go` and `message.go` are the same now, and they embed `protobuf.ChatMessage`
* Use `SendChatMessage` for sending chat messages, this is basically the old `Send` but a bit more flexible so we can send different message types (stickers,commands), and not just text.
* Remove dedup from services/shhext. Because now we process in status-protocol, dedup makes less sense, as those messages are going to be processed anyway, so removing for now, we can re-evaluate if bringing it to status-go or not.
* Change the various retrieveX method to a single one:
`RetrieveAll` will be processing those messages that it can process (Currently only `Message`), and return the rest in `RawMessages` (still transit). The format for the response is:
`Chats`: -> The chats updated by receiving the message
`Messages`: -> The messages retrieved (already matched to a chat)
`Contacts`: -> The contacts updated by the messages
`RawMessages` -> Anything else that can't be parsed, eventually as we move everything to status-protocol-go this will go away.
2019-12-05 16:25:34 +00:00
|
|
|
ID: strconv.Itoa(i),
|
|
|
|
LocalChatID: chatID,
|
|
|
|
ChatMessage: protobuf.ChatMessage{
|
|
|
|
Clock: clock,
|
|
|
|
},
|
|
|
|
From: "me",
|
2019-11-21 16:19:22 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-05-20 12:16:12 +00:00
|
|
|
err = p.SaveMessages(messages)
|
2019-11-21 16:19:22 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
var (
|
2020-09-01 13:27:01 +00:00
|
|
|
result []*common.Message
|
2019-11-21 16:19:22 +00:00
|
|
|
cursor string
|
|
|
|
iter int
|
|
|
|
)
|
|
|
|
for {
|
|
|
|
var (
|
2020-09-01 13:27:01 +00:00
|
|
|
items []*common.Message
|
2019-11-21 16:19:22 +00:00
|
|
|
err error
|
|
|
|
)
|
|
|
|
|
|
|
|
items, cursor, err = p.MessageByChatID(chatID, cursor, pageSize)
|
|
|
|
require.NoError(t, err)
|
|
|
|
result = append(result, items...)
|
|
|
|
|
|
|
|
iter++
|
|
|
|
if cursor == "" || iter > count {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
require.Empty(t, cursor) // for loop should exit because of cursor being empty
|
|
|
|
require.Len(t, result, count)
|
|
|
|
// Verify the order.
|
Move to protobuf for Message type (#1706)
* Use a single Message type `v1/message.go` and `message.go` are the same now, and they embed `protobuf.ChatMessage`
* Use `SendChatMessage` for sending chat messages, this is basically the old `Send` but a bit more flexible so we can send different message types (stickers,commands), and not just text.
* Remove dedup from services/shhext. Because now we process in status-protocol, dedup makes less sense, as those messages are going to be processed anyway, so removing for now, we can re-evaluate if bringing it to status-go or not.
* Change the various retrieveX method to a single one:
`RetrieveAll` will be processing those messages that it can process (Currently only `Message`), and return the rest in `RawMessages` (still transit). The format for the response is:
`Chats`: -> The chats updated by receiving the message
`Messages`: -> The messages retrieved (already matched to a chat)
`Contacts`: -> The contacts updated by the messages
`RawMessages` -> Anything else that can't be parsed, eventually as we move everything to status-protocol-go this will go away.
2019-12-05 16:25:34 +00:00
|
|
|
expectedClocks := make([]uint64, len(clockValues))
|
|
|
|
copy(expectedClocks, clockValues)
|
|
|
|
sort.Slice(expectedClocks, func(i, j int) bool {
|
|
|
|
return expectedClocks[i] > expectedClocks[j]
|
2019-11-21 16:19:22 +00:00
|
|
|
})
|
Move to protobuf for Message type (#1706)
* Use a single Message type `v1/message.go` and `message.go` are the same now, and they embed `protobuf.ChatMessage`
* Use `SendChatMessage` for sending chat messages, this is basically the old `Send` but a bit more flexible so we can send different message types (stickers,commands), and not just text.
* Remove dedup from services/shhext. Because now we process in status-protocol, dedup makes less sense, as those messages are going to be processed anyway, so removing for now, we can re-evaluate if bringing it to status-go or not.
* Change the various retrieveX method to a single one:
`RetrieveAll` will be processing those messages that it can process (Currently only `Message`), and return the rest in `RawMessages` (still transit). The format for the response is:
`Chats`: -> The chats updated by receiving the message
`Messages`: -> The messages retrieved (already matched to a chat)
`Contacts`: -> The contacts updated by the messages
`RawMessages` -> Anything else that can't be parsed, eventually as we move everything to status-protocol-go this will go away.
2019-12-05 16:25:34 +00:00
|
|
|
resultClocks := make([]uint64, 0, len(clockValues))
|
2019-11-21 16:19:22 +00:00
|
|
|
for _, m := range result {
|
Move to protobuf for Message type (#1706)
* Use a single Message type `v1/message.go` and `message.go` are the same now, and they embed `protobuf.ChatMessage`
* Use `SendChatMessage` for sending chat messages, this is basically the old `Send` but a bit more flexible so we can send different message types (stickers,commands), and not just text.
* Remove dedup from services/shhext. Because now we process in status-protocol, dedup makes less sense, as those messages are going to be processed anyway, so removing for now, we can re-evaluate if bringing it to status-go or not.
* Change the various retrieveX method to a single one:
`RetrieveAll` will be processing those messages that it can process (Currently only `Message`), and return the rest in `RawMessages` (still transit). The format for the response is:
`Chats`: -> The chats updated by receiving the message
`Messages`: -> The messages retrieved (already matched to a chat)
`Contacts`: -> The contacts updated by the messages
`RawMessages` -> Anything else that can't be parsed, eventually as we move everything to status-protocol-go this will go away.
2019-12-05 16:25:34 +00:00
|
|
|
resultClocks = append(resultClocks, m.Clock)
|
2019-11-21 16:19:22 +00:00
|
|
|
}
|
Move to protobuf for Message type (#1706)
* Use a single Message type `v1/message.go` and `message.go` are the same now, and they embed `protobuf.ChatMessage`
* Use `SendChatMessage` for sending chat messages, this is basically the old `Send` but a bit more flexible so we can send different message types (stickers,commands), and not just text.
* Remove dedup from services/shhext. Because now we process in status-protocol, dedup makes less sense, as those messages are going to be processed anyway, so removing for now, we can re-evaluate if bringing it to status-go or not.
* Change the various retrieveX method to a single one:
`RetrieveAll` will be processing those messages that it can process (Currently only `Message`), and return the rest in `RawMessages` (still transit). The format for the response is:
`Chats`: -> The chats updated by receiving the message
`Messages`: -> The messages retrieved (already matched to a chat)
`Contacts`: -> The contacts updated by the messages
`RawMessages` -> Anything else that can't be parsed, eventually as we move everything to status-protocol-go this will go away.
2019-12-05 16:25:34 +00:00
|
|
|
require.EqualValues(t, expectedClocks, resultClocks)
|
2019-11-21 16:19:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestDeleteMessageByID(t *testing.T) {
|
|
|
|
db, err := openTestDB()
|
|
|
|
require.NoError(t, err)
|
2022-03-28 10:10:40 +00:00
|
|
|
p := newSQLitePersistence(db)
|
2019-11-21 16:19:22 +00:00
|
|
|
id := "1"
|
|
|
|
|
|
|
|
err = insertMinimalMessage(p, id)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
m, err := p.MessageByID(id)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, id, m.ID)
|
|
|
|
|
|
|
|
err = p.DeleteMessage(m.ID)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
_, err = p.MessageByID(id)
|
|
|
|
require.EqualError(t, err, "record not found")
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestDeleteMessagesByChatID(t *testing.T) {
|
|
|
|
db, err := openTestDB()
|
|
|
|
require.NoError(t, err)
|
2022-03-28 10:10:40 +00:00
|
|
|
p := newSQLitePersistence(db)
|
2019-11-21 16:19:22 +00:00
|
|
|
|
|
|
|
err = insertMinimalMessage(p, "1")
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
err = insertMinimalMessage(p, "2")
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
2020-09-01 13:27:01 +00:00
|
|
|
m, _, err := p.MessageByChatID(testPublicChatID, "", 10)
|
2019-11-21 16:19:22 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 2, len(m))
|
|
|
|
|
2020-09-01 13:27:01 +00:00
|
|
|
err = p.DeleteMessagesByChatID(testPublicChatID)
|
2019-11-21 16:19:22 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
2020-09-01 13:27:01 +00:00
|
|
|
m, _, err = p.MessageByChatID(testPublicChatID, "", 10)
|
2019-11-21 16:19:22 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 0, len(m))
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestMarkMessageSeen(t *testing.T) {
|
Move to protobuf for Message type (#1706)
* Use a single Message type `v1/message.go` and `message.go` are the same now, and they embed `protobuf.ChatMessage`
* Use `SendChatMessage` for sending chat messages, this is basically the old `Send` but a bit more flexible so we can send different message types (stickers,commands), and not just text.
* Remove dedup from services/shhext. Because now we process in status-protocol, dedup makes less sense, as those messages are going to be processed anyway, so removing for now, we can re-evaluate if bringing it to status-go or not.
* Change the various retrieveX method to a single one:
`RetrieveAll` will be processing those messages that it can process (Currently only `Message`), and return the rest in `RawMessages` (still transit). The format for the response is:
`Chats`: -> The chats updated by receiving the message
`Messages`: -> The messages retrieved (already matched to a chat)
`Contacts`: -> The contacts updated by the messages
`RawMessages` -> Anything else that can't be parsed, eventually as we move everything to status-protocol-go this will go away.
2019-12-05 16:25:34 +00:00
|
|
|
chatID := "test-chat"
|
2019-11-21 16:19:22 +00:00
|
|
|
db, err := openTestDB()
|
|
|
|
require.NoError(t, err)
|
2022-03-28 10:10:40 +00:00
|
|
|
p := newSQLitePersistence(db)
|
2019-11-21 16:19:22 +00:00
|
|
|
id := "1"
|
|
|
|
|
|
|
|
err = insertMinimalMessage(p, id)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
m, err := p.MessageByID(id)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.False(t, m.Seen)
|
|
|
|
|
2021-08-31 08:49:39 +00:00
|
|
|
count, countWithMention, err := p.MarkMessagesSeen(chatID, []string{m.ID})
|
2019-11-21 16:19:22 +00:00
|
|
|
require.NoError(t, err)
|
2020-04-06 12:08:53 +00:00
|
|
|
require.Equal(t, uint64(1), count)
|
2021-08-31 08:49:39 +00:00
|
|
|
require.Equal(t, uint64(0), countWithMention)
|
2019-11-21 16:19:22 +00:00
|
|
|
|
|
|
|
m, err = p.MessageByID(id)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.True(t, m.Seen)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestUpdateMessageOutgoingStatus(t *testing.T) {
|
|
|
|
db, err := openTestDB()
|
|
|
|
require.NoError(t, err)
|
2022-03-28 10:10:40 +00:00
|
|
|
p := newSQLitePersistence(db)
|
2019-11-21 16:19:22 +00:00
|
|
|
id := "1"
|
|
|
|
|
|
|
|
err = insertMinimalMessage(p, id)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
err = p.UpdateMessageOutgoingStatus(id, "new-status")
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
m, err := p.MessageByID(id)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, "new-status", m.OutgoingStatus)
|
|
|
|
}
|
|
|
|
|
2020-12-15 14:43:41 +00:00
|
|
|
func TestMessagesIDsByType(t *testing.T) {
|
|
|
|
db, err := openTestDB()
|
|
|
|
require.NoError(t, err)
|
2022-03-28 10:10:40 +00:00
|
|
|
p := newSQLitePersistence(db)
|
2020-12-15 14:43:41 +00:00
|
|
|
|
|
|
|
ids, err := p.RawMessagesIDsByType(protobuf.ApplicationMetadataMessage_CHAT_MESSAGE)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Empty(t, ids)
|
|
|
|
|
|
|
|
err = p.SaveRawMessage(minimalRawMessage("chat-message-id", protobuf.ApplicationMetadataMessage_CHAT_MESSAGE))
|
|
|
|
require.NoError(t, err)
|
|
|
|
ids, err = p.RawMessagesIDsByType(protobuf.ApplicationMetadataMessage_CHAT_MESSAGE)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 1, len(ids))
|
|
|
|
require.Equal(t, "chat-message-id", ids[0])
|
|
|
|
|
|
|
|
ids, err = p.RawMessagesIDsByType(protobuf.ApplicationMetadataMessage_EMOJI_REACTION)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Empty(t, ids)
|
|
|
|
|
|
|
|
err = p.SaveRawMessage(minimalRawMessage("emoji-message-id", protobuf.ApplicationMetadataMessage_EMOJI_REACTION))
|
|
|
|
require.NoError(t, err)
|
|
|
|
ids, err = p.RawMessagesIDsByType(protobuf.ApplicationMetadataMessage_EMOJI_REACTION)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 1, len(ids))
|
|
|
|
require.Equal(t, "emoji-message-id", ids[0])
|
|
|
|
}
|
|
|
|
|
2021-11-17 09:11:51 +00:00
|
|
|
func TestExpiredMessagesIDs(t *testing.T) {
|
2020-12-15 14:43:41 +00:00
|
|
|
db, err := openTestDB()
|
|
|
|
require.NoError(t, err)
|
2022-03-28 10:10:40 +00:00
|
|
|
p := newSQLitePersistence(db)
|
2020-12-15 14:43:41 +00:00
|
|
|
|
2021-11-17 09:11:51 +00:00
|
|
|
ids, err := p.ExpiredMessagesIDs(messageResendMaxCount)
|
2020-12-15 14:43:41 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Empty(t, ids)
|
|
|
|
|
|
|
|
//save expired emoji message
|
|
|
|
rawEmojiReaction := minimalRawMessage("emoji-message-id", protobuf.ApplicationMetadataMessage_EMOJI_REACTION)
|
|
|
|
rawEmojiReaction.Sent = false
|
|
|
|
err = p.SaveRawMessage(rawEmojiReaction)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
//make sure it appered in expired emoji reactions list
|
2021-11-17 09:11:51 +00:00
|
|
|
ids, err = p.ExpiredMessagesIDs(messageResendMaxCount)
|
2020-12-15 14:43:41 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 1, len(ids))
|
|
|
|
|
|
|
|
//save non-expired emoji reaction
|
|
|
|
rawEmojiReaction2 := minimalRawMessage("emoji-message-id2", protobuf.ApplicationMetadataMessage_EMOJI_REACTION)
|
|
|
|
rawEmojiReaction2.Sent = true
|
|
|
|
err = p.SaveRawMessage(rawEmojiReaction2)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
//make sure it didn't appear in expired emoji reactions list
|
2021-11-17 09:11:51 +00:00
|
|
|
ids, err = p.ExpiredMessagesIDs(messageResendMaxCount)
|
2020-12-15 14:43:41 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 1, len(ids))
|
|
|
|
}
|
|
|
|
|
2020-07-27 15:57:01 +00:00
|
|
|
func TestPersistenceEmojiReactions(t *testing.T) {
|
|
|
|
db, err := openTestDB()
|
|
|
|
require.NoError(t, err)
|
2022-03-28 10:10:40 +00:00
|
|
|
p := newSQLitePersistence(db)
|
2020-07-27 15:57:01 +00:00
|
|
|
// reverse order as we use DESC
|
|
|
|
id1 := "1"
|
|
|
|
id2 := "2"
|
|
|
|
id3 := "3"
|
|
|
|
|
|
|
|
from1 := "from-1"
|
|
|
|
from2 := "from-2"
|
|
|
|
from3 := "from-3"
|
|
|
|
|
2020-09-01 13:27:01 +00:00
|
|
|
chatID := testPublicChatID
|
2020-07-27 15:57:01 +00:00
|
|
|
|
|
|
|
err = insertMinimalMessage(p, id1)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
err = insertMinimalMessage(p, id2)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
err = insertMinimalMessage(p, id3)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
// Insert normal emoji reaction
|
|
|
|
require.NoError(t, p.SaveEmojiReaction(&EmojiReaction{
|
|
|
|
EmojiReaction: protobuf.EmojiReaction{
|
|
|
|
Clock: 1,
|
|
|
|
MessageId: id3,
|
|
|
|
ChatId: chatID,
|
|
|
|
Type: protobuf.EmojiReaction_SAD,
|
|
|
|
},
|
2020-07-28 07:53:32 +00:00
|
|
|
LocalChatID: chatID,
|
|
|
|
From: from1,
|
2020-07-27 15:57:01 +00:00
|
|
|
}))
|
|
|
|
|
|
|
|
// Insert retracted emoji reaction
|
|
|
|
require.NoError(t, p.SaveEmojiReaction(&EmojiReaction{
|
|
|
|
EmojiReaction: protobuf.EmojiReaction{
|
|
|
|
Clock: 1,
|
|
|
|
MessageId: id3,
|
|
|
|
ChatId: chatID,
|
|
|
|
Type: protobuf.EmojiReaction_SAD,
|
|
|
|
Retracted: true,
|
|
|
|
},
|
2020-07-28 07:53:32 +00:00
|
|
|
LocalChatID: chatID,
|
|
|
|
From: from2,
|
2020-07-27 15:57:01 +00:00
|
|
|
}))
|
|
|
|
|
|
|
|
// Insert retracted emoji reaction out of pagination
|
|
|
|
require.NoError(t, p.SaveEmojiReaction(&EmojiReaction{
|
|
|
|
EmojiReaction: protobuf.EmojiReaction{
|
|
|
|
Clock: 1,
|
|
|
|
MessageId: id1,
|
|
|
|
ChatId: chatID,
|
|
|
|
Type: protobuf.EmojiReaction_SAD,
|
|
|
|
},
|
2020-07-28 07:53:32 +00:00
|
|
|
LocalChatID: chatID,
|
|
|
|
From: from2,
|
2020-07-27 15:57:01 +00:00
|
|
|
}))
|
|
|
|
|
|
|
|
// Insert retracted emoji reaction out of pagination
|
|
|
|
require.NoError(t, p.SaveEmojiReaction(&EmojiReaction{
|
|
|
|
EmojiReaction: protobuf.EmojiReaction{
|
|
|
|
Clock: 1,
|
|
|
|
MessageId: id1,
|
|
|
|
ChatId: chatID,
|
|
|
|
Type: protobuf.EmojiReaction_SAD,
|
|
|
|
},
|
2020-07-28 07:53:32 +00:00
|
|
|
LocalChatID: chatID,
|
|
|
|
From: from3,
|
|
|
|
}))
|
|
|
|
|
|
|
|
// Wrong local chat id
|
|
|
|
require.NoError(t, p.SaveEmojiReaction(&EmojiReaction{
|
|
|
|
EmojiReaction: protobuf.EmojiReaction{
|
|
|
|
Clock: 1,
|
|
|
|
MessageId: id1,
|
|
|
|
ChatId: chatID,
|
|
|
|
Type: protobuf.EmojiReaction_LOVE,
|
|
|
|
},
|
|
|
|
LocalChatID: "wrong-chat-id",
|
|
|
|
From: from3,
|
2020-07-27 15:57:01 +00:00
|
|
|
}))
|
|
|
|
|
|
|
|
reactions, err := p.EmojiReactionsByChatID(chatID, "", 1)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, reactions, 1)
|
|
|
|
require.Equal(t, id3, reactions[0].MessageId)
|
|
|
|
|
|
|
|
// Try with a cursor
|
|
|
|
_, cursor, err := p.MessageByChatID(chatID, "", 1)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
reactions, err = p.EmojiReactionsByChatID(chatID, cursor, 2)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, reactions, 2)
|
|
|
|
require.Equal(t, id1, reactions[0].MessageId)
|
|
|
|
require.Equal(t, id1, reactions[1].MessageId)
|
|
|
|
}
|
|
|
|
|
2019-11-21 16:19:22 +00:00
|
|
|
func openTestDB() (*sql.DB, error) {
|
2022-08-31 14:41:58 +00:00
|
|
|
dbPath, err := ioutil.TempFile("", "status-go-test-db-")
|
2019-11-21 16:19:22 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2022-09-27 20:27:20 +00:00
|
|
|
return sqlite.Open(dbPath.Name(), "", sqlite.ReducedKDFIterationsNumber)
|
2019-11-21 16:19:22 +00:00
|
|
|
}
|
|
|
|
|
2021-03-09 12:48:15 +00:00
|
|
|
func insertMinimalMessage(p *sqlitePersistence, id string) error {
|
2020-09-01 13:27:01 +00:00
|
|
|
return p.SaveMessages([]*common.Message{{
|
Move to protobuf for Message type (#1706)
* Use a single Message type `v1/message.go` and `message.go` are the same now, and they embed `protobuf.ChatMessage`
* Use `SendChatMessage` for sending chat messages, this is basically the old `Send` but a bit more flexible so we can send different message types (stickers,commands), and not just text.
* Remove dedup from services/shhext. Because now we process in status-protocol, dedup makes less sense, as those messages are going to be processed anyway, so removing for now, we can re-evaluate if bringing it to status-go or not.
* Change the various retrieveX method to a single one:
`RetrieveAll` will be processing those messages that it can process (Currently only `Message`), and return the rest in `RawMessages` (still transit). The format for the response is:
`Chats`: -> The chats updated by receiving the message
`Messages`: -> The messages retrieved (already matched to a chat)
`Contacts`: -> The contacts updated by the messages
`RawMessages` -> Anything else that can't be parsed, eventually as we move everything to status-protocol-go this will go away.
2019-12-05 16:25:34 +00:00
|
|
|
ID: id,
|
2020-09-01 13:27:01 +00:00
|
|
|
LocalChatID: testPublicChatID,
|
Move to protobuf for Message type (#1706)
* Use a single Message type `v1/message.go` and `message.go` are the same now, and they embed `protobuf.ChatMessage`
* Use `SendChatMessage` for sending chat messages, this is basically the old `Send` but a bit more flexible so we can send different message types (stickers,commands), and not just text.
* Remove dedup from services/shhext. Because now we process in status-protocol, dedup makes less sense, as those messages are going to be processed anyway, so removing for now, we can re-evaluate if bringing it to status-go or not.
* Change the various retrieveX method to a single one:
`RetrieveAll` will be processing those messages that it can process (Currently only `Message`), and return the rest in `RawMessages` (still transit). The format for the response is:
`Chats`: -> The chats updated by receiving the message
`Messages`: -> The messages retrieved (already matched to a chat)
`Contacts`: -> The contacts updated by the messages
`RawMessages` -> Anything else that can't be parsed, eventually as we move everything to status-protocol-go this will go away.
2019-12-05 16:25:34 +00:00
|
|
|
ChatMessage: protobuf.ChatMessage{Text: "some-text"},
|
|
|
|
From: "me",
|
2019-11-21 16:19:22 +00:00
|
|
|
}})
|
|
|
|
}
|
2020-07-30 06:26:19 +00:00
|
|
|
|
2022-11-17 10:11:58 +00:00
|
|
|
func insertMinimalDeletedMessage(p *sqlitePersistence, id string) error {
|
|
|
|
return p.SaveMessages([]*common.Message{{
|
|
|
|
ID: id,
|
|
|
|
Deleted: true,
|
|
|
|
LocalChatID: testPublicChatID,
|
|
|
|
ChatMessage: protobuf.ChatMessage{Text: "some-text"},
|
|
|
|
From: "me",
|
|
|
|
}})
|
|
|
|
}
|
|
|
|
|
|
|
|
func insertMinimalDeletedForMeMessage(p *sqlitePersistence, id string) error {
|
|
|
|
return p.SaveMessages([]*common.Message{{
|
|
|
|
ID: id,
|
|
|
|
DeletedForMe: true,
|
|
|
|
LocalChatID: testPublicChatID,
|
|
|
|
ChatMessage: protobuf.ChatMessage{Text: "some-text"},
|
|
|
|
From: "me",
|
|
|
|
}})
|
|
|
|
}
|
|
|
|
|
2022-09-20 09:13:44 +00:00
|
|
|
func insertDiscordMessageWithAttachments(p *sqlitePersistence, id string, discordMessageID string) error {
|
|
|
|
err := insertMinimalDiscordMessage(p, id, discordMessageID)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
attachment := &protobuf.DiscordMessageAttachment{
|
|
|
|
Id: "1",
|
|
|
|
MessageId: discordMessageID,
|
|
|
|
Url: "https://does-not-exist.com",
|
|
|
|
Payload: []byte{1, 2, 3, 4},
|
|
|
|
}
|
|
|
|
|
|
|
|
attachment2 := &protobuf.DiscordMessageAttachment{
|
|
|
|
Id: "2",
|
|
|
|
MessageId: discordMessageID,
|
|
|
|
Url: "https://does-not-exist.com",
|
|
|
|
Payload: []byte{5, 6, 7, 8},
|
|
|
|
}
|
|
|
|
|
|
|
|
return p.SaveDiscordMessageAttachments([]*protobuf.DiscordMessageAttachment{
|
|
|
|
attachment,
|
|
|
|
attachment2,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2022-08-04 16:16:56 +00:00
|
|
|
func insertMinimalDiscordMessage(p *sqlitePersistence, id string, discordMessageID string) error {
|
|
|
|
discordMessage := &protobuf.DiscordMessage{
|
|
|
|
Id: discordMessageID,
|
|
|
|
Type: "Default",
|
|
|
|
Timestamp: "123456",
|
|
|
|
Content: "This is the message",
|
|
|
|
Author: &protobuf.DiscordMessageAuthor{
|
|
|
|
Id: "2",
|
|
|
|
},
|
|
|
|
Reference: &protobuf.DiscordMessageReference{},
|
|
|
|
}
|
|
|
|
|
|
|
|
err := p.SaveDiscordMessage(discordMessage)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return p.SaveMessages([]*common.Message{{
|
|
|
|
ID: id,
|
|
|
|
LocalChatID: testPublicChatID,
|
|
|
|
From: "me",
|
|
|
|
ChatMessage: protobuf.ChatMessage{
|
|
|
|
Text: "some-text",
|
|
|
|
ContentType: protobuf.ChatMessage_DISCORD_MESSAGE,
|
|
|
|
ChatId: testPublicChatID,
|
|
|
|
Payload: &protobuf.ChatMessage_DiscordMessage{
|
|
|
|
DiscordMessage: discordMessage,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}})
|
|
|
|
}
|
|
|
|
|
2020-12-15 14:43:41 +00:00
|
|
|
func minimalRawMessage(id string, messageType protobuf.ApplicationMetadataMessage_Type) *common.RawMessage {
|
|
|
|
return &common.RawMessage{
|
|
|
|
ID: id,
|
|
|
|
LocalChatID: "test-chat",
|
|
|
|
MessageType: messageType,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-30 06:26:19 +00:00
|
|
|
// Regression test making sure that if audio_duration_ms is null, no error is thrown
|
|
|
|
func TestMessagesAudioDurationMsNull(t *testing.T) {
|
|
|
|
db, err := openTestDB()
|
|
|
|
require.NoError(t, err)
|
2022-03-28 10:10:40 +00:00
|
|
|
p := newSQLitePersistence(db)
|
2020-07-30 06:26:19 +00:00
|
|
|
id := "message-id-1"
|
|
|
|
|
|
|
|
err = insertMinimalMessage(p, id)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
_, err = p.db.Exec("UPDATE user_messages SET audio_duration_ms = NULL")
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
m, err := p.MessagesByIDs([]string{id})
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, m, 1)
|
|
|
|
|
2020-09-01 13:27:01 +00:00
|
|
|
m, _, err = p.MessageByChatID(testPublicChatID, "", 10)
|
2020-07-30 06:26:19 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, m, 1)
|
|
|
|
}
|
2020-08-17 06:37:18 +00:00
|
|
|
|
|
|
|
func TestSaveChat(t *testing.T) {
|
|
|
|
db, err := openTestDB()
|
|
|
|
require.NoError(t, err)
|
2022-03-28 10:10:40 +00:00
|
|
|
p := newSQLitePersistence(db)
|
2020-08-17 06:37:18 +00:00
|
|
|
|
|
|
|
chat := CreatePublicChat("test-chat", &testTimeSource{})
|
2020-09-01 13:27:01 +00:00
|
|
|
chat.LastMessage = &common.Message{}
|
2021-01-11 10:32:51 +00:00
|
|
|
err = p.SaveChat(*chat)
|
2020-08-17 06:37:18 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
retrievedChat, err := p.Chat(chat.ID)
|
|
|
|
require.NoError(t, err)
|
2021-01-11 10:32:51 +00:00
|
|
|
require.Equal(t, chat, retrievedChat)
|
2020-08-17 06:37:18 +00:00
|
|
|
}
|
2020-09-01 10:34:28 +00:00
|
|
|
|
|
|
|
func TestSaveMentions(t *testing.T) {
|
2020-09-01 13:27:01 +00:00
|
|
|
chatID := testPublicChatID
|
2020-09-01 10:34:28 +00:00
|
|
|
db, err := openTestDB()
|
|
|
|
require.NoError(t, err)
|
2022-03-28 10:10:40 +00:00
|
|
|
p := newSQLitePersistence(db)
|
2020-09-01 10:34:28 +00:00
|
|
|
|
|
|
|
key, err := crypto.GenerateKey()
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
pkString := types.EncodeHex(crypto.FromECDSAPub(&key.PublicKey))
|
|
|
|
|
2020-09-01 13:27:01 +00:00
|
|
|
message := common.Message{
|
2020-09-01 10:34:28 +00:00
|
|
|
ID: "1",
|
|
|
|
LocalChatID: chatID,
|
|
|
|
ChatMessage: protobuf.ChatMessage{Text: "some-text"},
|
|
|
|
From: "me",
|
|
|
|
Mentions: []string{pkString},
|
|
|
|
}
|
|
|
|
|
2020-09-01 13:27:01 +00:00
|
|
|
err = p.SaveMessages([]*common.Message{&message})
|
2020-09-01 10:34:28 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
retrievedMessages, _, err := p.MessageByChatID(chatID, "", 10)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, retrievedMessages, 1)
|
|
|
|
require.Len(t, retrievedMessages[0].Mentions, 1)
|
|
|
|
require.Equal(t, retrievedMessages[0].Mentions, message.Mentions)
|
2020-10-28 13:18:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestSqlitePersistence_GetWhenChatIdentityLastPublished(t *testing.T) {
|
|
|
|
db, err := openTestDB()
|
|
|
|
require.NoError(t, err)
|
2022-03-28 10:10:40 +00:00
|
|
|
p := newSQLitePersistence(db)
|
2020-10-28 13:41:22 +00:00
|
|
|
|
2020-11-24 23:16:19 +00:00
|
|
|
chatID := "0xabcd1234"
|
2020-12-10 10:12:51 +00:00
|
|
|
hash := []byte{0x1}
|
2020-10-28 13:41:22 +00:00
|
|
|
now := time.Now().Unix()
|
2020-10-28 13:18:24 +00:00
|
|
|
|
2020-12-10 10:12:51 +00:00
|
|
|
err = p.SaveWhenChatIdentityLastPublished(chatID, hash)
|
2020-10-28 13:18:24 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
2020-12-10 10:12:51 +00:00
|
|
|
ts, actualHash, err := p.GetWhenChatIdentityLastPublished(chatID)
|
2020-10-28 13:18:24 +00:00
|
|
|
require.NoError(t, err)
|
2020-09-01 10:34:28 +00:00
|
|
|
|
2020-10-28 13:59:51 +00:00
|
|
|
// Check that the save happened in the last 2 seconds
|
2020-12-16 18:28:34 +00:00
|
|
|
diff := ts - now
|
2020-10-28 13:41:22 +00:00
|
|
|
require.LessOrEqual(t, diff, int64(2))
|
2020-10-28 13:59:51 +00:00
|
|
|
|
2020-12-10 10:12:51 +00:00
|
|
|
require.True(t, bytes.Equal(hash, actualHash))
|
|
|
|
|
2020-10-28 13:59:51 +00:00
|
|
|
// Require unsaved values to be zero
|
2020-12-10 10:12:51 +00:00
|
|
|
ts2, actualHash2, err := p.GetWhenChatIdentityLastPublished("0xdeadbeef")
|
2020-10-28 13:59:51 +00:00
|
|
|
require.NoError(t, err)
|
2020-12-16 18:28:34 +00:00
|
|
|
require.Exactly(t, int64(0), ts2)
|
2020-12-10 10:12:51 +00:00
|
|
|
require.Nil(t, actualHash2)
|
2020-09-01 10:34:28 +00:00
|
|
|
}
|
2020-10-27 17:35:28 +00:00
|
|
|
|
2022-08-02 12:56:26 +00:00
|
|
|
func TestSaveContactChatIdentity(t *testing.T) {
|
2020-12-15 15:28:05 +00:00
|
|
|
db, err := openTestDB()
|
|
|
|
require.NoError(t, err)
|
2022-03-28 10:10:40 +00:00
|
|
|
p := newSQLitePersistence(db)
|
2020-12-15 15:28:05 +00:00
|
|
|
|
|
|
|
key, err := crypto.GenerateKey()
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
contactID := types.EncodeHex(crypto.FromECDSAPub(&key.PublicKey))
|
|
|
|
|
|
|
|
err = p.SaveContact(&Contact{ID: contactID}, nil)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
jpegType := []byte{0xff, 0xd8, 0xff, 0x1}
|
|
|
|
identityImages := make(map[string]*protobuf.IdentityImage)
|
|
|
|
identityImages["large"] = &protobuf.IdentityImage{
|
|
|
|
Payload: jpegType,
|
|
|
|
SourceType: protobuf.IdentityImage_RAW_PAYLOAD,
|
|
|
|
ImageType: protobuf.ImageType_PNG,
|
|
|
|
}
|
|
|
|
|
|
|
|
identityImages["small"] = &protobuf.IdentityImage{
|
|
|
|
Payload: jpegType,
|
|
|
|
SourceType: protobuf.IdentityImage_RAW_PAYLOAD,
|
|
|
|
ImageType: protobuf.ImageType_PNG,
|
|
|
|
}
|
|
|
|
|
2022-08-02 12:56:26 +00:00
|
|
|
toArrayOfPointers := func(array []protobuf.SocialLink) (result []*protobuf.SocialLink) {
|
|
|
|
result = make([]*protobuf.SocialLink, len(array))
|
|
|
|
for i := range array {
|
|
|
|
result[i] = &array[i]
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
chatIdentity := &protobuf.ChatIdentity{
|
2020-12-15 15:28:05 +00:00
|
|
|
Clock: 1,
|
|
|
|
Images: identityImages,
|
2022-08-02 12:56:26 +00:00
|
|
|
SocialLinks: toArrayOfPointers([]protobuf.SocialLink{
|
|
|
|
{
|
|
|
|
Text: "Personal Site",
|
|
|
|
Url: "status.im",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Text: "Twitter",
|
|
|
|
Url: "Status_ico",
|
|
|
|
},
|
|
|
|
}),
|
2020-12-15 15:28:05 +00:00
|
|
|
}
|
|
|
|
|
2022-08-02 12:56:26 +00:00
|
|
|
clockUpdated, imagesUpdated, err := p.SaveContactChatIdentity(contactID, chatIdentity)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.True(t, clockUpdated)
|
|
|
|
require.True(t, imagesUpdated)
|
|
|
|
|
|
|
|
// Save again same clock and data
|
|
|
|
clockUpdated, imagesUpdated, err = p.SaveContactChatIdentity(contactID, chatIdentity)
|
2020-12-15 15:28:05 +00:00
|
|
|
require.NoError(t, err)
|
2022-08-02 12:56:26 +00:00
|
|
|
require.False(t, clockUpdated)
|
|
|
|
require.False(t, imagesUpdated)
|
2020-12-15 15:28:05 +00:00
|
|
|
|
2022-08-02 12:56:26 +00:00
|
|
|
// Save again newer clock and no images
|
|
|
|
chatIdentity.Clock = 2
|
|
|
|
chatIdentity.Images = make(map[string]*protobuf.IdentityImage)
|
|
|
|
clockUpdated, imagesUpdated, err = p.SaveContactChatIdentity(contactID, chatIdentity)
|
2020-12-15 15:28:05 +00:00
|
|
|
require.NoError(t, err)
|
2022-08-02 12:56:26 +00:00
|
|
|
require.True(t, clockUpdated)
|
|
|
|
require.False(t, imagesUpdated)
|
2020-12-15 15:28:05 +00:00
|
|
|
|
|
|
|
contacts, err := p.Contacts()
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, contacts, 1)
|
|
|
|
|
|
|
|
require.Len(t, contacts[0].Images, 2)
|
2022-08-02 12:56:26 +00:00
|
|
|
require.Len(t, contacts[0].SocialLinks, 2)
|
|
|
|
require.Equal(t, "Personal Site", contacts[0].SocialLinks[0].Text)
|
|
|
|
require.Equal(t, "status.im", contacts[0].SocialLinks[0].URL)
|
|
|
|
require.Equal(t, "Twitter", contacts[0].SocialLinks[1].Text)
|
|
|
|
require.Equal(t, "Status_ico", contacts[0].SocialLinks[1].URL)
|
2020-12-15 15:28:05 +00:00
|
|
|
}
|
|
|
|
|
2020-10-27 17:35:28 +00:00
|
|
|
func TestSaveLinks(t *testing.T) {
|
|
|
|
chatID := testPublicChatID
|
|
|
|
db, err := openTestDB()
|
|
|
|
require.NoError(t, err)
|
2022-03-28 10:10:40 +00:00
|
|
|
p := newSQLitePersistence(db)
|
2020-10-27 17:35:28 +00:00
|
|
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
message := common.Message{
|
|
|
|
ID: "1",
|
|
|
|
LocalChatID: chatID,
|
|
|
|
ChatMessage: protobuf.ChatMessage{Text: "some-text"},
|
|
|
|
From: "me",
|
2022-07-17 13:37:14 +00:00
|
|
|
Links: []string{"https://github.com/status-im/status-mobile"},
|
2020-10-27 17:35:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
err = p.SaveMessages([]*common.Message{&message})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
retrievedMessages, _, err := p.MessageByChatID(chatID, "", 10)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, retrievedMessages, 1)
|
|
|
|
require.Len(t, retrievedMessages[0].Links, 1)
|
|
|
|
require.Equal(t, retrievedMessages[0].Links, message.Links)
|
|
|
|
|
|
|
|
}
|
2020-12-07 15:13:39 +00:00
|
|
|
|
|
|
|
func TestHideMessage(t *testing.T) {
|
|
|
|
db, err := openTestDB()
|
|
|
|
require.NoError(t, err)
|
2022-03-28 10:10:40 +00:00
|
|
|
p := newSQLitePersistence(db)
|
2020-12-07 15:13:39 +00:00
|
|
|
chatID := testPublicChatID
|
|
|
|
message := &common.Message{
|
|
|
|
ID: "id-1",
|
|
|
|
LocalChatID: chatID,
|
|
|
|
ChatMessage: protobuf.ChatMessage{
|
|
|
|
Text: "content-1",
|
|
|
|
Clock: uint64(1),
|
|
|
|
},
|
|
|
|
From: "1",
|
|
|
|
}
|
|
|
|
|
|
|
|
messages := []*common.Message{message}
|
|
|
|
|
|
|
|
err = p.SaveMessages(messages)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
err = p.HideMessage(message.ID)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
var actualHidden, actualSeen bool
|
|
|
|
err = p.db.QueryRow("SELECT hide, seen FROM user_messages WHERE id = ?", message.ID).Scan(&actualHidden, &actualSeen)
|
|
|
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.True(t, actualHidden)
|
|
|
|
require.True(t, actualSeen)
|
|
|
|
}
|
2020-12-22 10:49:25 +00:00
|
|
|
|
|
|
|
func TestDeactivatePublicChat(t *testing.T) {
|
|
|
|
db, err := openTestDB()
|
|
|
|
require.NoError(t, err)
|
2022-03-28 10:10:40 +00:00
|
|
|
p := newSQLitePersistence(db)
|
2020-12-22 10:49:25 +00:00
|
|
|
publicChatID := "public-chat-id"
|
|
|
|
var currentClockValue uint64 = 10
|
|
|
|
|
|
|
|
timesource := &testTimeSource{}
|
|
|
|
lastMessage := common.Message{
|
|
|
|
ID: "0x01",
|
|
|
|
LocalChatID: publicChatID,
|
|
|
|
ChatMessage: protobuf.ChatMessage{Text: "some-text"},
|
|
|
|
From: "me",
|
|
|
|
}
|
|
|
|
lastMessage.Clock = 20
|
|
|
|
|
|
|
|
require.NoError(t, p.SaveMessages([]*common.Message{&lastMessage}))
|
|
|
|
|
|
|
|
publicChat := CreatePublicChat(publicChatID, timesource)
|
|
|
|
publicChat.LastMessage = &lastMessage
|
|
|
|
publicChat.UnviewedMessagesCount = 1
|
|
|
|
|
2022-12-07 19:34:48 +00:00
|
|
|
err = p.DeactivateChat(publicChat, currentClockValue, true)
|
2020-12-22 10:49:25 +00:00
|
|
|
|
|
|
|
// It does not set deleted at for a public chat
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, uint64(0), publicChat.DeletedAtClockValue)
|
|
|
|
|
|
|
|
// It sets the lastMessage to nil
|
|
|
|
require.Nil(t, publicChat.LastMessage)
|
|
|
|
|
|
|
|
// It sets unviewed messages count
|
|
|
|
require.Equal(t, uint(0), publicChat.UnviewedMessagesCount)
|
|
|
|
|
|
|
|
// It sets active as false
|
|
|
|
require.False(t, publicChat.Active)
|
|
|
|
|
|
|
|
// It deletes messages
|
|
|
|
messages, _, err := p.MessageByChatID(publicChatID, "", 10)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, messages, 0)
|
|
|
|
|
|
|
|
// Reload chat to make sure it has been save
|
|
|
|
dbChat, err := p.Chat(publicChatID)
|
|
|
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, dbChat)
|
|
|
|
|
|
|
|
// Same checks on the chat pulled from the db
|
|
|
|
// It does not set deleted at for a public chat
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, uint64(0), dbChat.DeletedAtClockValue)
|
|
|
|
|
|
|
|
// It sets the lastMessage to nil
|
|
|
|
require.Nil(t, dbChat.LastMessage)
|
|
|
|
|
|
|
|
// It sets unviewed messages count
|
|
|
|
require.Equal(t, uint(0), dbChat.UnviewedMessagesCount)
|
|
|
|
|
|
|
|
// It sets active as false
|
|
|
|
require.False(t, dbChat.Active)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestDeactivateOneToOneChat(t *testing.T) {
|
|
|
|
key, err := crypto.GenerateKey()
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
pkString := types.EncodeHex(crypto.FromECDSAPub(&key.PublicKey))
|
|
|
|
|
|
|
|
db, err := openTestDB()
|
|
|
|
require.NoError(t, err)
|
2022-03-28 10:10:40 +00:00
|
|
|
p := newSQLitePersistence(db)
|
2020-12-22 10:49:25 +00:00
|
|
|
var currentClockValue uint64 = 10
|
|
|
|
|
|
|
|
timesource := &testTimeSource{}
|
|
|
|
|
|
|
|
chat := CreateOneToOneChat(pkString, &key.PublicKey, timesource)
|
|
|
|
|
|
|
|
lastMessage := common.Message{
|
|
|
|
ID: "0x01",
|
|
|
|
LocalChatID: chat.ID,
|
|
|
|
ChatMessage: protobuf.ChatMessage{Text: "some-text"},
|
|
|
|
From: "me",
|
|
|
|
}
|
|
|
|
lastMessage.Clock = 20
|
|
|
|
|
|
|
|
require.NoError(t, p.SaveMessages([]*common.Message{&lastMessage}))
|
|
|
|
|
|
|
|
chat.LastMessage = &lastMessage
|
|
|
|
chat.UnviewedMessagesCount = 1
|
|
|
|
|
2022-12-07 19:34:48 +00:00
|
|
|
err = p.DeactivateChat(chat, currentClockValue, true)
|
2020-12-22 10:49:25 +00:00
|
|
|
|
|
|
|
// It does set deleted at for a public chat
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotEqual(t, uint64(0), chat.DeletedAtClockValue)
|
|
|
|
|
|
|
|
// It sets the lastMessage to nil
|
|
|
|
require.Nil(t, chat.LastMessage)
|
|
|
|
|
|
|
|
// It sets unviewed messages count
|
|
|
|
require.Equal(t, uint(0), chat.UnviewedMessagesCount)
|
|
|
|
|
|
|
|
// It sets active as false
|
|
|
|
require.False(t, chat.Active)
|
|
|
|
|
|
|
|
// It deletes messages
|
|
|
|
messages, _, err := p.MessageByChatID(chat.ID, "", 10)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, messages, 0)
|
|
|
|
|
|
|
|
// Reload chat to make sure it has been save
|
|
|
|
dbChat, err := p.Chat(chat.ID)
|
|
|
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, dbChat)
|
|
|
|
|
|
|
|
// Same checks on the chat pulled from the db
|
|
|
|
// It does set deleted at for a public chat
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotEqual(t, uint64(0), dbChat.DeletedAtClockValue)
|
|
|
|
|
|
|
|
// It sets the lastMessage to nil
|
|
|
|
require.Nil(t, dbChat.LastMessage)
|
|
|
|
|
|
|
|
// It sets unviewed messages count
|
|
|
|
require.Equal(t, uint(0), dbChat.UnviewedMessagesCount)
|
|
|
|
|
|
|
|
// It sets active as false
|
|
|
|
require.False(t, dbChat.Active)
|
|
|
|
}
|
2021-03-09 12:48:15 +00:00
|
|
|
|
|
|
|
func TestConfirmations(t *testing.T) {
|
|
|
|
dataSyncID1 := []byte("datsync-id-1")
|
|
|
|
dataSyncID2 := []byte("datsync-id-2")
|
|
|
|
dataSyncID3 := []byte("datsync-id-3")
|
|
|
|
dataSyncID4 := []byte("datsync-id-3")
|
|
|
|
|
|
|
|
messageID1 := []byte("message-id-1")
|
|
|
|
messageID2 := []byte("message-id-2")
|
|
|
|
|
|
|
|
publicKey1 := []byte("pk-1")
|
|
|
|
publicKey2 := []byte("pk-2")
|
|
|
|
publicKey3 := []byte("pk-3")
|
|
|
|
|
|
|
|
db, err := openTestDB()
|
|
|
|
require.NoError(t, err)
|
2022-03-28 10:10:40 +00:00
|
|
|
p := newSQLitePersistence(db)
|
2021-03-09 12:48:15 +00:00
|
|
|
|
|
|
|
confirmation1 := &common.RawMessageConfirmation{
|
|
|
|
DataSyncID: dataSyncID1,
|
|
|
|
MessageID: messageID1,
|
|
|
|
PublicKey: publicKey1,
|
|
|
|
}
|
|
|
|
|
|
|
|
// Same datasyncID and same messageID, different pubkey
|
|
|
|
confirmation2 := &common.RawMessageConfirmation{
|
|
|
|
DataSyncID: dataSyncID2,
|
|
|
|
MessageID: messageID1,
|
|
|
|
PublicKey: publicKey2,
|
|
|
|
}
|
|
|
|
|
|
|
|
// Different datasyncID and same messageID, different pubkey
|
|
|
|
confirmation3 := &common.RawMessageConfirmation{
|
|
|
|
DataSyncID: dataSyncID3,
|
|
|
|
MessageID: messageID1,
|
|
|
|
PublicKey: publicKey3,
|
|
|
|
}
|
|
|
|
|
|
|
|
// Same dataSyncID, different messageID
|
|
|
|
confirmation4 := &common.RawMessageConfirmation{
|
|
|
|
DataSyncID: dataSyncID4,
|
|
|
|
MessageID: messageID2,
|
|
|
|
PublicKey: publicKey1,
|
|
|
|
}
|
|
|
|
|
|
|
|
require.NoError(t, p.InsertPendingConfirmation(confirmation1))
|
|
|
|
require.NoError(t, p.InsertPendingConfirmation(confirmation2))
|
|
|
|
require.NoError(t, p.InsertPendingConfirmation(confirmation3))
|
|
|
|
require.NoError(t, p.InsertPendingConfirmation(confirmation4))
|
|
|
|
|
|
|
|
// We confirm the first datasync message, no confirmations
|
|
|
|
messageID, err := p.MarkAsConfirmed(dataSyncID1, false)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Nil(t, messageID)
|
|
|
|
|
|
|
|
// We confirm the second datasync message, no confirmations
|
|
|
|
messageID, err = p.MarkAsConfirmed(dataSyncID2, false)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Nil(t, messageID)
|
|
|
|
|
|
|
|
// We confirm the third datasync message, messageID1 should be confirmed
|
|
|
|
messageID, err = p.MarkAsConfirmed(dataSyncID3, false)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, messageID, types.HexBytes(messageID1))
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestConfirmationsAtLeastOne(t *testing.T) {
|
|
|
|
dataSyncID1 := []byte("datsync-id-1")
|
|
|
|
dataSyncID2 := []byte("datsync-id-2")
|
|
|
|
dataSyncID3 := []byte("datsync-id-3")
|
|
|
|
|
|
|
|
messageID1 := []byte("message-id-1")
|
|
|
|
|
|
|
|
publicKey1 := []byte("pk-1")
|
|
|
|
publicKey2 := []byte("pk-2")
|
|
|
|
publicKey3 := []byte("pk-3")
|
|
|
|
|
|
|
|
db, err := openTestDB()
|
|
|
|
require.NoError(t, err)
|
2022-03-28 10:10:40 +00:00
|
|
|
p := newSQLitePersistence(db)
|
2021-03-09 12:48:15 +00:00
|
|
|
|
|
|
|
confirmation1 := &common.RawMessageConfirmation{
|
|
|
|
DataSyncID: dataSyncID1,
|
|
|
|
MessageID: messageID1,
|
|
|
|
PublicKey: publicKey1,
|
|
|
|
}
|
|
|
|
|
|
|
|
// Same datasyncID and same messageID, different pubkey
|
|
|
|
confirmation2 := &common.RawMessageConfirmation{
|
|
|
|
DataSyncID: dataSyncID2,
|
|
|
|
MessageID: messageID1,
|
|
|
|
PublicKey: publicKey2,
|
|
|
|
}
|
|
|
|
|
|
|
|
// Different datasyncID and same messageID, different pubkey
|
|
|
|
confirmation3 := &common.RawMessageConfirmation{
|
|
|
|
DataSyncID: dataSyncID3,
|
|
|
|
MessageID: messageID1,
|
|
|
|
PublicKey: publicKey3,
|
|
|
|
}
|
|
|
|
|
|
|
|
require.NoError(t, p.InsertPendingConfirmation(confirmation1))
|
|
|
|
require.NoError(t, p.InsertPendingConfirmation(confirmation2))
|
|
|
|
require.NoError(t, p.InsertPendingConfirmation(confirmation3))
|
|
|
|
|
|
|
|
// We confirm the first datasync message, messageID1 and 3 should be confirmed
|
|
|
|
messageID, err := p.MarkAsConfirmed(dataSyncID1, true)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, messageID)
|
|
|
|
require.Equal(t, types.HexBytes(messageID1), messageID)
|
|
|
|
}
|
2021-04-07 12:57:14 +00:00
|
|
|
|
2022-08-31 14:41:58 +00:00
|
|
|
func TestActivityCenterReadUnread(t *testing.T) {
|
|
|
|
nID1 := types.HexBytes([]byte("1"))
|
|
|
|
nID2 := types.HexBytes([]byte("2"))
|
|
|
|
// nID3 := types.HexBytes([]byte("3"))
|
|
|
|
// nID4 := types.HexBytes([]byte("4"))
|
|
|
|
|
|
|
|
db, err := openTestDB()
|
|
|
|
require.NoError(t, err)
|
|
|
|
p := newSQLitePersistence(db)
|
|
|
|
|
|
|
|
chat := CreatePublicChat("test-chat", &testTimeSource{})
|
|
|
|
message := &common.Message{}
|
|
|
|
message.Text = "sample text"
|
|
|
|
chat.LastMessage = message
|
|
|
|
err = p.SaveChat(*chat)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
notification := &ActivityCenterNotification{
|
|
|
|
ID: nID1,
|
|
|
|
Type: ActivityCenterNotificationTypeNewOneToOne,
|
|
|
|
ChatID: chat.ID,
|
|
|
|
Timestamp: 1,
|
|
|
|
}
|
|
|
|
|
|
|
|
err = p.SaveActivityCenterNotification(notification)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
notification = &ActivityCenterNotification{
|
|
|
|
ID: nID2,
|
|
|
|
Type: ActivityCenterNotificationTypeNewOneToOne,
|
|
|
|
ChatID: chat.ID,
|
|
|
|
Timestamp: 1,
|
|
|
|
}
|
|
|
|
|
|
|
|
err = p.SaveActivityCenterNotification(notification)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
// Mark the notification as read
|
|
|
|
err = p.MarkActivityCenterNotificationsRead([]types.HexBytes{nID2})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
cursor, notifications, err := p.UnreadActivityCenterNotifications("", 2, ActivityCenterNotificationTypeNewOneToOne)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Empty(t, cursor)
|
|
|
|
require.Len(t, notifications, 1)
|
|
|
|
require.Equal(t, nID1, notifications[0].ID)
|
|
|
|
|
|
|
|
cursor, notifications, err = p.ReadActivityCenterNotifications("", 2, ActivityCenterNotificationTypeNewOneToOne)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Empty(t, cursor)
|
|
|
|
require.Len(t, notifications, 1)
|
|
|
|
require.Equal(t, nID2, notifications[0].ID)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestActivityCenterReadUnreadFilterByType(t *testing.T) {
|
|
|
|
db, err := openTestDB()
|
|
|
|
require.NoError(t, err)
|
|
|
|
p := newSQLitePersistence(db)
|
|
|
|
|
|
|
|
chat := CreatePublicChat("test-chat", &testTimeSource{})
|
|
|
|
message := &common.Message{}
|
|
|
|
message.Text = "sample text"
|
|
|
|
chat.LastMessage = message
|
|
|
|
err = p.SaveChat(*chat)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
initialCursor := ""
|
|
|
|
limit := uint64(3)
|
|
|
|
|
|
|
|
nID1 := types.HexBytes([]byte("1"))
|
|
|
|
nID2 := types.HexBytes([]byte("2"))
|
|
|
|
nID3 := types.HexBytes([]byte("3"))
|
|
|
|
|
|
|
|
allNotifications := []*ActivityCenterNotification{
|
|
|
|
{
|
|
|
|
ID: nID1,
|
|
|
|
Type: ActivityCenterNotificationTypeMention,
|
|
|
|
ChatID: chat.ID,
|
|
|
|
Timestamp: 1,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
ID: nID2,
|
|
|
|
Type: ActivityCenterNotificationTypeNewOneToOne,
|
|
|
|
ChatID: chat.ID,
|
|
|
|
Timestamp: 1,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
ID: nID3,
|
|
|
|
Type: ActivityCenterNotificationTypeMention,
|
|
|
|
ChatID: chat.ID,
|
|
|
|
Timestamp: 1,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, notification := range allNotifications {
|
|
|
|
err = p.SaveActivityCenterNotification(notification)
|
|
|
|
require.NoError(t, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
_, notifications, err := p.UnreadActivityCenterNotifications(initialCursor, limit, ActivityCenterNotificationTypeNewOneToOne)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, notifications, 1)
|
|
|
|
require.Equal(t, nID2, notifications[0].ID)
|
|
|
|
|
|
|
|
_, notifications, err = p.UnreadActivityCenterNotifications(initialCursor, limit, ActivityCenterNotificationTypeMention)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, notifications, 2)
|
|
|
|
require.Equal(t, nID3, notifications[0].ID)
|
|
|
|
require.Equal(t, nID1, notifications[1].ID)
|
|
|
|
|
|
|
|
// Mark all notifications as read.
|
|
|
|
for _, notification := range allNotifications {
|
|
|
|
err = p.MarkActivityCenterNotificationsRead([]types.HexBytes{notification.ID})
|
|
|
|
require.NoError(t, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
_, notifications, err = p.ReadActivityCenterNotifications(initialCursor, limit, ActivityCenterNotificationTypeNewOneToOne)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, notifications, 1)
|
|
|
|
require.Equal(t, nID2, notifications[0].ID)
|
|
|
|
|
|
|
|
_, notifications, err = p.ReadActivityCenterNotifications(initialCursor, limit, ActivityCenterNotificationTypeMention)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, notifications, 2)
|
|
|
|
require.Equal(t, nID3, notifications[0].ID)
|
|
|
|
require.Equal(t, nID1, notifications[1].ID)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestActivityCenterReadUnreadPagination(t *testing.T) {
|
|
|
|
db, err := openTestDB()
|
|
|
|
require.NoError(t, err)
|
|
|
|
p := newSQLitePersistence(db)
|
|
|
|
|
|
|
|
initialOrFinalCursor := ""
|
|
|
|
|
|
|
|
chat := CreatePublicChat("test-chat", &testTimeSource{})
|
|
|
|
message := &common.Message{}
|
|
|
|
message.Text = "sample text"
|
|
|
|
chat.LastMessage = message
|
|
|
|
err = p.SaveChat(*chat)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
nID1 := types.HexBytes([]byte("1"))
|
|
|
|
nID2 := types.HexBytes([]byte("2"))
|
|
|
|
nID3 := types.HexBytes([]byte("3"))
|
|
|
|
nID4 := types.HexBytes([]byte("4"))
|
|
|
|
nID5 := types.HexBytes([]byte("5"))
|
|
|
|
|
|
|
|
allNotifications := []*ActivityCenterNotification{
|
|
|
|
{
|
|
|
|
ID: nID1,
|
|
|
|
Type: ActivityCenterNotificationTypeNewOneToOne,
|
|
|
|
ChatID: chat.ID,
|
|
|
|
Timestamp: 1,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
ID: nID2,
|
|
|
|
Type: ActivityCenterNotificationTypeNewOneToOne,
|
|
|
|
ChatID: chat.ID,
|
|
|
|
Timestamp: 1,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
ID: nID3,
|
|
|
|
Type: ActivityCenterNotificationTypeNewOneToOne,
|
|
|
|
ChatID: chat.ID,
|
|
|
|
Timestamp: 1,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
ID: nID4,
|
|
|
|
Type: ActivityCenterNotificationTypeNewOneToOne,
|
|
|
|
ChatID: chat.ID,
|
|
|
|
Timestamp: 1,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
ID: nID5,
|
|
|
|
Type: ActivityCenterNotificationTypeNewOneToOne,
|
|
|
|
ChatID: chat.ID,
|
|
|
|
Timestamp: 1,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, notification := range allNotifications {
|
|
|
|
err = p.SaveActivityCenterNotification(notification)
|
|
|
|
require.NoError(t, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Mark the notification as read
|
|
|
|
err = p.MarkActivityCenterNotificationsRead([]types.HexBytes{nID2})
|
|
|
|
require.NoError(t, err)
|
|
|
|
err = p.MarkActivityCenterNotificationsRead([]types.HexBytes{nID4})
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
// Fetch UNREAD notifications, first page.
|
|
|
|
cursor, notifications, err := p.UnreadActivityCenterNotifications(initialOrFinalCursor, 1, ActivityCenterNotificationTypeNewOneToOne)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, notifications, 1)
|
|
|
|
require.Equal(t, nID5, notifications[0].ID)
|
|
|
|
require.NotEmpty(t, cursor)
|
|
|
|
|
|
|
|
// Fetch next pages.
|
|
|
|
cursor, notifications, err = p.UnreadActivityCenterNotifications(cursor, 1, ActivityCenterNotificationTypeNewOneToOne)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, notifications, 1)
|
|
|
|
require.Equal(t, nID3, notifications[0].ID)
|
|
|
|
require.NotEmpty(t, cursor)
|
|
|
|
|
|
|
|
cursor, notifications, err = p.UnreadActivityCenterNotifications(cursor, 1, ActivityCenterNotificationTypeNewOneToOne)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, notifications, 1)
|
|
|
|
require.Equal(t, nID1, notifications[0].ID)
|
|
|
|
require.Empty(t, cursor)
|
|
|
|
|
|
|
|
// Fetch READ notifications, first page.
|
|
|
|
cursor, notifications, err = p.ReadActivityCenterNotifications(initialOrFinalCursor, 1, ActivityCenterNotificationTypeNewOneToOne)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, notifications, 1)
|
|
|
|
require.Equal(t, nID4, notifications[0].ID)
|
|
|
|
require.NotEmpty(t, cursor)
|
|
|
|
|
|
|
|
// Fetch next page.
|
|
|
|
cursor, notifications, err = p.ReadActivityCenterNotifications(cursor, 1, ActivityCenterNotificationTypeNewOneToOne)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, notifications, 1)
|
|
|
|
require.Equal(t, nID2, notifications[0].ID)
|
|
|
|
require.Empty(t, cursor)
|
|
|
|
}
|
|
|
|
|
2021-04-07 12:57:14 +00:00
|
|
|
func TestActivityCenterPersistence(t *testing.T) {
|
|
|
|
nID1 := types.HexBytes([]byte("1"))
|
|
|
|
nID2 := types.HexBytes([]byte("2"))
|
|
|
|
nID3 := types.HexBytes([]byte("3"))
|
|
|
|
nID4 := types.HexBytes([]byte("4"))
|
|
|
|
|
|
|
|
db, err := openTestDB()
|
|
|
|
require.NoError(t, err)
|
2022-03-28 10:10:40 +00:00
|
|
|
p := newSQLitePersistence(db)
|
2021-04-07 12:57:14 +00:00
|
|
|
|
|
|
|
chat := CreatePublicChat("test-chat", &testTimeSource{})
|
|
|
|
message := &common.Message{}
|
|
|
|
message.Text = "sample text"
|
|
|
|
chat.LastMessage = message
|
|
|
|
err = p.SaveChat(*chat)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
notification := &ActivityCenterNotification{
|
|
|
|
ID: nID1,
|
|
|
|
Type: ActivityCenterNotificationTypeNewOneToOne,
|
|
|
|
ChatID: chat.ID,
|
|
|
|
Timestamp: 1,
|
|
|
|
}
|
|
|
|
err = p.SaveActivityCenterNotification(notification)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
cursor, notifications, err := p.ActivityCenterNotifications("", 2)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Empty(t, cursor)
|
|
|
|
require.Len(t, notifications, 1)
|
|
|
|
require.Equal(t, chat.ID, notifications[0].ChatID)
|
|
|
|
require.Equal(t, message, notifications[0].LastMessage)
|
|
|
|
|
|
|
|
// Add another notification
|
|
|
|
|
|
|
|
notification = &ActivityCenterNotification{
|
|
|
|
ID: nID2,
|
|
|
|
Type: ActivityCenterNotificationTypeNewOneToOne,
|
|
|
|
Timestamp: 2,
|
|
|
|
}
|
|
|
|
err = p.SaveActivityCenterNotification(notification)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
cursor, notifications, err = p.ActivityCenterNotifications("", 1)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, notifications, 1)
|
|
|
|
require.NotEmpty(t, cursor)
|
|
|
|
require.Equal(t, nID2, notifications[0].ID)
|
|
|
|
|
|
|
|
// fetch next pagination
|
|
|
|
|
|
|
|
cursor, notifications, err = p.ActivityCenterNotifications(cursor, 1)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, notifications, 1)
|
|
|
|
require.Empty(t, cursor)
|
|
|
|
require.False(t, notifications[0].Read)
|
|
|
|
require.Equal(t, nID1, notifications[0].ID)
|
|
|
|
|
|
|
|
// Check count
|
|
|
|
count, err := p.UnreadActivityCenterNotificationsCount()
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, uint64(2), count)
|
|
|
|
|
2021-06-11 16:47:53 +00:00
|
|
|
// Mark first one as read
|
|
|
|
require.NoError(t, p.MarkActivityCenterNotificationsRead([]types.HexBytes{nID1}))
|
|
|
|
count, err = p.UnreadActivityCenterNotificationsCount()
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, uint64(1), count)
|
|
|
|
|
2021-09-24 10:57:15 +00:00
|
|
|
// Mark first one as unread
|
|
|
|
require.NoError(t, p.MarkActivityCenterNotificationsUnread([]types.HexBytes{nID1}))
|
|
|
|
count, err = p.UnreadActivityCenterNotificationsCount()
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, uint64(2), count)
|
|
|
|
|
2021-06-11 16:47:53 +00:00
|
|
|
// Mark all read
|
2021-04-07 12:57:14 +00:00
|
|
|
require.NoError(t, p.MarkAllActivityCenterNotificationsRead())
|
|
|
|
_, notifications, err = p.ActivityCenterNotifications(cursor, 2)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, notifications, 2)
|
|
|
|
require.Empty(t, cursor)
|
|
|
|
require.True(t, notifications[0].Read)
|
|
|
|
require.True(t, notifications[1].Read)
|
|
|
|
|
|
|
|
// Check count
|
|
|
|
count, err = p.UnreadActivityCenterNotificationsCount()
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, uint64(0), count)
|
|
|
|
|
|
|
|
// Mark first one as accepted
|
|
|
|
|
|
|
|
notifications, err = p.AcceptActivityCenterNotifications([]types.HexBytes{nID1})
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, notifications, 1)
|
|
|
|
_, notifications, err = p.ActivityCenterNotifications("", 2)
|
|
|
|
require.NoError(t, err)
|
|
|
|
// It should not be returned anymore
|
|
|
|
require.Len(t, notifications, 1)
|
|
|
|
|
|
|
|
// Mark last one as dismissed
|
|
|
|
require.NoError(t, p.DismissActivityCenterNotifications([]types.HexBytes{nID2}))
|
|
|
|
_, notifications, err = p.ActivityCenterNotifications("", 2)
|
|
|
|
require.NoError(t, err)
|
|
|
|
// Dismissed notifications should not be returned
|
|
|
|
require.Len(t, notifications, 0)
|
|
|
|
|
|
|
|
// Insert new notification
|
|
|
|
notification = &ActivityCenterNotification{
|
|
|
|
ID: nID3,
|
|
|
|
Type: ActivityCenterNotificationTypeNewOneToOne,
|
|
|
|
Timestamp: 3,
|
|
|
|
}
|
|
|
|
err = p.SaveActivityCenterNotification(notification)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
// Mark all as accepted
|
|
|
|
notifications, err = p.AcceptAllActivityCenterNotifications()
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, notifications, 1)
|
|
|
|
|
|
|
|
_, notifications, err = p.ActivityCenterNotifications("", 2)
|
|
|
|
require.NoError(t, err)
|
|
|
|
// It should not return those
|
|
|
|
require.Len(t, notifications, 0)
|
|
|
|
|
|
|
|
// Insert new notification
|
|
|
|
notification = &ActivityCenterNotification{
|
|
|
|
ID: nID4,
|
|
|
|
Type: ActivityCenterNotificationTypeNewOneToOne,
|
|
|
|
Timestamp: 4,
|
|
|
|
}
|
|
|
|
err = p.SaveActivityCenterNotification(notification)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
// Mark all as dismissed
|
|
|
|
require.NoError(t, p.DismissAllActivityCenterNotifications())
|
|
|
|
_, notifications, err = p.ActivityCenterNotifications("", 2)
|
|
|
|
require.NoError(t, err)
|
|
|
|
// It should not return those
|
|
|
|
require.Len(t, notifications, 0)
|
|
|
|
}
|
2021-06-01 12:13:17 +00:00
|
|
|
|
|
|
|
func TestSaveCommunityChat(t *testing.T) {
|
|
|
|
db, err := openTestDB()
|
|
|
|
require.NoError(t, err)
|
2022-03-28 10:10:40 +00:00
|
|
|
p := newSQLitePersistence(db)
|
2021-06-01 12:13:17 +00:00
|
|
|
|
|
|
|
identity := &protobuf.ChatIdentity{
|
2022-09-02 08:36:07 +00:00
|
|
|
DisplayName: "community-chat-name",
|
|
|
|
Description: "community-chat-name-description",
|
|
|
|
FirstMessageTimestamp: 1,
|
2021-06-01 12:13:17 +00:00
|
|
|
}
|
|
|
|
permissions := &protobuf.CommunityPermissions{
|
|
|
|
Access: protobuf.CommunityPermissions_NO_MEMBERSHIP,
|
|
|
|
}
|
|
|
|
|
|
|
|
communityChat := &protobuf.CommunityChat{
|
|
|
|
Identity: identity,
|
|
|
|
Permissions: permissions,
|
|
|
|
}
|
|
|
|
|
|
|
|
chat := CreateCommunityChat("test-or-gid", "test-chat-id", communityChat, &testTimeSource{})
|
|
|
|
chat.LastMessage = &common.Message{}
|
|
|
|
err = p.SaveChat(*chat)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
retrievedChat, err := p.Chat(chat.ID)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, chat, retrievedChat)
|
|
|
|
}
|
2021-12-10 14:34:16 +00:00
|
|
|
|
|
|
|
func TestHasPendingNotificationsForChatSanityCheck(t *testing.T) {
|
|
|
|
db, err := openTestDB()
|
|
|
|
require.NoError(t, err)
|
2022-03-28 10:10:40 +00:00
|
|
|
p := newSQLitePersistence(db)
|
2021-12-10 14:34:16 +00:00
|
|
|
|
|
|
|
result, err := p.HasPendingNotificationsForChat("test-chat-id")
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.False(t, result)
|
|
|
|
}
|
2022-07-21 19:34:03 +00:00
|
|
|
|
|
|
|
func TestSaveDiscordMessageAuthor(t *testing.T) {
|
|
|
|
|
|
|
|
db, err := openTestDB()
|
|
|
|
require.NoError(t, err)
|
|
|
|
p := newSQLitePersistence(db)
|
|
|
|
|
2022-09-15 09:05:30 +00:00
|
|
|
testAuthor := &protobuf.DiscordMessageAuthor{
|
|
|
|
Id: "1",
|
|
|
|
Name: "Testuser",
|
|
|
|
Discriminator: "1234",
|
|
|
|
Nickname: "User",
|
|
|
|
AvatarUrl: "http://example.com/profile.jpg",
|
|
|
|
AvatarImagePayload: []byte{1, 2, 3},
|
|
|
|
}
|
|
|
|
|
|
|
|
require.NoError(t, p.SaveDiscordMessageAuthor(testAuthor))
|
2022-07-21 19:34:03 +00:00
|
|
|
|
|
|
|
exists, err := p.HasDiscordMessageAuthor("1")
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.True(t, exists)
|
2022-09-15 09:05:30 +00:00
|
|
|
author, err := p.GetDiscordMessageAuthorByID("1")
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, author.Id, testAuthor.Id)
|
|
|
|
require.Equal(t, author.Name, testAuthor.Name)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestGetDiscordMessageAuthorImagePayloadByID(t *testing.T) {
|
|
|
|
db, err := openTestDB()
|
|
|
|
require.NoError(t, err)
|
|
|
|
p := newSQLitePersistence(db)
|
|
|
|
|
|
|
|
testAuthor := &protobuf.DiscordMessageAuthor{
|
|
|
|
Id: "1",
|
|
|
|
Name: "Testuser",
|
|
|
|
Discriminator: "1234",
|
|
|
|
Nickname: "User",
|
|
|
|
AvatarUrl: "http://example.com/profile.jpg",
|
|
|
|
AvatarImagePayload: []byte{1, 2, 3},
|
|
|
|
}
|
|
|
|
|
|
|
|
require.NoError(t, p.SaveDiscordMessageAuthor(testAuthor))
|
|
|
|
|
|
|
|
payload, err := p.GetDiscordMessageAuthorImagePayloadByID("1")
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
require.Equal(t, testAuthor.AvatarImagePayload, payload)
|
2022-07-21 19:34:03 +00:00
|
|
|
}
|
2022-08-04 16:16:56 +00:00
|
|
|
|
|
|
|
func TestSaveDiscordMessage(t *testing.T) {
|
|
|
|
|
|
|
|
db, err := openTestDB()
|
|
|
|
require.NoError(t, err)
|
|
|
|
p := newSQLitePersistence(db)
|
|
|
|
|
|
|
|
require.NoError(t, p.SaveDiscordMessage(&protobuf.DiscordMessage{
|
|
|
|
Id: "1",
|
|
|
|
Type: "Default",
|
|
|
|
Timestamp: "123456",
|
|
|
|
Content: "This is the message",
|
|
|
|
Author: &protobuf.DiscordMessageAuthor{
|
|
|
|
Id: "2",
|
|
|
|
},
|
|
|
|
Reference: &protobuf.DiscordMessageReference{},
|
|
|
|
}))
|
|
|
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestSaveDiscordMessages(t *testing.T) {
|
|
|
|
db, err := openTestDB()
|
|
|
|
require.NoError(t, err)
|
|
|
|
p := newSQLitePersistence(db)
|
|
|
|
|
|
|
|
for i := 0; i < 10; i++ {
|
|
|
|
id := strconv.Itoa(i)
|
|
|
|
err := insertMinimalDiscordMessage(p, id, id)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
m, err := p.MessageByID(id)
|
|
|
|
require.NoError(t, err)
|
|
|
|
dm := m.GetDiscordMessage()
|
|
|
|
require.NotNil(t, dm)
|
|
|
|
require.EqualValues(t, id, dm.Id)
|
2022-08-19 12:30:11 +00:00
|
|
|
require.EqualValues(t, "2", dm.Author.Id)
|
2022-08-04 16:16:56 +00:00
|
|
|
}
|
|
|
|
}
|
2022-09-20 09:14:11 +00:00
|
|
|
|
|
|
|
func TestUpdateDiscordMessageAuthorImage(t *testing.T) {
|
|
|
|
|
|
|
|
db, err := openTestDB()
|
|
|
|
require.NoError(t, err)
|
|
|
|
p := newSQLitePersistence(db)
|
|
|
|
|
|
|
|
require.NoError(t, p.SaveDiscordMessageAuthor(&protobuf.DiscordMessageAuthor{
|
|
|
|
Id: "1",
|
|
|
|
Name: "Testuser",
|
|
|
|
Discriminator: "1234",
|
|
|
|
Nickname: "User",
|
|
|
|
AvatarUrl: "http://example.com/profile.jpg",
|
|
|
|
}))
|
|
|
|
|
|
|
|
exists, err := p.HasDiscordMessageAuthor("1")
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.True(t, exists)
|
|
|
|
|
|
|
|
err = p.UpdateDiscordMessageAuthorImage("1", []byte{0, 1, 2, 3})
|
|
|
|
require.NoError(t, err)
|
|
|
|
payload, err := p.GetDiscordMessageAuthorImagePayloadByID("1")
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, []byte{0, 1, 2, 3}, payload)
|
|
|
|
}
|
2022-09-21 16:05:29 +00:00
|
|
|
|
|
|
|
func TestSaveHashRatchetMessage(t *testing.T) {
|
|
|
|
db, err := openTestDB()
|
|
|
|
require.NoError(t, err)
|
|
|
|
p := newSQLitePersistence(db)
|
|
|
|
|
|
|
|
groupID1 := []byte("group-id-1")
|
|
|
|
groupID2 := []byte("group-id-2")
|
|
|
|
var keyID uint32 = 3
|
|
|
|
|
|
|
|
message1 := &types.Message{
|
|
|
|
Hash: []byte{1},
|
|
|
|
Sig: []byte{2},
|
|
|
|
TTL: 1,
|
|
|
|
Timestamp: 2,
|
|
|
|
Payload: []byte{3},
|
|
|
|
}
|
|
|
|
|
|
|
|
require.NoError(t, p.SaveHashRatchetMessage(groupID1, keyID, message1))
|
|
|
|
|
|
|
|
message2 := &types.Message{
|
|
|
|
Hash: []byte{2},
|
|
|
|
Sig: []byte{2},
|
|
|
|
TTL: 1,
|
|
|
|
Topic: types.BytesToTopic([]byte{5}),
|
|
|
|
Timestamp: 2,
|
|
|
|
Payload: []byte{3},
|
|
|
|
Dst: []byte{4},
|
|
|
|
P2P: true,
|
|
|
|
}
|
|
|
|
|
|
|
|
require.NoError(t, p.SaveHashRatchetMessage(groupID2, keyID, message2))
|
|
|
|
|
|
|
|
fetchedMessages, err := p.GetHashRatchetMessages(groupID1, keyID)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, fetchedMessages)
|
|
|
|
require.Len(t, fetchedMessages, 1)
|
|
|
|
require.Equal(t, fetchedMessages[0], message1)
|
|
|
|
}
|