Merge branch 'master' into mark-as-unread

This commit is contained in:
Harrison Healey
2019-09-10 15:34:29 -04:00
197 changed files with 5210 additions and 686 deletions

View File

@@ -217,6 +217,10 @@ func (s *LayeredStore) TotalSearchDbConnections() int {
return s.DatabaseLayer.TotalSearchDbConnections()
}
func (s *LayeredStore) CheckIntegrity() <-chan IntegrityCheckResult {
return s.DatabaseLayer.CheckIntegrity()
}
type LayeredRoleStore struct {
*LayeredStore
}

View File

@@ -35,6 +35,9 @@ const (
CHANNEL_GUESTS_COUNTS_CACHE_SIZE = model.CHANNEL_CACHE_SIZE
CHANNEL_GUESTS_COUNTS_CACHE_SEC = 1800 // 30 mins
CHANNEL_PINNEDPOSTS_COUNTS_CACHE_SIZE = model.CHANNEL_CACHE_SIZE
CHANNEL_PINNEDPOSTS_COUNTS_CACHE_SEC = 1800 // 30 mins
CHANNEL_CACHE_SEC = 900 // 15 mins
)
@@ -281,6 +284,7 @@ type publicChannel struct {
}
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)
var allChannelMembersNotifyPropsForChannelCache = utils.NewLru(ALL_CHANNEL_MEMBERS_NOTIFY_PROPS_FOR_CHANNEL_CACHE_SIZE)
@@ -289,6 +293,7 @@ var channelByNameCache = utils.NewLru(model.CHANNEL_CACHE_SIZE)
func (s SqlChannelStore) ClearCaches() {
channelMemberCountsCache.Purge()
channelPinnedPostCountsCache.Purge()
channelGuestCountsCache.Purge()
allChannelMembersForUserCache.Purge()
allChannelMembersNotifyPropsForChannelCache.Purge()
@@ -297,6 +302,7 @@ func (s SqlChannelStore) ClearCaches() {
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")
s.metrics.IncrementMemCacheInvalidationCounter("Channel - Purge")
@@ -1626,6 +1632,66 @@ func (s SqlChannelStore) GetMemberCount(channelId string, allowFromCache bool) (
return count, nil
}
func (s SqlChannelStore) InvalidatePinnedPostCount(channelId string) {
channelPinnedPostCountsCache.Remove(channelId)
if s.metrics != nil {
s.metrics.IncrementMemCacheInvalidationCounter("Channel Pinned Post Counts - Remove by ChannelId")
}
}
func (s SqlChannelStore) GetPinnedPostCountFromCache(channelId string) int64 {
if cacheItem, ok := channelPinnedPostCountsCache.Get(channelId); ok {
if s.metrics != nil {
s.metrics.IncrementMemCacheHitCounter("Channel Pinned Post Counts")
}
return cacheItem.(int64)
}
if s.metrics != nil {
s.metrics.IncrementMemCacheMissCounter("Channel Pinned Post Counts")
}
count, err := s.GetPinnedPostCount(channelId, true)
if err != nil {
return 0
}
return count
}
func (s SqlChannelStore) GetPinnedPostCount(channelId string, allowFromCache bool) (int64, *model.AppError) {
if allowFromCache {
if cacheItem, ok := channelPinnedPostCountsCache.Get(channelId); ok {
if s.metrics != nil {
s.metrics.IncrementMemCacheHitCounter("Channel Pinned Post Counts")
}
return cacheItem.(int64), nil
}
}
if s.metrics != nil {
s.metrics.IncrementMemCacheMissCounter("Channel Pinned Post Counts")
}
count, err := s.GetReplica().SelectInt(`
SELECT count(*)
FROM Posts
WHERE
IsPinned = true
AND ChannelId = :ChannelId
AND DeleteAt = 0`, map[string]interface{}{"ChannelId": channelId})
if err != nil {
return 0, model.NewAppError("SqlChannelStore.GetPinnedPostCount", "store.sql_channel.get_pinnedpost_count.app_error", nil, "channel_id="+channelId+", "+err.Error(), http.StatusInternalServerError)
}
if allowFromCache {
channelPinnedPostCountsCache.AddWithExpiresInSecs(channelId, count, CHANNEL_PINNEDPOSTS_COUNTS_CACHE_SEC)
}
return count, nil
}
func (s SqlChannelStore) InvalidateGuestCount(channelId string) {
channelGuestCountsCache.Remove(channelId)
if s.metrics != nil {

514
store/sqlstore/integrity.go Normal file
View File

@@ -0,0 +1,514 @@
// Copyright (c) 2019-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package sqlstore
import (
"github.com/mattermost/mattermost-server/mlog"
"github.com/mattermost/mattermost-server/store"
sq "github.com/Masterminds/squirrel"
)
type relationalCheckConfig struct {
parentName string
parentIdAttr string
childName string
childIdAttr string
canParentIdBeEmpty bool
sortRecords bool
}
func getOrphanedRecords(ss *SqlSupplier, cfg relationalCheckConfig) ([]store.OrphanedRecord, error) {
var records []store.OrphanedRecord
sub := ss.getQueryBuilder().
Select("TRUE").
From(cfg.parentName).
Prefix("NOT EXISTS (").
Suffix(")").
Where(sq.Eq{"id": cfg.childName + "." + cfg.parentIdAttr})
main := ss.getQueryBuilder().
Select().
Column(cfg.parentIdAttr + " AS ParentId").
From(cfg.childName).
Where(sub)
if cfg.childIdAttr != "" {
main = main.Column(cfg.childIdAttr + " AS ChildId")
}
if cfg.canParentIdBeEmpty {
main = main.Where(sq.NotEq{cfg.parentIdAttr: ""})
}
if cfg.sortRecords {
main = main.OrderBy(cfg.parentIdAttr)
}
query, args, _ := main.ToSql()
_, err := ss.GetMaster().Select(&records, query, args...)
return records, err
}
func checkParentChildIntegrity(ss *SqlSupplier, config relationalCheckConfig) store.IntegrityCheckResult {
var result store.IntegrityCheckResult
var data store.RelationalIntegrityCheckData
config.sortRecords = true
data.Records, result.Err = getOrphanedRecords(ss, config)
if result.Err != nil {
mlog.Error(result.Err.Error())
return result
}
data.ParentName = config.parentName
data.ChildName = config.childName
data.ParentIdAttr = config.parentIdAttr
data.ChildIdAttr = config.childIdAttr
result.Data = data
return result
}
func checkChannelsCommandWebhooksIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
return checkParentChildIntegrity(ss, relationalCheckConfig{
parentName: "Channels",
parentIdAttr: "ChannelId",
childName: "CommandWebhooks",
childIdAttr: "Id",
})
}
func checkChannelsChannelMemberHistoryIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
return checkParentChildIntegrity(ss, relationalCheckConfig{
parentName: "Channels",
parentIdAttr: "ChannelId",
childName: "ChannelMemberHistory",
childIdAttr: "",
})
}
func checkChannelsChannelMembersIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
return checkParentChildIntegrity(ss, relationalCheckConfig{
parentName: "Channels",
parentIdAttr: "ChannelId",
childName: "ChannelMembers",
childIdAttr: "",
})
}
func checkChannelsIncomingWebhooksIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
return checkParentChildIntegrity(ss, relationalCheckConfig{
parentName: "Channels",
parentIdAttr: "ChannelId",
childName: "IncomingWebhooks",
childIdAttr: "Id",
})
}
func checkChannelsOutgoingWebhooksIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
return checkParentChildIntegrity(ss, relationalCheckConfig{
parentName: "Channels",
parentIdAttr: "ChannelId",
childName: "OutgoingWebhooks",
childIdAttr: "Id",
})
}
func checkChannelsPostsIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
return checkParentChildIntegrity(ss, relationalCheckConfig{
parentName: "Channels",
parentIdAttr: "ChannelId",
childName: "Posts",
childIdAttr: "Id",
})
}
func checkCommandsCommandWebhooksIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
return checkParentChildIntegrity(ss, relationalCheckConfig{
parentName: "Commands",
parentIdAttr: "CommandId",
childName: "CommandWebhooks",
childIdAttr: "Id",
})
}
func checkPostsFileInfoIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
return checkParentChildIntegrity(ss, relationalCheckConfig{
parentName: "Posts",
parentIdAttr: "PostId",
childName: "FileInfo",
childIdAttr: "",
})
}
func checkPostsPostsParentIdIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
return checkParentChildIntegrity(ss, relationalCheckConfig{
parentName: "Posts",
parentIdAttr: "ParentId",
childName: "Posts",
childIdAttr: "Id",
canParentIdBeEmpty: true,
})
}
func checkPostsPostsRootIdIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
return checkParentChildIntegrity(ss, relationalCheckConfig{
parentName: "Posts",
parentIdAttr: "RootId",
childName: "Posts",
childIdAttr: "Id",
canParentIdBeEmpty: true,
})
}
func checkPostsReactionsIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
return checkParentChildIntegrity(ss, relationalCheckConfig{
parentName: "Posts",
parentIdAttr: "PostId",
childName: "Reactions",
childIdAttr: "",
})
}
func checkSchemesChannelsIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
return checkParentChildIntegrity(ss, relationalCheckConfig{
parentName: "Schemes",
parentIdAttr: "SchemeId",
childName: "Channels",
childIdAttr: "Id",
canParentIdBeEmpty: true,
})
}
func checkSchemesTeamsIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
return checkParentChildIntegrity(ss, relationalCheckConfig{
parentName: "Schemes",
parentIdAttr: "SchemeId",
childName: "Teams",
childIdAttr: "Id",
canParentIdBeEmpty: true,
})
}
func checkSessionsAuditsIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
return checkParentChildIntegrity(ss, relationalCheckConfig{
parentName: "Sessions",
parentIdAttr: "SessionId",
childName: "Audits",
childIdAttr: "Id",
canParentIdBeEmpty: true,
})
}
func checkTeamsChannelsIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
return checkParentChildIntegrity(ss, relationalCheckConfig{
parentName: "Teams",
parentIdAttr: "TeamId",
childName: "Channels",
childIdAttr: "Id",
})
}
func checkTeamsCommandsIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
return checkParentChildIntegrity(ss, relationalCheckConfig{
parentName: "Teams",
parentIdAttr: "TeamId",
childName: "Commands",
childIdAttr: "Id",
})
}
func checkTeamsIncomingWebhooksIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
return checkParentChildIntegrity(ss, relationalCheckConfig{
parentName: "Teams",
parentIdAttr: "TeamId",
childName: "IncomingWebhooks",
childIdAttr: "Id",
})
}
func checkTeamsOutgoingWebhooksIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
return checkParentChildIntegrity(ss, relationalCheckConfig{
parentName: "Teams",
parentIdAttr: "TeamId",
childName: "OutgoingWebhooks",
childIdAttr: "Id",
})
}
func checkTeamsTeamMembersIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
return checkParentChildIntegrity(ss, relationalCheckConfig{
parentName: "Teams",
parentIdAttr: "TeamId",
childName: "TeamMembers",
childIdAttr: "",
})
}
func checkUsersAuditsIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
return checkParentChildIntegrity(ss, relationalCheckConfig{
parentName: "Users",
parentIdAttr: "UserId",
childName: "Audits",
childIdAttr: "Id",
canParentIdBeEmpty: true,
})
}
func checkUsersCommandWebhooksIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
return checkParentChildIntegrity(ss, relationalCheckConfig{
parentName: "Users",
parentIdAttr: "UserId",
childName: "CommandWebhooks",
childIdAttr: "Id",
})
}
func checkUsersChannelMemberHistoryIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
return checkParentChildIntegrity(ss, relationalCheckConfig{
parentName: "Users",
parentIdAttr: "UserId",
childName: "ChannelMemberHistory",
childIdAttr: "",
})
}
func checkUsersChannelMembersIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
return checkParentChildIntegrity(ss, relationalCheckConfig{
parentName: "Users",
parentIdAttr: "UserId",
childName: "ChannelMembers",
childIdAttr: "",
})
}
func checkUsersChannelsIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
return checkParentChildIntegrity(ss, relationalCheckConfig{
parentName: "Users",
parentIdAttr: "CreatorId",
childName: "Channels",
childIdAttr: "Id",
canParentIdBeEmpty: true,
})
}
func checkUsersCommandsIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
return checkParentChildIntegrity(ss, relationalCheckConfig{
parentName: "Users",
parentIdAttr: "CreatorId",
childName: "Commands",
childIdAttr: "Id",
})
}
func checkUsersCompliancesIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
return checkParentChildIntegrity(ss, relationalCheckConfig{
parentName: "Users",
parentIdAttr: "UserId",
childName: "Compliances",
childIdAttr: "Id",
})
}
func checkUsersEmojiIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
return checkParentChildIntegrity(ss, relationalCheckConfig{
parentName: "Users",
parentIdAttr: "CreatorId",
childName: "Emoji",
childIdAttr: "Id",
})
}
func checkUsersFileInfoIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
return checkParentChildIntegrity(ss, relationalCheckConfig{
parentName: "Posts",
parentIdAttr: "CreatorId",
childName: "FileInfo",
childIdAttr: "",
})
}
func checkUsersIncomingWebhooksIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
return checkParentChildIntegrity(ss, relationalCheckConfig{
parentName: "Users",
parentIdAttr: "UserId",
childName: "IncomingWebhooks",
childIdAttr: "Id",
})
}
func checkUsersOAuthAccessDataIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
return checkParentChildIntegrity(ss, relationalCheckConfig{
parentName: "Users",
parentIdAttr: "UserId",
childName: "OAuthAccessData",
childIdAttr: "Token",
})
}
func checkUsersOAuthAppsIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
return checkParentChildIntegrity(ss, relationalCheckConfig{
parentName: "Users",
parentIdAttr: "CreatorId",
childName: "OAuthApps",
childIdAttr: "Id",
})
}
func checkUsersOAuthAuthDataIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
return checkParentChildIntegrity(ss, relationalCheckConfig{
parentName: "Users",
parentIdAttr: "UserId",
childName: "OAuthAuthData",
childIdAttr: "Code",
})
}
func checkUsersOutgoingWebhooksIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
return checkParentChildIntegrity(ss, relationalCheckConfig{
parentName: "Users",
parentIdAttr: "CreatorId",
childName: "OutgoingWebhooks",
childIdAttr: "Id",
})
}
func checkUsersPostsIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
return checkParentChildIntegrity(ss, relationalCheckConfig{
parentName: "Users",
parentIdAttr: "UserId",
childName: "Posts",
childIdAttr: "Id",
})
}
func checkUsersPreferencesIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
return checkParentChildIntegrity(ss, relationalCheckConfig{
parentName: "Users",
parentIdAttr: "UserId",
childName: "Preferences",
childIdAttr: "",
})
}
func checkUsersReactionsIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
return checkParentChildIntegrity(ss, relationalCheckConfig{
parentName: "Users",
parentIdAttr: "UserId",
childName: "Reactions",
childIdAttr: "",
})
}
func checkUsersSessionsIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
return checkParentChildIntegrity(ss, relationalCheckConfig{
parentName: "Users",
parentIdAttr: "UserId",
childName: "Sessions",
childIdAttr: "Id",
})
}
func checkUsersStatusIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
return checkParentChildIntegrity(ss, relationalCheckConfig{
parentName: "Users",
parentIdAttr: "UserId",
childName: "Status",
childIdAttr: "",
})
}
func checkUsersTeamMembersIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
return checkParentChildIntegrity(ss, relationalCheckConfig{
parentName: "Users",
parentIdAttr: "UserId",
childName: "TeamMembers",
childIdAttr: "",
})
}
func checkUsersUserAccessTokensIntegrity(ss *SqlSupplier) store.IntegrityCheckResult {
return checkParentChildIntegrity(ss, relationalCheckConfig{
parentName: "Users",
parentIdAttr: "UserId",
childName: "UserAccessTokens",
childIdAttr: "Id",
})
}
func checkChannelsIntegrity(ss *SqlSupplier, results chan<- store.IntegrityCheckResult) {
results <- checkChannelsCommandWebhooksIntegrity(ss)
results <- checkChannelsChannelMemberHistoryIntegrity(ss)
results <- checkChannelsChannelMembersIntegrity(ss)
results <- checkChannelsIncomingWebhooksIntegrity(ss)
results <- checkChannelsOutgoingWebhooksIntegrity(ss)
results <- checkChannelsPostsIntegrity(ss)
}
func checkCommandsIntegrity(ss *SqlSupplier, results chan<- store.IntegrityCheckResult) {
results <- checkCommandsCommandWebhooksIntegrity(ss)
}
func checkPostsIntegrity(ss *SqlSupplier, results chan<- store.IntegrityCheckResult) {
results <- checkPostsFileInfoIntegrity(ss)
results <- checkPostsPostsParentIdIntegrity(ss)
results <- checkPostsPostsRootIdIntegrity(ss)
results <- checkPostsReactionsIntegrity(ss)
}
func checkSchemesIntegrity(ss *SqlSupplier, results chan<- store.IntegrityCheckResult) {
results <- checkSchemesChannelsIntegrity(ss)
results <- checkSchemesTeamsIntegrity(ss)
}
func checkSessionsIntegrity(ss *SqlSupplier, results chan<- store.IntegrityCheckResult) {
results <- checkSessionsAuditsIntegrity(ss)
}
func checkTeamsIntegrity(ss *SqlSupplier, results chan<- store.IntegrityCheckResult) {
results <- checkTeamsChannelsIntegrity(ss)
results <- checkTeamsCommandsIntegrity(ss)
results <- checkTeamsIncomingWebhooksIntegrity(ss)
results <- checkTeamsOutgoingWebhooksIntegrity(ss)
results <- checkTeamsTeamMembersIntegrity(ss)
}
func checkUsersIntegrity(ss *SqlSupplier, results chan<- store.IntegrityCheckResult) {
results <- checkUsersAuditsIntegrity(ss)
results <- checkUsersCommandWebhooksIntegrity(ss)
results <- checkUsersChannelMemberHistoryIntegrity(ss)
results <- checkUsersChannelMembersIntegrity(ss)
results <- checkUsersChannelsIntegrity(ss)
results <- checkUsersCommandsIntegrity(ss)
results <- checkUsersCompliancesIntegrity(ss)
results <- checkUsersEmojiIntegrity(ss)
results <- checkUsersFileInfoIntegrity(ss)
results <- checkUsersIncomingWebhooksIntegrity(ss)
results <- checkUsersOAuthAccessDataIntegrity(ss)
results <- checkUsersOAuthAppsIntegrity(ss)
results <- checkUsersOAuthAuthDataIntegrity(ss)
results <- checkUsersOutgoingWebhooksIntegrity(ss)
results <- checkUsersPostsIntegrity(ss)
results <- checkUsersPreferencesIntegrity(ss)
results <- checkUsersReactionsIntegrity(ss)
results <- checkUsersSessionsIntegrity(ss)
results <- checkUsersStatusIntegrity(ss)
results <- checkUsersTeamMembersIntegrity(ss)
results <- checkUsersUserAccessTokensIntegrity(ss)
}
func CheckRelationalIntegrity(ss *SqlSupplier, results chan<- store.IntegrityCheckResult) {
mlog.Info("Starting relational integrity checks...")
checkChannelsIntegrity(ss, results)
checkCommandsIntegrity(ss, results)
checkPostsIntegrity(ss, results)
checkSchemesIntegrity(ss, results)
checkSessionsIntegrity(ss, results)
checkTeamsIntegrity(ss, results)
checkUsersIntegrity(ss, results)
mlog.Info("Done with relational integrity checks")
close(results)
}

