Этот коммит содержится в:
Ben Schumacher
2025-01-13 20:23:09 +01:00
коммит произвёл GitHub
родитель 091d1bba8b
Коммит 8d4bf4bae0
50 изменённых файлов: 2429 добавлений и 745 удалений

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

@@ -4,200 +4,29 @@
package app
import (
"bytes"
"encoding/json"
"errors"
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"gopkg.in/yaml.v2"
"gopkg.in/yaml.v3"
"github.com/mattermost/mattermost/server/public/model"
"github.com/mattermost/mattermost/server/v8/channels/app/platform"
smocks "github.com/mattermost/mattermost/server/v8/channels/store/storetest/mocks"
"github.com/mattermost/mattermost/server/v8/channels/utils/fileutils"
"github.com/mattermost/mattermost/server/v8/config"
emocks "github.com/mattermost/mattermost/server/v8/einterfaces/mocks"
fmocks "github.com/mattermost/mattermost/server/v8/platform/shared/filestore/mocks"
)
func TestCreatePluginsFile(t *testing.T) {
th := Setup(t)
defer th.TearDown()
// Happy path where we have a plugins file with no err
fileData, err := th.App.createPluginsFile(th.Context)
require.NotNil(t, fileData)
assert.Equal(t, "plugins.json", fileData.Filename)
assert.Positive(t, len(fileData.Body))
assert.NoError(t, err)
// Turn off plugins so we can get an error
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.PluginSettings.Enable = false
})
// Plugins off in settings so no fileData and we get a warning instead
fileData, err = th.App.createPluginsFile(th.Context)
assert.Nil(t, fileData)
assert.ErrorContains(t, err, "failed to get plugin list for Support Packet")
}
func TestGenerateSupportPacketYaml(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
licenseUsers := 100
license := model.NewTestLicense("ldap")
license.Features.Users = model.NewPointer(licenseUsers)
th.App.Srv().SetLicense(license)
generateSupportPacket := func(t *testing.T) *model.SupportPacket {
t.Helper()
fileData, err := th.App.generateSupportPacketYaml(th.Context)
require.NotNil(t, fileData)
assert.Equal(t, "support_packet.yaml", fileData.Filename)
assert.Positive(t, len(fileData.Body))
assert.NoError(t, err)
var packet model.SupportPacket
require.NoError(t, yaml.Unmarshal(fileData.Body, &packet))
require.NotNil(t, packet)
return &packet
}
t.Run("Happy path", func(t *testing.T) {
// Happy path where we have a Support Packet yaml file without any warnings
packet := generateSupportPacket(t)
/* Build information */
assert.NotEmpty(t, packet.ServerOS)
assert.NotEmpty(t, packet.ServerArchitecture)
assert.Equal(t, model.CurrentVersion, packet.ServerVersion)
// BuildHash is not present in tests
/* DB */
assert.NotEmpty(t, packet.DatabaseType)
assert.NotEmpty(t, packet.DatabaseVersion)
assert.NotEmpty(t, packet.DatabaseSchemaVersion)
assert.Zero(t, packet.WebsocketConnections)
assert.NotZero(t, packet.MasterDbConnections)
assert.Zero(t, packet.ReplicaDbConnections)
/* Cluster */
assert.Empty(t, packet.ClusterID)
/* File store */
assert.Equal(t, "local", packet.FileDriver)
assert.Equal(t, "OK", packet.FileStatus)
/* LDAP */
assert.Empty(t, packet.LdapVendorName)
assert.Empty(t, packet.LdapVendorVersion)
/* Elastic Search */
assert.Empty(t, packet.ElasticServerVersion)
assert.Empty(t, packet.ElasticServerPlugins)
/* License */
assert.Equal(t, "My awesome Company", packet.LicenseTo)
assert.Equal(t, licenseUsers, packet.LicenseSupportedUsers)
assert.Equal(t, false, packet.LicenseIsTrial)
/* Server stats */
assert.Equal(t, 3, packet.ActiveUsers) // from InitBasic()
assert.Equal(t, 0, packet.DailyActiveUsers)
assert.Equal(t, 0, packet.MonthlyActiveUsers)
assert.Equal(t, 0, packet.InactiveUserCount)
assert.Equal(t, 5, packet.TotalPosts) // from InitBasic()
assert.Equal(t, 3, packet.TotalChannels) // from InitBasic()
assert.Equal(t, 1, packet.TotalTeams) // from InitBasic()
/* Jobs */
assert.Empty(t, packet.DataRetentionJobs)
assert.Empty(t, packet.MessageExportJobs)
assert.Empty(t, packet.ElasticPostIndexingJobs)
assert.Empty(t, packet.ElasticPostAggregationJobs)
assert.Empty(t, packet.BlevePostIndexingJobs)
assert.Empty(t, packet.LdapSyncJobs)
assert.Empty(t, packet.MigrationJobs)
})
t.Run("post count should be present if number of users extends AnalyticsSettings.MaxUsersForStatistics", func(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) {
cfg.AnalyticsSettings.MaxUsersForStatistics = model.NewPointer(1)
})
for i := 0; i < 5; i++ {
p := th.CreatePost(th.BasicChannel)
require.NotNil(t, p)
}
// InitBasic() already creats 5 posts
packet := generateSupportPacket(t)
assert.Equal(t, 10, packet.TotalPosts)
})
t.Run("filestore fails", func(t *testing.T) {
fb := &fmocks.FileBackend{}
platform.SetFileStore(fb)(th.Server.Platform())
fb.On("DriverName").Return("mock")
fb.On("TestConnection").Return(errors.New("all broken"))
packet := generateSupportPacket(t)
assert.Equal(t, "mock", packet.FileDriver)
assert.Equal(t, "FAIL: all broken", packet.FileStatus)
})
t.Run("no LDAP info if LDAP sync is disabled", func(t *testing.T) {
ldapMock := &emocks.LdapInterface{}
th.App.Channels().Ldap = ldapMock
packet := generateSupportPacket(t)
assert.Equal(t, "", packet.LdapVendorName)
assert.Equal(t, "", packet.LdapVendorVersion)
})
th.App.UpdateConfig(func(cfg *model.Config) {
cfg.LdapSettings.EnableSync = model.NewPointer(true)
})
t.Run("no LDAP vendor info found", func(t *testing.T) {
ldapMock := &emocks.LdapInterface{}
ldapMock.On(
"GetVendorNameAndVendorVersion",
mock.AnythingOfType("*request.Context"),
).Return("", "", nil)
th.App.Channels().Ldap = ldapMock
packet := generateSupportPacket(t)
assert.Equal(t, "unknown", packet.LdapVendorName)
assert.Equal(t, "unknown", packet.LdapVendorVersion)
})
t.Run("found LDAP vendor info", func(t *testing.T) {
ldapMock := &emocks.LdapInterface{}
ldapMock.On(
"GetVendorNameAndVendorVersion",
mock.AnythingOfType("*request.Context"),
).Return("some vendor", "v1.0.0", nil)
th.App.Channels().Ldap = ldapMock
packet := generateSupportPacket(t)
assert.Equal(t, "some vendor", packet.LdapVendorName)
assert.Equal(t, "v1.0.0", packet.LdapVendorVersion)
})
}
func TestGenerateSupportPacket(t *testing.T) {
th := Setup(t)
defer th.TearDown()
th.App.SetPhase2PermissionsMigrationStatus(true)
dir, err := os.MkdirTemp("", "")
require.NoError(t, err)
t.Cleanup(func() {
@@ -222,29 +51,42 @@ func TestGenerateSupportPacket(t *testing.T) {
}
genMockLogFiles()
t.Run("generate Support Packet with logs", func(t *testing.T) {
fileDatas := th.App.GenerateSupportPacket(th.Context, &model.SupportPacketOptions{
IncludeLogs: true,
})
getFileNames := func(t *testing.T, fileDatas []model.FileData) []string {
var rFileNames []string
testFiles := []string{
"support_packet.yaml",
"metadata.yaml",
"plugins.json",
"sanitized_config.json",
"mattermost.log",
"notifications.log",
"cpu.prof",
"heap.prof",
"goroutines",
}
for _, fileData := range fileDatas {
require.NotNil(t, fileData)
assert.Positive(t, len(fileData.Body))
rFileNames = append(rFileNames, fileData.Filename)
}
assert.ElementsMatch(t, testFiles, rFileNames)
return rFileNames
}
expectedFileNames := []string{
"metadata.yaml",
"stats.yaml",
"jobs.yaml",
"permissions.yaml",
"plugins.json",
"sanitized_config.json",
"diagnostics.yaml",
"cpu.prof",
"heap.prof",
"goroutines",
}
expectedFileNamesWithLogs := append(expectedFileNames, []string{
"mattermost.log",
"notifications.log",
}...)
t.Run("generate Support Packet with logs", func(t *testing.T) {
fileDatas := th.App.GenerateSupportPacket(th.Context, &model.SupportPacketOptions{
IncludeLogs: true,
})
rFileNames := getFileNames(t, fileDatas)
assert.ElementsMatch(t, expectedFileNamesWithLogs, rFileNames)
})
t.Run("generate Support Packet without logs", func(t *testing.T) {
@@ -252,27 +94,12 @@ func TestGenerateSupportPacket(t *testing.T) {
IncludeLogs: false,
})
testFiles := []string{
"support_packet.yaml",
"metadata.yaml",
"plugins.json",
"sanitized_config.json",
"cpu.prof",
"heap.prof",
"goroutines",
}
var rFileNames []string
for _, fileData := range fileDatas {
require.NotNil(t, fileData)
assert.Positive(t, len(fileData.Body))
rFileNames := getFileNames(t, fileDatas)
rFileNames = append(rFileNames, fileData.Filename)
}
assert.ElementsMatch(t, testFiles, rFileNames)
assert.ElementsMatch(t, expectedFileNames, rFileNames)
})
t.Run("remove the log files and ensure that warning.txt file is generated", func(t *testing.T) {
// Remove these two files and ensure that warning.txt file is generated
err = os.Remove(logLocation)
require.NoError(t, err)
err = os.Remove(notificationsLogLocation)
@@ -282,24 +109,9 @@ func TestGenerateSupportPacket(t *testing.T) {
fileDatas := th.App.GenerateSupportPacket(th.Context, &model.SupportPacketOptions{
IncludeLogs: true,
})
testFiles := []string{
"support_packet.yaml",
"metadata.yaml",
"plugins.json",
"sanitized_config.json",
"cpu.prof",
"heap.prof",
"warning.txt",
"goroutines",
}
var rFileNames []string
for _, fileData := range fileDatas {
require.NotNil(t, fileData)
assert.Positive(t, len(fileData.Body))
rFileNames := getFileNames(t, fileDatas)
rFileNames = append(rFileNames, fileData.Filename)
}
assert.ElementsMatch(t, testFiles, rFileNames)
assert.ElementsMatch(t, append(expectedFileNames, "warning.txt"), rFileNames)
})
t.Run("steps that generated an error should still return file data", func(t *testing.T) {
@@ -320,45 +132,536 @@ func TestGenerateSupportPacket(t *testing.T) {
mockStore.On("Webhook").Return(th.App.Srv().Store().Webhook())
mockStore.On("System").Return(th.App.Srv().Store().System())
mockStore.On("License").Return(th.App.Srv().Store().License())
mockStore.On("Command").Return(th.App.Srv().Store().Command())
mockStore.On("Role").Return(th.App.Srv().Store().Role())
mockStore.On("Scheme").Return(th.App.Srv().Store().Scheme())
mockStore.On("Close").Return(nil)
mockStore.On("GetDBSchemaVersion").Return(1, nil)
mockStore.On("GetDbVersion", false).Return("1.0.0", nil)
mockStore.On("TotalMasterDbConnections").Return(30)
mockStore.On("TotalReadDbConnections").Return(20)
mockStore.On("TotalSearchDbConnections").Return(10)
oldStore := th.App.Srv().Store()
t.Cleanup(func() {
th.App.Srv().SetStore(oldStore)
})
th.App.Srv().SetStore(&mockStore)
fileDatas := th.App.GenerateSupportPacket(th.Context, &model.SupportPacketOptions{
IncludeLogs: false,
})
rFileNames := getFileNames(t, fileDatas)
var rFileNames []string
for _, fileData := range fileDatas {
require.NotNil(t, fileData)
assert.Positive(t, len(fileData.Body))
rFileNames = append(rFileNames, fileData.Filename)
}
assert.Contains(t, rFileNames, "warning.txt")
assert.Contains(t, rFileNames, "support_packet.yaml")
assert.Contains(t, rFileNames, "stats.yaml")
assert.ElementsMatch(t, append(expectedFileNames, "warning.txt"), rFileNames)
})
pluginID := "testplugin"
pluginCode := `
package main
import (
"github.com/mattermost/mattermost/server/public/plugin"
"github.com/mattermost/mattermost/server/public/model"
)
type TestPlugin struct {
plugin.MattermostPlugin
}
func (p *TestPlugin) GenerateSupportData(c *plugin.Context) ([]*model.FileData, error) {
return []*model.FileData{{
Filename: "testplugin/diagnostics.yaml",
Body: []byte("foo"),
}}, nil
}
func main() {
plugin.ClientMain(&TestPlugin{})
}`
t.Run("Support Packet always contains plugin data if the plugin doesn't define the support_packet prop", func(t *testing.T) {
pluginManifest := `{"id": "testplugin", "server": {"executable": "backend.exe"}}`
setupPluginAPITest(t, pluginCode, pluginManifest, pluginID, th.App, th.Context)
t.Cleanup(func() {
appErr := th.App.ch.RemovePlugin(pluginID)
require.Nil(t, appErr)
})
fileDatas := th.App.GenerateSupportPacket(th.Context, &model.SupportPacketOptions{
IncludeLogs: false,
})
rFileNames := getFileNames(t, fileDatas)
assert.ElementsMatch(t, append(expectedFileNames, "testplugin/diagnostics.yaml"), rFileNames)
})
t.Run("Support Packet contains plugin data if the plugin defines the support_packet prop and it gets queried", func(t *testing.T) {
pluginManifest := `{"id": "testplugin", "server": {"executable": "backend.exe"}, "props": {"support_packet": "some text"}}`
setupPluginAPITest(t, pluginCode, pluginManifest, pluginID, th.App, th.Context)
t.Cleanup(func() {
appErr := th.App.ch.RemovePlugin(pluginID)
require.Nil(t, appErr)
})
fileDatas := th.App.GenerateSupportPacket(th.Context, &model.SupportPacketOptions{
IncludeLogs: false,
PluginPackets: []string{pluginID},
})
rFileNames := getFileNames(t, fileDatas)
assert.ElementsMatch(t, append(expectedFileNames, "testplugin/diagnostics.yaml"), rFileNames)
})
t.Run("Support Packet doesn't contain plugin data if the plugin defines the support_packet prop and it doesn't get queried", func(t *testing.T) {
pluginManifest := `{"id": "testplugin", "server": {"executable": "backend.exe"}, "props": {"support_packet": "some text"}}`
setupPluginAPITest(t, pluginCode, pluginManifest, pluginID, th.App, th.Context)
t.Cleanup(func() {
appErr := th.App.ch.RemovePlugin(pluginID)
require.Nil(t, appErr)
})
fileDatas := th.App.GenerateSupportPacket(th.Context, &model.SupportPacketOptions{
IncludeLogs: false,
})
rFileNames := getFileNames(t, fileDatas)
assert.ElementsMatch(t, expectedFileNames, rFileNames)
})
t.Run("Plugin config values in the Support Packet are obfuscated, if the plugin marks them as secrets", func(t *testing.T) {
pluginManifest := `{"id": "testplugin", "server": {"executable": "backend.exe"}, "settings_schema": {"settings": [{"key": "foo", "type": "text"}, {"key": "bar", "type": "text", "secret": true}]}}`
setupPluginAPITest(t, pluginCode, pluginManifest, pluginID, th.App, th.Context)
t.Cleanup(func() {
appErr := th.App.ch.RemovePlugin(pluginID)
require.Nil(t, appErr)
})
th.App.UpdateConfig(func(cfg *model.Config) {
cfg.PluginSettings.Plugins[pluginID] = map[string]any{
"foo": "foo_value",
"bar": "bar_value",
}
})
fileDatas := th.App.GenerateSupportPacket(th.Context, &model.SupportPacketOptions{
IncludeLogs: false,
})
found := false
for _, f := range fileDatas {
if f.Filename != "sanitized_config.json" {
continue
}
var config model.Config
err = json.Unmarshal(f.Body, &config)
require.NoError(t, err)
assert.Equal(t, "foo_value", config.PluginSettings.Plugins[pluginID]["foo"])
assert.Equal(t, model.FakeSetting, config.PluginSettings.Plugins[pluginID]["bar"])
found = true
}
assert.True(t, found)
})
}
func TestCreateSanitizedConfigFile(t *testing.T) {
func TestGetPluginsFile(t *testing.T) {
th := Setup(t)
defer th.TearDown()
// Happy path where we have a sanitized config file with no err
fileData, err := th.App.createSanitizedConfigFile(th.Context)
require.NotNil(t, fileData)
assert.Equal(t, "sanitized_config.json", fileData.Filename)
assert.Positive(t, len(fileData.Body))
assert.NoError(t, err)
getJobList := func(t *testing.T) *model.SupportPacketPluginList {
t.Helper()
fileData, err := th.App.getPluginsFile(th.Context)
assert.NoError(t, err)
require.NotNil(t, fileData)
assert.Equal(t, "plugins.json", fileData.Filename)
assert.Positive(t, len(fileData.Body))
var pl model.SupportPacketPluginList
err = json.Unmarshal(fileData.Body, &pl)
require.NoError(t, err)
return &pl
}
t.Run("no errors if no plugins are installed", func(t *testing.T) {
pl := getJobList(t)
assert.Len(t, pl.Enabled, 0)
assert.Len(t, pl.Disabled, 0)
})
t.Run("two plugins are installed", func(t *testing.T) {
path, _ := fileutils.FindDir("tests")
bundle1, err := os.ReadFile(filepath.Join(path, "testplugin.tar.gz"))
require.NoError(t, err)
manifest1, appErr := th.App.InstallPlugin(bytes.NewReader(bundle1), false)
require.Nil(t, appErr)
require.Equal(t, "testplugin", manifest1.Id)
appErr = th.App.EnablePlugin(manifest1.Id)
require.Nil(t, appErr)
bundle2, err := os.ReadFile(filepath.Join(path, "testplugin2.tar.gz"))
require.NoError(t, err)
manifest2, appErr := th.App.InstallPlugin(bytes.NewReader(bundle2), false)
require.Nil(t, appErr)
require.Equal(t, "testplugin2", manifest2.Id)
pl := getJobList(t)
require.Len(t, pl.Enabled, 1)
assert.Equal(t, "testplugin", pl.Enabled[0].Id)
require.Len(t, pl.Disabled, 1)
assert.Equal(t, "testplugin2", pl.Disabled[0].Id)
})
t.Run("error if plugin are disabled", func(t *testing.T) {
// Turn off plugins so we can get an error
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.PluginSettings.Enable = false
})
// Plugins off in settings so no fileData and we get a warning instead
fileData, err := th.App.getPluginsFile(th.Context)
assert.Nil(t, fileData)
assert.ErrorContains(t, err, "failed to get plugin list for Support Packet")
})
}
func TestCreateSupportPacketMetadata(t *testing.T) {
func TestGetSupportPacketStats(t *testing.T) {
th := Setup(t)
generateStats := func(t *testing.T) *model.SupportPacketStats {
t.Helper()
fileData, err := th.App.getSupportPacketStats(th.Context)
require.NotNil(t, fileData)
assert.Equal(t, "stats.yaml", fileData.Filename)
assert.Positive(t, len(fileData.Body))
assert.NoError(t, err)
var packet model.SupportPacketStats
err = yaml.Unmarshal(fileData.Body, &packet)
require.NoError(t, err)
return &packet
}
t.Run("fresh server", func(t *testing.T) {
sp := generateStats(t)
assert.Equal(t, int64(0), sp.RegisteredUsers)
assert.Equal(t, int64(0), sp.ActiveUsers)
assert.Equal(t, int64(0), sp.DailyActiveUsers)
assert.Equal(t, int64(0), sp.MonthlyActiveUsers)
assert.Equal(t, int64(0), sp.DeactivatedUsers)
assert.Equal(t, int64(0), sp.Guests)
assert.Equal(t, int64(0), sp.BotAccounts)
assert.Equal(t, int64(0), sp.Posts)
assert.Equal(t, int64(0), sp.Channels)
assert.Equal(t, int64(0), sp.Teams)
assert.Equal(t, int64(0), sp.SlashCommands)
assert.Equal(t, int64(0), sp.IncomingWebhooks)
assert.Equal(t, int64(0), sp.OutgoingWebhooks)
})
t.Run("Happy path", func(t *testing.T) {
var user *model.User
for i := 0; i < 4; i++ {
user = th.CreateUser()
}
th.BasicUser = user
for i := 0; i < 3; i++ {
deactivatedUser := th.CreateUser()
require.NotNil(t, deactivatedUser)
_, appErr := th.App.UpdateActive(th.Context, deactivatedUser, false)
require.Nil(t, appErr)
}
for i := 0; i < 2; i++ {
guest := th.CreateGuest()
require.NotNil(t, guest)
}
th.CreateBot()
team := th.CreateTeam()
channel := th.CreateChannel(th.Context, team)
for i := 0; i < 3; i++ {
p := th.CreatePost(channel)
require.NotNil(t, p)
}
cmd, appErr := th.App.CreateCommand(&model.Command{
CreatorId: user.Id,
TeamId: team.Id,
Trigger: "test",
Method: model.CommandMethodGet,
URL: "http://nowhere.com/",
})
require.Nil(t, appErr)
require.NotNil(t, cmd)
webhookIn, appErr := th.App.CreateIncomingWebhookForChannel(user.Id, channel, &model.IncomingWebhook{ChannelId: channel.Id})
require.Nil(t, appErr)
require.NotNil(t, webhookIn)
webhookOut, appErr := th.App.CreateOutgoingWebhook(&model.OutgoingWebhook{
ChannelId: channel.Id,
TeamId: channel.TeamId,
CreatorId: th.BasicUser.Id,
CallbackURLs: []string{"http://nowhere.com/"},
})
require.Nil(t, appErr)
require.NotNil(t, webhookOut)
sp := generateStats(t)
assert.Equal(t, int64(9), sp.RegisteredUsers)
assert.Equal(t, int64(6), sp.ActiveUsers)
assert.Equal(t, int64(0), sp.DailyActiveUsers)
assert.Equal(t, int64(0), sp.MonthlyActiveUsers)
assert.Equal(t, int64(3), sp.DeactivatedUsers)
assert.Equal(t, int64(2), sp.Guests)
assert.Equal(t, int64(1), sp.BotAccounts)
assert.Equal(t, int64(4), sp.Posts) // 1 from the bot creation and 3 created directly
assert.Equal(t, int64(3), sp.Channels) // 2 from the team creation and 1 created directly
assert.Equal(t, int64(1), sp.Teams)
assert.Equal(t, int64(1), sp.SlashCommands)
assert.Equal(t, int64(1), sp.IncomingWebhooks)
assert.Equal(t, int64(1), sp.OutgoingWebhooks)
})
// Reset test server
th.TearDown()
th = Setup(t).InitBasic()
defer th.TearDown()
t.Run("post count should be present if number of users extends AnalyticsSettings.MaxUsersForStatistics", func(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) {
cfg.AnalyticsSettings.MaxUsersForStatistics = model.NewPointer(1)
})
for i := 0; i < 5; i++ {
p := th.CreatePost(th.BasicChannel)
require.NotNil(t, p)
}
// InitBasic() already creats 5 posts
packet := generateStats(t)
assert.Equal(t, int64(10), packet.Posts)
})
}
func TestGetSupportPacketJobList(t *testing.T) {
th := Setup(t)
defer th.TearDown()
getJobList := func(t *testing.T) *model.SupportPacketJobList {
t.Helper()
fileData, err := th.App.getSupportPacketJobList(th.Context)
require.NoError(t, err)
require.NotNil(t, fileData)
assert.Equal(t, "jobs.yaml", fileData.Filename)
assert.Positive(t, len(fileData.Body))
var jobs model.SupportPacketJobList
err = yaml.Unmarshal(fileData.Body, &jobs)
require.NoError(t, err)
return &jobs
}
t.Run("no jobs run yet", func(t *testing.T) {
jobs := getJobList(t)
assert.Empty(t, jobs.LDAPSyncJobs)
assert.Empty(t, jobs.DataRetentionJobs)
assert.Empty(t, jobs.MessageExportJobs)
assert.Empty(t, jobs.ElasticPostIndexingJobs)
assert.Empty(t, jobs.ElasticPostAggregationJobs)
assert.Empty(t, jobs.BlevePostIndexingJobs)
assert.Empty(t, jobs.MigrationJobs)
})
t.Run("jobs exist", func(t *testing.T) {
getJob := func(jobType string) *model.Job {
return &model.Job{
Id: model.NewId(),
Type: jobType,
Priority: 1,
CreateAt: model.GetMillis() - 1,
StartAt: model.GetMillis(),
LastActivityAt: model.GetMillis() + 1,
Status: model.JobStatusPending,
Progress: 51,
Data: model.StringMap{"key": "value"},
}
}
// Create some jobs
jobsToCreate := []*model.Job{
getJob(model.JobTypeLdapSync),
getJob(model.JobTypeDataRetention),
getJob(model.JobTypeMessageExport),
getJob(model.JobTypeElasticsearchPostIndexing),
getJob(model.JobTypeElasticsearchPostAggregation),
getJob(model.JobTypeBlevePostIndexing),
getJob(model.JobTypeMigrations),
}
var expectedJobs []*model.Job
for _, job := range jobsToCreate {
// Create the job using the store directly.
// Creating the job at the job service would error as the workers require enterprise code.
rJob, err := th.App.Srv().Store().Job().Save(job)
require.NoError(t, err)
expectedJobs = append(expectedJobs, rJob)
}
jobs := getJobList(t)
// Helper to verify job content matches
verifyJob := func(t *testing.T, expected, actual *model.Job) {
t.Helper()
assert.Equal(t, expected.Id, actual.Id)
assert.Equal(t, expected.Type, actual.Type)
assert.Equal(t, expected.Priority, actual.Priority)
assert.Equal(t, expected.CreateAt, actual.CreateAt)
assert.Equal(t, expected.StartAt, actual.StartAt)
assert.Equal(t, expected.LastActivityAt, actual.LastActivityAt)
assert.Equal(t, expected.Status, actual.Status)
assert.Equal(t, expected.Progress, actual.Progress)
assert.Equal(t, expected.Data, actual.Data)
}
// Verify LDAP sync jobs
require.Len(t, jobs.LDAPSyncJobs, 1, "Should have 1 LDAP sync job")
verifyJob(t, expectedJobs[0], jobs.LDAPSyncJobs[0])
// Verify data retention jobs
require.Len(t, jobs.DataRetentionJobs, 1, "Should have 1 data retention job")
verifyJob(t, expectedJobs[1], jobs.DataRetentionJobs[0])
// Verify message export jobs
require.Len(t, jobs.MessageExportJobs, 1, "Should have 1 message export job")
verifyJob(t, expectedJobs[2], jobs.MessageExportJobs[0])
// Verify elasticsearch post indexing jobs
require.Len(t, jobs.ElasticPostIndexingJobs, 1, "Should have 1 elasticsearch post indexing job")
verifyJob(t, expectedJobs[3], jobs.ElasticPostIndexingJobs[0])
// Verify elasticsearch post aggregation jobs
require.Len(t, jobs.ElasticPostAggregationJobs, 1, "Should have 1 elasticsearch post aggregation job")
verifyJob(t, expectedJobs[4], jobs.ElasticPostAggregationJobs[0])
// Verify bleve post indexing jobs
require.Len(t, jobs.BlevePostIndexingJobs, 1, "Should have 1 bleve post indexing job")
verifyJob(t, expectedJobs[5], jobs.BlevePostIndexingJobs[0])
// Verify migration jobs
require.Len(t, jobs.MigrationJobs, 1, "Should have 1 migration job")
verifyJob(t, expectedJobs[6], jobs.MigrationJobs[0])
})
}
func TestGetSupportPacketPermissionsInfo(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
th.App.SetPhase2PermissionsMigrationStatus(true)
generatePermissionInfo := func(t *testing.T) *model.SupportPacketPermissionInfo {
t.Helper()
fileData, err := th.App.getSupportPacketPermissionsInfo(th.Context)
require.NotNil(t, fileData)
assert.Equal(t, "permissions.yaml", fileData.Filename)
assert.Positive(t, len(fileData.Body))
assert.NoError(t, err)
var permissions model.SupportPacketPermissionInfo
err = yaml.Unmarshal(fileData.Body, &permissions)
require.NoError(t, err)
return &permissions
}
t.Run("No custom permissions", func(t *testing.T) {
permissions := generatePermissionInfo(t)
assert.Len(t, permissions.Roles, 23)
assert.Empty(t, permissions.Schemes)
})
scheme, appErr := th.App.CreateScheme(&model.Scheme{
Name: "custom_scheme",
DisplayName: "Custom Scheme",
Scope: model.SchemeScopeTeam,
})
require.Nil(t, appErr)
t.Run("with custom scheme", func(t *testing.T) {
permissions := generatePermissionInfo(t)
assert.Len(t, permissions.Roles, 33) // 23 default roles + 10 custom roles from the scheme
require.Len(t, permissions.Schemes, 1)
assert.Equal(t, scheme.Id, permissions.Schemes[0].Id)
assert.Equal(t, model.FakeSetting, permissions.Schemes[0].Name, "Name should be obfuscated")
assert.Equal(t, model.FakeSetting, permissions.Schemes[0].DisplayName, "DisplayName should be obfuscated")
assert.Equal(t, model.FakeSetting, permissions.Schemes[0].Description, "Description should be obfuscated")
})
t.Run("with custom role", func(t *testing.T) {
role, appErr := th.App.CreateRole(&model.Role{
Name: "custom_role",
DisplayName: "Custom Role",
})
require.Nil(t, appErr)
t.Cleanup(func() {
_, appErr := th.App.DeleteRole(role.Id)
require.Nil(t, appErr)
})
permissions := generatePermissionInfo(t)
require.Len(t, permissions.Schemes, 1)
require.Len(t, permissions.Roles, 34) // 23 default roles + 10 custom roles from the scheme + 1 custom role
found := false
for _, r := range permissions.Roles {
// Confirm that sensitive fields are obfuscated
assert.Equal(t, model.FakeSetting, r.DisplayName, "DisplayName should be obfuscated")
assert.Equal(t, model.FakeSetting, r.Description, "Description should be obfuscated")
// Fine the custom role
if r.Id == role.Id {
assert.Equal(t, role.Name, r.Name)
assert.Equal(t, role.CreateAt, r.CreateAt)
assert.Equal(t, role.UpdateAt, r.UpdateAt)
assert.Equal(t, role.DeleteAt, r.DeleteAt)
assert.Equal(t, role.Permissions, r.Permissions)
assert.Equal(t, role.SchemeManaged, r.SchemeManaged)
assert.Equal(t, role.BuiltIn, r.BuiltIn)
found = true
break
}
}
assert.True(t, found)
})
}
func TestGetSupportPacketMetadata(t *testing.T) {
th := Setup(t)
defer th.TearDown()
t.Run("Happy path", func(t *testing.T) {
fileData, err := th.App.createSupportPacketMetadata(th.Context)
fileData, err := th.App.getSupportPacketMetadata(th.Context)
require.NoError(t, err)
require.NotNil(t, fileData)
assert.Equal(t, "metadata.yaml", fileData.Filename)