Merge branch 'master' into mark-as-unread

Этот коммит содержится в:
Harrison Healey
2019-11-19 09:45:03 -05:00
родитель 2f066da704 c40f0a4aea
Коммит de913e7537
108 изменённых файлов: 11124 добавлений и 1190 удалений

65
store/localcachelayer/channel_layer.go Обычный файл
Просмотреть файл

@@ -0,0 +1,65 @@
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package localcachelayer
import (
"github.com/mattermost/mattermost-server/model"
"github.com/mattermost/mattermost-server/store"
)
type LocalCacheChannelStore struct {
store.ChannelStore
rootStore *LocalCacheStore
}
func (s *LocalCacheChannelStore) handleClusterInvalidateChannelMemberCounts(msg *model.ClusterMessage) {
if msg.Data == CLEAR_CACHE_MESSAGE_DATA {
s.rootStore.channelMemberCountsCache.Purge()
} else {
s.rootStore.channelMemberCountsCache.Remove(msg.Data)
}
}
func (s LocalCacheChannelStore) ClearCaches() {
s.rootStore.doClearCacheCluster(s.rootStore.channelMemberCountsCache)
s.ChannelStore.ClearCaches()
if s.rootStore.metrics != nil {
s.rootStore.metrics.IncrementMemCacheInvalidationCounter("Channel Member Counts - Purge")
}
}
func (s LocalCacheChannelStore) InvalidateMemberCount(channelId string) {
s.rootStore.doInvalidateCacheCluster(s.rootStore.channelMemberCountsCache, channelId)
if s.rootStore.metrics != nil {
s.rootStore.metrics.IncrementMemCacheInvalidationCounter("Channel Member Counts - Remove by ChannelId")
}
}
func (s LocalCacheChannelStore) GetMemberCount(channelId string, allowFromCache bool) (int64, *model.AppError) {
if allowFromCache {
if count := s.rootStore.doStandardReadCache(s.rootStore.channelMemberCountsCache, channelId); count != nil {
return count.(int64), nil
}
}
count, err := s.ChannelStore.GetMemberCount(channelId, allowFromCache)
if allowFromCache && err == nil {
s.rootStore.doStandardAddToCache(s.rootStore.channelMemberCountsCache, channelId, count)
}
return count, err
}
func (s LocalCacheChannelStore) GetMemberCountFromCache(channelId string) int64 {
if count := s.rootStore.doStandardReadCache(s.rootStore.channelMemberCountsCache, channelId); count != nil {
return count.(int64)
}
count, err := s.GetMemberCount(channelId, true)
if err != nil {
return 0
}
return count
}

88
store/localcachelayer/channel_layer_test.go Обычный файл
Просмотреть файл