File diff suppressed because it is too large Load Diff

View File

@@ -4,7 +4,6 @@
package sqlstore
import (
"fmt"
"net/http"
"time"
@@ -251,13 +250,13 @@ func (me SqlSessionStore) Cleanup(expiryTime int64, batchSize int64) {
for rowsAffected > 0 {
if sqlResult, err := me.GetMaster().Exec(query, map[string]interface{}{"ExpiresAt": expiryTime, "Limit": batchSize}); err != nil {
mlog.Error(fmt.Sprintf("Unable to cleanup session store. err=%v", err.Error()))
mlog.Error("Unable to cleanup session store.", mlog.Err(err))
return
} else {
var rowErr error
rowsAffected, rowErr = sqlResult.RowsAffected()
if rowErr != nil {
mlog.Error(fmt.Sprintf("Unable to cleanup session store. err=%v", err.Error()))
mlog.Error("Unable to cleanup session store.", mlog.Err(err))
return
}
}

View File

@@ -159,14 +159,14 @@ func NewSqlSupplier(settings model.SqlSettings, metrics einterfaces.MetricsInter
err := supplier.GetMaster().CreateTablesIfNotExists()
if err != nil {
mlog.Critical(fmt.Sprintf("Error creating database tables: %v", err))
mlog.Critical("Error creating database tables.", mlog.Err(err))
time.Sleep(time.Second)
os.Exit(EXIT_CREATE_TABLE)
}
err = UpgradeDatabase(supplier, model.CurrentVersion)
if err != nil {
mlog.Critical("Failed to upgrade database", mlog.Err(err))
mlog.Critical("Failed to upgrade database.", mlog.Err(err))
time.Sleep(time.Second)
os.Exit(EXIT_GENERIC_FAILURE)
}
@@ -214,13 +214,13 @@ func (s *SqlSupplier) Next() store.LayeredStoreSupplier {
func setupConnection(con_type string, dataSource string, settings *model.SqlSettings) *gorp.DbMap {
db, err := dbsql.Open(*settings.DriverName, dataSource)
if err != nil {
mlog.Critical(fmt.Sprintf("Failed to open SQL connection to err:%v", err.Error()))
mlog.Critical("Failed to open SQL connection to err.", mlog.Err(err))
time.Sleep(time.Second)
os.Exit(EXIT_DB_OPEN)
}
for i := 0; i < DB_PING_ATTEMPTS; i++ {
mlog.Info(fmt.Sprintf("Pinging SQL %v database", con_type))
mlog.Info("Pinging SQL", mlog.String("database", con_type))
ctx, cancel := context.WithTimeout(context.Background(), DB_PING_TIMEOUT_SECS*time.Second)
defer cancel()
err = db.PingContext(ctx)
@@ -228,11 +228,11 @@ func setupConnection(con_type string, dataSource string, settings *model.SqlSett
break
} else {
if i == DB_PING_ATTEMPTS-1 {
mlog.Critical(fmt.Sprintf("Failed to ping DB, server will exit err=%v", err))
mlog.Critical("Failed to ping DB, server will exit.", mlog.Err(err))
time.Sleep(time.Second)
os.Exit(EXIT_PING)
} else {
mlog.Error(fmt.Sprintf("Failed to ping DB retrying in %v seconds err=%v", DB_PING_TIMEOUT_SECS, err))
mlog.Error("Failed to ping DB", mlog.Err(err), mlog.Int("retrying in seconds", DB_PING_TIMEOUT_SECS))
time.Sleep(DB_PING_TIMEOUT_SECS * time.Second)
}
}
@@ -365,7 +365,7 @@ func (ss *SqlSupplier) DoesTableExist(tableName string) bool {
)
if err != nil {
mlog.Critical(fmt.Sprintf("Failed to check if table exists %v", err))
mlog.Critical("Failed to check if table exists", mlog.Err(err))
time.Sleep(time.Second)
os.Exit(EXIT_TABLE_EXISTS)
}
@@ -387,7 +387,7 @@ func (ss *SqlSupplier) DoesTableExist(tableName string) bool {
)
if err != nil {
mlog.Critical(fmt.Sprintf("Failed to check if table exists %v", err))
mlog.Critical("Failed to check if table exists", mlog.Err(err))
time.Sleep(time.Second)
os.Exit(EXIT_TABLE_EXISTS_MYSQL)
}
@@ -401,7 +401,7 @@ func (ss *SqlSupplier) DoesTableExist(tableName string) bool {
)
if err != nil {
mlog.Critical(fmt.Sprintf("Failed to check if table exists %v", err))
mlog.Critical("Failed to check if table exists", mlog.Err(err))
time.Sleep(time.Second)
os.Exit(EXIT_TABLE_EXISTS_SQLITE)
}
@@ -433,7 +433,7 @@ func (ss *SqlSupplier) DoesColumnExist(tableName string, columnName string) bool
return false
}
mlog.Critical(fmt.Sprintf("Failed to check if column exists %v", err))
mlog.Critical("Failed to check if column exists", mlog.Err(err))
time.Sleep(time.Second)
os.Exit(EXIT_DOES_COLUMN_EXISTS_POSTGRES)
}
@@ -456,7 +456,7 @@ func (ss *SqlSupplier) DoesColumnExist(tableName string, columnName string) bool
)
if err != nil {
mlog.Critical(fmt.Sprintf("Failed to check if column exists %v", err))
mlog.Critical("Failed to check if column exists", mlog.Err(err))
time.Sleep(time.Second)
os.Exit(EXIT_DOES_COLUMN_EXISTS_MYSQL)
}
@@ -471,7 +471,7 @@ func (ss *SqlSupplier) DoesColumnExist(tableName string, columnName string) bool
)
if err != nil {
mlog.Critical(fmt.Sprintf("Failed to check if column exists %v", err))
mlog.Critical("Failed to check if column exists", mlog.Err(err))
time.Sleep(time.Second)
os.Exit(EXIT_DOES_COLUMN_EXISTS_SQLITE)
}
@@ -498,7 +498,7 @@ func (ss *SqlSupplier) DoesTriggerExist(triggerName string) bool {
`, triggerName)
if err != nil {
mlog.Critical(fmt.Sprintf("Failed to check if trigger exists %v", err))
mlog.Critical("Failed to check if trigger exists", mlog.Err(err))
time.Sleep(time.Second)
os.Exit(EXIT_GENERIC_FAILURE)
}
@@ -517,7 +517,7 @@ func (ss *SqlSupplier) DoesTriggerExist(triggerName string) bool {
`, triggerName)
if err != nil {
mlog.Critical(fmt.Sprintf("Failed to check if trigger exists %v", err))
mlog.Critical("Failed to check if trigger exists", mlog.Err(err))
time.Sleep(time.Second)
os.Exit(EXIT_GENERIC_FAILURE)
}
@@ -541,7 +541,7 @@ func (ss *SqlSupplier) CreateColumnIfNotExists(tableName string, columnName stri
if ss.DriverName() == model.DATABASE_DRIVER_POSTGRES {
_, err := ss.GetMaster().ExecNoTimeout("ALTER TABLE " + tableName + " ADD " + columnName + " " + postgresColType + " DEFAULT '" + defaultValue + "'")
if err != nil {
mlog.Critical(fmt.Sprintf("Failed to create column %v", err))
mlog.Critical("Failed to create column", mlog.Err(err))
time.Sleep(time.Second)
os.Exit(EXIT_CREATE_COLUMN_POSTGRES)
}
@@ -551,7 +551,7 @@ func (ss *SqlSupplier) CreateColumnIfNotExists(tableName string, columnName stri
} else if ss.DriverName() == model.DATABASE_DRIVER_MYSQL {
_, err := ss.GetMaster().ExecNoTimeout("ALTER TABLE " + tableName + " ADD " + columnName + " " + mySqlColType + " DEFAULT '" + defaultValue + "'")
if err != nil {
mlog.Critical(fmt.Sprintf("Failed to create column %v", err))
mlog.Critical("Failed to create column", mlog.Err(err))
time.Sleep(time.Second)
os.Exit(EXIT_CREATE_COLUMN_MYSQL)
}
@@ -575,7 +575,7 @@ func (ss *SqlSupplier) CreateColumnIfNotExistsNoDefault(tableName string, column
if ss.DriverName() == model.DATABASE_DRIVER_POSTGRES {
_, err := ss.GetMaster().ExecNoTimeout("ALTER TABLE " + tableName + " ADD " + columnName + " " + postgresColType)
if err != nil {
mlog.Critical(fmt.Sprintf("Failed to create column %v", err))
mlog.Critical("Failed to create column", mlog.Err(err))
time.Sleep(time.Second)
os.Exit(EXIT_CREATE_COLUMN_POSTGRES)
}
@@ -585,7 +585,7 @@ func (ss *SqlSupplier) CreateColumnIfNotExistsNoDefault(tableName string, column
} else if ss.DriverName() == model.DATABASE_DRIVER_MYSQL {
_, err := ss.GetMaster().ExecNoTimeout("ALTER TABLE " + tableName + " ADD " + columnName + " " + mySqlColType)
if err != nil {
mlog.Critical(fmt.Sprintf("Failed to create column %v", err))
mlog.Critical("Failed to create column", mlog.Err(err))
time.Sleep(time.Second)
os.Exit(EXIT_CREATE_COLUMN_MYSQL)
}
@@ -608,7 +608,7 @@ func (ss *SqlSupplier) RemoveColumnIfExists(tableName string, columnName string)
_, err := ss.GetMaster().ExecNoTimeout("ALTER TABLE " + tableName + " DROP COLUMN " + columnName)
if err != nil {
mlog.Critical(fmt.Sprintf("Failed to drop column %v", err))
mlog.Critical("Failed to drop column", mlog.Err(err))
time.Sleep(time.Second)
os.Exit(EXIT_REMOVE_COLUMN)
}
@@ -623,7 +623,7 @@ func (ss *SqlSupplier) RemoveTableIfExists(tableName string) bool {
_, err := ss.GetMaster().ExecNoTimeout("DROP TABLE " + tableName)
if err != nil {
mlog.Critical(fmt.Sprintf("Failed to drop table %v", err))
mlog.Critical("Failed to drop table", mlog.Err(err))
time.Sleep(time.Second)
os.Exit(EXIT_REMOVE_TABLE)
}
@@ -644,7 +644,7 @@ func (ss *SqlSupplier) RenameColumnIfExists(tableName string, oldColumnName stri
}
if err != nil {
mlog.Critical(fmt.Sprintf("Failed to rename column %v", err))
mlog.Critical("Failed to rename column", mlog.Err(err))
time.Sleep(time.Second)
os.Exit(EXIT_RENAME_COLUMN)
}
@@ -666,7 +666,7 @@ func (ss *SqlSupplier) GetMaxLengthOfColumnIfExists(tableName string, columnName
}
if err != nil {
mlog.Critical(fmt.Sprintf("Failed to get max length of column %v", err))
mlog.Critical("Failed to get max length of column", mlog.Err(err))
time.Sleep(time.Second)
os.Exit(EXIT_MAX_COLUMN)
}
@@ -687,7 +687,7 @@ func (ss *SqlSupplier) AlterColumnTypeIfExists(tableName string, columnName stri
}
if err != nil {
mlog.Critical(fmt.Sprintf("Failed to alter column type %v", err))
mlog.Critical("Failed to alter column type", mlog.Err(err))
time.Sleep(time.Second)
os.Exit(EXIT_ALTER_COLUMN)
}
@@ -736,7 +736,7 @@ func (ss *SqlSupplier) AlterColumnDefaultIfExists(tableName string, columnName s
}
if err != nil {
mlog.Critical(fmt.Sprintf("Failed to alter column %s.%s default %s: %v", tableName, columnName, defaultValue, err))
mlog.Critical("Failed to alter column", mlog.String("table", tableName), mlog.String("column", columnName), mlog.String("default value", defaultValue), mlog.Err(err))
time.Sleep(time.Second)
os.Exit(EXIT_GENERIC_FAILURE)
return false
@@ -790,7 +790,7 @@ func (ss *SqlSupplier) createIndexIfNotExists(indexName string, tableName string
_, err := ss.GetMaster().ExecNoTimeout(query)
if err != nil {
mlog.Critical(fmt.Sprintf("Failed to create index %v, %v", errExists, err))
mlog.Critical("Failed to create index", mlog.Err(errExists), mlog.Err(err))
time.Sleep(time.Second)
os.Exit(EXIT_CREATE_INDEX_POSTGRES)
}
@@ -798,7 +798,7 @@ func (ss *SqlSupplier) createIndexIfNotExists(indexName string, tableName string
count, err := ss.GetMaster().SelectInt("SELECT COUNT(0) AS index_exists FROM information_schema.statistics WHERE TABLE_SCHEMA = DATABASE() and table_name = ? AND index_name = ?", tableName, indexName)
if err != nil {
mlog.Critical(fmt.Sprintf("Failed to check index %v", err))
mlog.Critical("Failed to check index", mlog.Err(err))
time.Sleep(time.Second)
os.Exit(EXIT_CREATE_INDEX_MYSQL)
}
@@ -814,14 +814,14 @@ func (ss *SqlSupplier) createIndexIfNotExists(indexName string, tableName string
_, err = ss.GetMaster().ExecNoTimeout("CREATE " + uniqueStr + fullTextIndex + " INDEX " + indexName + " ON " + tableName + " (" + strings.Join(columnNames, ", ") + ")")
if err != nil {
mlog.Critical(fmt.Sprintf("Failed to create index %v", err))
mlog.Critical("Failed to create index", mlog.Err(err))
time.Sleep(time.Second)
os.Exit(EXIT_CREATE_INDEX_FULL_MYSQL)
}
} else if ss.DriverName() == model.DATABASE_DRIVER_SQLITE {
_, err := ss.GetMaster().ExecNoTimeout("CREATE INDEX IF NOT EXISTS " + indexName + " ON " + tableName + " (" + strings.Join(columnNames, ", ") + ")")
if err != nil {
mlog.Critical(fmt.Sprintf("Failed to create index %v", err))
mlog.Critical("Failed to create index", mlog.Err(err))
time.Sleep(time.Second)
os.Exit(EXIT_CREATE_INDEX_SQLITE)
}
@@ -845,7 +845,7 @@ func (ss *SqlSupplier) RemoveIndexIfExists(indexName string, tableName string) b
_, err = ss.GetMaster().ExecNoTimeout("DROP INDEX " + indexName)
if err != nil {
mlog.Critical(fmt.Sprintf("Failed to remove index %v", err))
mlog.Critical("Failed to remove index", mlog.Err(err))
time.Sleep(time.Second)
os.Exit(EXIT_REMOVE_INDEX_POSTGRES)
}
@@ -855,7 +855,7 @@ func (ss *SqlSupplier) RemoveIndexIfExists(indexName string, tableName string) b
count, err := ss.GetMaster().SelectInt("SELECT COUNT(0) AS index_exists FROM information_schema.statistics WHERE TABLE_SCHEMA = DATABASE() and table_name = ? AND index_name = ?", tableName, indexName)
if err != nil {
mlog.Critical(fmt.Sprintf("Failed to check index %v", err))
mlog.Critical("Failed to check index", mlog.Err(err))
time.Sleep(time.Second)
os.Exit(EXIT_REMOVE_INDEX_MYSQL)
}
@@ -866,14 +866,14 @@ func (ss *SqlSupplier) RemoveIndexIfExists(indexName string, tableName string) b
_, err = ss.GetMaster().ExecNoTimeout("DROP INDEX " + indexName + " ON " + tableName)
if err != nil {
mlog.Critical(fmt.Sprintf("Failed to remove index %v", err))
mlog.Critical("Failed to remove index", mlog.Err(err))
time.Sleep(time.Second)
os.Exit(EXIT_REMOVE_INDEX_MYSQL)
}
} else if ss.DriverName() == model.DATABASE_DRIVER_SQLITE {
_, err := ss.GetMaster().ExecNoTimeout("DROP INDEX IF EXISTS " + indexName)
if err != nil {
mlog.Critical(fmt.Sprintf("Failed to remove index %v", err))
mlog.Critical("Failed to remove index", mlog.Err(err))
time.Sleep(time.Second)
os.Exit(EXIT_REMOVE_INDEX_SQLITE)
}
@@ -1066,6 +1066,12 @@ func (ss *SqlSupplier) getQueryBuilder() sq.StatementBuilderType {
return builder
}
func (ss *SqlSupplier) CheckIntegrity() <-chan store.IntegrityCheckResult {
results := make(chan store.IntegrityCheckResult)
go CheckRelationalIntegrity(ss, results)
return results
}
type mattermConverter struct{}
func (me mattermConverter) ToDb(val interface{}) (interface{}, error) {

View File

@@ -4,7 +4,6 @@
package sqlstore
import (
"fmt"
"net/http"
"github.com/mattermost/gorp"
@@ -141,7 +140,7 @@ func (s *SqlReactionStore) DeleteAllWithEmojiName(emojiName string) *model.AppEr
for _, reaction := range reactions {
if _, err := s.GetMaster().Exec(UPDATE_POST_HAS_REACTIONS_ON_DELETE_QUERY,
map[string]interface{}{"PostId": reaction.PostId, "UpdateAt": model.GetMillis()}); err != nil {
mlog.Warn(fmt.Sprintf("Unable to update Post.HasReactions while removing reactions post_id=%v, error=%v", reaction.PostId, err.Error()))
mlog.Warn("Unable to update Post.HasReactions while removing reactions", mlog.String("post_id", reaction.PostId), mlog.Err(err))
}
}

View File

@@ -381,6 +381,21 @@ func (s SqlTeamStore) GetAllPrivateTeamListing() ([]*model.Team, *model.AppError
return data, nil
}
func (s SqlTeamStore) GetAllPublicTeamPageListing(offset int, limit int) ([]*model.Team, *model.AppError) {
query := "SELECT * FROM Teams WHERE AllowOpenInvite = 1 ORDER BY DisplayName LIMIT :Limit OFFSET :Offset"
if s.DriverName() == model.DATABASE_DRIVER_POSTGRES {
query = "SELECT * FROM Teams WHERE AllowOpenInvite = true ORDER BY DisplayName LIMIT :Limit OFFSET :Offset"
}
var data []*model.Team
if _, err := s.GetReplica().Select(&data, query, map[string]interface{}{"Offset": offset, "Limit": limit}); err != nil {
return nil, model.NewAppError("SqlTeamStore.GetAllPrivateTeamListing", "store.sql_team.get_all_private_team_listing.app_error", nil, err.Error(), http.StatusInternalServerError)
}
return data, nil
}
func (s SqlTeamStore) GetAllPrivateTeamPageListing(offset int, limit int) ([]*model.Team, *model.AppError) {
query := "SELECT * FROM Teams WHERE AllowOpenInvite = 0 ORDER BY DisplayName LIMIT :Limit OFFSET :Offset"
@@ -433,6 +448,35 @@ func (s SqlTeamStore) PermanentDelete(teamId string) *model.AppError {
return nil
}
func (s SqlTeamStore) AnalyticsPublicTeamCount() (int64, *model.AppError) {
c, err := s.GetReplica().SelectInt("SELECT COUNT(*) FROM Teams WHERE DeleteAt = 0 AND AllowOpenInvite = 1", map[string]interface{}{})
if s.DriverName() == model.DATABASE_DRIVER_POSTGRES {
c, err = s.GetReplica().SelectInt("SELECT COUNT(*) FROM Teams WHERE DeleteAt = 0 AND AllowOpenInvite = true", map[string]interface{}{})
}
if err != nil {
return int64(0), model.NewAppError("SqlTeamStore.AnalyticsPublicTeamCount", "store.sql_team.analytics_public_team_count.app_error", nil, err.Error(), http.StatusInternalServerError)
}
return c, nil
}
func (s SqlTeamStore) AnalyticsPrivateTeamCount() (int64, *model.AppError) {
c, err := s.GetReplica().SelectInt("SELECT COUNT(*) FROM Teams WHERE DeleteAt = 0 AND AllowOpenInvite = 0", map[string]interface{}{})
if s.DriverName() == model.DATABASE_DRIVER_POSTGRES {
c, err = s.GetReplica().SelectInt("SELECT COUNT(*) FROM Teams WHERE DeleteAt = 0 AND AllowOpenInvite = false", map[string]interface{}{})
}
if err != nil {
return int64(0), model.NewAppError("SqlTeamStore.AnalyticsPrivateTeamCount", "store.sql_team.analytics_private_team_count.app_error", nil, err.Error(), http.StatusInternalServerError)
}
return c, nil
}
func (s SqlTeamStore) AnalyticsTeamCount() (int64, *model.AppError) {
c, err := s.GetReplica().SelectInt("SELECT COUNT(*) FROM Teams WHERE DeleteAt = 0", map[string]interface{}{})

View File

@@ -729,11 +729,9 @@ func UpgradeDatabaseToVersion514(sqlStore SqlStore) {
}
func UpgradeDatabaseToVersion515(sqlStore SqlStore) {
// TODO: Uncomment following condition when version 5.15.0 is released
// if shouldPerformUpgrade(sqlStore, VERSION_5_14_0, VERSION_5_15_0) {
// saveSchemaVersion(sqlStore, VERSION_5_15_0)
// }
if shouldPerformUpgrade(sqlStore, VERSION_5_14_0, VERSION_5_15_0) {
saveSchemaVersion(sqlStore, VERSION_5_15_0)
}
}
func UpgradeDatabaseToVersion516(sqlStore SqlStore) {

View File

@@ -55,6 +55,7 @@ type Store interface {
TotalMasterDbConnections() int
TotalReadDbConnections() int
TotalSearchDbConnections() int
CheckIntegrity() <-chan IntegrityCheckResult
}
type TeamStore interface {
@@ -69,12 +70,15 @@ type TeamStore interface {
GetAllPage(offset int, limit int) ([]*model.Team, *model.AppError)
GetAllPrivateTeamListing() ([]*model.Team, *model.AppError)
GetAllPrivateTeamPageListing(offset int, limit int) ([]*model.Team, *model.AppError)
GetAllPublicTeamPageListing(offset int, limit int) ([]*model.Team, *model.AppError)
GetAllTeamListing() ([]*model.Team, *model.AppError)
GetAllTeamPageListing(offset int, limit int) ([]*model.Team, *model.AppError)
GetTeamsByUserId(userId string) ([]*model.Team, *model.AppError)
GetByInviteId(inviteId string) (*model.Team, *model.AppError)
PermanentDelete(teamId string) *model.AppError
AnalyticsTeamCount() (int64, *model.AppError)
AnalyticsPublicTeamCount() (int64, *model.AppError)
AnalyticsPrivateTeamCount() (int64, *model.AppError)
SaveMember(member *model.TeamMember, maxUsersPerTeam int) (*model.TeamMember, *model.AppError)
UpdateMember(member *model.TeamMember) (*model.TeamMember, *model.AppError)
GetMember(teamId string, userId string) (*model.TeamMember, *model.AppError)
@@ -147,6 +151,9 @@ type ChannelStore interface {
InvalidateMemberCount(channelId string)
GetMemberCountFromCache(channelId string) int64
GetMemberCount(channelId string, allowFromCache bool) (int64, *model.AppError)
InvalidatePinnedPostCount(channelId string)
GetPinnedPostCountFromCache(channelId string) int64
GetPinnedPostCount(channelId string, allowFromCache bool) (int64, *model.AppError)
InvalidateGuestCount(channelId string)
GetGuestCountFromCache(channelId string) int64
GetGuestCount(channelId string, allowFromCache bool) (int64, *model.AppError)
@@ -628,3 +635,21 @@ type UserGetByIdsOpts struct {
// Since filters the users based on their UpdateAt timestamp.
Since int64
}
type OrphanedRecord struct {
ParentId string
ChildId string
}
type RelationalIntegrityCheckData struct {
ParentName string
ChildName string
ParentIdAttr string
ChildIdAttr string
Records []OrphanedRecord
}
type IntegrityCheckResult struct {
Data interface{}
Err error
}

View File

@@ -75,6 +75,7 @@ func TestChannelStore(t *testing.T, ss store.Store, s SqlSupplier) {
t.Run("SearchGroupChannels", func(t *testing.T) { testChannelStoreSearchGroupChannels(t, ss) })
t.Run("AnalyticsDeletedTypeCount", func(t *testing.T) { testChannelStoreAnalyticsDeletedTypeCount(t, ss) })
t.Run("GetPinnedPosts", func(t *testing.T) { testChannelStoreGetPinnedPosts(t, ss) })
t.Run("GetPinnedPostCount", func(t *testing.T) { testChannelStoreGetPinnedPostCount(t, ss) })
t.Run("MaxChannelsPerTeam", func(t *testing.T) { testChannelStoreMaxChannelsPerTeam(t, ss) })
t.Run("GetChannelsByScheme", func(t *testing.T) { testChannelStoreGetChannelsByScheme(t, ss) })
t.Run("MigrateChannelMembers", func(t *testing.T) { testChannelStoreMigrateChannelMembers(t, ss) })
@@ -3379,6 +3380,78 @@ func testChannelStoreGetPinnedPosts(t *testing.T, ss store.Store) {
}
}
func testChannelStoreGetPinnedPostCount(t *testing.T, ss store.Store) {
ch1 := &model.Channel{
TeamId: model.NewId(),
DisplayName: "Name",
Name: "zz" + model.NewId() + "b",
Type: model.CHANNEL_OPEN,
}
o1, err := ss.Channel().Save(ch1, -1)
require.Nil(t, err)
_, err = ss.Post().Save(&model.Post{
UserId: model.NewId(),
ChannelId: o1.Id,
Message: "test",
IsPinned: true,
})
require.Nil(t, err)
_, err = ss.Post().Save(&model.Post{
UserId: model.NewId(),
ChannelId: o1.Id,
Message: "test",
IsPinned: true,
})
require.Nil(t, err)
if count, errGet := ss.Channel().GetPinnedPostCount(o1.Id, true); errGet != nil {
t.Fatal(errGet)
} else if count != 2 {
t.Fatal("didn't return right count")
}
if ss.Channel().GetPinnedPostCountFromCache(o1.Id) != 2 {
t.Fatal("should have saved 2 pinned post count ")
}
ch2 := &model.Channel{
TeamId: model.NewId(),
DisplayName: "Name",
Name: "zz" + model.NewId() + "b",
Type: model.CHANNEL_OPEN,
}
o2, err := ss.Channel().Save(ch2, -1)
require.Nil(t, err)
_, err = ss.Post().Save(&model.Post{
UserId: model.NewId(),
ChannelId: o2.Id,
Message: "test",
})
require.Nil(t, err)
_, err = ss.Post().Save(&model.Post{
UserId: model.NewId(),
ChannelId: o2.Id,
Message: "test",
})
require.Nil(t, err)
if count, errGet := ss.Channel().GetPinnedPostCount(o2.Id, true); errGet != nil {
t.Fatal(errGet)
} else if count != 0 {
t.Fatal("should return 0")
}
if ss.Channel().GetPinnedPostCountFromCache(o2.Id) != 0 {
t.Fatal("should have saved 0 pinned post count ")
}
}
func testChannelStoreMaxChannelsPerTeam(t *testing.T, ss store.Store) {
channel := &model.Channel{
TeamId: model.NewId(),

View File

@@ -4,8 +4,10 @@
package mocks
import mock "github.com/stretchr/testify/mock"
import model "github.com/mattermost/mattermost-server/model"
import (
model "github.com/mattermost/mattermost-server/model"
mock "github.com/stretchr/testify/mock"
)
// AuditStore is an autogenerated mock type for the AuditStore type
type AuditStore struct {

View File

@@ -4,8 +4,10 @@
package mocks
import mock "github.com/stretchr/testify/mock"
import model "github.com/mattermost/mattermost-server/model"
import (
model "github.com/mattermost/mattermost-server/model"
mock "github.com/stretchr/testify/mock"
)
// BotStore is an autogenerated mock type for the BotStore type
type BotStore struct {

View File

@@ -4,8 +4,10 @@
package mocks
import mock "github.com/stretchr/testify/mock"
import model "github.com/mattermost/mattermost-server/model"
import (
model "github.com/mattermost/mattermost-server/model"
mock "github.com/stretchr/testify/mock"
)
// ChannelMemberHistoryStore is an autogenerated mock type for the ChannelMemberHistoryStore type
type ChannelMemberHistoryStore struct {

View File

@@ -4,9 +4,11 @@
package mocks
import mock "github.com/stretchr/testify/mock"
import model "github.com/mattermost/mattermost-server/model"
import store "github.com/mattermost/mattermost-server/store"
import (
model "github.com/mattermost/mattermost-server/model"
store "github.com/mattermost/mattermost-server/store"
mock "github.com/stretchr/testify/mock"
)
// ChannelStore is an autogenerated mock type for the ChannelStore type
type ChannelStore struct {
@@ -993,6 +995,43 @@ func (_m *ChannelStore) GetMoreChannels(teamId string, userId string, offset int
return r0, r1
}
// GetPinnedPostCount provides a mock function with given fields: channelId, allowFromCache
func (_m *ChannelStore) GetPinnedPostCount(channelId string, allowFromCache bool) (int64, *model.AppError) {
ret := _m.Called(channelId, allowFromCache)
var r0 int64
if rf, ok := ret.Get(0).(func(string, bool) int64); ok {
r0 = rf(channelId, allowFromCache)
} else {
r0 = ret.Get(0).(int64)
}
var r1 *model.AppError
if rf, ok := ret.Get(1).(func(string, bool) *model.AppError); ok {
r1 = rf(channelId, allowFromCache)
} else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)
}
}
return r0, r1
}
// GetPinnedPostCountFromCache provides a mock function with given fields: channelId
func (_m *ChannelStore) GetPinnedPostCountFromCache(channelId string) int64 {
ret := _m.Called(channelId)
var r0 int64
if rf, ok := ret.Get(0).(func(string) int64); ok {
r0 = rf(channelId)
} else {
r0 = ret.Get(0).(int64)
}
return r0
}
// GetPinnedPosts provides a mock function with given fields: channelId
func (_m *ChannelStore) GetPinnedPosts(channelId string) (*model.PostList, *model.AppError) {
ret := _m.Called(channelId)
@@ -1139,6 +1178,11 @@ func (_m *ChannelStore) InvalidateMemberCount(channelId string) {
_m.Called(channelId)
}
// InvalidatePinnedPostCount provides a mock function with given fields: channelId
func (_m *ChannelStore) InvalidatePinnedPostCount(channelId string) {
_m.Called(channelId)
}
// IsUserInChannelUseCache provides a mock function with given fields: userId, channelId
func (_m *ChannelStore) IsUserInChannelUseCache(userId string, channelId string) bool {
ret := _m.Called(userId, channelId)

View File

@@ -4,8 +4,10 @@
package mocks
import mock "github.com/stretchr/testify/mock"
import model "github.com/mattermost/mattermost-server/model"
import (
model "github.com/mattermost/mattermost-server/model"
mock "github.com/stretchr/testify/mock"
)
// ClusterDiscoveryStore is an autogenerated mock type for the ClusterDiscoveryStore type
type ClusterDiscoveryStore struct {

View File

@@ -4,8 +4,10 @@
package mocks
import mock "github.com/stretchr/testify/mock"
import model "github.com/mattermost/mattermost-server/model"
import (
model "github.com/mattermost/mattermost-server/model"
mock "github.com/stretchr/testify/mock"
)
// CommandStore is an autogenerated mock type for the CommandStore type
type CommandStore struct {

View File

@@ -4,8 +4,10 @@
package mocks
import mock "github.com/stretchr/testify/mock"
import model "github.com/mattermost/mattermost-server/model"
import (
model "github.com/mattermost/mattermost-server/model"
mock "github.com/stretchr/testify/mock"
)
// CommandWebhookStore is an autogenerated mock type for the CommandWebhookStore type
type CommandWebhookStore struct {

View File

@@ -4,8 +4,10 @@
package mocks
import mock "github.com/stretchr/testify/mock"
import model "github.com/mattermost/mattermost-server/model"
import (
model "github.com/mattermost/mattermost-server/model"
mock "github.com/stretchr/testify/mock"
)
// ComplianceStore is an autogenerated mock type for the ComplianceStore type
type ComplianceStore struct {

View File

@@ -4,8 +4,10 @@
package mocks
import mock "github.com/stretchr/testify/mock"
import model "github.com/mattermost/mattermost-server/model"
import (
model "github.com/mattermost/mattermost-server/model"
mock "github.com/stretchr/testify/mock"
)
// EmojiStore is an autogenerated mock type for the EmojiStore type
type EmojiStore struct {

View File

@@ -4,8 +4,10 @@
package mocks
import mock "github.com/stretchr/testify/mock"
import model "github.com/mattermost/mattermost-server/model"
import (
model "github.com/mattermost/mattermost-server/model"
mock "github.com/stretchr/testify/mock"
)
// FileInfoStore is an autogenerated mock type for the FileInfoStore type
type FileInfoStore struct {

View File

@@ -4,8 +4,10 @@
package mocks
import mock "github.com/stretchr/testify/mock"
import model "github.com/mattermost/mattermost-server/model"
import (
model "github.com/mattermost/mattermost-server/model"
mock "github.com/stretchr/testify/mock"
)
// GroupStore is an autogenerated mock type for the GroupStore type
type GroupStore struct {

View File

@@ -4,8 +4,10 @@
package mocks
import mock "github.com/stretchr/testify/mock"
import model "github.com/mattermost/mattermost-server/model"
import (
model "github.com/mattermost/mattermost-server/model"
mock "github.com/stretchr/testify/mock"
)
// JobStore is an autogenerated mock type for the JobStore type
type JobStore struct {

View File

@@ -4,10 +4,14 @@
package mocks
import context "context"
import mock "github.com/stretchr/testify/mock"
import model "github.com/mattermost/mattermost-server/model"
import store "github.com/mattermost/mattermost-server/store"
import (
context "context"
model "github.com/mattermost/mattermost-server/model"
mock "github.com/stretchr/testify/mock"
store "github.com/mattermost/mattermost-server/store"
)
// LayeredStoreDatabaseLayer is an autogenerated mock type for the LayeredStoreDatabaseLayer type
type LayeredStoreDatabaseLayer struct {
@@ -78,6 +82,22 @@ func (_m *LayeredStoreDatabaseLayer) ChannelMemberHistory() store.ChannelMemberH
return r0
}
// CheckIntegrity provides a mock function with given fields:
func (_m *LayeredStoreDatabaseLayer) CheckIntegrity() <-chan store.IntegrityCheckResult {
ret := _m.Called()
var r0 <-chan store.IntegrityCheckResult
if rf, ok := ret.Get(0).(func() <-chan store.IntegrityCheckResult); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(<-chan store.IntegrityCheckResult)
}
}
return r0
}
// Close provides a mock function with given fields:
func (_m *LayeredStoreDatabaseLayer) Close() {
_m.Called()

View File

@@ -4,10 +4,14 @@
package mocks
import context "context"
import mock "github.com/stretchr/testify/mock"
import model "github.com/mattermost/mattermost-server/model"
import store "github.com/mattermost/mattermost-server/store"
import (
context "context"
model "github.com/mattermost/mattermost-server/model"
mock "github.com/stretchr/testify/mock"
store "github.com/mattermost/mattermost-server/store"
)
// LayeredStoreSupplier is an autogenerated mock type for the LayeredStoreSupplier type
type LayeredStoreSupplier struct {

View File

@@ -4,8 +4,10 @@
package mocks
import mock "github.com/stretchr/testify/mock"
import model "github.com/mattermost/mattermost-server/model"
import (
model "github.com/mattermost/mattermost-server/model"
mock "github.com/stretchr/testify/mock"
)
// LicenseStore is an autogenerated mock type for the LicenseStore type
type LicenseStore struct {

View File

@@ -4,8 +4,10 @@
package mocks
import mock "github.com/stretchr/testify/mock"
import model "github.com/mattermost/mattermost-server/model"
import (
model "github.com/mattermost/mattermost-server/model"
mock "github.com/stretchr/testify/mock"
)
// LinkMetadataStore is an autogenerated mock type for the LinkMetadataStore type
type LinkMetadataStore struct {

View File

@@ -4,8 +4,10 @@
package mocks
import mock "github.com/stretchr/testify/mock"
import model "github.com/mattermost/mattermost-server/model"
import (
model "github.com/mattermost/mattermost-server/model"
mock "github.com/stretchr/testify/mock"
)
// OAuthStore is an autogenerated mock type for the OAuthStore type
type OAuthStore struct {

View File

@@ -4,8 +4,10 @@
package mocks
import mock "github.com/stretchr/testify/mock"
import model "github.com/mattermost/mattermost-server/model"
import (
model "github.com/mattermost/mattermost-server/model"
mock "github.com/stretchr/testify/mock"
)
// PluginStore is an autogenerated mock type for the PluginStore type
type PluginStore struct {

View File

@@ -4,8 +4,10 @@
package mocks
import mock "github.com/stretchr/testify/mock"
import model "github.com/mattermost/mattermost-server/model"
import (
model "github.com/mattermost/mattermost-server/model"
mock "github.com/stretchr/testify/mock"
)
// PostStore is an autogenerated mock type for the PostStore type
type PostStore struct {

View File

@@ -4,8 +4,10 @@
package mocks
import mock "github.com/stretchr/testify/mock"
import model "github.com/mattermost/mattermost-server/model"
import (
model "github.com/mattermost/mattermost-server/model"
mock "github.com/stretchr/testify/mock"
)
// PreferenceStore is an autogenerated mock type for the PreferenceStore type
type PreferenceStore struct {

View File

@@ -4,8 +4,10 @@
package mocks
import mock "github.com/stretchr/testify/mock"
import model "github.com/mattermost/mattermost-server/model"
import (
model "github.com/mattermost/mattermost-server/model"
mock "github.com/stretchr/testify/mock"
)
// ReactionStore is an autogenerated mock type for the ReactionStore type
type ReactionStore struct {

View File

@@ -4,8 +4,10 @@
package mocks
import mock "github.com/stretchr/testify/mock"
import model "github.com/mattermost/mattermost-server/model"
import (
model "github.com/mattermost/mattermost-server/model"
mock "github.com/stretchr/testify/mock"
)
// RoleStore is an autogenerated mock type for the RoleStore type
type RoleStore struct {

View File

@@ -4,8 +4,10 @@
package mocks
import mock "github.com/stretchr/testify/mock"
import model "github.com/mattermost/mattermost-server/model"
import (
model "github.com/mattermost/mattermost-server/model"
mock "github.com/stretchr/testify/mock"
)
// SchemeStore is an autogenerated mock type for the SchemeStore type
type SchemeStore struct {

View File

@@ -4,8 +4,10 @@
package mocks
import mock "github.com/stretchr/testify/mock"
import model "github.com/mattermost/mattermost-server/model"
import (
model "github.com/mattermost/mattermost-server/model"
mock "github.com/stretchr/testify/mock"
)
// SessionStore is an autogenerated mock type for the SessionStore type
type SessionStore struct {

View File

@@ -4,11 +4,14 @@
package mocks
import gorp "github.com/mattermost/gorp"
import mock "github.com/stretchr/testify/mock"
import (
gorp "github.com/mattermost/gorp"
mock "github.com/stretchr/testify/mock"
import squirrel "github.com/Masterminds/squirrel"
import store "github.com/mattermost/mattermost-server/store"
squirrel "github.com/Masterminds/squirrel"
store "github.com/mattermost/mattermost-server/store"
)
// SqlStore is an autogenerated mock type for the SqlStore type
type SqlStore struct {

View File

@@ -4,8 +4,10 @@
package mocks
import mock "github.com/stretchr/testify/mock"
import model "github.com/mattermost/mattermost-server/model"
import (
model "github.com/mattermost/mattermost-server/model"
mock "github.com/stretchr/testify/mock"
)
// StatusStore is an autogenerated mock type for the StatusStore type
type StatusStore struct {

View File

@@ -4,8 +4,10 @@
package mocks
import mock "github.com/stretchr/testify/mock"
import store "github.com/mattermost/mattermost-server/store"
import (
store "github.com/mattermost/mattermost-server/store"
mock "github.com/stretchr/testify/mock"
)
// Store is an autogenerated mock type for the Store type
type Store struct {
@@ -76,6 +78,22 @@ func (_m *Store) ChannelMemberHistory() store.ChannelMemberHistoryStore {
return r0
}
// CheckIntegrity provides a mock function with given fields:
func (_m *Store) CheckIntegrity() <-chan store.IntegrityCheckResult {
ret := _m.Called()
var r0 <-chan store.IntegrityCheckResult
if rf, ok := ret.Get(0).(func() <-chan store.IntegrityCheckResult); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(<-chan store.IntegrityCheckResult)
}
}
return r0
}
// Close provides a mock function with given fields:
func (_m *Store) Close() {
_m.Called()

View File

@@ -4,8 +4,10 @@
package mocks
import mock "github.com/stretchr/testify/mock"
import model "github.com/mattermost/mattermost-server/model"
import (
model "github.com/mattermost/mattermost-server/model"
mock "github.com/stretchr/testify/mock"
)
// SystemStore is an autogenerated mock type for the SystemStore type
type SystemStore struct {

View File

@@ -4,8 +4,10 @@
package mocks
import mock "github.com/stretchr/testify/mock"
import model "github.com/mattermost/mattermost-server/model"
import (
model "github.com/mattermost/mattermost-server/model"
mock "github.com/stretchr/testify/mock"
)
// TeamStore is an autogenerated mock type for the TeamStore type
type TeamStore struct {
@@ -35,6 +37,52 @@ func (_m *TeamStore) AnalyticsGetTeamCountForScheme(schemeId string) (int64, *mo
return r0, r1
}
// AnalyticsPrivateTeamCount provides a mock function with given fields:
func (_m *TeamStore) AnalyticsPrivateTeamCount() (int64, *model.AppError) {
ret := _m.Called()
var r0 int64
if rf, ok := ret.Get(0).(func() int64); ok {
r0 = rf()
} else {
r0 = ret.Get(0).(int64)
}
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
}
// AnalyticsPublicTeamCount provides a mock function with given fields:
func (_m *TeamStore) AnalyticsPublicTeamCount() (int64, *model.AppError) {
ret := _m.Called()
var r0 int64
if rf, ok := ret.Get(0).(func() int64); ok {
r0 = rf()
} else {
r0 = ret.Get(0).(int64)
}
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
}
// AnalyticsTeamCount provides a mock function with given fields:
func (_m *TeamStore) AnalyticsTeamCount() (int64, *model.AppError) {
ret := _m.Called()
@@ -252,6 +300,31 @@ func (_m *TeamStore) GetAllPrivateTeamPageListing(offset int, limit int) ([]*mod
return r0, r1
}
// GetAllPublicTeamPageListing provides a mock function with given fields: offset, limit
func (_m *TeamStore) GetAllPublicTeamPageListing(offset int, limit int) ([]*model.Team, *model.AppError) {
ret := _m.Called(offset, limit)
var r0 []*model.Team
if rf, ok := ret.Get(0).(func(int, int) []*model.Team); ok {
r0 = rf(offset, limit)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]*model.Team)
}
}
var r1 *model.AppError
if rf, ok := ret.Get(1).(func(int, int) *model.AppError); ok {
r1 = rf(offset, limit)
} else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)
}
}
return r0, r1
}
// GetAllTeamListing provides a mock function with given fields:
func (_m *TeamStore) GetAllTeamListing() ([]*model.Team, *model.AppError) {
ret := _m.Called()

View File

@@ -4,8 +4,10 @@
package mocks
import mock "github.com/stretchr/testify/mock"
import model "github.com/mattermost/mattermost-server/model"
import (
model "github.com/mattermost/mattermost-server/model"
mock "github.com/stretchr/testify/mock"
)
// TermsOfServiceStore is an autogenerated mock type for the TermsOfServiceStore type
type TermsOfServiceStore struct {

View File

@@ -4,8 +4,10 @@
package mocks
import mock "github.com/stretchr/testify/mock"
import model "github.com/mattermost/mattermost-server/model"
import (
model "github.com/mattermost/mattermost-server/model"
mock "github.com/stretchr/testify/mock"
)
// TokenStore is an autogenerated mock type for the TokenStore type
type TokenStore struct {

View File

@@ -4,8 +4,10 @@
package mocks
import mock "github.com/stretchr/testify/mock"
import model "github.com/mattermost/mattermost-server/model"
import (
model "github.com/mattermost/mattermost-server/model"
mock "github.com/stretchr/testify/mock"
)
// UserAccessTokenStore is an autogenerated mock type for the UserAccessTokenStore type
type UserAccessTokenStore struct {

View File

@@ -4,9 +4,11 @@
package mocks
import mock "github.com/stretchr/testify/mock"
import model "github.com/mattermost/mattermost-server/model"
import store "github.com/mattermost/mattermost-server/store"
import (
model "github.com/mattermost/mattermost-server/model"
store "github.com/mattermost/mattermost-server/store"
mock "github.com/stretchr/testify/mock"
)
// UserStore is an autogenerated mock type for the UserStore type
type UserStore struct {

View File

@@ -4,8 +4,10 @@
package mocks
import mock "github.com/stretchr/testify/mock"
import model "github.com/mattermost/mattermost-server/model"
import (
model "github.com/mattermost/mattermost-server/model"
mock "github.com/stretchr/testify/mock"
)
// UserTermsOfServiceStore is an autogenerated mock type for the UserTermsOfServiceStore type
type UserTermsOfServiceStore struct {

View File

@@ -4,8 +4,10 @@
package mocks
import mock "github.com/stretchr/testify/mock"
import model "github.com/mattermost/mattermost-server/model"
import (
model "github.com/mattermost/mattermost-server/model"
mock "github.com/stretchr/testify/mock"
)
// WebhookStore is an autogenerated mock type for the WebhookStore type
type WebhookStore struct {

View File

@@ -87,6 +87,9 @@ func (s *Store) TotalMasterDbConnections() int { return 1 }
func (s *Store) TotalReadDbConnections() int { return 1 }
func (s *Store) TotalSearchDbConnections() int { return 1 }
func (s *Store) GetCurrentSchemaVersion() string { return "" }
func (s *Store) CheckIntegrity() <-chan store.IntegrityCheckResult {
return make(chan store.IntegrityCheckResult)
}
func (s *Store) AssertExpectations(t mock.TestingT) bool {
return mock.AssertExpectationsForObjects(t,

View File

@@ -15,6 +15,14 @@ import (
"github.com/mattermost/mattermost-server/store"
)
func cleanupTeamStore(t *testing.T, ss store.Store) {
allTeams, err := ss.Team().GetAll()
for _, team := range allTeams {
ss.Team().PermanentDelete(team.Id)
}
assert.Nil(t, err)
}
func TestTeamStore(t *testing.T, ss store.Store) {
createDefaultRoles(t, ss)
@@ -31,8 +39,11 @@ func TestTeamStore(t *testing.T, ss store.Store) {
t.Run("GetAllTeamPageListing", func(t *testing.T) { testGetAllTeamPageListing(t, ss) })
t.Run("GetAllPrivateTeamListing", func(t *testing.T) { testGetAllPrivateTeamListing(t, ss) })
t.Run("GetAllPrivateTeamPageListing", func(t *testing.T) { testGetAllPrivateTeamPageListing(t, ss) })
t.Run("GetAllPublicTeamPageListing", func(t *testing.T) { testGetAllPublicTeamPageListing(t, ss) })
t.Run("Delete", func(t *testing.T) { testDelete(t, ss) })
t.Run("TeamCount", func(t *testing.T) { testTeamCount(t, ss) })
t.Run("TeamPublicCount", func(t *testing.T) { testPublicTeamCount(t, ss) })
t.Run("TeamPrivateCount", func(t *testing.T) { testPrivateTeamCount(t, ss) })
t.Run("TeamMembers", func(t *testing.T) { testTeamMembers(t, ss) })
t.Run("SaveTeamMemberMaxMembers", func(t *testing.T) { testSaveTeamMemberMaxMembers(t, ss) })
t.Run("GetTeamMember", func(t *testing.T) { testGetTeamMember(t, ss) })
@@ -678,6 +689,66 @@ func testGetAllPrivateTeamPageListing(t *testing.T, ss store.Store) {
}
}
func testGetAllPublicTeamPageListing(t *testing.T, ss store.Store) {
cleanupTeamStore(t, ss)
o1 := model.Team{}
o1.DisplayName = "DisplayName1"
o1.Name = "z-z-z" + model.NewId() + "b"
o1.Email = MakeEmail()
o1.Type = model.TEAM_OPEN
o1.AllowOpenInvite = true
t1, err := ss.Team().Save(&o1)
require.Nil(t, err)
o2 := model.Team{}
o2.DisplayName = "DisplayName2"
o2.Name = "zz" + model.NewId() + "b"
o2.Email = MakeEmail()
o2.Type = model.TEAM_OPEN
o2.AllowOpenInvite = false
_, err = ss.Team().Save(&o2)
require.Nil(t, err)
o3 := model.Team{}
o3.DisplayName = "DisplayName3"
o3.Name = "z-z-z" + model.NewId() + "b"
o3.Email = MakeEmail()
o3.Type = model.TEAM_INVITE
o3.AllowOpenInvite = true
t3, err := ss.Team().Save(&o3)
require.Nil(t, err)
o4 := model.Team{}
o4.DisplayName = "DisplayName4"
o4.Name = "zz" + model.NewId() + "b"
o4.Email = MakeEmail()
o4.Type = model.TEAM_INVITE
o4.AllowOpenInvite = false
_, err = ss.Team().Save(&o4)
require.Nil(t, err)
teams, err := ss.Team().GetAllPublicTeamPageListing(0, 10)
assert.Nil(t, err)
assert.Equal(t, []*model.Team{t1, t3}, teams)
o5 := model.Team{}
o5.DisplayName = "DisplayName5"
o5.Name = "z-z-z" + model.NewId() + "b"
o5.Email = MakeEmail()
o5.Type = model.TEAM_OPEN
o5.AllowOpenInvite = true
t5, err := ss.Team().Save(&o5)
require.Nil(t, err)
teams, err = ss.Team().GetAllPublicTeamPageListing(0, 4)
assert.Nil(t, err)
assert.Equal(t, []*model.Team{t1, t3, t5}, teams)
teams, err = ss.Team().GetAllPublicTeamPageListing(1, 1)
assert.Nil(t, err)
}
func testDelete(t *testing.T, ss store.Store) {
o1 := model.Team{}
o1.DisplayName = "DisplayName"
@@ -701,6 +772,76 @@ func testDelete(t *testing.T, ss store.Store) {
}
}
func testPublicTeamCount(t *testing.T, ss store.Store) {
cleanupTeamStore(t, ss)
o1 := model.Team{}
o1.DisplayName = "DisplayName"
o1.Name = "z-z-z" + model.NewId() + "b"
o1.Email = MakeEmail()
o1.Type = model.TEAM_OPEN
o1.AllowOpenInvite = true
_, err := ss.Team().Save(&o1)
require.Nil(t, err)
o2 := model.Team{}
o2.DisplayName = "DisplayName"
o2.Name = "z-z-z" + model.NewId() + "b"
o2.Email = MakeEmail()
o2.Type = model.TEAM_OPEN
o2.AllowOpenInvite = false
_, err = ss.Team().Save(&o2)
require.Nil(t, err)
o3 := model.Team{}
o3.DisplayName = "DisplayName"
o3.Name = "z-z-z" + model.NewId() + "b"
o3.Email = MakeEmail()
o3.Type = model.TEAM_OPEN
o3.AllowOpenInvite = true
_, err = ss.Team().Save(&o3)
require.Nil(t, err)
teamCount, err := ss.Team().AnalyticsPublicTeamCount()
require.Nil(t, err)
require.Equal(t, int64(2), teamCount, "should only be 1 team")
}
func testPrivateTeamCount(t *testing.T, ss store.Store) {
cleanupTeamStore(t, ss)
o1 := model.Team{}
o1.DisplayName = "DisplayName"
o1.Name = "z-z-z" + model.NewId() + "b"
o1.Email = MakeEmail()
o1.Type = model.TEAM_OPEN
o1.AllowOpenInvite = false
_, err := ss.Team().Save(&o1)
require.Nil(t, err)
o2 := model.Team{}
o2.DisplayName = "DisplayName"
o2.Name = "z-z-z" + model.NewId() + "b"
o2.Email = MakeEmail()
o2.Type = model.TEAM_OPEN
o2.AllowOpenInvite = true
_, err = ss.Team().Save(&o2)
require.Nil(t, err)
o3 := model.Team{}
o3.DisplayName = "DisplayName"
o3.Name = "z-z-z" + model.NewId() + "b"
o3.Email = MakeEmail()
o3.Type = model.TEAM_OPEN
o3.AllowOpenInvite = false
_, err = ss.Team().Save(&o3)
require.Nil(t, err)
teamCount, err := ss.Team().AnalyticsPrivateTeamCount()
require.Nil(t, err)
require.Equal(t, int64(2), teamCount, "should only be 1 team")
}
func testTeamCount(t *testing.T, ss store.Store) {
o1 := model.Team{}
o1.DisplayName = "DisplayName"

View File

@@ -1382,6 +1382,23 @@ func (s *TimerLayerChannelStore) InvalidateMemberCount(channelId string) {
return
}
func (s *TimerLayerChannelStore) InvalidatePinnedPostCount(channelId string) {
start := timemodule.Now()
s.ChannelStore.InvalidatePinnedPostCount(channelId)
t := timemodule.Now()
elapsed := t.Sub(start)
if s.Root.Metrics != nil {
success := "false"
if true {
success = "true"
}
s.Root.Metrics.ObserveStoreMethodDuration("ChannelStore.InvalidatePinnedPostCount", success, float64(elapsed))
}
return
}
func (s *TimerLayerChannelStore) IsUserInChannelUseCache(userId string, channelId string) bool {
start := timemodule.Now()