Files
team/server/channels/app/recap_limits_test.go
zeekay 8feb24ea1f One name for this fork, and it is ours
The server module named github.com/hanzoai/team/server/v8 — a path that
resolves to the retired workspace's repository, not this one — while
server/public still published github.com/mattermost/mattermost/server/public.
Both are github.com/hanzoteam/server/... now, which is where this code
actually lives.

That second half is what made the binary unbootable. Upstream's public path
stayed claimed by upstream, mattermost-plugin-ai imported it, and the build
linked public/model twice; public/plugin's gob.Register then ran twice under
one name and panicked at init, before main. Reverting the rename traded the
brand for a working binary. Rebranding the plugin alongside it needs no such
trade: the agents fork is github.com/hanzoteam/agents/v2 against our public
module, so no module named mattermost/mattermost is in the graph at all.

Measured: `go list -deps ./cmd/mattermost` names exactly one public/model, and
it is ours.
2026-08-28 23:35:36 -07:00

189 lines
8.0 KiB
Go

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package app
import (
"testing"
"github.com/hanzoteam/server/server/public/model"
"github.com/stretchr/testify/require"
)
func TestGetEffectiveLimitsDefaults(t *testing.T) {
t.Setenv("MM_FEATUREFLAGS_ENABLEAIRECAPS", "true")
th := Setup(t).InitBasic(t)
th.App.UpdateConfig(func(cfg *model.Config) { cfg.FeatureFlags.EnableAIRecaps = true })
// Ensure defaults are set (they should be by default)
limits, appErr := th.App.GetEffectiveLimits()
require.Nil(t, appErr)
require.NotNil(t, limits)
// Verify system defaults
require.Equal(t, 10, limits.MaxRecapsPerDay, "default MaxRecapsPerDay")
require.Equal(t, 5, limits.MaxScheduledRecaps, "default MaxScheduledRecaps")
require.Equal(t, -1, limits.MaxChannelsPerRecap, "default MaxChannelsPerRecap (unlimited)")
require.Equal(t, 500, limits.MaxPostsPerRecap, "default MaxPostsPerRecap")
require.Equal(t, 100000, limits.MaxTokensPerRecap, "default MaxTokensPerRecap")
require.Equal(t, 5000, limits.MaxPostsPerDay, "default MaxPostsPerDay")
require.Equal(t, 60, limits.CooldownMinutes, "default CooldownMinutes")
// Verify source tracking
require.Equal(t, model.LimitSourceSystem, limits.Source)
require.Equal(t, "", limits.SourceID)
}
func TestGetEffectiveLimitsWithDisabledToggle(t *testing.T) {
t.Setenv("MM_FEATUREFLAGS_ENABLEAIRECAPS", "true")
th := Setup(t).InitBasic(t)
th.App.UpdateConfig(func(cfg *model.Config) { cfg.FeatureFlags.EnableAIRecaps = true })
// Disable the EnforceRecapsPerDay toggle
th.App.UpdateConfig(func(cfg *model.Config) {
cfg.AIRecapSettings.EnforceRecapsPerDay = model.NewPointer(false)
})
limits, appErr := th.App.GetEffectiveLimits()
require.Nil(t, appErr)
require.NotNil(t, limits)
// MaxRecapsPerDay should be -1 (unlimited) because toggle is disabled
require.Equal(t, -1, limits.MaxRecapsPerDay, "MaxRecapsPerDay should be unlimited when toggle disabled")
// Other limits should remain at defaults
require.Equal(t, 5, limits.MaxScheduledRecaps, "MaxScheduledRecaps should remain default")
require.Equal(t, -1, limits.MaxChannelsPerRecap, "MaxChannelsPerRecap should remain default")
require.Equal(t, 500, limits.MaxPostsPerRecap, "MaxPostsPerRecap should remain default")
require.Equal(t, 100000, limits.MaxTokensPerRecap, "MaxTokensPerRecap should remain default")
require.Equal(t, 5000, limits.MaxPostsPerDay, "MaxPostsPerDay should remain default")
require.Equal(t, 60, limits.CooldownMinutes, "CooldownMinutes should remain default")
}
func TestGetEffectiveLimitsWithCustomDefaults(t *testing.T) {
t.Setenv("MM_FEATUREFLAGS_ENABLEAIRECAPS", "true")
th := Setup(t).InitBasic(t)
th.App.UpdateConfig(func(cfg *model.Config) { cfg.FeatureFlags.EnableAIRecaps = true })
// Set custom default limits
th.App.UpdateConfig(func(cfg *model.Config) {
cfg.AIRecapSettings.DefaultLimits.MaxRecapsPerDay = model.NewPointer(20)
cfg.AIRecapSettings.DefaultLimits.MaxScheduledRecaps = model.NewPointer(15)
cfg.AIRecapSettings.DefaultLimits.MaxPostsPerRecap = model.NewPointer(1000)
})
limits, appErr := th.App.GetEffectiveLimits()
require.Nil(t, appErr)
require.NotNil(t, limits)
// Verify custom values are honored
require.Equal(t, 20, limits.MaxRecapsPerDay, "custom MaxRecapsPerDay should be honored")
require.Equal(t, 15, limits.MaxScheduledRecaps, "custom MaxScheduledRecaps should be honored")
require.Equal(t, 1000, limits.MaxPostsPerRecap, "custom MaxPostsPerRecap should be honored")
// Unchanged limits should remain at defaults
require.Equal(t, -1, limits.MaxChannelsPerRecap, "MaxChannelsPerRecap should remain default")
require.Equal(t, 100000, limits.MaxTokensPerRecap, "MaxTokensPerRecap should remain default")
require.Equal(t, 5000, limits.MaxPostsPerDay, "MaxPostsPerDay should remain default")
require.Equal(t, 60, limits.CooldownMinutes, "CooldownMinutes should remain default")
}
func TestGetEffectiveLimitsAllTogglesDisabled(t *testing.T) {
t.Setenv("MM_FEATUREFLAGS_ENABLEAIRECAPS", "true")
th := Setup(t).InitBasic(t)
th.App.UpdateConfig(func(cfg *model.Config) { cfg.FeatureFlags.EnableAIRecaps = true })
// Disable all enforcement toggles
th.App.UpdateConfig(func(cfg *model.Config) {
cfg.AIRecapSettings.EnforceRecapsPerDay = model.NewPointer(false)
cfg.AIRecapSettings.EnforceScheduledRecaps = model.NewPointer(false)
cfg.AIRecapSettings.EnforceChannelsPerRecap = model.NewPointer(false)
cfg.AIRecapSettings.EnforcePostsPerRecap = model.NewPointer(false)
cfg.AIRecapSettings.EnforceTokensPerRecap = model.NewPointer(false)
cfg.AIRecapSettings.EnforcePostsPerDay = model.NewPointer(false)
cfg.AIRecapSettings.EnforceCooldown = model.NewPointer(false)
})
limits, appErr := th.App.GetEffectiveLimits()
require.Nil(t, appErr)
require.NotNil(t, limits)
// All limits should be -1 (unlimited)
require.Equal(t, -1, limits.MaxRecapsPerDay, "MaxRecapsPerDay should be unlimited")
require.Equal(t, -1, limits.MaxScheduledRecaps, "MaxScheduledRecaps should be unlimited")
require.Equal(t, -1, limits.MaxChannelsPerRecap, "MaxChannelsPerRecap should be unlimited")
require.Equal(t, -1, limits.MaxPostsPerRecap, "MaxPostsPerRecap should be unlimited")
require.Equal(t, -1, limits.MaxTokensPerRecap, "MaxTokensPerRecap should be unlimited")
require.Equal(t, -1, limits.MaxPostsPerDay, "MaxPostsPerDay should be unlimited")
require.Equal(t, -1, limits.CooldownMinutes, "CooldownMinutes should be unlimited")
}
func TestGetEffectiveLimitsMasterToggleDisabled(t *testing.T) {
t.Setenv("MM_FEATUREFLAGS_ENABLEAIRECAPS", "true")
th := Setup(t).InitBasic(t)
th.App.UpdateConfig(func(cfg *model.Config) {
cfg.FeatureFlags.EnableAIRecaps = true
cfg.AIRecapSettings.Enable = model.NewPointer(false)
cfg.AIRecapSettings.EnforceRecapsPerDay = model.NewPointer(true)
cfg.AIRecapSettings.EnforceScheduledRecaps = model.NewPointer(true)
cfg.AIRecapSettings.EnforceChannelsPerRecap = model.NewPointer(true)
cfg.AIRecapSettings.EnforcePostsPerRecap = model.NewPointer(true)
cfg.AIRecapSettings.EnforceTokensPerRecap = model.NewPointer(true)
cfg.AIRecapSettings.EnforcePostsPerDay = model.NewPointer(true)
cfg.AIRecapSettings.EnforceCooldown = model.NewPointer(true)
})
limits, appErr := th.App.GetEffectiveLimits()
require.NotNil(t, appErr)
require.Nil(t, limits)
require.Equal(t, "api.recap.disabled.app_error", appErr.Id)
}
func TestGetEffectiveLimitsFeatureFlagDisabled(t *testing.T) {
t.Setenv("MM_FEATUREFLAGS_ENABLEAIRECAPS", "false")
th := Setup(t).InitBasic(t)
th.App.UpdateConfig(func(cfg *model.Config) {
cfg.FeatureFlags.EnableAIRecaps = false
cfg.AIRecapSettings.Enable = model.NewPointer(true)
})
limits, appErr := th.App.GetEffectiveLimits()
require.NotNil(t, appErr)
require.Nil(t, limits)
require.Equal(t, "api.recap.disabled.app_error", appErr.Id)
}
func TestGetEffectiveLimitsUnlimitedConfigValue(t *testing.T) {
t.Setenv("MM_FEATUREFLAGS_ENABLEAIRECAPS", "true")
th := Setup(t).InitBasic(t)
th.App.UpdateConfig(func(cfg *model.Config) { cfg.FeatureFlags.EnableAIRecaps = true })
// Set MaxRecapsPerDay to unlimited (-1) in config
th.App.UpdateConfig(func(cfg *model.Config) {
cfg.AIRecapSettings.DefaultLimits.MaxRecapsPerDay = model.NewPointer(-1)
})
limits, appErr := th.App.GetEffectiveLimits()
require.Nil(t, appErr)
require.NotNil(t, limits)
// Should return -1 from config (unlimited)
require.Equal(t, -1, limits.MaxRecapsPerDay, "unlimited config value should be honored")
// Other limits should remain at defaults
require.Equal(t, 5, limits.MaxScheduledRecaps)
}
func TestIsLimitEnabled(t *testing.T) {
mainHelper.Parallel(t)
// Test that IsLimitEnabled correctly identifies enabled vs disabled limits
require.True(t, model.IsLimitEnabled(10), "positive value should be enabled")
require.True(t, model.IsLimitEnabled(1), "1 should be enabled")
require.True(t, model.IsLimitEnabled(0), "0 should be enabled (0 cooldown is valid)")
require.False(t, model.IsLimitEnabled(-1), "-1 (UnlimitedValue) should not be enabled")
require.True(t, model.IsLimitEnabled(-2), "-2 should be enabled (only -1 is special)")
}