MM-29988 - Update exising Post APIs with collapsed threads (#16503)

Этот коммит содержится в:
Eli Yukelzon
2021-01-14 13:46:27 +02:00
коммит произвёл GitHub
родитель 2e1b578ccd
Коммит b0bddeb5e6
28 изменённых файлов: 616 добавлений и 257 удалений

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

@@ -100,13 +100,13 @@ func (_m *PostStore) Delete(postId string, time int64, deleteByID string) error
return r0
}
// Get provides a mock function with given fields: id, skipFetchThreads
func (_m *PostStore) Get(id string, skipFetchThreads bool) (*model.PostList, error) {
ret := _m.Called(id, skipFetchThreads)
// Get provides a mock function with given fields: id, skipFetchThreads, collapsedThreads, collapsedThreadsExtended
func (_m *PostStore) Get(id string, skipFetchThreads bool, collapsedThreads bool, collapsedThreadsExtended bool) (*model.PostList, error) {
ret := _m.Called(id, skipFetchThreads, collapsedThreads, collapsedThreadsExtended)
var r0 *model.PostList
if rf, ok := ret.Get(0).(func(string, bool) *model.PostList); ok {
r0 = rf(id, skipFetchThreads)
if rf, ok := ret.Get(0).(func(string, bool, bool, bool) *model.PostList); ok {
r0 = rf(id, skipFetchThreads, collapsedThreads, collapsedThreadsExtended)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.PostList)
@@ -114,8 +114,8 @@ func (_m *PostStore) Get(id string, skipFetchThreads bool) (*model.PostList, err
}
var r1 error
if rf, ok := ret.Get(1).(func(string, bool) error); ok {
r1 = rf(id, skipFetchThreads)
if rf, ok := ret.Get(1).(func(string, bool, bool, bool) error); ok {
r1 = rf(id, skipFetchThreads, collapsedThreads, collapsedThreadsExtended)
} else {
r1 = ret.Error(1)
}
@@ -146,13 +146,13 @@ func (_m *PostStore) GetDirectPostParentsForExportAfter(limit int, afterId strin
return r0, r1
}
// GetEtag provides a mock function with given fields: channelId, allowFromCache
func (_m *PostStore) GetEtag(channelId string, allowFromCache bool) string {
ret := _m.Called(channelId, allowFromCache)
// GetEtag provides a mock function with given fields: channelId, allowFromCache, collapsedThreads
func (_m *PostStore) GetEtag(channelId string, allowFromCache bool, collapsedThreads bool) string {
ret := _m.Called(channelId, allowFromCache, collapsedThreads)
var r0 string
if rf, ok := ret.Get(0).(func(string, bool) string); ok {
r0 = rf(channelId, allowFromCache)
if rf, ok := ret.Get(0).(func(string, bool, bool) string); ok {
r0 = rf(channelId, allowFromCache, collapsedThreads)
} else {
r0 = ret.Get(0).(string)
}

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

@@ -407,23 +407,23 @@ func testPostStoreGet(t *testing.T, ss store.Store) {
o1.UserId = model.NewId()
o1.Message = "zz" + model.NewId() + "b"
etag1 := ss.Post().GetEtag(o1.ChannelId, false)
etag1 := ss.Post().GetEtag(o1.ChannelId, false, false)
require.Equal(t, 0, strings.Index(etag1, model.CurrentVersion+"."), "Invalid Etag")
o1, err := ss.Post().Save(o1)
require.Nil(t, err)
etag2 := ss.Post().GetEtag(o1.ChannelId, false)
etag2 := ss.Post().GetEtag(o1.ChannelId, false, false)
require.Equal(t, 0, strings.Index(etag2, fmt.Sprintf("%v.%v", model.CurrentVersion, o1.UpdateAt)), "Invalid Etag")
r1, err := ss.Post().Get(o1.Id, false)
r1, err := ss.Post().Get(o1.Id, false, false, false)
require.Nil(t, err)
require.Equal(t, r1.Posts[o1.Id].CreateAt, o1.CreateAt, "invalid returned post")
_, err = ss.Post().Get("123", false)
_, err = ss.Post().Get("123", false, false, false)
require.NotNil(t, err, "Missing id should have failed")
_, err = ss.Post().Get("", false)
_, err = ss.Post().Get("", false, false, false)
require.NotNil(t, err, "should fail for blank post ids")
}
@@ -468,15 +468,15 @@ func testPostStoreUpdate(t *testing.T, ss store.Store) {
o3, err = ss.Post().Save(o3)
require.Nil(t, err)
r1, err := ss.Post().Get(o1.Id, false)
r1, err := ss.Post().Get(o1.Id, false, false, false)
require.Nil(t, err)
ro1 := r1.Posts[o1.Id]
r2, err := ss.Post().Get(o1.Id, false)
r2, err := ss.Post().Get(o1.Id, false, false, false)
require.Nil(t, err)
ro2 := r2.Posts[o2.Id]
r3, err := ss.Post().Get(o3.Id, false)
r3, err := ss.Post().Get(o3.Id, false, false, false)
require.Nil(t, err)
ro3 := r3.Posts[o3.Id]
@@ -487,7 +487,7 @@ func testPostStoreUpdate(t *testing.T, ss store.Store) {
_, err = ss.Post().Update(o1a, ro1)
require.Nil(t, err)
r1, err = ss.Post().Get(o1.Id, false)
r1, err = ss.Post().Get(o1.Id, false, false, false)
require.Nil(t, err)
ro1a := r1.Posts[o1.Id]
@@ -498,7 +498,7 @@ func testPostStoreUpdate(t *testing.T, ss store.Store) {
_, err = ss.Post().Update(o2a, ro2)
require.Nil(t, err)
r2, err = ss.Post().Get(o1.Id, false)
r2, err = ss.Post().Get(o1.Id, false, false, false)
require.Nil(t, err)
ro2a := r2.Posts[o2.Id]
@@ -509,7 +509,7 @@ func testPostStoreUpdate(t *testing.T, ss store.Store) {
_, err = ss.Post().Update(o3a, ro3)
require.Nil(t, err)
r3, err = ss.Post().Get(o3.Id, false)
r3, err = ss.Post().Get(o3.Id, false, false, false)
require.Nil(t, err)
ro3a := r3.Posts[o3.Id]
@@ -525,7 +525,7 @@ func testPostStoreUpdate(t *testing.T, ss store.Store) {
})
require.Nil(t, err)
r4, err := ss.Post().Get(o4.Id, false)
r4, err := ss.Post().Get(o4.Id, false, false, false)
require.Nil(t, err)
ro4 := r4.Posts[o4.Id]
@@ -535,7 +535,7 @@ func testPostStoreUpdate(t *testing.T, ss store.Store) {
_, err = ss.Post().Update(o4a, ro4)
require.Nil(t, err)
r4, err = ss.Post().Get(o4.Id, false)
r4, err = ss.Post().Get(o4.Id, false, false, false)
require.Nil(t, err)
ro4a := r4.Posts[o4.Id]
@@ -550,13 +550,13 @@ func testPostStoreDelete(t *testing.T, ss store.Store) {
o1.Message = "zz" + model.NewId() + "b"
deleteByID := model.NewId()
etag1 := ss.Post().GetEtag(o1.ChannelId, false)
etag1 := ss.Post().GetEtag(o1.ChannelId, false, false)
require.Equal(t, 0, strings.Index(etag1, model.CurrentVersion+"."), "Invalid Etag")
o1, err := ss.Post().Save(o1)
require.Nil(t, err)
r1, err := ss.Post().Get(o1.Id, false)
r1, err := ss.Post().Get(o1.Id, false, false, false)
require.Nil(t, err)
require.Equal(t, r1.Posts[o1.Id].CreateAt, o1.CreateAt, "invalid returned post")
@@ -569,10 +569,10 @@ func testPostStoreDelete(t *testing.T, ss store.Store) {
assert.Equal(t, deleteByID, actual, "Expected (*Post).Props[model.POST_PROPS_DELETE_BY] to be %v but got %v.", deleteByID, actual)
r3, err := ss.Post().Get(o1.Id, false)
r3, err := ss.Post().Get(o1.Id, false, false, false)
require.NotNil(t, err, "Missing id should have failed - PostList %v", r3)
etag2 := ss.Post().GetEtag(o1.ChannelId, false)
etag2 := ss.Post().GetEtag(o1.ChannelId, false, false)
require.Equal(t, 0, strings.Index(etag2, model.CurrentVersion+"."), "Invalid Etag")
}
@@ -596,10 +596,10 @@ func testPostStoreDelete1Level(t *testing.T, ss store.Store) {
err = ss.Post().Delete(o1.Id, model.GetMillis(), "")
require.Nil(t, err)
_, err = ss.Post().Get(o1.Id, false)
_, err = ss.Post().Get(o1.Id, false, false, false)
require.NotNil(t, err, "Deleted id should have failed")
_, err = ss.Post().Get(o2.Id, false)
_, err = ss.Post().Get(o2.Id, false, false, false)
require.NotNil(t, err, "Deleted id should have failed")
}
@@ -639,16 +639,16 @@ func testPostStoreDelete2Level(t *testing.T, ss store.Store) {
err = ss.Post().Delete(o1.Id, model.GetMillis(), "")
require.Nil(t, err)
_, err = ss.Post().Get(o1.Id, false)
_, err = ss.Post().Get(o1.Id, false, false, false)
require.NotNil(t, err, "Deleted id should have failed")
_, err = ss.Post().Get(o2.Id, false)
_, err = ss.Post().Get(o2.Id, false, false, false)
require.NotNil(t, err, "Deleted id should have failed")
_, err = ss.Post().Get(o3.Id, false)
_, err = ss.Post().Get(o3.Id, false, false, false)
require.NotNil(t, err, "Deleted id should have failed")
_, err = ss.Post().Get(o4.Id, false)
_, err = ss.Post().Get(o4.Id, false, false, false)
require.Nil(t, err)
}
@@ -679,16 +679,16 @@ func testPostStorePermDelete1Level(t *testing.T, ss store.Store) {
err2 := ss.Post().PermanentDeleteByUser(o2.UserId)
require.Nil(t, err2)
_, err = ss.Post().Get(o1.Id, false)
_, err = ss.Post().Get(o1.Id, false, false, false)
require.Nil(t, err, "Deleted id shouldn't have failed")
_, err = ss.Post().Get(o2.Id, false)
_, err = ss.Post().Get(o2.Id, false, false, false)
require.NotNil(t, err, "Deleted id should have failed")
err = ss.Post().PermanentDeleteByChannel(o3.ChannelId)
require.Nil(t, err)
_, err = ss.Post().Get(o3.Id, false)
_, err = ss.Post().Get(o3.Id, false, false, false)
require.NotNil(t, err, "Deleted id should have failed")
}
@@ -719,13 +719,13 @@ func testPostStorePermDelete1Level2(t *testing.T, ss store.Store) {
err2 := ss.Post().PermanentDeleteByUser(o1.UserId)
require.Nil(t, err2)
_, err = ss.Post().Get(o1.Id, false)
_, err = ss.Post().Get(o1.Id, false, false, false)
require.NotNil(t, err, "Deleted id should have failed")
_, err = ss.Post().Get(o2.Id, false)
_, err = ss.Post().Get(o2.Id, false, false, false)
require.NotNil(t, err, "Deleted id should have failed")
_, err = ss.Post().Get(o3.Id, false)
_, err = ss.Post().Get(o3.Id, false, false, false)
require.Nil(t, err, "Deleted id should have failed")
}
@@ -755,7 +755,7 @@ func testPostStoreGetWithChildren(t *testing.T, ss store.Store) {
o3, err = ss.Post().Save(o3)
require.Nil(t, err)
pl, err := ss.Post().Get(o1.Id, false)
pl, err := ss.Post().Get(o1.Id, false, false, false)
require.Nil(t, err)
require.Len(t, pl.Posts, 3, "invalid returned post")
@@ -763,7 +763,7 @@ func testPostStoreGetWithChildren(t *testing.T, ss store.Store) {
dErr := ss.Post().Delete(o3.Id, model.GetMillis(), "")
require.Nil(t, dErr)
pl, err = ss.Post().Get(o1.Id, false)
pl, err = ss.Post().Get(o1.Id, false, false, false)
require.Nil(t, err)
require.Len(t, pl.Posts, 2, "invalid returned post")
@@ -771,7 +771,7 @@ func testPostStoreGetWithChildren(t *testing.T, ss store.Store) {
dErr = ss.Post().Delete(o2.Id, model.GetMillis(), "")
require.Nil(t, dErr)
pl, err = ss.Post().Get(o1.Id, false)
pl, err = ss.Post().Get(o1.Id, false, false, false)
require.Nil(t, err)
require.Len(t, pl.Posts, 1, "invalid returned post")
@@ -1181,6 +1181,101 @@ func testPostStoreGetPostsBeforeAfter(t *testing.T, ss store.Store) {
}, postList.Posts)
})
})
t.Run("with threads (collapsedThreads)", func(t *testing.T) {
channelId := model.NewId()
userId := model.NewId()
// This creates a series of posts that looks like:
// post1
// post2
// post3 (in response to post1)
// post4 (in response to post2)
// post5
// post6 (in response to post2)
post1, err := ss.Post().Save(&model.Post{
ChannelId: channelId,
UserId: userId,
Message: "post1",
})
require.Nil(t, err)
post1.ReplyCount = 1
time.Sleep(time.Millisecond)
post2, err := ss.Post().Save(&model.Post{
ChannelId: channelId,
UserId: userId,
Message: "post2",
})
require.Nil(t, err)
post2.ReplyCount = 2
time.Sleep(time.Millisecond)
post3, err := ss.Post().Save(&model.Post{
ChannelId: channelId,
UserId: userId,
ParentId: post1.Id,
RootId: post1.Id,
Message: "post3",
})
require.Nil(t, err)
post3.ReplyCount = 1
time.Sleep(time.Millisecond)
post4, err := ss.Post().Save(&model.Post{
ChannelId: channelId,
UserId: userId,
RootId: post2.Id,
ParentId: post2.Id,
Message: "post4",
})
require.Nil(t, err)
post4.ReplyCount = 2
time.Sleep(time.Millisecond)
post5, err := ss.Post().Save(&model.Post{
ChannelId: channelId,
UserId: userId,
Message: "post5",
})
require.Nil(t, err)
time.Sleep(time.Millisecond)
post6, err := ss.Post().Save(&model.Post{
ChannelId: channelId,
UserId: userId,
ParentId: post2.Id,
RootId: post2.Id,
Message: "post6",
})
post6.ReplyCount = 2
require.Nil(t, err)
// Adding a post to a thread changes the UpdateAt timestamp of the parent post
post1.UpdateAt = post3.UpdateAt
post2.UpdateAt = post6.UpdateAt
t.Run("should return each root post before a post", func(t *testing.T) {
postList, err := ss.Post().GetPostsBefore(model.GetPostsOptions{ChannelId: channelId, PostId: post4.Id, PerPage: 2, CollapsedThreads: true})
assert.Nil(t, err)
assert.Equal(t, []string{post2.Id, post1.Id}, postList.Order)
})
t.Run("should return each root post before a post with limit", func(t *testing.T) {
postList, err := ss.Post().GetPostsBefore(model.GetPostsOptions{ChannelId: channelId, PostId: post4.Id, PerPage: 1, CollapsedThreads: true})
assert.Nil(t, err)
assert.Equal(t, []string{post2.Id}, postList.Order)
})
t.Run("should return each root after a post", func(t *testing.T) {
postList, err := ss.Post().GetPostsAfter(model.GetPostsOptions{ChannelId: channelId, PostId: post4.Id, PerPage: 2, CollapsedThreads: true})
require.Nil(t, err)
assert.Equal(t, []string{post5.Id}, postList.Order)
})
})
}
func testPostStoreGetPostsSince(t *testing.T, ss store.Store) {
@@ -2146,23 +2241,23 @@ func testPostStoreOverwriteMultiple(t *testing.T, ss store.Store) {
})
require.Nil(t, err)
r1, err := ss.Post().Get(o1.Id, false)
r1, err := ss.Post().Get(o1.Id, false, false, false)
require.Nil(t, err)
ro1 := r1.Posts[o1.Id]
r2, err := ss.Post().Get(o2.Id, false)
r2, err := ss.Post().Get(o2.Id, false, false, false)
require.Nil(t, err)
ro2 := r2.Posts[o2.Id]
r3, err := ss.Post().Get(o3.Id, false)
r3, err := ss.Post().Get(o3.Id, false, false, false)
require.Nil(t, err)
ro3 := r3.Posts[o3.Id]
r4, err := ss.Post().Get(o4.Id, false)
r4, err := ss.Post().Get(o4.Id, false, false, false)
require.Nil(t, err)
ro4 := r4.Posts[o4.Id]
r5, err := ss.Post().Get(o5.Id, false)
r5, err := ss.Post().Get(o5.Id, false, false, false)
require.Nil(t, err)
ro5 := r5.Posts[o5.Id]
@@ -2188,15 +2283,15 @@ func testPostStoreOverwriteMultiple(t *testing.T, ss store.Store) {
require.Nil(t, err)
require.Equal(t, -1, errIdx)
r1, nErr := ss.Post().Get(o1.Id, false)
r1, nErr := ss.Post().Get(o1.Id, false, false, false)
require.Nil(t, nErr)
ro1a := r1.Posts[o1.Id]
r2, nErr = ss.Post().Get(o1.Id, false)
r2, nErr = ss.Post().Get(o1.Id, false, false, false)
require.Nil(t, nErr)
ro2a := r2.Posts[o2.Id]
r3, nErr = ss.Post().Get(o3.Id, false)
r3, nErr = ss.Post().Get(o3.Id, false, false, false)
require.Nil(t, nErr)
ro3a := r3.Posts[o3.Id]
@@ -2218,11 +2313,11 @@ func testPostStoreOverwriteMultiple(t *testing.T, ss store.Store) {
require.Nil(t, err)
require.Equal(t, -1, errIdx)
r4, nErr := ss.Post().Get(o4.Id, false)
r4, nErr := ss.Post().Get(o4.Id, false, false, false)
require.Nil(t, nErr)
ro4a := r4.Posts[o4.Id]
r5, nErr = ss.Post().Get(o5.Id, false)
r5, nErr = ss.Post().Get(o5.Id, false, false, false)
require.Nil(t, nErr)
ro5a := r5.Posts[o5.Id]
@@ -2265,19 +2360,19 @@ func testPostStoreOverwrite(t *testing.T, ss store.Store) {
})
require.Nil(t, err)
r1, err := ss.Post().Get(o1.Id, false)
r1, err := ss.Post().Get(o1.Id, false, false, false)
require.Nil(t, err)
ro1 := r1.Posts[o1.Id]
r2, err := ss.Post().Get(o2.Id, false)
r2, err := ss.Post().Get(o2.Id, false, false, false)
require.Nil(t, err)
ro2 := r2.Posts[o2.Id]
r3, err := ss.Post().Get(o3.Id, false)
r3, err := ss.Post().Get(o3.Id, false, false, false)
require.Nil(t, err)
ro3 := r3.Posts[o3.Id]
r4, err := ss.Post().Get(o4.Id, false)
r4, err := ss.Post().Get(o4.Id, false, false, false)
require.Nil(t, err)
ro4 := r4.Posts[o4.Id]
@@ -2302,15 +2397,15 @@ func testPostStoreOverwrite(t *testing.T, ss store.Store) {
_, err = ss.Post().Overwrite(o3a)
require.Nil(t, err)
r1, err = ss.Post().Get(o1.Id, false)
r1, err = ss.Post().Get(o1.Id, false, false, false)
require.Nil(t, err)
ro1a := r1.Posts[o1.Id]
r2, err = ss.Post().Get(o1.Id, false)
r2, err = ss.Post().Get(o1.Id, false, false, false)
require.Nil(t, err)
ro2a := r2.Posts[o2.Id]
r3, err = ss.Post().Get(o3.Id, false)
r3, err = ss.Post().Get(o3.Id, false, false, false)
require.Nil(t, err)
ro3a := r3.Posts[o3.Id]
@@ -2326,7 +2421,7 @@ func testPostStoreOverwrite(t *testing.T, ss store.Store) {
_, err = ss.Post().Overwrite(o4a)
require.Nil(t, err)
r4, err = ss.Post().Get(o4.Id, false)
r4, err = ss.Post().Get(o4.Id, false, false, false)
require.Nil(t, err)
ro4a := r4.Posts[o4.Id]
@@ -2357,15 +2452,15 @@ func testPostStoreGetPostsByIds(t *testing.T, ss store.Store) {
o3, err = ss.Post().Save(o3)
require.Nil(t, err)
r1, err := ss.Post().Get(o1.Id, false)
r1, err := ss.Post().Get(o1.Id, false, false, false)
require.Nil(t, err)
ro1 := r1.Posts[o1.Id]
r2, err := ss.Post().Get(o2.Id, false)
r2, err := ss.Post().Get(o2.Id, false, false, false)
require.Nil(t, err)
ro2 := r2.Posts[o2.Id]
r3, err := ss.Post().Get(o3.Id, false)
r3, err := ss.Post().Get(o3.Id, false, false, false)
require.Nil(t, err)
ro3 := r3.Posts[o3.Id]
@@ -2472,13 +2567,13 @@ func testPostStorePermanentDeleteBatch(t *testing.T, ss store.Store) {
_, err = ss.Post().PermanentDeleteBatch(2000, 1000)
require.Nil(t, err)
_, err = ss.Post().Get(o1.Id, false)
_, err = ss.Post().Get(o1.Id, false, false, false)
require.NotNil(t, err, "Should have not found post 1 after purge")
_, err = ss.Post().Get(o2.Id, false)
_, err = ss.Post().Get(o2.Id, false, false, false)
require.NotNil(t, err, "Should have not found post 2 after purge")
_, err = ss.Post().Get(o3.Id, false)
_, err = ss.Post().Get(o3.Id, false, false, false)
require.Nil(t, err, "Should have not found post 3 after purge")
}

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

@@ -50,7 +50,7 @@ func testReactionSave(t *testing.T, ss store.Store) {
assert.Equal(t, saved.EmojiName, reaction1.EmojiName, "should've saved reaction emoji_name and returned it")
var secondUpdateAt int64
postList, err := ss.Post().Get(reaction1.PostId, false)
postList, err := ss.Post().Get(reaction1.PostId, false, false, false)
require.Nil(t, err)
assert.True(t, postList.Posts[post.Id].HasReactions, "should've set HasReactions = true on post")
@@ -74,7 +74,7 @@ func testReactionSave(t *testing.T, ss store.Store) {
_, nErr = ss.Reaction().Save(reaction2)
require.Nil(t, nErr)
postList, err = ss.Post().Get(reaction2.PostId, false)
postList, err = ss.Post().Get(reaction2.PostId, false, false, false)
require.Nil(t, err)
assert.NotEqual(t, postList.Posts[post.Id].UpdateAt, secondUpdateAt, "should've marked post as updated even if HasReactions doesn't change")
@@ -123,7 +123,7 @@ func testReactionDelete(t *testing.T, ss store.Store) {
_, nErr := ss.Reaction().Save(reaction)
require.Nil(t, nErr)
result, err := ss.Post().Get(reaction.PostId, false)
result, err := ss.Post().Get(reaction.PostId, false, false, false)
require.Nil(t, err)
firstUpdateAt := result.Posts[post.Id].UpdateAt
@@ -136,7 +136,7 @@ func testReactionDelete(t *testing.T, ss store.Store) {
assert.Empty(t, reactions, "should've deleted reaction")
postList, err := ss.Post().Get(post.Id, false)
postList, err := ss.Post().Get(post.Id, false, false, false)
require.Nil(t, err)
assert.False(t, postList.Posts[post.Id].HasReactions, "should've set HasReactions = false on post")
@@ -297,15 +297,15 @@ func testReactionDeleteAllWithEmojiName(t *testing.T, ss store.Store) {
assert.Empty(t, returned, "should've only removed reactions with emoji name")
// check that the posts are updated
postList, err := ss.Post().Get(post.Id, false)
postList, err := ss.Post().Get(post.Id, false, false, false)
require.Nil(t, err)
assert.True(t, postList.Posts[post.Id].HasReactions, "post should still have reactions")
postList, err = ss.Post().Get(post2.Id, false)
postList, err = ss.Post().Get(post2.Id, false, false, false)
require.Nil(t, err)
assert.True(t, postList.Posts[post2.Id].HasReactions, "post should still have reactions")
postList, err = ss.Post().Get(post3.Id, false)
postList, err = ss.Post().Get(post3.Id, false, false, false)
require.Nil(t, err)
assert.False(t, postList.Posts[post3.Id].HasReactions, "post shouldn't have reactions any more")

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

@@ -69,7 +69,7 @@ func testThreadStorePopulation(t *testing.T, ss store.Store) {
newPosts, errIdx, err3 := ss.Post().SaveMultiple([]*model.Post{&o2, &o3, &o4})
olist, _ := ss.Post().Get(otmp.Id, true)
olist, _ := ss.Post().Get(otmp.Id, true, false, false)
o1 := olist.Posts[olist.Order[0]]
newPosts = append([]*model.Post{o1}, newPosts...)