Files
team/server/channels/app/limits_test.go
a699e1f838 Automated cherry pick of #36999 (#37162)
The GET /api/v4/limits/server endpoint ran expensive active-user and
single-channel-guest count queries for every user on login and app
refresh, even though non-admins never receive those counts. The
single-channel-guest count is a full ChannelMembers scan, so this put a
full-table-scan query on a high-frequency hot path.

Add an includeUserCounts parameter to App.GetServerLimits so the user
and guest count queries only run when the caller needs them. The api4
handler passes the existing admin check, keeping the cheap
license-derived and post-history fields for all users while skipping the
expensive queries for non-admins. Internal callers that genuinely need
the counts (isAtUserLimit, user creation/activation) pass true.

(cherry picked from commit cdc10d47fe)

Co-authored-by: Ben Schumacher <[email protected]>

Co-authored-by: Hanzo Dev <[email protected]>
2026-06-23 10:34:07 +00:00

856 lines
27 KiB
Go

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package app
import (
"errors"
"testing"
"github.com/mattermost/mattermost/server/public/model"
"github.com/mattermost/mattermost/server/v8/channels/store"
storemocks "github.com/mattermost/mattermost/server/v8/channels/store/storetest/mocks"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
)
func TestGetServerLimits(t *testing.T) {
mainHelper.Parallel(t)
t.Run("unlicensed server shows hard-coded limits", func(t *testing.T) {
th := Setup(t).InitBasic(t)
th.App.Srv().SetLicense(nil)
serverLimits, appErr := th.App.GetServerLimits(true)
require.Nil(t, appErr)
// InitBasic creates 3 users by default
require.Equal(t, int64(3), serverLimits.ActiveUserCount)
require.Equal(t, int64(200), serverLimits.MaxUsersLimit)
require.Equal(t, int64(250), serverLimits.MaxUsersHardLimit)
})
t.Run("user counts are skipped when includeUserCounts is false", func(t *testing.T) {
th := Setup(t).InitBasic(t)
th.App.Srv().SetLicense(nil)
// With counts included we get the real active user count (InitBasic creates 3 users).
withCounts, appErr := th.App.GetServerLimits(true)
require.Nil(t, appErr)
require.Equal(t, int64(3), withCounts.ActiveUserCount)
// Without counts the expensive count queries are skipped, so the count is zero even
// though users exist. The cheap license-derived limits are still returned.
withoutCounts, appErr := th.App.GetServerLimits(false)
require.Nil(t, appErr)
require.Equal(t, int64(0), withoutCounts.ActiveUserCount)
require.Equal(t, int64(0), withoutCounts.SingleChannelGuestCount)
require.Equal(t, int64(200), withoutCounts.MaxUsersLimit)
require.Equal(t, int64(250), withoutCounts.MaxUsersHardLimit)
})
t.Run("user count should increase on creating new user and decrease on permanently deleting", func(t *testing.T) {
th := Setup(t).InitBasic(t)
th.App.Srv().SetLicense(nil)
serverLimits, appErr := th.App.GetServerLimits(true)
require.Nil(t, appErr)
require.Equal(t, int64(3), serverLimits.ActiveUserCount)
// now we create a new user
newUser := th.CreateUser(t)
serverLimits, appErr = th.App.GetServerLimits(true)
require.Nil(t, appErr)
require.Equal(t, int64(4), serverLimits.ActiveUserCount)
// now we'll delete the user
_ = th.App.PermanentDeleteUser(th.Context, newUser)
serverLimits, appErr = th.App.GetServerLimits(true)
require.Nil(t, appErr)
require.Equal(t, int64(3), serverLimits.ActiveUserCount)
})
t.Run("user count should increase on creating new guest user and decrease on permanently deleting", func(t *testing.T) {
th := Setup(t).InitBasic(t)
th.App.Srv().SetLicense(nil)
serverLimits, appErr := th.App.GetServerLimits(true)
require.Nil(t, appErr)
require.Equal(t, int64(3), serverLimits.ActiveUserCount)
// now we create a new user
newGuestUser := th.CreateGuest(t)
serverLimits, appErr = th.App.GetServerLimits(true)
require.Nil(t, appErr)
require.Equal(t, int64(4), serverLimits.ActiveUserCount)
// now we'll delete the user
_ = th.App.PermanentDeleteUser(th.Context, newGuestUser)
serverLimits, appErr = th.App.GetServerLimits(true)
require.Nil(t, appErr)
require.Equal(t, int64(3), serverLimits.ActiveUserCount)
})
t.Run("user count should increase on creating new user and decrease on soft deleting", func(t *testing.T) {
th := Setup(t).InitBasic(t)
th.App.Srv().SetLicense(nil)
serverLimits, appErr := th.App.GetServerLimits(true)
require.Nil(t, appErr)
require.Equal(t, int64(3), serverLimits.ActiveUserCount)
// now we create a new user
newUser := th.CreateUser(t)
serverLimits, appErr = th.App.GetServerLimits(true)
require.Nil(t, appErr)
require.Equal(t, int64(4), serverLimits.ActiveUserCount)
// now we'll delete the user
_, appErr = th.App.UpdateActive(th.Context, newUser, false)
require.Nil(t, appErr)
serverLimits, appErr = th.App.GetServerLimits(true)
require.Nil(t, appErr)
require.Equal(t, int64(3), serverLimits.ActiveUserCount)
})
t.Run("user count should increase on creating new guest user and decrease on soft deleting", func(t *testing.T) {
th := Setup(t).InitBasic(t)
th.App.Srv().SetLicense(nil)
serverLimits, appErr := th.App.GetServerLimits(true)
require.Nil(t, appErr)
require.Equal(t, int64(3), serverLimits.ActiveUserCount)
// now we create a new user
newGuestUser := th.CreateGuest(t)
serverLimits, appErr = th.App.GetServerLimits(true)
require.Nil(t, appErr)
require.Equal(t, int64(4), serverLimits.ActiveUserCount)
// now we'll delete the user
_, appErr = th.App.UpdateActive(th.Context, newGuestUser, false)
require.Nil(t, appErr)
serverLimits, appErr = th.App.GetServerLimits(true)
require.Nil(t, appErr)
require.Equal(t, int64(3), serverLimits.ActiveUserCount)
})
t.Run("user count should not change on creating or deleting bots", func(t *testing.T) {
th := Setup(t).InitBasic(t)
th.App.Srv().SetLicense(nil)
serverLimits, appErr := th.App.GetServerLimits(true)
require.Nil(t, appErr)
require.Equal(t, int64(3), serverLimits.ActiveUserCount)
// now we create a new bot
newBot := th.CreateBot(t)
serverLimits, appErr = th.App.GetServerLimits(true)
require.Nil(t, appErr)
require.Equal(t, int64(3), serverLimits.ActiveUserCount)
// now we'll delete the bot
_ = th.App.PermanentDeleteBot(th.Context, newBot.UserId)
serverLimits, appErr = th.App.GetServerLimits(true)
require.Nil(t, appErr)
require.Equal(t, int64(3), serverLimits.ActiveUserCount)
})
t.Run("licensed server without seat count enforcement shows no limits", func(t *testing.T) {
th := Setup(t).InitBasic(t)
license := model.NewTestLicense("")
license.IsSeatCountEnforced = false
th.App.Srv().SetLicense(license)
serverLimits, appErr := th.App.GetServerLimits(true)
require.Nil(t, appErr)
require.Greater(t, serverLimits.ActiveUserCount, int64(0))
require.Equal(t, int64(0), serverLimits.MaxUsersLimit)
require.Equal(t, int64(0), serverLimits.MaxUsersHardLimit)
})
t.Run("licensed server with seat count enforcement shows license limits with configurable extra users", func(t *testing.T) {
th := Setup(t).InitBasic(t)
userLimit := 100
extraUsers := 10
license := model.NewTestLicense("")
license.IsSeatCountEnforced = true
license.Features.Users = &userLimit
license.ExtraUsers = &extraUsers
th.App.Srv().SetLicense(license)
serverLimits, appErr := th.App.GetServerLimits(true)
require.Nil(t, appErr)
// InitBasic creates 3 users by default
require.Equal(t, int64(3), serverLimits.ActiveUserCount)
require.Equal(t, int64(100), serverLimits.MaxUsersLimit)
require.Equal(t, int64(110), serverLimits.MaxUsersHardLimit) // 100 + 10 extra users = 110
})
t.Run("licensed server with seat count enforcement and no ExtraUsers configured defaults to zero", func(t *testing.T) {
th := Setup(t).InitBasic(t)
userLimit := 100
license := model.NewTestLicense("")
license.IsSeatCountEnforced = true
license.Features.Users = &userLimit
license.ExtraUsers = nil // Not configured
th.App.Srv().SetLicense(license)
serverLimits, appErr := th.App.GetServerLimits(true)
require.Nil(t, appErr)
// InitBasic creates 3 users by default
require.Equal(t, int64(3), serverLimits.ActiveUserCount)
require.Equal(t, int64(100), serverLimits.MaxUsersLimit)
require.Equal(t, int64(100), serverLimits.MaxUsersHardLimit) // 100 + 0 extra users = 100 (hard cap)
})
t.Run("licensed server with seat count enforcement and zero ExtraUsers creates hard cap", func(t *testing.T) {
th := Setup(t).InitBasic(t)
userLimit := 100
extraUsers := 0
license := model.NewTestLicense("")
license.IsSeatCountEnforced = true
license.Features.Users = &userLimit
license.ExtraUsers = &extraUsers
th.App.Srv().SetLicense(license)
serverLimits, appErr := th.App.GetServerLimits(true)
require.Nil(t, appErr)
// InitBasic creates 3 users by default
require.Equal(t, int64(3), serverLimits.ActiveUserCount)
require.Equal(t, int64(100), serverLimits.MaxUsersLimit)
require.Equal(t, int64(100), serverLimits.MaxUsersHardLimit) // 100 + 0 extra users = 100 (hard cap)
})
t.Run("licensed server with seat count enforcement but no Users feature shows no limits", func(t *testing.T) {
th := Setup(t).InitBasic(t)
license := model.NewTestLicense("")
license.IsSeatCountEnforced = true
license.Features.Users = nil
th.App.Srv().SetLicense(license)
serverLimits, appErr := th.App.GetServerLimits(true)
require.Nil(t, appErr)
require.Greater(t, serverLimits.ActiveUserCount, int64(0))
require.Equal(t, int64(0), serverLimits.MaxUsersLimit)
require.Equal(t, int64(0), serverLimits.MaxUsersHardLimit)
})
t.Run("licensed server with seat count enforcement and zero Users shows zero limits", func(t *testing.T) {
th := Setup(t).InitBasic(t)
userLimit := 0
license := model.NewTestLicense("")
license.IsSeatCountEnforced = true
license.Features.Users = &userLimit
th.App.Srv().SetLicense(license)
serverLimits, appErr := th.App.GetServerLimits(true)
require.Nil(t, appErr)
require.Greater(t, serverLimits.ActiveUserCount, int64(0))
require.Equal(t, int64(0), serverLimits.MaxUsersLimit)
require.Equal(t, int64(0), serverLimits.MaxUsersHardLimit) // 0 + 0 (default) extra users = 0
})
}
func TestIsAtUserLimit(t *testing.T) {
mainHelper.Parallel(t)
t.Run("unlicensed server", func(t *testing.T) {
t.Run("below hard limit", func(t *testing.T) {
th := SetupWithStoreMock(t)
th.App.Srv().SetLicense(nil)
mockUserStore := storemocks.UserStore{}
mockUserStore.On("Count", mock.Anything).Return(int64(200), nil) // Under hard limit of 250
mockUserStore.On("AnalyticsGetSingleChannelGuestCount").Return(int64(0), nil)
mockStore := th.App.Srv().Store().(*storemocks.Store)
mockStore.On("User").Return(&mockUserStore)
atLimit, appErr := th.App.isAtUserLimit()
require.Nil(t, appErr)
require.False(t, atLimit)
})
t.Run("at hard limit", func(t *testing.T) {
th := SetupWithStoreMock(t)
th.App.Srv().SetLicense(nil)
mockUserStore := storemocks.UserStore{}
mockUserStore.On("Count", mock.Anything).Return(int64(250), nil) // At hard limit of 250
mockUserStore.On("AnalyticsGetSingleChannelGuestCount").Return(int64(0), nil)
mockStore := th.App.Srv().Store().(*storemocks.Store)
mockStore.On("User").Return(&mockUserStore)
atLimit, appErr := th.App.isAtUserLimit()
require.Nil(t, appErr)
require.True(t, atLimit)
})
t.Run("above hard limit", func(t *testing.T) {
th := SetupWithStoreMock(t)
th.App.Srv().SetLicense(nil)
mockUserStore := storemocks.UserStore{}
mockUserStore.On("Count", mock.Anything).Return(int64(300), nil) // Over hard limit of 250
mockUserStore.On("AnalyticsGetSingleChannelGuestCount").Return(int64(0), nil)
mockStore := th.App.Srv().Store().(*storemocks.Store)
mockStore.On("User").Return(&mockUserStore)
atLimit, appErr := th.App.isAtUserLimit()
require.Nil(t, appErr)
require.True(t, atLimit)
})
})
t.Run("licensed server with seat count enforcement", func(t *testing.T) {
t.Run("below base limit", func(t *testing.T) {
th := Setup(t).InitBasic(t)
userLimit := 5
license := model.NewTestLicense("")
license.IsSeatCountEnforced = true
license.Features.Users = &userLimit
th.App.Srv().SetLicense(license)
// InitBasic creates 3 users, so we're below the base limit of 5 and grace limit of 6
atLimit, appErr := th.App.isAtUserLimit()
require.Nil(t, appErr)
require.False(t, atLimit)
})
t.Run("at base limit but below hard limit with extra users", func(t *testing.T) {
th := Setup(t).InitBasic(t)
userLimit := 5
extraUsers := 2
license := model.NewTestLicense("")
license.IsSeatCountEnforced = true
license.Features.Users = &userLimit
license.ExtraUsers = &extraUsers
th.App.Srv().SetLicense(license)
// Create 2 additional users to have 5 total (at base limit of 5, but below hard limit of 7)
th.CreateUser(t)
th.CreateUser(t)
atLimit, appErr := th.App.isAtUserLimit()
require.Nil(t, appErr)
require.False(t, atLimit) // Should be false due to extra users
})
t.Run("at hard limit with extra users", func(t *testing.T) {
th := SetupWithStoreMock(t)
userLimit := 5
extraUsers := 1
license := model.NewTestLicense("")
license.IsSeatCountEnforced = true
license.Features.Users = &userLimit
license.ExtraUsers = &extraUsers
th.App.Srv().SetLicense(license)
mockUserStore := storemocks.UserStore{}
mockUserStore.On("Count", mock.Anything).Return(int64(6), nil) // At hard limit of 6 (5 + 1)
mockUserStore.On("AnalyticsGetSingleChannelGuestCount").Return(int64(0), nil)
mockStore := th.App.Srv().Store().(*storemocks.Store)
mockStore.On("User").Return(&mockUserStore)
atLimit, appErr := th.App.isAtUserLimit()
require.Nil(t, appErr)
require.True(t, atLimit)
})
t.Run("above hard limit with extra users", func(t *testing.T) {
th := SetupWithStoreMock(t)
userLimit := 5
extraUsers := 1
license := model.NewTestLicense("")
license.IsSeatCountEnforced = true
license.Features.Users = &userLimit
license.ExtraUsers = &extraUsers
th.App.Srv().SetLicense(license)
mockUserStore := storemocks.UserStore{}
mockUserStore.On("Count", mock.Anything).Return(int64(7), nil) // Above hard limit of 6
mockUserStore.On("AnalyticsGetSingleChannelGuestCount").Return(int64(0), nil)
mockStore := th.App.Srv().Store().(*storemocks.Store)
mockStore.On("User").Return(&mockUserStore)
atLimit, appErr := th.App.isAtUserLimit()
require.Nil(t, appErr)
require.True(t, atLimit)
})
})
t.Run("licensed server without seat count enforcement", func(t *testing.T) {
t.Run("below unenforced limit", func(t *testing.T) {
th := Setup(t).InitBasic(t)
userLimit := 5
license := model.NewTestLicense("")
license.IsSeatCountEnforced = false
license.Features.Users = &userLimit
th.App.Srv().SetLicense(license)
// Create 2 additional users to have 3 total (below limit of 5)
th.CreateUser(t)
th.CreateUser(t)
atLimit, appErr := th.App.isAtUserLimit()
require.Nil(t, appErr)
require.False(t, atLimit)
})
t.Run("at unenforced limit", func(t *testing.T) {
th := Setup(t).InitBasic(t)
userLimit := 5
license := model.NewTestLicense("")
license.IsSeatCountEnforced = false
license.Features.Users = &userLimit
th.App.Srv().SetLicense(license)
// Create 4 additional users to have 5 total (at limit of 5)
th.CreateUser(t)
th.CreateUser(t)
th.CreateUser(t)
th.CreateUser(t)
atLimit, appErr := th.App.isAtUserLimit()
require.Nil(t, appErr)
require.False(t, atLimit)
})
t.Run("above unenforced limit", func(t *testing.T) {
th := Setup(t).InitBasic(t)
userLimit := 5
license := model.NewTestLicense("")
license.IsSeatCountEnforced = false
license.Features.Users = &userLimit
th.App.Srv().SetLicense(license)
// Create 5 additional users to have 6 total (above limit of 5)
th.CreateUser(t)
th.CreateUser(t)
th.CreateUser(t)
th.CreateUser(t)
th.CreateUser(t)
atLimit, appErr := th.App.isAtUserLimit()
require.Nil(t, appErr)
require.False(t, atLimit)
})
})
}
func TestExtraUsersBehavior(t *testing.T) {
mainHelper.Parallel(t)
t.Run("extra users examples", func(t *testing.T) {
tests := []struct {
name string
licenseUserLimit int
extraUsers *int
expectedBaseLimit int64
expectedHardLimit int64
}{
{
name: "zero license users with extra users",
licenseUserLimit: 0,
extraUsers: new(5),
expectedBaseLimit: 0,
expectedHardLimit: 5, // 0 + 5 extra users = 5
},
{
name: "license with configured extra users",
licenseUserLimit: 10,
extraUsers: new(2),
expectedBaseLimit: 10,
expectedHardLimit: 12, // 10 + 2 extra users = 12
},
{
name: "license with zero extra users (hard cap)",
licenseUserLimit: 100,
extraUsers: new(0),
expectedBaseLimit: 100,
expectedHardLimit: 100, // 100 + 0 extra users = 100 (hard cap)
},
{
name: "license with no extra users configured defaults to zero",
licenseUserLimit: 100,
extraUsers: nil,
expectedBaseLimit: 100,
expectedHardLimit: 100, // 100 + 0 (default) extra users = 100 (hard cap)
},
{
name: "license with large number of extra users",
licenseUserLimit: 1000,
extraUsers: new(200),
expectedBaseLimit: 1000,
expectedHardLimit: 1200, // 1000 + 200 extra users = 1200
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
th := Setup(t).InitBasic(t)
license := model.NewTestLicense("")
license.IsSeatCountEnforced = true
license.Features.Users = &tt.licenseUserLimit
license.ExtraUsers = tt.extraUsers
th.App.Srv().SetLicense(license)
serverLimits, appErr := th.App.GetServerLimits(true)
require.Nil(t, appErr)
require.Equal(t, tt.expectedBaseLimit, serverLimits.MaxUsersLimit)
require.Equal(t, tt.expectedHardLimit, serverLimits.MaxUsersHardLimit)
})
}
})
t.Run("unlicensed server has no extra users", func(t *testing.T) {
th := Setup(t).InitBasic(t)
th.App.Srv().SetLicense(nil)
serverLimits, appErr := th.App.GetServerLimits(true)
require.Nil(t, appErr)
// Unlicensed servers use hard-coded limits without extra users
require.Equal(t, int64(200), serverLimits.MaxUsersLimit)
require.Equal(t, int64(250), serverLimits.MaxUsersHardLimit)
})
}
func TestGetServerLimitsWithPostHistory(t *testing.T) {
mainHelper.Parallel(t)
t.Run("unlicensed server has no post history limits", func(t *testing.T) {
th := Setup(t).InitBasic(t)
th.App.Srv().SetLicense(nil)
serverLimits, appErr := th.App.GetServerLimits(true)
require.Nil(t, appErr)
// Unlicensed servers should have no post history limits
require.Equal(t, int64(0), serverLimits.PostHistoryLimit)
require.Equal(t, int64(0), serverLimits.LastAccessiblePostTime)
})
t.Run("licensed server without post history limits", func(t *testing.T) {
th := Setup(t).InitBasic(t)
license := model.NewTestLicense("")
license.Limits = nil // No limits configured
th.App.Srv().SetLicense(license)
serverLimits, appErr := th.App.GetServerLimits(true)
require.Nil(t, appErr)
// Should have no post history limits when Limits is nil
require.Equal(t, int64(0), serverLimits.PostHistoryLimit)
require.Equal(t, int64(0), serverLimits.LastAccessiblePostTime)
})
t.Run("licensed server with zero post history limit", func(t *testing.T) {
th := Setup(t).InitBasic(t)
license := model.NewTestLicense("")
license.Limits = &model.LicenseLimits{
PostHistory: 0, // Zero limit
}
th.App.Srv().SetLicense(license)
serverLimits, appErr := th.App.GetServerLimits(true)
require.Nil(t, appErr)
// Should have no post history limits when PostHistory is 0
require.Equal(t, int64(0), serverLimits.PostHistoryLimit)
require.Equal(t, int64(0), serverLimits.LastAccessiblePostTime)
})
t.Run("licensed server with positive post history limit and successful GetLastAccessiblePostTime", func(t *testing.T) {
th := SetupWithStoreMock(t)
// Mock user store for existing functionality
mockStore := th.App.Srv().Store().(*storemocks.Store)
mockUserStore := storemocks.UserStore{}
mockUserStore.On("Count", mock.Anything).Return(int64(5), nil)
mockUserStore.On("AnalyticsGetSingleChannelGuestCount").Return(int64(0), nil)
mockStore.On("User").Return(&mockUserStore)
// Mock system store for GetLastAccessiblePostTime
mockSystemStore := storemocks.SystemStore{}
mockSystemStore.On("GetByName", model.SystemLastAccessiblePostTime).Return(&model.System{
Name: model.SystemLastAccessiblePostTime,
Value: "1234567890",
}, nil)
mockStore.On("System").Return(&mockSystemStore)
// Create Entry license with post history limit
license := model.NewTestLicenseSKU(model.LicenseShortSkuMattermostEntry)
license.Limits = &model.LicenseLimits{
PostHistory: 1000,
}
th.App.Srv().SetLicense(license)
serverLimits, appErr := th.App.GetServerLimits(true)
require.Nil(t, appErr)
// Should have proper post history limits set
require.Equal(t, int64(1000), serverLimits.PostHistoryLimit)
require.Equal(t, int64(1234567890), serverLimits.LastAccessiblePostTime)
require.Equal(t, int64(5), serverLimits.ActiveUserCount)
})
t.Run("licensed server with post history limit but GetLastAccessiblePostTime fails", func(t *testing.T) {
th := SetupWithStoreMock(t)
// Mock user store for existing functionality
mockStore := th.App.Srv().Store().(*storemocks.Store)
mockUserStore := storemocks.UserStore{}
mockUserStore.On("Count", mock.Anything).Return(int64(5), nil)
mockUserStore.On("AnalyticsGetSingleChannelGuestCount").Return(int64(0), nil)
mockStore.On("User").Return(&mockUserStore)
// Mock system store to return error
mockSystemStore := storemocks.SystemStore{}
mockSystemStore.On("GetByName", model.SystemLastAccessiblePostTime).Return(nil, errors.New("database error"))
mockStore.On("System").Return(&mockSystemStore)
// Create Entry license with post history limit
license := model.NewTestLicenseSKU(model.LicenseShortSkuMattermostEntry)
license.Limits = &model.LicenseLimits{
PostHistory: 1000,
}
th.App.Srv().SetLicense(license)
_, appErr := th.App.GetServerLimits(true)
require.NotNil(t, appErr)
require.Contains(t, appErr.Message, "Unable to find the system variable")
})
t.Run("licensed server with post history limit but no system value found", func(t *testing.T) {
th := SetupWithStoreMock(t)
// Mock user store for existing functionality
mockStore := th.App.Srv().Store().(*storemocks.Store)
mockUserStore := storemocks.UserStore{}
mockUserStore.On("Count", mock.Anything).Return(int64(5), nil)
mockUserStore.On("AnalyticsGetSingleChannelGuestCount").Return(int64(0), nil)
mockStore.On("User").Return(&mockUserStore)
// Mock system store to return ErrNotFound (all posts accessible)
mockSystemStore := storemocks.SystemStore{}
mockSystemStore.On("GetByName", model.SystemLastAccessiblePostTime).Return(nil, store.NewErrNotFound("", ""))
mockStore.On("System").Return(&mockSystemStore)
// Create Entry license with post history limit
license := model.NewTestLicenseSKU(model.LicenseShortSkuMattermostEntry)
license.Limits = &model.LicenseLimits{
PostHistory: 1000,
}
th.App.Srv().SetLicense(license)
serverLimits, appErr := th.App.GetServerLimits(true)
require.Nil(t, appErr)
// Should have post history limit set but LastAccessiblePostTime should be 0 (all posts accessible)
require.Equal(t, int64(1000), serverLimits.PostHistoryLimit)
require.Equal(t, int64(0), serverLimits.LastAccessiblePostTime)
require.Equal(t, int64(5), serverLimits.ActiveUserCount)
})
}
func TestShouldTrackSingleChannelGuests(t *testing.T) {
mainHelper.Parallel(t)
t.Run("returns false for unlicensed server", func(t *testing.T) {
th := Setup(t).InitBasic(t)
th.App.Srv().SetLicense(nil)
require.False(t, th.App.shouldTrackSingleChannelGuests())
})
t.Run("returns false for Entry SKU license", func(t *testing.T) {
th := Setup(t).InitBasic(t)
license := model.NewTestLicenseSKU(model.LicenseShortSkuMattermostEntry)
th.App.Srv().SetLicense(license)
require.False(t, th.App.shouldTrackSingleChannelGuests())
})
t.Run("returns true when license GuestAccounts feature is disabled but config is enabled", func(t *testing.T) {
th := Setup(t).InitBasic(t)
license := model.NewTestLicense("")
license.Features.GuestAccounts = new(false)
th.App.Srv().SetLicense(license)
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.GuestAccountsSettings.Enable = true })
require.True(t, th.App.shouldTrackSingleChannelGuests())
})
t.Run("returns false when config GuestAccountsSettings.Enable is false", func(t *testing.T) {
th := Setup(t).InitBasic(t)
license := model.NewTestLicense("")
th.App.Srv().SetLicense(license)
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.GuestAccountsSettings.Enable = false })
require.False(t, th.App.shouldTrackSingleChannelGuests())
})
t.Run("returns true for non-Entry license with guest accounts enabled", func(t *testing.T) {
th := Setup(t).InitBasic(t)
license := model.NewTestLicense("")
th.App.Srv().SetLicense(license)
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.GuestAccountsSettings.Enable = true })
require.True(t, th.App.shouldTrackSingleChannelGuests())
})
}
func TestGetServerLimitsWithSingleChannelGuests(t *testing.T) {
mainHelper.Parallel(t)
t.Run("populates single channel guest fields when tracking is enabled", func(t *testing.T) {
th := Setup(t).InitBasic(t)
userLimit := 100
license := model.NewTestLicense("")
license.Features.Users = &userLimit
th.App.Srv().SetLicense(license)
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.GuestAccountsSettings.Enable = true })
guest := th.CreateGuest(t)
th.LinkUserToTeam(t, guest, th.BasicTeam)
th.AddUserToChannel(t, guest, th.BasicChannel)
serverLimits, appErr := th.App.GetServerLimits(true)
require.Nil(t, appErr)
require.Greater(t, serverLimits.SingleChannelGuestCount, int64(0))
require.Equal(t, int64(userLimit), serverLimits.SingleChannelGuestLimit)
require.Equal(t, serverLimits.ActiveUserCount, int64(4)-serverLimits.SingleChannelGuestCount)
})
t.Run("does not populate single channel guest fields for Entry SKU", func(t *testing.T) {
th := Setup(t).InitBasic(t)
license := model.NewTestLicenseSKU(model.LicenseShortSkuMattermostEntry)
th.App.Srv().SetLicense(license)
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.GuestAccountsSettings.Enable = true })
serverLimits, appErr := th.App.GetServerLimits(true)
require.Nil(t, appErr)
require.Equal(t, int64(0), serverLimits.SingleChannelGuestCount)
require.Equal(t, int64(0), serverLimits.SingleChannelGuestLimit)
require.Equal(t, int64(3), serverLimits.ActiveUserCount)
})
}
func TestGetPostHistoryLimit(t *testing.T) {
mainHelper.Parallel(t)
t.Run("unlicensed server returns zero limit", func(t *testing.T) {
th := Setup(t).InitBasic(t)
th.App.Srv().SetLicense(nil)
limit := th.App.GetPostHistoryLimit()
require.Equal(t, int64(0), limit)
})
t.Run("licensed server with no Limits returns zero", func(t *testing.T) {
th := Setup(t).InitBasic(t)
license := model.NewTestLicense("")
license.Limits = nil // No limits configured
th.App.Srv().SetLicense(license)
limit := th.App.GetPostHistoryLimit()
require.Equal(t, int64(0), limit)
})
t.Run("licensed server with zero PostHistory returns zero", func(t *testing.T) {
th := Setup(t).InitBasic(t)
license := model.NewTestLicense("")
license.Limits = &model.LicenseLimits{
PostHistory: 0,
}
th.App.Srv().SetLicense(license)
limit := th.App.GetPostHistoryLimit()
require.Equal(t, int64(0), limit)
})
t.Run("licensed server with positive PostHistory returns exact value", func(t *testing.T) {
th := Setup(t).InitBasic(t)
license := model.NewTestLicense("")
license.Limits = &model.LicenseLimits{
PostHistory: 1500,
}
th.App.Srv().SetLicense(license)
limit := th.App.GetPostHistoryLimit()
require.Equal(t, int64(1500), limit)
})
t.Run("Entry license with PostHistory returns exact value", func(t *testing.T) {
th := Setup(t).InitBasic(t)
license := model.NewTestLicenseSKU(model.LicenseShortSkuMattermostEntry)
license.Limits = &model.LicenseLimits{
PostHistory: 2000,
}
th.App.Srv().SetLicense(license)
limit := th.App.GetPostHistoryLimit()
require.Equal(t, int64(2000), limit)
})
}