MM-11210 Add "GET /posts/unread" API to support landing on the last unread post (#11486)

* [MM-11210] Add API GET 'api/v4/channels/{channel_id:[A-Za-z0-9]+}/posts/unread' for scrolling overhaul (#9108)

* Add API GET 'api/v4/channels/{channel_id:[A-Za-z0-9]+}/posts/unread'

* add constants

* refactor GetPostSince and added more tests

* move constants to app package

* [MM-11528 &&  MM-11583] Add userId to in the "posts/unread" path and update test with time delay to fix intermittent failure (#9229)

* add userId to in the "posts/unread" path and update test with time delay to fix intermittent failure

* add limit before and after to query

* remove time delay on test and put pretermined value of Post.CreateAt

* Fix conflict

* [MM-11876] Add cursor to posts list such as next_post_id and previous_post_id (#9707)

* add cursor to posts list such as next_post_id and previous_post_id

add publish previous_post_id on WEBSOCKET_EVENT_POSTED and only get next or previous post IDs if necessary

revert change on adding previous_post_id in WEBSOCKET_EVENT_POSTED

add missing strings import

fix merge conflicts

* update per comment

* update per feedback

* corrected the logic in getting the next and previous post ID

* fix logic to determine next and post IDs, and rename function to have suffix of "Time"

* rearrange logics and add mote tests

* fix merge conflict

* fix missing message when using unread API (#10233)

* MM-15569 Fixes failing test on TestGetPostsForChannelAroundLastUnread (#11039)

* Fix missing posts when getting posts since

* revert changes to GetPostsSince

* migrate Post.GetPostAfterTime and Post.GetPostBeforeTime to sync by default

* revert change to cacheItem

* Fix post ID validation, build query on squirrel and only return post ID as necessary
Этот коммит содержится в:
Saturnino Abril
2019-07-04 05:23:04 +08:00
коммит произвёл Sudheer
родитель f56a8f5a99
Коммит b832985f1d
12 изменённых файлов: 1085 добавлений и 32 удалений

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

@@ -16,6 +16,7 @@ import (
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/mattermost/mattermost-server/app"
"github.com/mattermost/mattermost-server/model"
@@ -911,6 +912,13 @@ func TestGetPostsForChannel(t *testing.T) {
t.Log(posts.Posts)
t.Fatal("should return 2 posts")
}
// "since" query to return empty NextPostId and PrevPostId
if posts.NextPostId != "" {
t.Fatal("should return an empty NextPostId")
}
if posts.PrevPostId != "" {
t.Fatal("should return an empty PrevPostId")
}
found := make([]bool, 2)
for _, p := range posts.Posts {
@@ -945,6 +953,97 @@ func TestGetPostsForChannel(t *testing.T) {
_, resp = th.SystemAdminClient.GetPostsForChannel(th.BasicChannel.Id, 0, 60, "")
CheckNoError(t, resp)
// more tests for next_post_id, prev_post_id, and order
// There are 12 posts composed of first 2 system messages and 10 created posts
Client.Login(th.BasicUser.Email, th.BasicUser.Password)
th.CreatePost() // post6
post7 := th.CreatePost()
post8 := th.CreatePost()
th.CreatePost() // post9
post10 := th.CreatePost()
// get the system post IDs posted before the created posts above
posts, resp = Client.GetPostsBefore(th.BasicChannel.Id, post1.Id, 0, 2, "")
systemPostId1 := posts.Order[1]
// similar to '/posts'
posts, resp = Client.GetPostsForChannel(th.BasicChannel.Id, 0, 60, "")
CheckNoError(t, resp)
if len(posts.Order) != 12 || posts.Order[0] != post10.Id || posts.Order[11] != systemPostId1 {
t.Fatal("should return 12 posts and match order")
}
if posts.NextPostId != "" {
t.Fatal("should return an empty NextPostId")
}
if posts.PrevPostId != "" {
t.Fatal("should return an empty PrevPostId")
}
// similar to '/posts?per_page=3'
posts, resp = Client.GetPostsForChannel(th.BasicChannel.Id, 0, 3, "")
CheckNoError(t, resp)
if len(posts.Order) != 3 || posts.Order[0] != post10.Id || posts.Order[2] != post8.Id {
t.Fatal("should return 3 posts and match order")
}
if posts.NextPostId != "" {
t.Fatal("should return an empty NextPostId")
}
if posts.PrevPostId != post7.Id {
t.Fatal("should return post7.Id as PrevPostId")
}
// similar to '/posts?per_page=3&page=1'
posts, resp = Client.GetPostsForChannel(th.BasicChannel.Id, 1, 3, "")
CheckNoError(t, resp)
if len(posts.Order) != 3 || posts.Order[0] != post7.Id || posts.Order[2] != post5.Id {
t.Fatal("should return 3 posts and match order")
}
if posts.NextPostId != post8.Id {
t.Fatal("should return post8.Id as NextPostId")
}
if posts.PrevPostId != post4.Id {
t.Fatal("should return post4.Id as PrevPostId")
}
// similar to '/posts?per_page=3&page=2'
posts, resp = Client.GetPostsForChannel(th.BasicChannel.Id, 2, 3, "")
CheckNoError(t, resp)
if len(posts.Order) != 3 || posts.Order[0] != post4.Id || posts.Order[2] != post2.Id {
t.Fatal("should return 3 posts and match order")
}
if posts.NextPostId != post5.Id {
t.Fatal("should return post5.Id as NextPostId")
}
if posts.PrevPostId != post1.Id {
t.Fatal("should return post1.Id as PrevPostId")
}
// similar to '/posts?per_page=3&page=3'
posts, resp = Client.GetPostsForChannel(th.BasicChannel.Id, 3, 3, "")
CheckNoError(t, resp)
if len(posts.Order) != 3 || posts.Order[0] != post1.Id || posts.Order[2] != systemPostId1 {
t.Fatal("should return 3 posts and match order")
}
if posts.NextPostId != post2.Id {
t.Fatal("should return post2.Id as NextPostId")
}
if posts.PrevPostId != "" {
t.Fatal("should return an empty PrevPostId")
}
// similar to '/posts?per_page=3&page=4'
posts, resp = Client.GetPostsForChannel(th.BasicChannel.Id, 4, 3, "")
CheckNoError(t, resp)
if len(posts.Order) != 0 {
t.Fatal("should return 0 post")
}
if posts.NextPostId != "" {
t.Fatal("should return an empty NextPostId")
}
if posts.PrevPostId != "" {
t.Fatal("should return an empty PrevPostId")
}
}
func TestGetFlaggedPostsForUser(t *testing.T) {
@@ -1190,7 +1289,7 @@ func TestGetFlaggedPostsForUser(t *testing.T) {
CheckNoError(t, resp)
}
func TestGetPostsAfterAndBefore(t *testing.T) {
func TestGetPostsBefore(t *testing.T) {
th := Setup().InitBasic()
defer th.TearDown()
Client := th.Client
@@ -1223,24 +1322,208 @@ func TestGetPostsAfterAndBefore(t *testing.T) {
}
}
posts, resp = Client.GetPostsBefore(th.BasicChannel.Id, post3.Id, 1, 1, "")
if posts.NextPostId != post3.Id {
t.Fatal("should match NextPostId")
}
if posts.PrevPostId != "" {
t.Fatal("should match empty PrevPostId")
}
posts, resp = Client.GetPostsBefore(th.BasicChannel.Id, post4.Id, 1, 1, "")
CheckNoError(t, resp)
if len(posts.Posts) != 1 {
t.Fatal("too many posts returned")
}
posts, resp = Client.GetPostsBefore(th.BasicChannel.Id, "junk", 1, 1, "")
CheckNoError(t, resp)
if len(posts.Posts) != 0 {
t.Fatal("should have no posts")
if posts.Order[0] != post2.Id {
t.Fatal("should match returned post")
}
if posts.NextPostId != post3.Id {
t.Fatal("should match NextPostId")
}
if posts.PrevPostId != post1.Id {
t.Fatal("should match PrevPostId")
}
posts, resp = Client.GetPostsAfter(th.BasicChannel.Id, post3.Id, 0, 100, "")
posts, resp = Client.GetPostsBefore(th.BasicChannel.Id, "junk", 1, 1, "")
CheckBadRequestStatus(t, resp)
posts, resp = Client.GetPostsBefore(th.BasicChannel.Id, post5.Id, 0, 3, "")
CheckNoError(t, resp)
found = make([]bool, 2)
if len(posts.Posts) != 3 {
t.Fatal("should match length of posts returned")
}
if posts.Order[0] != post4.Id {
t.Fatal("should match returned post")
}
if posts.Order[2] != post2.Id {
t.Fatal("should match returned post")
}
if posts.NextPostId != post5.Id {
t.Fatal("should match NextPostId")
}
if posts.PrevPostId != post1.Id {
t.Fatal("should match PrevPostId")
}
// get the system post IDs posted before the created posts above
posts, resp = Client.GetPostsBefore(th.BasicChannel.Id, post1.Id, 0, 2, "")
CheckNoError(t, resp)
systemPostId2 := posts.Order[0]
systemPostId1 := posts.Order[1]
posts, resp = Client.GetPostsBefore(th.BasicChannel.Id, post5.Id, 1, 3, "")
CheckNoError(t, resp)
if len(posts.Posts) != 3 {
t.Fatal("should match length of posts returned")
}
if posts.Order[0] != post1.Id {
t.Fatal("should match returned post")
}
if posts.Order[1] != systemPostId2 {
t.Fatal("should match returned post")
}
if posts.Order[2] != systemPostId1 {
t.Fatal("should match returned post")
}
if posts.NextPostId != post2.Id {
t.Fatal("should match NextPostId")
}
if posts.PrevPostId != "" {
t.Fatal("should return empty PrevPostId")
}
// more tests for next_post_id, prev_post_id, and order
// There are 12 posts composed of first 2 system messages and 10 created posts
post6 := th.CreatePost()
th.CreatePost() // post7
post8 := th.CreatePost()
post9 := th.CreatePost()
th.CreatePost() // post10
// similar to '/posts?before=post9'
posts, resp = Client.GetPostsBefore(th.BasicChannel.Id, post9.Id, 0, 60, "")
CheckNoError(t, resp)
if len(posts.Order) != 10 || posts.Order[0] != post8.Id || posts.Order[9] != systemPostId1 {
t.Fatal("should return 10 posts and match order")
}
if posts.NextPostId != post9.Id {
t.Fatal("should return post9.Id as NextPostId")
}
if posts.PrevPostId != "" {
t.Fatal("should return an empty PrevPostId")
}
// similar to '/posts?before=post9&per_page=3'
posts, resp = Client.GetPostsBefore(th.BasicChannel.Id, post9.Id, 0, 3, "")
CheckNoError(t, resp)
if len(posts.Order) != 3 || posts.Order[0] != post8.Id || posts.Order[2] != post6.Id {
t.Fatal("should return 3 posts and match order")
}
if posts.NextPostId != post9.Id {
t.Fatal("should return post9.Id as NextPostId")
}
if posts.PrevPostId != post5.Id {
t.Fatal("should return post5.Id as PrevPostId")
}
// similar to '/posts?before=post9&per_page=3&page=1'
posts, resp = Client.GetPostsBefore(th.BasicChannel.Id, post9.Id, 1, 3, "")
CheckNoError(t, resp)
if len(posts.Order) != 3 || posts.Order[0] != post5.Id || posts.Order[2] != post3.Id {
t.Fatal("should return 3 posts and match order")
}
if posts.NextPostId != post6.Id {
t.Fatal("should return post6.Id as NextPostId")
}
if posts.PrevPostId != post2.Id {
t.Fatal("should return post2.Id as PrevPostId")
}
// similar to '/posts?before=post9&per_page=3&page=2'
posts, resp = Client.GetPostsBefore(th.BasicChannel.Id, post9.Id, 2, 3, "")
CheckNoError(t, resp)
if len(posts.Order) != 3 || posts.Order[0] != post2.Id || posts.Order[2] != systemPostId2 {
t.Fatal("should return 3 posts and match order")
}
if posts.NextPostId != post3.Id {
t.Fatal("should return post3.Id as NextPostId")
}
if posts.PrevPostId != systemPostId1 {
t.Fatal("should return systemPostId1 as PrevPostId")
}
// similar to '/posts?before=post1&per_page=3'
posts, resp = Client.GetPostsBefore(th.BasicChannel.Id, post1.Id, 0, 3, "")
CheckNoError(t, resp)
if len(posts.Order) != 2 || posts.Order[0] != systemPostId2 || posts.Order[1] != systemPostId1 {
t.Fatal("should return 2 posts and match order")
}
if posts.NextPostId != post1.Id {
t.Fatal("should return post1.Id as NextPostId")
}
if posts.PrevPostId != "" {
t.Fatal("should return an empty PrevPostId")
}
// similar to '/posts?before=systemPostId1'
posts, resp = Client.GetPostsBefore(th.BasicChannel.Id, systemPostId1, 0, 60, "")
CheckNoError(t, resp)
if len(posts.Order) != 0 {
t.Fatal("should return 0 post")
}
if posts.NextPostId != systemPostId1 {
t.Fatal("should return systemPostId1 as NextPostId")
}
if posts.PrevPostId != "" {
t.Fatal("should return an empty PrevPostId")
}
// similar to '/posts?before=systemPostId1&per_page=60&page=1'
posts, resp = Client.GetPostsBefore(th.BasicChannel.Id, systemPostId1, 1, 60, "")
CheckNoError(t, resp)
if len(posts.Order) != 0 {
t.Fatal("should return 0 post")
}
if posts.NextPostId != "" {
t.Fatal("should return an empty NextPostId")
}
if posts.PrevPostId != "" {
t.Fatal("should return an empty PrevPostId")
}
// similar to '/posts?before=non-existent-post'
nonExistentPostId := model.NewId()
posts, resp = Client.GetPostsBefore(th.BasicChannel.Id, nonExistentPostId, 0, 60, "")
CheckNoError(t, resp)
if len(posts.Order) != 0 {
t.Fatal("should return 0 post")
}
if posts.NextPostId != nonExistentPostId {
t.Fatal("should return nonExistentPostId as NextPostId")
}
if posts.PrevPostId != "" {
t.Fatal("should return an empty PrevPostId")
}
}
func TestGetPostsAfter(t *testing.T) {
th := Setup().InitBasic()
defer th.TearDown()
Client := th.Client
post1 := th.CreatePost()
post2 := th.CreatePost()
post3 := th.CreatePost()
post4 := th.CreatePost()
post5 := th.CreatePost()
posts, resp := Client.GetPostsAfter(th.BasicChannel.Id, post3.Id, 0, 100, "")
CheckNoError(t, resp)
found := make([]bool, 2)
for _, p := range posts.Posts {
if p.Id == post4.Id {
found[0] = true
@@ -1259,18 +1542,298 @@ func TestGetPostsAfterAndBefore(t *testing.T) {
}
}
posts, resp = Client.GetPostsAfter(th.BasicChannel.Id, post3.Id, 1, 1, "")
if posts.NextPostId != "" {
t.Fatal("should match empty NextPostId")
}
if posts.PrevPostId != post3.Id {
t.Fatal("should match PrevPostId")
}
posts, resp = Client.GetPostsAfter(th.BasicChannel.Id, post2.Id, 1, 1, "")
CheckNoError(t, resp)
if len(posts.Posts) != 1 {
t.Fatal("too many posts returned")
}
if posts.Order[0] != post4.Id {
t.Fatal("should match returned post")
}
if posts.NextPostId != post5.Id {
t.Fatal("should match NextPostId")
}
if posts.PrevPostId != post3.Id {
t.Fatal("should match PrevPostId")
}
posts, resp = Client.GetPostsAfter(th.BasicChannel.Id, "junk", 1, 1, "")
CheckBadRequestStatus(t, resp)
posts, resp = Client.GetPostsAfter(th.BasicChannel.Id, post1.Id, 0, 3, "")
CheckNoError(t, resp)
if len(posts.Posts) != 0 {
t.Fatal("should have no posts")
if len(posts.Posts) != 3 {
t.Fatal("should match length of posts returned")
}
if posts.Order[0] != post4.Id {
t.Fatal("should match returned post")
}
if posts.Order[2] != post2.Id {
t.Fatal("should match returned post")
}
if posts.NextPostId != post5.Id {
t.Fatal("should match NextPostId")
}
if posts.PrevPostId != post1.Id {
t.Fatal("should match PrevPostId")
}
posts, resp = Client.GetPostsAfter(th.BasicChannel.Id, post1.Id, 1, 3, "")
CheckNoError(t, resp)
if len(posts.Posts) != 1 {
t.Fatal("should match length of posts returned")
}
if posts.Order[0] != post5.Id {
t.Fatal("should match returned post")
}
if posts.NextPostId != "" {
t.Fatal("should match NextPostId")
}
if posts.PrevPostId != post4.Id {
t.Fatal("should match PrevPostId")
}
// more tests for next_post_id, prev_post_id, and order
// There are 12 posts composed of first 2 system messages and 10 created posts
post6 := th.CreatePost()
th.CreatePost() // post7
post8 := th.CreatePost()
post9 := th.CreatePost()
post10 := th.CreatePost()
// similar to '/posts?after=post2'
posts, resp = Client.GetPostsAfter(th.BasicChannel.Id, post2.Id, 0, 60, "")
CheckNoError(t, resp)
if len(posts.Order) != 8 || posts.Order[0] != post10.Id || posts.Order[7] != post3.Id {
t.Fatal("should return 8 posts and match order")
}
if posts.NextPostId != "" {
t.Fatal("should return an empty NextPostId")
}
if posts.PrevPostId != post2.Id {
t.Fatal("should return post2.Id as PrevPostId")
}
// similar to '/posts?after=post2&per_page=3'
posts, resp = Client.GetPostsAfter(th.BasicChannel.Id, post2.Id, 0, 3, "")
CheckNoError(t, resp)
if len(posts.Order) != 3 || posts.Order[0] != post5.Id || posts.Order[2] != post3.Id {
t.Fatal("should return 3 posts and match order")
}
if posts.NextPostId != post6.Id {
t.Fatal("should return post6.Id as NextPostId")
}
if posts.PrevPostId != post2.Id {
t.Fatal("should return post2.Id as PrevPostId")
}
// similar to '/posts?after=post2&per_page=3&page=1'
posts, resp = Client.GetPostsAfter(th.BasicChannel.Id, post2.Id, 1, 3, "")
CheckNoError(t, resp)
if len(posts.Order) != 3 || posts.Order[0] != post8.Id || posts.Order[2] != post6.Id {
t.Fatal("should return 3 posts and match order")
}
if posts.NextPostId != post9.Id {
t.Fatal("should return post9.Id as NextPostId")
}
if posts.PrevPostId != post5.Id {
t.Fatal("should return post5.Id as PrevPostId")
}
// similar to '/posts?after=post2&per_page=3&page=2'
posts, resp = Client.GetPostsAfter(th.BasicChannel.Id, post2.Id, 2, 3, "")
CheckNoError(t, resp)
if len(posts.Order) != 2 || posts.Order[0] != post10.Id || posts.Order[1] != post9.Id {
t.Fatal("should return 2 posts and match order")
}
if posts.NextPostId != "" {
t.Fatal("should return an empty NextPostId")
}
if posts.PrevPostId != post8.Id {
t.Fatal("should return post8.Id as PrevPostId")
}
// similar to '/posts?after=post10'
posts, resp = Client.GetPostsAfter(th.BasicChannel.Id, post10.Id, 0, 60, "")
CheckNoError(t, resp)
if len(posts.Order) != 0 {
t.Fatal("should return 0 post")
}
if posts.NextPostId != "" {
t.Fatal("should return an empty NextPostId")
}
if posts.PrevPostId != post10.Id {
t.Fatal("should return post10.Id as PrevPostId")
}
// similar to '/posts?after=post10&page=1'
posts, resp = Client.GetPostsAfter(th.BasicChannel.Id, post10.Id, 1, 60, "")
CheckNoError(t, resp)
if len(posts.Order) != 0 {
t.Fatal("should return 0 post")
}
if posts.NextPostId != "" {
t.Fatal("should return an empty NextPostId")
}
if posts.PrevPostId != "" {
t.Fatal("should return an empty PrevPostId")
}
// similar to '/posts?after=non-existent-post'
nonExistentPostId := model.NewId()
posts, resp = Client.GetPostsAfter(th.BasicChannel.Id, nonExistentPostId, 0, 60, "")
CheckNoError(t, resp)
if len(posts.Order) != 0 {
t.Fatal("should return 0 post")
}
if posts.NextPostId != "" {
t.Fatal("should return an empty NextPostId")
}
if posts.PrevPostId != nonExistentPostId {
t.Fatal("should return nonExistentPostId as PrevPostId")
}
}
func TestGetPostsForChannelAroundLastUnread(t *testing.T) {
th := Setup().InitBasic()
defer th.TearDown()
Client := th.Client
userId := th.BasicUser.Id
channelId := th.BasicChannel.Id
// 12 posts = 2 systems posts + 10 created posts below
post1 := th.CreatePost()
post2 := th.CreatePost()
post3 := th.CreatePost()
post4 := th.CreatePost()
th.CreatePost() // post5
post6 := th.CreatePost()
post7 := th.CreatePost()
post8 := th.CreatePost()
post9 := th.CreatePost()
post10 := th.CreatePost()
// All returned posts are all read by the user, since it's created by the user itself.
posts, resp := Client.GetPostsAroundLastUnread(userId, channelId, 20, 20)
CheckNoError(t, resp)
if len(posts.Order) != 12 {
t.Fatal("Should return 12 posts only since there's no unread post")
}
// Set channel member's last viewed to 0.
// All returned posts are latest posts as if all previous posts were already read by the user.
channelMember, err := th.App.Srv.Store.Channel().GetMember(channelId, userId)
require.Nil(t, err)
channelMember.LastViewedAt = 0
_, err = th.App.Srv.Store.Channel().UpdateMember(channelMember)
require.Nil(t, err)
th.App.Srv.Store.Post().InvalidateLastPostTimeCache(channelId)
posts, resp = Client.GetPostsAroundLastUnread(userId, channelId, 20, 20)
CheckNoError(t, resp)
if len(posts.Order) != 12 {
t.Fatal("Should return 12 posts only since there's no unread post")
}
// get the first system post generated before the created posts above
posts, resp = Client.GetPostsBefore(th.BasicChannel.Id, post1.Id, 0, 2, "")
CheckNoError(t, resp)
systemPostId1 := posts.Order[1]
// Set channel member's last viewed before post1.
channelMember, err = th.App.Srv.Store.Channel().GetMember(channelId, userId)
require.Nil(t, err)
channelMember.LastViewedAt = post1.CreateAt - 1
_, err = th.App.Srv.Store.Channel().UpdateMember(channelMember)
require.Nil(t, err)
th.App.Srv.Store.Post().InvalidateLastPostTimeCache(channelId)
posts, resp = Client.GetPostsAroundLastUnread(userId, channelId, 3, 3)
CheckNoError(t, resp)
if len(posts.Order) != 5 || posts.Order[0] != post3.Id || posts.Order[4] != systemPostId1 {
t.Fatal("Should return 5 posts and match order")
}
if posts.NextPostId != post4.Id {
t.Fatal("should return post4.Id as NextPostId")
}
if posts.PrevPostId != "" {
t.Fatal("should return an empty PrevPostId")
}
// Set channel member's last viewed before post6.
channelMember, err = th.App.Srv.Store.Channel().GetMember(channelId, userId)
require.Nil(t, err)
channelMember.LastViewedAt = post6.CreateAt - 1
_, err = th.App.Srv.Store.Channel().UpdateMember(channelMember)
require.Nil(t, err)
th.App.Srv.Store.Post().InvalidateLastPostTimeCache(channelId)
posts, resp = Client.GetPostsAroundLastUnread(userId, channelId, 3, 3)
CheckNoError(t, resp)
if len(posts.Order) != 6 || posts.Order[0] != post8.Id || posts.Order[5] != post3.Id {
t.Fatal("Should return 6 posts and match order")
}
if posts.NextPostId != post9.Id {
t.Fatal("should return post8.Id as NextPostId")
}
if posts.PrevPostId != post2.Id {
t.Fatal("should return post2.Id as PrevPostId")
}
// Set channel member's last viewed before post10.
channelMember, err = th.App.Srv.Store.Channel().GetMember(channelId, userId)
require.Nil(t, err)
channelMember.LastViewedAt = post10.CreateAt - 1
_, err = th.App.Srv.Store.Channel().UpdateMember(channelMember)
require.Nil(t, err)
th.App.Srv.Store.Post().InvalidateLastPostTimeCache(channelId)
posts, resp = Client.GetPostsAroundLastUnread(userId, channelId, 3, 3)
CheckNoError(t, resp)
if len(posts.Order) != 4 || posts.Order[0] != post10.Id || posts.Order[3] != post7.Id {
t.Fatal("Should return 4 posts and match order")
}
if posts.NextPostId != "" {
t.Fatal("should return an empty NextPostId")
}
if posts.PrevPostId != post6.Id {
t.Fatal("should return post6.Id as PrevPostId")
}
// Set channel member's last viewed equal to post10.
channelMember, err = th.App.Srv.Store.Channel().GetMember(channelId, userId)
require.Nil(t, err)
channelMember.LastViewedAt = post10.CreateAt
_, err = th.App.Srv.Store.Channel().UpdateMember(channelMember)
require.Nil(t, err)
th.App.Srv.Store.Post().InvalidateLastPostTimeCache(channelId)
posts, resp = Client.GetPostsAroundLastUnread(userId, channelId, 3, 3)
CheckNoError(t, resp)
if len(posts.Order) != 3 || posts.Order[0] != post10.Id || posts.Order[2] != post8.Id {
t.Fatal("Should return 3 posts and match order")
}
if posts.NextPostId != "" {
t.Fatal("should return an empty NextPostId")
}
if posts.PrevPostId != post7.Id {
t.Fatal("should return post7.Id as PrevPostId")
}
}