@@ -0,0 +1,88 @@
package localcachelayer
import (
"testing"
"github.com/mattermost/mattermost-server/store/storetest"
"github.com/mattermost/mattermost-server/store/storetest/mocks"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestChannelStore(t *testing.T) {
StoreTest(t, storetest.TestReactionStore)
}
func TestChannelStoreChannelMemberCountsCache(t *testing.T) {
countResult := int64(10)
t.Run("first call not cached, second cached and returning same data", func(t *testing.T) {
mockStore := getMockStore()
cachedStore := NewLocalCacheLayer(mockStore, nil, nil)
count, err := cachedStore.Channel().GetMemberCount("id", true)
require.Nil(t, err)
assert.Equal(t, count, countResult)
mockStore.Channel().(*mocks.ChannelStore).AssertNumberOfCalls(t, "GetMemberCount", 1)
count, err = cachedStore.Channel().GetMemberCount("id", true)
require.Nil(t, err)
assert.Equal(t, count, countResult)
mockStore.Channel().(*mocks.ChannelStore).AssertNumberOfCalls(t, "GetMemberCount", 1)
})
t.Run("first call not cached, second force no cached", func(t *testing.T) {
mockStore := getMockStore()
cachedStore := NewLocalCacheLayer(mockStore, nil, nil)
cachedStore.Channel().GetMemberCount("id", true)
mockStore.Channel().(*mocks.ChannelStore).AssertNumberOfCalls(t, "GetMemberCount", 1)
cachedStore.Channel().GetMemberCount("id", false)
mockStore.Channel().(*mocks.ChannelStore).AssertNumberOfCalls(t, "GetMemberCount", 2)
})
t.Run("first call force no cached, second not cached, third cached", func(t *testing.T) {
mockStore := getMockStore()
cachedStore := NewLocalCacheLayer(mockStore, nil, nil)
cachedStore.Channel().GetMemberCount("id", false)
mockStore.Channel().(*mocks.ChannelStore).AssertNumberOfCalls(t, "GetMemberCount", 1)
cachedStore.Channel().GetMemberCount("id", true)
mockStore.Channel().(*mocks.ChannelStore).AssertNumberOfCalls(t, "GetMemberCount", 2)
cachedStore.Channel().GetMemberCount("id", true)
mockStore.Channel().(*mocks.ChannelStore).AssertNumberOfCalls(t, "GetMemberCount", 2)
})
t.Run("first call with GetMemberCountFromCache not cached, second cached and returning same data", func(t *testing.T) {
mockStore := getMockStore()
cachedStore := NewLocalCacheLayer(mockStore, nil, nil)
count := cachedStore.Channel().GetMemberCountFromCache("id")
assert.Equal(t, count, countResult)
mockStore.Channel().(*mocks.ChannelStore).AssertNumberOfCalls(t, "GetMemberCount", 1)
count = cachedStore.Channel().GetMemberCountFromCache("id")
assert.Equal(t, count, countResult)
mockStore.Channel().(*mocks.ChannelStore).AssertNumberOfCalls(t, "GetMemberCount", 1)
})
t.Run("first call not cached, clear cache, second call not cached", func(t *testing.T) {
mockStore := getMockStore()
cachedStore := NewLocalCacheLayer(mockStore, nil, nil)
cachedStore.Channel().GetMemberCount("id", true)
mockStore.Channel().(*mocks.ChannelStore).AssertNumberOfCalls(t, "GetMemberCount", 1)
cachedStore.Channel().ClearCaches()
cachedStore.Channel().GetMemberCount("id", true)
mockStore.Channel().(*mocks.ChannelStore).AssertNumberOfCalls(t, "GetMemberCount", 2)
})
t.Run("first call not cached, invalidate cache, second call not cached", func(t *testing.T) {
mockStore := getMockStore()
cachedStore := NewLocalCacheLayer(mockStore, nil, nil)
cachedStore.Channel().GetMemberCount("id", true)
mockStore.Channel().(*mocks.ChannelStore).AssertNumberOfCalls(t, "GetMemberCount", 1)
cachedStore.Channel().InvalidateMemberCount("id")
cachedStore.Channel().GetMemberCount("id", true)
mockStore.Channel().(*mocks.ChannelStore).AssertNumberOfCalls(t, "GetMemberCount", 2)
})
}

100
store/localcachelayer/emoji_layer.go Обычный файл
Просмотреть файл

@@ -0,0 +1,100 @@
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package localcachelayer
import (
"github.com/mattermost/mattermost-server/model"
"github.com/mattermost/mattermost-server/store"
)
type LocalCacheEmojiStore struct {
store.EmojiStore
rootStore *LocalCacheStore
}
func (es *LocalCacheEmojiStore) handleClusterInvalidateEmojiById(msg *model.ClusterMessage) {
if msg.Data == CLEAR_CACHE_MESSAGE_DATA {
es.rootStore.emojiCacheById.Purge()
} else {
es.rootStore.emojiCacheById.Remove(msg.Data)
}
}
func (es *LocalCacheEmojiStore) handleClusterInvalidateEmojiIdByName(msg *model.ClusterMessage) {
if msg.Data == CLEAR_CACHE_MESSAGE_DATA {
es.rootStore.emojiIdCacheByName.Purge()
} else {
es.rootStore.emojiIdCacheByName.Remove(msg.Data)
}
}
func (es LocalCacheEmojiStore) Get(id string, allowFromCache bool) (*model.Emoji, *model.AppError) {
if allowFromCache {
if emoji, ok := es.getFromCacheById(id); ok {
return emoji, nil
}
}
emoji, err := es.EmojiStore.Get(id, allowFromCache)
if allowFromCache && err == nil {
es.addToCache(emoji)
}
return emoji, err
}
func (es LocalCacheEmojiStore) GetByName(name string, allowFromCache bool) (*model.Emoji, *model.AppError) {
if id, ok := model.GetSystemEmojiId(name); ok {
return es.Get(id, allowFromCache)
}
if allowFromCache {
if emoji, ok := es.getFromCacheByName(name); ok {
return emoji, nil
}
}
emoji, err := es.EmojiStore.GetByName(name, allowFromCache)
if allowFromCache && err == nil {
es.addToCache(emoji)
}
return emoji, err
}
func (es LocalCacheEmojiStore) Delete(emoji *model.Emoji, time int64) *model.AppError {
err := es.EmojiStore.Delete(emoji, time)
if err == nil {
es.removeFromCache(emoji)
}
return err
}
func (es LocalCacheEmojiStore) addToCache(emoji *model.Emoji) {
es.rootStore.doStandardAddToCache(es.rootStore.emojiCacheById, emoji.Id, emoji)
es.rootStore.doStandardAddToCache(es.rootStore.emojiIdCacheByName, emoji.Name, emoji.Id)
}
func (es LocalCacheEmojiStore) getFromCacheById(id string) (*model.Emoji, bool) {
if emoji := es.rootStore.doStandardReadCache(es.rootStore.emojiCacheById, id); emoji != nil {
return emoji.(*model.Emoji), true
}
return nil, false
}
func (es LocalCacheEmojiStore) getFromCacheByName(name string) (*model.Emoji, bool) {
if emojiId := es.rootStore.doStandardReadCache(es.rootStore.emojiIdCacheByName, name); emojiId != nil {
return es.getFromCacheById(emojiId.(string))
}
return nil, false
}
func (es LocalCacheEmojiStore) removeFromCache(emoji *model.Emoji) {
es.rootStore.doInvalidateCacheCluster(es.rootStore.emojiCacheById, emoji.Id)
es.rootStore.doInvalidateCacheCluster(es.rootStore.emojiIdCacheByName, emoji.Name)
}

136
store/localcachelayer/emoji_layer_test.go Обычный файл
Просмотреть файл

@@ -0,0 +1,136 @@
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package localcachelayer
import (
"testing"
"github.com/mattermost/mattermost-server/model"
"github.com/mattermost/mattermost-server/store/storetest"
"github.com/mattermost/mattermost-server/store/storetest/mocks"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestEmojiStore(t *testing.T) {
StoreTest(t, storetest.TestEmojiStore)
}
func TestEmojiStoreCache(t *testing.T) {
fakeEmoji := model.Emoji{Id: "123", Name: "name123"}
t.Run("first call by id not cached, second cached and returning same data", func(t *testing.T) {
mockStore := getMockStore()
cachedStore := NewLocalCacheLayer(mockStore, nil, nil)
emoji, err := cachedStore.Emoji().Get("123", true)
require.Nil(t, err)
assert.Equal(t, emoji, &fakeEmoji)
mockStore.Emoji().(*mocks.EmojiStore).AssertNumberOfCalls(t, "Get", 1)
emoji, err = cachedStore.Emoji().Get("123", true)
require.Nil(t, err)
assert.Equal(t, emoji, &fakeEmoji)
mockStore.Emoji().(*mocks.EmojiStore).AssertNumberOfCalls(t, "Get", 1)
})
t.Run("first call by name not cached, second cached and returning same data", func(t *testing.T) {
mockStore := getMockStore()
cachedStore := NewLocalCacheLayer(mockStore, nil, nil)
emoji, err := cachedStore.Emoji().GetByName("name123", true)
require.Nil(t, err)
assert.Equal(t, emoji, &fakeEmoji)
mockStore.Emoji().(*mocks.EmojiStore).AssertNumberOfCalls(t, "GetByName", 1)
emoji, err = cachedStore.Emoji().GetByName("name123", true)
require.Nil(t, err)
assert.Equal(t, emoji, &fakeEmoji)
mockStore.Emoji().(*mocks.EmojiStore).AssertNumberOfCalls(t, "GetByName", 1)
})
t.Run("first call by id not cached, second force no cached", func(t *testing.T) {
mockStore := getMockStore()
cachedStore := NewLocalCacheLayer(mockStore, nil, nil)
cachedStore.Emoji().Get("123", true)
mockStore.Emoji().(*mocks.EmojiStore).AssertNumberOfCalls(t, "Get", 1)
cachedStore.Emoji().Get("123", false)
mockStore.Emoji().(*mocks.EmojiStore).AssertNumberOfCalls(t, "Get", 2)
})
t.Run("first call by name not cached, second force no cached", func(t *testing.T) {
mockStore := getMockStore()
cachedStore := NewLocalCacheLayer(mockStore, nil, nil)
cachedStore.Emoji().GetByName("name123", true)
mockStore.Emoji().(*mocks.EmojiStore).AssertNumberOfCalls(t, "GetByName", 1)
cachedStore.Emoji().GetByName("name123", false)
mockStore.Emoji().(*mocks.EmojiStore).AssertNumberOfCalls(t, "GetByName", 2)
})
t.Run("first call by id force no cached, second not cached, third cached", func(t *testing.T) {
mockStore := getMockStore()
cachedStore := NewLocalCacheLayer(mockStore, nil, nil)
cachedStore.Emoji().Get("123", false)
mockStore.Emoji().(*mocks.EmojiStore).AssertNumberOfCalls(t, "Get", 1)
cachedStore.Emoji().Get("123", true)
mockStore.Emoji().(*mocks.EmojiStore).AssertNumberOfCalls(t, "Get", 2)
cachedStore.Emoji().Get("123", true)
mockStore.Emoji().(*mocks.EmojiStore).AssertNumberOfCalls(t, "Get", 2)
})
t.Run("first call by id force no cached, second not cached, third cached", func(t *testing.T) {
mockStore := getMockStore()
cachedStore := NewLocalCacheLayer(mockStore, nil, nil)
cachedStore.Emoji().GetByName("name123", false)
mockStore.Emoji().(*mocks.EmojiStore).AssertNumberOfCalls(t, "GetByName", 1)
cachedStore.Emoji().GetByName("name123", true)
mockStore.Emoji().(*mocks.EmojiStore).AssertNumberOfCalls(t, "GetByName", 2)
cachedStore.Emoji().GetByName("name123", true)
mockStore.Emoji().(*mocks.EmojiStore).AssertNumberOfCalls(t, "GetByName", 2)
})
t.Run("first call by id, second call by name cached", func(t *testing.T) {
mockStore := getMockStore()
cachedStore := NewLocalCacheLayer(mockStore, nil, nil)
cachedStore.Emoji().Get("123", true)
mockStore.Emoji().(*mocks.EmojiStore).AssertNumberOfCalls(t, "Get", 1)
cachedStore.Emoji().GetByName("name123", true)
mockStore.Emoji().(*mocks.EmojiStore).AssertNumberOfCalls(t, "GetByName", 0)
})
t.Run("first call by name, second call by id cached", func(t *testing.T) {
mockStore := getMockStore()
cachedStore := NewLocalCacheLayer(mockStore, nil, nil)
cachedStore.Emoji().GetByName("name123", true)
mockStore.Emoji().(*mocks.EmojiStore).AssertNumberOfCalls(t, "GetByName", 1)
cachedStore.Emoji().Get("123", true)
mockStore.Emoji().(*mocks.EmojiStore).AssertNumberOfCalls(t, "Get", 0)
})
t.Run("first call by id not cached, invalidate, and then not cached again", func(t *testing.T) {
mockStore := getMockStore()
cachedStore := NewLocalCacheLayer(mockStore, nil, nil)
cachedStore.Emoji().Get("123", true)
mockStore.Emoji().(*mocks.EmojiStore).AssertNumberOfCalls(t, "Get", 1)
cachedStore.Emoji().Delete(&fakeEmoji, 0)
cachedStore.Emoji().Get("123", true)
mockStore.Emoji().(*mocks.EmojiStore).AssertNumberOfCalls(t, "Get", 2)
})
t.Run("first call by name not cached, invalidate, and then not cached again", func(t *testing.T) {
mockStore := getMockStore()
cachedStore := NewLocalCacheLayer(mockStore, nil, nil)
cachedStore.Emoji().GetByName("name123", true)
mockStore.Emoji().(*mocks.EmojiStore).AssertNumberOfCalls(t, "GetByName", 1)
cachedStore.Emoji().Delete(&fakeEmoji, 0)
cachedStore.Emoji().GetByName("name123", true)
mockStore.Emoji().(*mocks.EmojiStore).AssertNumberOfCalls(t, "GetByName", 2)
})
}

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

@@ -20,19 +20,30 @@ const (
SCHEME_CACHE_SIZE = 20000
SCHEME_CACHE_SEC = 30 * 60
EMOJI_CACHE_SIZE = 5000
EMOJI_CACHE_SEC = 30 * 60
CHANNEL_MEMBERS_COUNTS_CACHE_SIZE = model.CHANNEL_CACHE_SIZE
CHANNEL_MEMBERS_COUNTS_CACHE_SEC = 30 * 60
CLEAR_CACHE_MESSAGE_DATA = ""
)
type LocalCacheStore struct {
store.Store
metrics einterfaces.MetricsInterface
cluster einterfaces.ClusterInterface
reaction LocalCacheReactionStore
reactionCache *utils.Cache
role LocalCacheRoleStore
roleCache *utils.Cache
scheme LocalCacheSchemeStore
schemeCache *utils.Cache
metrics einterfaces.MetricsInterface
cluster einterfaces.ClusterInterface
reaction LocalCacheReactionStore
reactionCache *utils.Cache
role LocalCacheRoleStore
roleCache *utils.Cache
scheme LocalCacheSchemeStore
schemeCache *utils.Cache
emoji LocalCacheEmojiStore
emojiCacheById *utils.Cache
emojiIdCacheByName *utils.Cache
channel LocalCacheChannelStore
channelMemberCountsCache *utils.Cache
}
func NewLocalCacheLayer(baseStore store.Store, metrics einterfaces.MetricsInterface, cluster einterfaces.ClusterInterface) LocalCacheStore {
@@ -47,11 +58,19 @@ func NewLocalCacheLayer(baseStore store.Store, metrics einterfaces.MetricsInterf
localCacheStore.role = LocalCacheRoleStore{RoleStore: baseStore.Role(), rootStore: &localCacheStore}
localCacheStore.schemeCache = utils.NewLruWithParams(SCHEME_CACHE_SIZE, "Scheme", SCHEME_CACHE_SEC, model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_SCHEMES)
localCacheStore.scheme = LocalCacheSchemeStore{SchemeStore: baseStore.Scheme(), rootStore: &localCacheStore}
localCacheStore.emojiCacheById = utils.NewLruWithParams(EMOJI_CACHE_SIZE, "EmojiById", EMOJI_CACHE_SEC, model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_EMOJIS_BY_ID)
localCacheStore.emojiIdCacheByName = utils.NewLruWithParams(EMOJI_CACHE_SIZE, "EmojiByName", EMOJI_CACHE_SEC, model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_EMOJIS_ID_BY_NAME)
localCacheStore.emoji = LocalCacheEmojiStore{EmojiStore: baseStore.Emoji(), rootStore: &localCacheStore}
localCacheStore.channelMemberCountsCache = utils.NewLruWithParams(CHANNEL_MEMBERS_COUNTS_CACHE_SIZE, "ChannelMemberCounts", CHANNEL_MEMBERS_COUNTS_CACHE_SEC, model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_CHANNEL_MEMBER_COUNTS)
localCacheStore.channel = LocalCacheChannelStore{ChannelStore: baseStore.Channel(), rootStore: &localCacheStore}
if cluster != nil {
cluster.RegisterClusterMessageHandler(model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_REACTIONS, localCacheStore.reaction.handleClusterInvalidateReaction)
cluster.RegisterClusterMessageHandler(model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_ROLES, localCacheStore.role.handleClusterInvalidateRole)
cluster.RegisterClusterMessageHandler(model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_SCHEMES, localCacheStore.scheme.handleClusterInvalidateScheme)
cluster.RegisterClusterMessageHandler(model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_EMOJIS_BY_ID, localCacheStore.emoji.handleClusterInvalidateEmojiById)
cluster.RegisterClusterMessageHandler(model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_EMOJIS_ID_BY_NAME, localCacheStore.emoji.handleClusterInvalidateEmojiIdByName)
cluster.RegisterClusterMessageHandler(model.CLUSTER_EVENT_INVALIDATE_CACHE_FOR_CHANNEL_MEMBER_COUNTS, localCacheStore.channel.handleClusterInvalidateChannelMemberCounts)
}
return localCacheStore
}
@@ -68,6 +87,14 @@ func (s LocalCacheStore) Scheme() store.SchemeStore {
return s.scheme
}
func (s LocalCacheStore) Emoji() store.EmojiStore {
return s.emoji
}
func (s LocalCacheStore) Channel() store.ChannelStore {
return s.channel
}
func (s LocalCacheStore) DropAllTables() {
s.Invalidate()
s.Store.DropAllTables()
@@ -118,4 +145,7 @@ func (s *LocalCacheStore) doClearCacheCluster(cache *utils.Cache) {
func (s *LocalCacheStore) Invalidate() {
s.doClearCacheCluster(s.reactionCache)
s.doClearCacheCluster(s.emojiCacheById)
s.doClearCacheCluster(s.emojiIdCacheByName)
s.doClearCacheCluster(s.channelMemberCountsCache)
}

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

@@ -41,6 +41,22 @@ func getMockStore() *mocks.Store {
mockSchemesStore.On("PermanentDeleteAll").Return(nil)
mockStore.On("Scheme").Return(&mockSchemesStore)
fakeEmoji := model.Emoji{Id: "123", Name: "name123"}
mockEmojiStore := mocks.EmojiStore{}
mockEmojiStore.On("Get", "123", true).Return(&fakeEmoji, nil)
mockEmojiStore.On("Get", "123", false).Return(&fakeEmoji, nil)
mockEmojiStore.On("GetByName", "name123", true).Return(&fakeEmoji, nil)
mockEmojiStore.On("GetByName", "name123", false).Return(&fakeEmoji, nil)
mockEmojiStore.On("Delete", &fakeEmoji, int64(0)).Return(nil)
mockStore.On("Emoji").Return(&mockEmojiStore)
mockCount := int64(10)
mockChannelStore := mocks.ChannelStore{}
mockChannelStore.On("ClearCaches").Return()
mockChannelStore.On("GetMemberCount", "id", true).Return(mockCount, nil)
mockChannelStore.On("GetMemberCount", "id", false).Return(mockCount, nil)
mockStore.On("Channel").Return(&mockChannelStore)
return &mockStore
}

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

@@ -29,9 +29,6 @@ const (
ALL_CHANNEL_MEMBERS_NOTIFY_PROPS_FOR_CHANNEL_CACHE_SIZE = model.SESSION_CACHE_SIZE
ALL_CHANNEL_MEMBERS_NOTIFY_PROPS_FOR_CHANNEL_CACHE_SEC = 1800 // 30 mins
CHANNEL_MEMBERS_COUNTS_CACHE_SIZE = model.CHANNEL_CACHE_SIZE
CHANNEL_MEMBERS_COUNTS_CACHE_SEC = 1800 // 30 mins
CHANNEL_GUESTS_COUNTS_CACHE_SIZE = model.CHANNEL_CACHE_SIZE
CHANNEL_GUESTS_COUNTS_CACHE_SEC = 1800 // 30 mins
@@ -283,7 +280,6 @@ type publicChannel struct {
Purpose string `json:"purpose"`
}
var channelMemberCountsCache = utils.NewLru(CHANNEL_MEMBERS_COUNTS_CACHE_SIZE)
var channelPinnedPostCountsCache = utils.NewLru(CHANNEL_PINNEDPOSTS_COUNTS_CACHE_SIZE)
var channelGuestCountsCache = utils.NewLru(CHANNEL_GUESTS_COUNTS_CACHE_SIZE)
var allChannelMembersForUserCache = utils.NewLru(ALL_CHANNEL_MEMBERS_FOR_USER_CACHE_SIZE)
@@ -292,7 +288,6 @@ var channelCache = utils.NewLru(model.CHANNEL_CACHE_SIZE)
var channelByNameCache = utils.NewLru(model.CHANNEL_CACHE_SIZE)
func (s SqlChannelStore) ClearCaches() {
channelMemberCountsCache.Purge()
channelPinnedPostCountsCache.Purge()
channelGuestCountsCache.Purge()
allChannelMembersForUserCache.Purge()
@@ -301,7 +296,6 @@ func (s SqlChannelStore) ClearCaches() {
channelByNameCache.Purge()
if s.metrics != nil {
s.metrics.IncrementMemCacheInvalidationCounter("Channel Member Counts - Purge")
s.metrics.IncrementMemCacheInvalidationCounter("Channel Pinned Post Counts - Purge")
s.metrics.IncrementMemCacheInvalidationCounter("All Channel Members for User - Purge")
s.metrics.IncrementMemCacheInvalidationCounter("All Channel Members Notify Props for Channel - Purge")
@@ -1585,46 +1579,14 @@ func (s SqlChannelStore) GetAllChannelMembersNotifyPropsForChannel(channelId str
}
func (s SqlChannelStore) InvalidateMemberCount(channelId string) {
channelMemberCountsCache.Remove(channelId)
if s.metrics != nil {
s.metrics.IncrementMemCacheInvalidationCounter("Channel Member Counts - Remove by ChannelId")
}
}
func (s SqlChannelStore) GetMemberCountFromCache(channelId string) int64 {
if cacheItem, ok := channelMemberCountsCache.Get(channelId); ok {
if s.metrics != nil {
s.metrics.IncrementMemCacheHitCounter("Channel Member Counts")
}
return cacheItem.(int64)
}
if s.metrics != nil {
s.metrics.IncrementMemCacheMissCounter("Channel Member Counts")
}
count, err := s.GetMemberCount(channelId, true)
if err != nil {
return 0
}
count, _ := s.GetMemberCount(channelId, true)
return count
}
func (s SqlChannelStore) GetMemberCount(channelId string, allowFromCache bool) (int64, *model.AppError) {
if allowFromCache {
if cacheItem, ok := channelMemberCountsCache.Get(channelId); ok {
if s.metrics != nil {
s.metrics.IncrementMemCacheHitCounter("Channel Member Counts")
}
return cacheItem.(int64), nil
}
}
if s.metrics != nil {
s.metrics.IncrementMemCacheMissCounter("Channel Member Counts")
}
count, err := s.GetReplica().SelectInt(`
SELECT
count(*)
@@ -1639,10 +1601,6 @@ func (s SqlChannelStore) GetMemberCount(channelId string, allowFromCache bool) (
return 0, model.NewAppError("SqlChannelStore.GetMemberCount", "store.sql_channel.get_member_count.app_error", nil, "channel_id="+channelId+", "+err.Error(), http.StatusInternalServerError)
}
if allowFromCache {
channelMemberCountsCache.AddWithExpiresInSecs(channelId, count, CHANNEL_MEMBERS_COUNTS_CACHE_SEC)
}
return count, nil
}

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

@@ -216,6 +216,7 @@ func (s SqlComplianceStore) MessageExport(after int64, limit int) ([]*model.Mess
Posts.DeleteAt AS PostDeleteAt,
Posts.Message AS PostMessage,
Posts.Type AS PostType,
Posts.Props AS PostProps,
Posts.OriginalId AS PostOriginalId,
Posts.RootId AS PostRootId,
Posts.Props AS PostProps,
@@ -243,7 +244,7 @@ func (s SqlComplianceStore) MessageExport(after int64, limit int) ([]*model.Mess
LEFT JOIN Bots ON Bots.UserId = Posts.UserId
WHERE
(Posts.CreateAt > :StartTime OR Posts.EditAt > :StartTime OR Posts.DeleteAt > :StartTime) AND
Posts.Type = ''
Posts.Type NOT LIKE 'system_%'
ORDER BY PostUpdateAt
LIMIT :Limit`

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

@@ -11,17 +11,8 @@ import (
"github.com/mattermost/mattermost-server/einterfaces"
"github.com/mattermost/mattermost-server/model"
"github.com/mattermost/mattermost-server/store"
"github.com/mattermost/mattermost-server/utils"
)
const (
EMOJI_CACHE_SIZE = 5000
EMOJI_CACHE_SEC = 1800 // 30 mins
)
var emojiCacheById = utils.NewLru(EMOJI_CACHE_SIZE)
var emojiIdCacheByName = utils.NewLru(EMOJI_CACHE_SIZE)
type SqlEmojiStore struct {
SqlStore
metrics einterfaces.MetricsInterface
@@ -66,26 +57,10 @@ func (es SqlEmojiStore) Save(emoji *model.Emoji) (*model.Emoji, *model.AppError)
}
func (es SqlEmojiStore) Get(id string, allowFromCache bool) (*model.Emoji, *model.AppError) {
if allowFromCache {
if emoji, ok := es.getFromCacheById(id); ok {
return emoji, nil
}
}
return es.getBy("Id", id, allowFromCache)
}
func (es SqlEmojiStore) GetByName(name string, allowFromCache bool) (*model.Emoji, *model.AppError) {
if id, ok := model.GetSystemEmojiId(name); ok {
return es.Get(id, allowFromCache)
}
if allowFromCache {
if emoji, ok := es.getFromCacheByName(name); ok {
return emoji, nil
}
}
return es.getBy("Name", name, allowFromCache)
}
@@ -139,8 +114,6 @@ func (es SqlEmojiStore) Delete(emoji *model.Emoji, time int64) *model.AppError {
return model.NewAppError("SqlEmojiStore.Delete", "store.sql_emoji.delete.no_results", nil, "id="+emoji.Id, http.StatusBadRequest)
}
es.removeFromCache(emoji)
return nil
}
@@ -193,51 +166,5 @@ func (es SqlEmojiStore) getBy(what string, key interface{}, addToCache bool) (*m
return nil, model.NewAppError("SqlEmojiStore.GetByName", "store.sql_emoji.get.app_error", nil, "key="+fmt.Sprintf("%v", key)+", "+err.Error(), status)
}
if addToCache {
es.addToCache(emoji)
}
return emoji, nil
}
func (es SqlEmojiStore) addToCache(emoji *model.Emoji) {
emojiCacheById.AddWithExpiresInSecs(emoji.Id, emoji, EMOJI_CACHE_SEC)
emojiIdCacheByName.AddWithExpiresInSecs(emoji.Name, emoji.Id, EMOJI_CACHE_SEC)
}
func (es SqlEmojiStore) getFromCacheById(id string) (*model.Emoji, bool) {
if cacheItem, ok := emojiCacheById.Get(id); ok {
es.incrementMemCacheHitCounter("Emoji")
return cacheItem.(*model.Emoji), true
}
es.incrementMemCacheMissCounter("Emoji")
return nil, false
}
func (es SqlEmojiStore) getFromCacheByName(name string) (*model.Emoji, bool) {
if id, ok := emojiIdCacheByName.Get(name); ok {
return es.getFromCacheById(id.(string))
}
es.incrementMemCacheMissCounter("Emoji")
return nil, false
}
func (es SqlEmojiStore) incrementMemCacheHitCounter(cache string) {
if es.metrics == nil {
return
}
es.metrics.IncrementMemCacheHitCounter(cache)
}
func (es SqlEmojiStore) incrementMemCacheMissCounter(cache string) {
if es.metrics == nil {
return
}
es.metrics.IncrementMemCacheMissCounter(cache)
}
func (es SqlEmojiStore) removeFromCache(emoji *model.Emoji) {
emojiCacheById.Remove(emoji.Id)
emojiIdCacheByName.Remove(emoji.Name)
}

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

@@ -18,7 +18,8 @@ import (
)
const (
CURRENT_SCHEMA_VERSION = VERSION_5_16_0
CURRENT_SCHEMA_VERSION = VERSION_5_17_0
VERSION_5_17_0 = "5.17.0"
VERSION_5_16_0 = "5.16.0"
VERSION_5_15_0 = "5.15.0"
VERSION_5_14_0 = "5.14.0"
@@ -163,6 +164,7 @@ func upgradeDatabase(sqlStore SqlStore, currentModelVersionString string) error
upgradeDatabaseToVersion514(sqlStore)
upgradeDatabaseToVersion515(sqlStore)
upgradeDatabaseToVersion516(sqlStore)
upgradeDatabaseToVersion517(sqlStore)
return nil
}
@@ -721,3 +723,9 @@ func upgradeDatabaseToVersion516(sqlStore SqlStore) {
sqlStore.CreateIndexIfNotExists("idx_groupchannels_channelid", "GroupChannels", "ChannelId")
}
}
func upgradeDatabaseToVersion517(sqlStore SqlStore) {
if shouldPerformUpgrade(sqlStore, VERSION_5_16_0, VERSION_5_17_0) {
saveSchemaVersion(sqlStore, VERSION_5_17_0)
}
}

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

@@ -141,6 +141,40 @@ func (us SqlUserStore) Save(user *model.User) (*model.User, *model.AppError) {
return user, nil
}
func (us SqlUserStore) DeactivateGuests() ([]string, *model.AppError) {
curTime := model.GetMillis()
updateQuery := us.getQueryBuilder().Update("Users").
Set("UpdateAt", curTime).
Set("DeleteAt", curTime).
Where(sq.Eq{"Roles": "system_guest"}).
Where(sq.Eq{"DeleteAt": 0})
queryString, args, err := updateQuery.ToSql()
if err != nil {
return nil, model.NewAppError("SqlUserStore.UpdateActiveForMultipleUsers", "store.sql_user.app_error", nil, err.Error(), http.StatusInternalServerError)
}
_, err = us.GetMaster().Exec(queryString, args...)
if err != nil {
return nil, model.NewAppError("SqlUserStore.UpdateActiveForMultipleUsers", "store.sql_user.update_active_for_multiple_users.updating.app_error", nil, err.Error(), http.StatusInternalServerError)
}
selectQuery := us.getQueryBuilder().Select("Id").From("Users").Where(sq.Eq{"DeleteAt": curTime})
queryString, args, err = selectQuery.ToSql()
if err != nil {
return nil, model.NewAppError("SqlUserStore.UpdateActiveForMultipleUsers", "store.sql_user.app_error", nil, err.Error(), http.StatusInternalServerError)
}
userIds := []string{}
_, err = us.GetMaster().Select(&userIds, queryString, args...)
if err != nil {
return nil, model.NewAppError("SqlUserStore.UpdateActiveForMultipleUsers", "store.sql_user.update_active_for_multiple_users.getting_changed_users.app_error", nil, err.Error(), http.StatusInternalServerError)
}
return userIds, nil
}
func (us SqlUserStore) Update(user *model.User, trustedUpdateData bool) (*model.UserUpdate, *model.AppError) {
user.PreUpdate()

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

@@ -301,6 +301,7 @@ type UserStore interface {
GetChannelGroupUsers(channelID string) ([]*model.User, *model.AppError)
PromoteGuestToUser(userID string) *model.AppError
DemoteUserToGuest(userID string) *model.AppError
DeactivateGuests() ([]string, *model.AppError)
}
type BotStore interface {

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

@@ -21,7 +21,6 @@ func TestEmojiStore(t *testing.T, ss store.Store) {
t.Run("EmojiGetMultipleByName", func(t *testing.T) { testEmojiGetMultipleByName(t, ss) })
t.Run("EmojiGetList", func(t *testing.T) { testEmojiGetList(t, ss) })
t.Run("EmojiSearch", func(t *testing.T) { testEmojiSearch(t, ss) })
t.Run("EmojiCaching", func(t *testing.T) { testEmojiCaching(t, ss) })
}
func testEmojiSaveDelete(t *testing.T, ss store.Store) {
@@ -91,61 +90,6 @@ func testEmojiGet(t *testing.T, ss store.Store) {
}
}
func testEmojiCaching(t *testing.T, ss store.Store) {
emojis := make([]*model.Emoji, 3)
for i := range emojis {
emojis[i] = &model.Emoji{
CreatorId: model.NewId(),
Name: model.NewId(),
}
}
for _, emoji := range emojis {
_, err := ss.Emoji().Save(emoji)
require.Nil(t, err)
}
defer func() {
for _, emoji := range emojis {
err := ss.Emoji().Delete(emoji, time.Now().Unix())
require.Nil(t, err)
}
}()
var retrievedEmoji *model.Emoji
var cachedEmoji *model.Emoji
var err *model.AppError
for _, emoji := range emojis {
cachedEmoji, err = ss.Emoji().Get(emoji.Id, true)
assert.Nilf(t, err, "should be able to retrieve emoji with id %v", emoji.Id)
retrievedEmoji, err = ss.Emoji().Get(emoji.Id, false)
if assert.Nilf(t, err, "should be able to retrieve emoji with id %v", emoji.Id) {
assert.Falsef(t, retrievedEmoji == cachedEmoji, "should not be the same as cached with id %v", emoji.Id)
}
retrievedEmoji, err = ss.Emoji().Get(emoji.Id, true)
if assert.Nilf(t, err, "should be able to retrieve emoji with id %v", emoji.Id) {
assert.Truef(t, retrievedEmoji == cachedEmoji, "should be the cached emoji with id %v", emoji.Id)
}
retrievedEmoji, err = ss.Emoji().GetByName(emoji.Name, false)
if assert.Nilf(t, err, "should be able to retrieve emoji with name %v", emoji.Name) {
assert.Falsef(t, retrievedEmoji == cachedEmoji, "should not be the same as cached with name %v", emoji.Name)
}
retrievedEmoji, _ = ss.Emoji().GetByName(emoji.Name, true)
if assert.Nilf(t, err, "should be able to retrieve emoji with name %v", emoji.Name) {
assert.Truef(t, retrievedEmoji == cachedEmoji, "should be the cached emoji with name %v", emoji.Name)
}
}
_, err = ss.Emoji().Get(model.NewId(), false)
assert.NotNilf(t, err, "should not retrieve emoji with unsaved ID")
_, err = ss.Emoji().GetByName(model.NewId(), false)
assert.NotNilf(t, err, "should not retrieve emoji with unsaved name")
}
func testEmojiGetByName(t *testing.T, ss store.Store) {
emojis := []model.Emoji{
{

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

@@ -128,6 +128,31 @@ func (_m *UserStore) Count(options model.UserCountOptions) (int64, *model.AppErr
return r0, r1
}
// DeactivateGuests provides a mock function with given fields:
func (_m *UserStore) DeactivateGuests() ([]string, *model.AppError) {
ret := _m.Called()
var r0 []string
if rf, ok := ret.Get(0).(func() []string); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]string)
}
}
var r1 *model.AppError
if rf, ok := ret.Get(1).(func() *model.AppError); ok {
r1 = rf()
} else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)
}
}
return r0, r1
}
// DemoteUserToGuest provides a mock function with given fields: userID
func (_m *UserStore) DemoteUserToGuest(userID string) *model.AppError {
ret := _m.Called(userID)

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

@@ -80,6 +80,7 @@ func TestUserStore(t *testing.T, ss store.Store, s SqlSupplier) {
t.Run("GetChannelGroupUsers", func(t *testing.T) { testUserStoreGetChannelGroupUsers(t, ss) })
t.Run("PromoteGuestToUser", func(t *testing.T) { testUserStorePromoteGuestToUser(t, ss) })
t.Run("DemoteUserToGuest", func(t *testing.T) { testUserStoreDemoteUserToGuest(t, ss) })
t.Run("DeactivateGuests", func(t *testing.T) { testDeactivateGuests(t, ss) })
t.Run("ResetLastPictureUpdate", func(t *testing.T) { testUserStoreResetLastPictureUpdate(t, ss) })
}
@@ -4206,6 +4207,7 @@ func testUserStorePromoteGuestToUser(t *testing.T, ss store.Store) {
Roles: "system_user",
})
require.Nil(t, err)
defer func() { require.Nil(t, ss.User().PermanentDelete(user.Id)) }()
teamId := model.NewId()
_, err = ss.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: user.Id, SchemeGuest: true, SchemeUser: false}, 999)
@@ -4251,6 +4253,7 @@ func testUserStorePromoteGuestToUser(t *testing.T, ss store.Store) {
Roles: "system_user system_admin",
})
require.Nil(t, err)
defer func() { require.Nil(t, ss.User().PermanentDelete(user.Id)) }()
teamId := model.NewId()
_, err = ss.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: user.Id, SchemeGuest: true, SchemeUser: false}, 999)
@@ -4295,6 +4298,7 @@ func testUserStorePromoteGuestToUser(t *testing.T, ss store.Store) {
Roles: "system_guest",
})
require.Nil(t, err)
defer func() { require.Nil(t, ss.User().PermanentDelete(user.Id)) }()
err = ss.User().PromoteGuestToUser(user.Id)
assert.Nil(t, err)
@@ -4315,6 +4319,7 @@ func testUserStorePromoteGuestToUser(t *testing.T, ss store.Store) {
Roles: "system_guest",
})
require.Nil(t, err)
defer func() { require.Nil(t, ss.User().PermanentDelete(user.Id)) }()
teamId := model.NewId()
_, err = ss.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: user.Id, SchemeGuest: true, SchemeUser: false}, 999)
@@ -4344,6 +4349,7 @@ func testUserStorePromoteGuestToUser(t *testing.T, ss store.Store) {
Roles: "system_guest",
})
require.Nil(t, err)
defer func() { require.Nil(t, ss.User().PermanentDelete(user.Id)) }()
teamId := model.NewId()
_, err = ss.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: user.Id, SchemeGuest: true, SchemeUser: false}, 999)
@@ -4388,6 +4394,7 @@ func testUserStorePromoteGuestToUser(t *testing.T, ss store.Store) {
Roles: "system_guest custom_role",
})
require.Nil(t, err)
defer func() { require.Nil(t, ss.User().PermanentDelete(user.Id)) }()
teamId := model.NewId()
_, err = ss.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: user.Id, SchemeGuest: true, SchemeUser: false}, 999)
@@ -4432,6 +4439,7 @@ func testUserStorePromoteGuestToUser(t *testing.T, ss store.Store) {
Roles: "system_guest",
})
require.Nil(t, err)
defer func() { require.Nil(t, ss.User().PermanentDelete(user1.Id)) }()
teamId1 := model.NewId()
_, err = ss.Team().SaveMember(&model.TeamMember{TeamId: teamId1, UserId: user1.Id, SchemeGuest: true, SchemeUser: false}, 999)
@@ -4459,6 +4467,7 @@ func testUserStorePromoteGuestToUser(t *testing.T, ss store.Store) {
Roles: "system_guest",
})
require.Nil(t, err)
defer func() { require.Nil(t, ss.User().PermanentDelete(user2.Id)) }()
teamId2 := model.NewId()
_, err = ss.Team().SaveMember(&model.TeamMember{TeamId: teamId2, UserId: user2.Id, SchemeGuest: true, SchemeUser: false}, 999)
@@ -4513,6 +4522,7 @@ func testUserStoreDemoteUserToGuest(t *testing.T, ss store.Store) {
Roles: "system_guest",
})
require.Nil(t, err)
defer func() { require.Nil(t, ss.User().PermanentDelete(user.Id)) }()
teamId := model.NewId()
_, err = ss.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: user.Id, SchemeGuest: false, SchemeUser: true}, 999)
@@ -4558,6 +4568,7 @@ func testUserStoreDemoteUserToGuest(t *testing.T, ss store.Store) {
Roles: "system_user system_admin",
})
require.Nil(t, err)
defer func() { require.Nil(t, ss.User().PermanentDelete(user.Id)) }()
teamId := model.NewId()
_, err = ss.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: user.Id, SchemeGuest: true, SchemeUser: false}, 999)
@@ -4602,6 +4613,7 @@ func testUserStoreDemoteUserToGuest(t *testing.T, ss store.Store) {
Roles: "system_user",
})
require.Nil(t, err)
defer func() { require.Nil(t, ss.User().PermanentDelete(user.Id)) }()
err = ss.User().DemoteUserToGuest(user.Id)
assert.Nil(t, err)
@@ -4622,6 +4634,7 @@ func testUserStoreDemoteUserToGuest(t *testing.T, ss store.Store) {
Roles: "system_user",
})
require.Nil(t, err)
defer func() { require.Nil(t, ss.User().PermanentDelete(user.Id)) }()
teamId := model.NewId()
_, err = ss.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: user.Id, SchemeGuest: false, SchemeUser: true}, 999)
@@ -4651,6 +4664,7 @@ func testUserStoreDemoteUserToGuest(t *testing.T, ss store.Store) {
Roles: "system_user",
})
require.Nil(t, err)
defer func() { require.Nil(t, ss.User().PermanentDelete(user.Id)) }()
teamId := model.NewId()
_, err = ss.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: user.Id, SchemeGuest: false, SchemeUser: true}, 999)
@@ -4695,6 +4709,7 @@ func testUserStoreDemoteUserToGuest(t *testing.T, ss store.Store) {
Roles: "system_user custom_role",
})
require.Nil(t, err)
defer func() { require.Nil(t, ss.User().PermanentDelete(user.Id)) }()
teamId := model.NewId()
_, err = ss.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: user.Id, SchemeGuest: false, SchemeUser: true}, 999)
@@ -4739,6 +4754,7 @@ func testUserStoreDemoteUserToGuest(t *testing.T, ss store.Store) {
Roles: "system_user",
})
require.Nil(t, err)
defer func() { require.Nil(t, ss.User().PermanentDelete(user1.Id)) }()
teamId1 := model.NewId()
_, err = ss.Team().SaveMember(&model.TeamMember{TeamId: teamId1, UserId: user1.Id, SchemeGuest: false, SchemeUser: true}, 999)
@@ -4766,6 +4782,7 @@ func testUserStoreDemoteUserToGuest(t *testing.T, ss store.Store) {
Roles: "system_user",
})
require.Nil(t, err)
defer func() { require.Nil(t, ss.User().PermanentDelete(user2.Id)) }()
teamId2 := model.NewId()
_, err = ss.Team().SaveMember(&model.TeamMember{TeamId: teamId2, UserId: user2.Id, SchemeGuest: false, SchemeUser: true}, 999)
@@ -4806,6 +4823,84 @@ func testUserStoreDemoteUserToGuest(t *testing.T, ss store.Store) {
})
}
func testDeactivateGuests(t *testing.T, ss store.Store) {
// create users
t.Run("Must disable all guests and no regular user or already deactivated users", func(t *testing.T) {
guest1Random := model.NewId()
guest1, err := ss.User().Save(&model.User{
Email: guest1Random + "@test.com",
Username: "un_" + guest1Random,
Nickname: "nn_" + guest1Random,
FirstName: "f_" + guest1Random,
LastName: "l_" + guest1Random,
Password: "Password1",
Roles: "system_guest",
})
require.Nil(t, err)
defer func() { require.Nil(t, ss.User().PermanentDelete(guest1.Id)) }()
guest2Random := model.NewId()
guest2, err := ss.User().Save(&model.User{
Email: guest2Random + "@test.com",
Username: "un_" + guest2Random,
Nickname: "nn_" + guest2Random,
FirstName: "f_" + guest2Random,
LastName: "l_" + guest2Random,
Password: "Password1",
Roles: "system_guest",
})
require.Nil(t, err)
defer func() { require.Nil(t, ss.User().PermanentDelete(guest2.Id)) }()
guest3Random := model.NewId()
guest3, err := ss.User().Save(&model.User{
Email: guest3Random + "@test.com",
Username: "un_" + guest3Random,
Nickname: "nn_" + guest3Random,
FirstName: "f_" + guest3Random,
LastName: "l_" + guest3Random,
Password: "Password1",
Roles: "system_guest",
DeleteAt: 10,
})
require.Nil(t, err)
defer func() { require.Nil(t, ss.User().PermanentDelete(guest3.Id)) }()
regularUserRandom := model.NewId()
regularUser, err := ss.User().Save(&model.User{
Email: regularUserRandom + "@test.com",
Username: "un_" + regularUserRandom,
Nickname: "nn_" + regularUserRandom,
FirstName: "f_" + regularUserRandom,
LastName: "l_" + regularUserRandom,
Password: "Password1",
Roles: "system_user",
})
require.Nil(t, err)
defer func() { require.Nil(t, ss.User().PermanentDelete(regularUser.Id)) }()
ids, err := ss.User().DeactivateGuests()
require.Nil(t, err)
assert.ElementsMatch(t, []string{guest1.Id, guest2.Id}, ids)
u, err := ss.User().Get(guest1.Id)
require.Nil(t, err)
assert.NotEqual(t, u.DeleteAt, int64(0))
u, err = ss.User().Get(guest2.Id)
require.Nil(t, err)
assert.NotEqual(t, u.DeleteAt, int64(0))
u, err = ss.User().Get(guest3.Id)
require.Nil(t, err)
assert.Equal(t, u.DeleteAt, int64(10))
u, err = ss.User().Get(regularUser.Id)
require.Nil(t, err)
assert.Equal(t, u.DeleteAt, int64(0))
})
}
func testUserStoreResetLastPictureUpdate(t *testing.T, ss store.Store) {
u1 := &model.User{}
u1.Email = MakeEmail()