* - columns added to ShareChannelRemotes: lastpostcreateat, lastpostupdateat
- SyncMsg and SyncResponse moved to `model` package
- field added to RemoteCluster struct: PluginID

* sync new posts before updated posts to ensure post order in MS Teams

* add plugid to remoteclusters table and store

* don't sync history by default
Этот коммит содержится в:
Doug Lauder
2023-12-04 13:10:20 -05:00
коммит произвёл GitHub
родитель b2ec1ff8ae
Коммит 8bf9e4c481
22 изменённых файлов: 471 добавлений и 132 удалений

Просмотреть файл

@@ -58,7 +58,8 @@ func TestPostStore(t *testing.T, rctx request.CTX, ss store.Store, s SqlStore) {
t.Run("GetDirectPostParentsForExportAfterBatched", func(t *testing.T) { testPostStoreGetDirectPostParentsForExportAfterBatched(t, rctx, ss, s) })
t.Run("GetForThread", func(t *testing.T) { testPostStoreGetForThread(t, rctx, ss) })
t.Run("HasAutoResponsePostByUserSince", func(t *testing.T) { testHasAutoResponsePostByUserSince(t, rctx, ss) })
t.Run("GetPostsSinceForSync", func(t *testing.T) { testGetPostsSinceForSync(t, rctx, ss, s) })
t.Run("GetPostsSinceUpdateForSync", func(t *testing.T) { testGetPostsSinceUpdateForSync(t, rctx, ss, s) })
t.Run("GetPostsSinceCreateForSync", func(t *testing.T) { testGetPostsSinceCreateForSync(t, rctx, ss, s) })
t.Run("SetPostReminder", func(t *testing.T) { testSetPostReminder(t, rctx, ss, s) })
t.Run("GetPostReminders", func(t *testing.T) { testGetPostReminders(t, rctx, ss, s) })
t.Run("GetPostReminderMetadata", func(t *testing.T) { testGetPostReminderMetadata(t, rctx, ss, s) })
@@ -4655,7 +4656,7 @@ func testHasAutoResponsePostByUserSince(t *testing.T, rctx request.CTX, ss store
})
}
func testGetPostsSinceForSync(t *testing.T, rctx request.CTX, ss store.Store, s SqlStore) {
func testGetPostsSinceUpdateForSync(t *testing.T, rctx request.CTX, ss store.Store, s SqlStore) {
// create some posts.
channelID := model.NewId()
remoteID := model.NewString(model.NewId())
@@ -4758,6 +4759,113 @@ func testGetPostsSinceForSync(t *testing.T, rctx request.CTX, ss store.Store, s
})
}
func testGetPostsSinceCreateForSync(t *testing.T, rctx request.CTX, ss store.Store, s SqlStore) {
// create some posts.
channelID := model.NewId()
remoteID := model.NewString(model.NewId())
first := model.GetMillis()
data := []*model.Post{
{Id: model.NewId(), ChannelId: channelID, UserId: model.NewId(), Message: "test post 0"},
{Id: model.NewId(), ChannelId: channelID, UserId: model.NewId(), Message: "test post 1"},
{Id: model.NewId(), ChannelId: channelID, UserId: model.NewId(), Message: "test post 2"},
{Id: model.NewId(), ChannelId: channelID, UserId: model.NewId(), Message: "test post 3", RemoteId: remoteID},
{Id: model.NewId(), ChannelId: channelID, UserId: model.NewId(), Message: "test post 4", RemoteId: remoteID},
{Id: model.NewId(), ChannelId: channelID, UserId: model.NewId(), Message: "test post 5", RemoteId: remoteID},
{Id: model.NewId(), ChannelId: channelID, UserId: model.NewId(), Message: "test post 6", RemoteId: remoteID},
{Id: model.NewId(), ChannelId: channelID, UserId: model.NewId(), Message: "test post 7"},
{Id: model.NewId(), ChannelId: channelID, UserId: model.NewId(), Message: "test post 8", DeleteAt: model.GetMillis()},
{Id: model.NewId(), ChannelId: channelID, UserId: model.NewId(), Message: "test post 9", DeleteAt: model.GetMillis()},
}
for i, p := range data {
p.CreateAt = first + (int64(i) * 300000)
if p.RemoteId == nil {
p.RemoteId = model.NewString(model.NewId())
}
_, err := ss.Post().Save(p)
require.NoError(t, err, "couldn't save post")
}
t.Run("Invalid channel id", func(t *testing.T) {
opt := model.GetPostsSinceForSyncOptions{
ChannelId: model.NewId(),
SinceCreateAt: true,
}
cursor := model.GetPostsSinceForSyncCursor{}
posts, cursorOut, err := ss.Post().GetPostsSinceForSync(opt, cursor, 100)
require.NoError(t, err)
require.Empty(t, posts, "should return zero posts")
require.Equal(t, cursor, cursorOut)
})
t.Run("Get by channel, exclude remotes, exclude deleted", func(t *testing.T) {
opt := model.GetPostsSinceForSyncOptions{
ChannelId: channelID,
ExcludeRemoteId: *remoteID,
SinceCreateAt: true,
}
cursor := model.GetPostsSinceForSyncCursor{}
posts, _, err := ss.Post().GetPostsSinceForSync(opt, cursor, 100)
require.NoError(t, err)
require.ElementsMatch(t, getPostIds(data[0:3], data[7]), getPostIds(posts))
})
t.Run("Include deleted", func(t *testing.T) {
opt := model.GetPostsSinceForSyncOptions{
ChannelId: channelID,
IncludeDeleted: true,
SinceCreateAt: true,
}
cursor := model.GetPostsSinceForSyncCursor{}
posts, _, err := ss.Post().GetPostsSinceForSync(opt, cursor, 100)
require.NoError(t, err)
require.ElementsMatch(t, getPostIds(data), getPostIds(posts))
})
t.Run("Limit and cursor", func(t *testing.T) {
opt := model.GetPostsSinceForSyncOptions{
ChannelId: channelID,
SinceCreateAt: true,
}
cursor := model.GetPostsSinceForSyncCursor{}
posts1, cursor, err := ss.Post().GetPostsSinceForSync(opt, cursor, 5)
require.NoError(t, err)
require.Len(t, posts1, 5, "should get 5 posts")
posts2, _, err := ss.Post().GetPostsSinceForSync(opt, cursor, 5)
require.NoError(t, err)
require.Len(t, posts2, 3, "should get 3 posts")
require.ElementsMatch(t, getPostIds(data[0:8]), getPostIds(posts1, posts2...))
})
t.Run("CreateAt collisions", func(t *testing.T) {
// this test requires all the CreateAt timestamps to be the same.
result, err := s.GetMasterX().Exec("UPDATE Posts SET CreateAt = ?", model.GetMillis())
require.NoError(t, err)
rows, err := result.RowsAffected()
require.NoError(t, err)
require.Greater(t, rows, int64(0))
opt := model.GetPostsSinceForSyncOptions{
ChannelId: channelID,
}
cursor := model.GetPostsSinceForSyncCursor{}
posts1, cursor, err := ss.Post().GetPostsSinceForSync(opt, cursor, 5)
require.NoError(t, err)
require.Len(t, posts1, 5, "should get 5 posts")
posts2, _, err := ss.Post().GetPostsSinceForSync(opt, cursor, 5)
require.NoError(t, err)
require.Len(t, posts2, 3, "should get 3 posts")
require.ElementsMatch(t, getPostIds(data[0:8]), getPostIds(posts1, posts2...))
})
}
func testSetPostReminder(t *testing.T, rctx request.CTX, ss store.Store, s SqlStore) {
// Basic
userID := NewTestId()

Просмотреть файл

@@ -15,6 +15,10 @@ import (
"github.com/stretchr/testify/require"
)
const (
testPluginID = "com.sample.blap"
)
func TestRemoteClusterStore(t *testing.T, rctx request.CTX, ss store.Store) {
t.Run("RemoteClusterGetAllInChannel", func(t *testing.T) { testRemoteClusterGetAllInChannel(t, rctx, ss) })
t.Run("RemoteClusterGetAllNotInChannel", func(t *testing.T) { testRemoteClusterGetAllNotInChannel(t, rctx, ss) })
@@ -89,6 +93,7 @@ func testRemoteClusterGet(t *testing.T, rctx request.CTX, ss store.Store) {
Name: "shortlived_remote_2",
SiteURL: "nowhere.com",
CreatorId: model.NewId(),
PluginID: testPluginID,
}
rcSaved, err := ss.RemoteCluster().Save(rc)
require.NoError(t, err)
@@ -96,6 +101,7 @@ func testRemoteClusterGet(t *testing.T, rctx request.CTX, ss store.Store) {
rcGet, err := ss.RemoteCluster().Get(rcSaved.RemoteId)
require.NoError(t, err)
require.Equal(t, rcSaved.RemoteId, rcGet.RemoteId)
require.Equal(t, testPluginID, rcGet.PluginID)
})
t.Run("Get not found", func(t *testing.T) {
@@ -237,8 +243,8 @@ func testRemoteClusterGetAllInChannel(t *testing.T, rctx request.CTX, ss store.S
// Create some remote clusters
rcData := []*model.RemoteCluster{
{Name: "AAAA_Inc", CreatorId: userId, SiteURL: "aaaa.com", RemoteId: model.NewId(), LastPingAt: now},
{Name: "BBBB_Inc", CreatorId: userId, SiteURL: "bbbb.com", RemoteId: model.NewId(), LastPingAt: 0},
{Name: "AAAA_Inc", CreatorId: userId, SiteURL: "aaaa.com", RemoteId: model.NewId(), LastPingAt: now, PluginID: testPluginID},
{Name: "BBBB_Inc", CreatorId: userId, SiteURL: "bbbb.com", RemoteId: model.NewId(), LastPingAt: 0, PluginID: testPluginID},
{Name: "CCCC_Inc", CreatorId: userId, SiteURL: "cccc.com", RemoteId: model.NewId(), LastPingAt: now},
{Name: "DDDD_Inc", CreatorId: userId, SiteURL: "dddd.com", RemoteId: model.NewId(), LastPingAt: now},
{Name: "EEEE_Inc", CreatorId: userId, SiteURL: "eeee.com", RemoteId: model.NewId(), LastPingAt: 0},
@@ -270,6 +276,8 @@ func testRemoteClusterGetAllInChannel(t *testing.T, rctx request.CTX, ss store.S
require.Len(t, list, 2, "channel 1 should have 2 remote clusters")
ids := getIds(list)
require.ElementsMatch(t, []string{rcData[0].RemoteId, rcData[1].RemoteId}, ids)
require.Equal(t, testPluginID, rcData[0].PluginID)
require.Equal(t, testPluginID, rcData[1].PluginID)
})
t.Run("Channel 1 online only", func(t *testing.T) {

Просмотреть файл

@@ -765,28 +765,52 @@ func testUpdateSharedChannelRemoteCursor(t *testing.T, rctx request.CTX, ss stor
remoteSaved, err := ss.SharedChannel().SaveRemote(remote)
require.NoError(t, err, "couldn't save remote", err)
future := model.GetMillis() + 3600000 // 1 hour in the future
postID := model.NewId()
futureCreateAt := model.GetMillis() + 3600000 // 1 hour in the future
postCreateID := model.NewId()
cursor := model.GetPostsSinceForSyncCursor{
LastPostUpdateAt: future,
LastPostId: postID,
futureUpdateAt := model.GetMillis() + (3600000 * 2) // 2 hours in the future
postUpdateID := model.NewId()
cursorCreate := model.GetPostsSinceForSyncCursor{
LastPostCreateAt: futureCreateAt,
LastPostCreateID: postCreateID,
}
t.Run("Update NextSyncAt for remote", func(t *testing.T) {
err := ss.SharedChannel().UpdateRemoteCursor(remoteSaved.Id, cursor)
require.NoError(t, err, "update NextSyncAt should not error", err)
cursorUpdate := model.GetPostsSinceForSyncCursor{
LastPostUpdateAt: futureUpdateAt,
LastPostUpdateID: postUpdateID,
}
t.Run("Update cursor CreateAt for remote", func(t *testing.T) {
err := ss.SharedChannel().UpdateRemoteCursor(remoteSaved.Id, cursorCreate)
require.NoError(t, err, "update cursor should not error", err)
r, err := ss.SharedChannel().GetRemote(remoteSaved.Id)
require.NoError(t, err)
require.Equal(t, future, r.LastPostUpdateAt)
require.Equal(t, postID, r.LastPostId)
require.Equal(t, futureCreateAt, r.LastPostCreateAt)
require.Equal(t, postCreateID, r.LastPostCreateID)
})
t.Run("Update NextSyncAt for non-existent shared channel remote", func(t *testing.T) {
err := ss.SharedChannel().UpdateRemoteCursor(model.NewId(), cursor)
t.Run("Update cursor UpdateAt for remote", func(t *testing.T) {
err := ss.SharedChannel().UpdateRemoteCursor(remoteSaved.Id, cursorUpdate)
require.NoError(t, err, "update cursor should not error", err)
r, err := ss.SharedChannel().GetRemote(remoteSaved.Id)
require.NoError(t, err)
require.Equal(t, futureUpdateAt, r.LastPostUpdateAt)
require.Equal(t, postUpdateID, r.LastPostUpdateID)
})
t.Run("Update cursor for non-existent shared channel remote", func(t *testing.T) {
err := ss.SharedChannel().UpdateRemoteCursor(model.NewId(), cursorUpdate)
require.Error(t, err, "update non-existent remote should error", err)
})
t.Run("Update with empty cursor", func(t *testing.T) {
emptyCursor := model.GetPostsSinceForSyncCursor{}
err := ss.SharedChannel().UpdateRemoteCursor(remoteSaved.Id, emptyCursor)
require.Error(t, err, "update with empty cursor should error", err)
})
}
func testDeleteSharedChannelRemote(t *testing.T, rctx request.CTX, ss store.Store) {