mattermost-community-enterp.../cmd/mmctl/commands/config_test.go
Claude ec1f89217a Merge: Complete Mattermost Server with Community Enterprise
Full Mattermost server source with integrated Community Enterprise features.
Includes vendor directory for offline/air-gapped builds.

Structure:
- enterprise-impl/: Enterprise feature implementations
- enterprise-community/: Init files that register implementations
- enterprise/: Bridge imports (community_imports.go)
- vendor/: All dependencies for offline builds

Build (online):
  go build ./cmd/mattermost

Build (offline/air-gapped):
  go build -mod=vendor ./cmd/mattermost

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-17 23:59:07 +09:00

1028 lines
30 KiB
Go

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package commands
import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"net/http"
"os"
"testing"
"github.com/mattermost/mattermost/server/public/model"
"github.com/spf13/cobra"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/mattermost/mattermost/server/v8/cmd/mmctl/printer"
)
const (
configFilePayload = "{\"TeamSettings\": {\"SiteName\": \"ADifferentName\"}}"
configFilePluginPayload = "{\"PluginSettings\": {\"Plugins\": {\"plugin.1\": {\"new\": \"key\", \"existing\": \"replacement\"}, \"plugin.2\": {\"this is\": \"new\"}}}}"
)
func (s *MmctlUnitTestSuite) TestConfigGetCmd() {
s.Run("Get a string config value for a given key", func() {
printer.Clean()
args := []string{"SqlSettings.DriverName"}
outputConfig := &model.Config{}
outputConfig.SetDefaults()
s.client.
EXPECT().
GetConfig(context.TODO()).
Return(outputConfig, &model.Response{}, nil).
Times(1)
err := configGetCmdF(s.client, &cobra.Command{}, args)
s.Require().Nil(err)
s.Require().Len(printer.GetLines(), 1)
s.Require().Equal("postgres", *(printer.GetLines()[0].(*string)))
s.Require().Len(printer.GetErrorLines(), 0)
})
s.Run("Get an int config value for a given key", func() {
printer.Clean()
args := []string{"SqlSettings.MaxIdleConns"}
outputConfig := &model.Config{}
outputConfig.SetDefaults()
s.client.
EXPECT().
GetConfig(context.TODO()).
Return(outputConfig, &model.Response{}, nil).
Times(1)
err := configGetCmdF(s.client, &cobra.Command{}, args)
s.Require().Nil(err)
s.Require().Len(printer.GetLines(), 1)
s.Require().Equal(*(printer.GetLines()[0].(*int)), 50)
s.Require().Len(printer.GetErrorLines(), 0)
})
s.Run("Get an int64 config value for a given key", func() {
printer.Clean()
args := []string{"FileSettings.MaxFileSize"}
outputConfig := &model.Config{}
outputConfig.SetDefaults()
s.client.
EXPECT().
GetConfig(context.TODO()).
Return(outputConfig, &model.Response{}, nil).
Times(1)
err := configGetCmdF(s.client, &cobra.Command{}, args)
s.Require().Nil(err)
s.Require().Len(printer.GetLines(), 1)
s.Require().Equal(int64(100*(1<<20)), *(printer.GetLines()[0].(*int64)))
s.Require().Len(printer.GetErrorLines(), 0)
})
s.Run("Get a boolean config value for a given key", func() {
printer.Clean()
args := []string{"SqlSettings.Trace"}
outputConfig := &model.Config{}
outputConfig.SetDefaults()
s.client.
EXPECT().
GetConfig(context.TODO()).
Return(outputConfig, &model.Response{}, nil).
Times(1)
err := configGetCmdF(s.client, &cobra.Command{}, args)
s.Require().Nil(err)
s.Require().Len(printer.GetLines(), 1)
s.Require().Equal(*(printer.GetLines()[0].(*bool)), false)
s.Require().Len(printer.GetErrorLines(), 0)
})
s.Run("Get a slice of string config value for a given key", func() {
printer.Clean()
args := []string{"SqlSettings.DataSourceReplicas"}
outputConfig := &model.Config{}
outputConfig.SetDefaults()
s.client.
EXPECT().
GetConfig(context.TODO()).
Return(outputConfig, &model.Response{}, nil).
Times(1)
err := configGetCmdF(s.client, &cobra.Command{}, args)
s.Require().Nil(err)
s.Require().Len(printer.GetLines(), 1)
s.Require().Equal(printer.GetLines()[0], []string{})
s.Require().Len(printer.GetErrorLines(), 0)
})
s.Run("Get config struct for a given key", func() {
printer.Clean()
args := []string{"SqlSettings"}
outputConfig := &model.Config{}
outputConfig.SetDefaults()
sqlSettings := model.SqlSettings{}
sqlSettings.SetDefaults(false)
s.client.
EXPECT().
GetConfig(context.TODO()).
Return(outputConfig, &model.Response{}, nil).
Times(1)
err := configGetCmdF(s.client, &cobra.Command{}, args)
s.Require().Nil(err)
s.Require().Len(printer.GetLines(), 1)
s.Require().Equal(printer.GetLines()[0], sqlSettings)
s.Require().Len(printer.GetErrorLines(), 0)
})
s.Run("Get error if the key doesn't exist", func() {
printer.Clean()
args := []string{"SqlSettings.WrongKey"}
outputConfig := &model.Config{}
outputConfig.SetDefaults()
sqlSettings := model.SqlSettings{}
sqlSettings.SetDefaults(false)
s.client.
EXPECT().
GetConfig(context.TODO()).
Return(outputConfig, &model.Response{}, nil).
Times(1)
err := configGetCmdF(s.client, &cobra.Command{}, args)
s.Require().NotNil(err)
s.Require().Len(printer.GetLines(), 0)
s.Require().Len(printer.GetErrorLines(), 0)
})
s.Run("Should handle the response error", func() {
printer.Clean()
args := []string{"SqlSettings.DriverName"}
outputConfig := &model.Config{}
outputConfig.SetDefaults()
sqlSettings := model.SqlSettings{}
sqlSettings.SetDefaults(false)
s.client.
EXPECT().
GetConfig(context.TODO()).
Return(outputConfig, &model.Response{StatusCode: 500}, errors.New("")).
Times(1)
err := configGetCmdF(s.client, &cobra.Command{}, args)
s.Require().NotNil(err)
s.Require().Len(printer.GetLines(), 0)
s.Require().Len(printer.GetErrorLines(), 0)
})
s.Run("Get value if the key points to a map element", func() {
outputConfig := &model.Config{}
pluginState := &model.PluginState{Enable: true}
pluginSettings := map[string]any{
"test1": 1,
"test2": []string{"a", "b"},
"test3": map[string]string{"a": "b"},
}
outputConfig.PluginSettings.PluginStates = map[string]*model.PluginState{
"com.mattermost.testplugin": pluginState,
}
outputConfig.PluginSettings.Plugins = map[string]map[string]any{
"com.mattermost.testplugin": pluginSettings,
}
s.client.
EXPECT().
GetConfig(context.TODO()).
Return(outputConfig, &model.Response{}, nil).
Times(7)
printer.Clean()
err := configGetCmdF(s.client, &cobra.Command{}, []string{"PluginSettings.PluginStates.com.mattermost.testplugin"})
s.Require().Nil(err)
s.Require().Len(printer.GetLines(), 1)
s.Require().Equal(printer.GetLines()[0], pluginState)
s.Require().Len(printer.GetErrorLines(), 0)
printer.Clean()
err = configGetCmdF(s.client, &cobra.Command{}, []string{"PluginSettings.Plugins.com.mattermost.testplugin"})
s.Require().Nil(err)
s.Require().Len(printer.GetLines(), 1)
s.Require().Equal(printer.GetLines()[0], pluginSettings)
s.Require().Len(printer.GetErrorLines(), 0)
printer.Clean()
err = configGetCmdF(s.client, &cobra.Command{}, []string{"PluginSettings.Plugins.com.mattermost.testplugin.test1"})
s.Require().Nil(err)
s.Require().Len(printer.GetLines(), 1)
s.Require().Equal(printer.GetLines()[0], 1)
s.Require().Len(printer.GetErrorLines(), 0)
printer.Clean()
err = configGetCmdF(s.client, &cobra.Command{}, []string{"PluginSettings.Plugins.com.mattermost.testplugin.test2"})
s.Require().Nil(err)
s.Require().Len(printer.GetLines(), 1)
s.Require().Equal(printer.GetLines()[0], []string{"a", "b"})
s.Require().Len(printer.GetErrorLines(), 0)
printer.Clean()
err = configGetCmdF(s.client, &cobra.Command{}, []string{"PluginSettings.Plugins.com.mattermost.testplugin.test3"})
s.Require().Nil(err)
s.Require().Len(printer.GetLines(), 1)
s.Require().Equal(printer.GetLines()[0], map[string]string{"a": "b"})
s.Require().Len(printer.GetErrorLines(), 0)
printer.Clean()
err = configGetCmdF(s.client, &cobra.Command{}, []string{"PluginSettings.Plugins.com.mattermost.testplugin.test3.a"})
s.Require().Nil(err)
s.Require().Len(printer.GetLines(), 1)
s.Require().Equal(printer.GetLines()[0], "b")
s.Require().Len(printer.GetErrorLines(), 0)
})
s.Run("Get error value if the key points to a missing map element", func() {
printer.Clean()
args := []string{"PluginSettings.PluginStates.com.mattermost.testplugin.x"}
outputConfig := &model.Config{}
pluginState := &model.PluginState{Enable: true}
outputConfig.PluginSettings.PluginStates = map[string]*model.PluginState{
"com.mattermost.testplugin": pluginState,
}
s.client.
EXPECT().
GetConfig(context.TODO()).
Return(outputConfig, &model.Response{}, nil).
Times(0)
err := configGetCmdF(s.client, &cobra.Command{}, args)
s.Require().NotNil(err)
s.Require().Len(printer.GetLines(), 0)
s.Require().Len(printer.GetErrorLines(), 0)
})
s.Run("Get cloud restricted error value if the path is cloud restricted and value is nil", func() {
printer.Clean()
args := []string{"ServiceSettings.EnableDeveloper"}
outputConfig := &model.Config{}
s.client.
EXPECT().
GetConfig(context.TODO()).
Return(outputConfig, &model.Response{}, nil).
Times(1)
err := configGetCmdF(s.client, &cobra.Command{}, args)
s.Require().NotNil(err)
s.Require().Len(printer.GetLines(), 0)
s.Require().Len(printer.GetErrorLines(), 0)
})
}
func (s *MmctlUnitTestSuite) TestConfigSetCmd() {
s.Run("Set a string config value for a given key", func() {
printer.Clean()
args := []string{"SqlSettings.DriverName", "postgres"}
defaultConfig := &model.Config{}
defaultConfig.SetDefaults()
inputConfig := &model.Config{}
inputConfig.SetDefaults()
changedValue := "postgres"
inputConfig.SqlSettings.DriverName = &changedValue
s.client.
EXPECT().
GetConfig(context.TODO()).
Return(defaultConfig, &model.Response{}, nil).
Times(1)
s.client.
EXPECT().
PatchConfig(context.TODO(), inputConfig).
Return(inputConfig, &model.Response{}, nil).
Times(1)
err := configSetCmdF(s.client, &cobra.Command{}, args)
s.Require().Nil(err)
s.Require().Len(printer.GetLines(), 1)
s.Require().Equal(printer.GetLines()[0], inputConfig)
s.Require().Len(printer.GetErrorLines(), 0)
})
s.Run("Set an int config value for a given key", func() {
printer.Clean()
args := []string{"SqlSettings.MaxIdleConns", "20"}
defaultConfig := &model.Config{}
defaultConfig.SetDefaults()
inputConfig := &model.Config{}
inputConfig.SetDefaults()
changedValue := 20
inputConfig.SqlSettings.MaxIdleConns = &changedValue
s.client.
EXPECT().
GetConfig(context.TODO()).
Return(defaultConfig, &model.Response{}, nil).
Times(1)
s.client.
EXPECT().
PatchConfig(context.TODO(), inputConfig).
Return(inputConfig, &model.Response{}, nil).
Times(1)
err := configSetCmdF(s.client, &cobra.Command{}, args)
s.Require().Nil(err)
s.Require().Len(printer.GetLines(), 1)
s.Require().Equal(printer.GetLines()[0], inputConfig)
s.Require().Len(printer.GetErrorLines(), 0)
})
s.Run("Set an int64 config value for a given key", func() {
printer.Clean()
args := []string{"FileSettings.MaxFileSize", "52428800"}
defaultConfig := &model.Config{}
defaultConfig.SetDefaults()
inputConfig := &model.Config{}
inputConfig.SetDefaults()
changedValue := int64(52428800)
inputConfig.FileSettings.MaxFileSize = &changedValue
s.client.
EXPECT().
GetConfig(context.TODO()).
Return(defaultConfig, &model.Response{}, nil).
Times(1)
s.client.
EXPECT().
PatchConfig(context.TODO(), inputConfig).
Return(inputConfig, &model.Response{}, nil).
Times(1)
err := configSetCmdF(s.client, &cobra.Command{}, args)
s.Require().Nil(err)
s.Require().Len(printer.GetLines(), 1)
s.Require().Equal(printer.GetLines()[0], inputConfig)
s.Require().Len(printer.GetErrorLines(), 0)
})
s.Run("Set a boolean config value for a given key", func() {
printer.Clean()
args := []string{"SqlSettings.Trace", "true"}
defaultConfig := &model.Config{}
defaultConfig.SetDefaults()
inputConfig := &model.Config{}
inputConfig.SetDefaults()
changedValue := true
inputConfig.SqlSettings.Trace = &changedValue
s.client.
EXPECT().
GetConfig(context.TODO()).
Return(defaultConfig, &model.Response{}, nil).
Times(1)
s.client.
EXPECT().
PatchConfig(context.TODO(), inputConfig).
Return(inputConfig, &model.Response{}, nil).
Times(1)
err := configSetCmdF(s.client, &cobra.Command{}, args)
s.Require().Nil(err)
s.Require().Len(printer.GetLines(), 1)
s.Require().Equal(printer.GetLines()[0], inputConfig)
s.Require().Len(printer.GetErrorLines(), 0)
})
s.Run("Set a slice of string config value for a given key", func() {
printer.Clean()
args := []string{"SqlSettings.DataSourceReplicas", "test1", "test2"}
defaultConfig := &model.Config{}
defaultConfig.SetDefaults()
inputConfig := &model.Config{}
inputConfig.SetDefaults()
inputConfig.SqlSettings.DataSourceReplicas = []string{"test1", "test2"}
s.client.
EXPECT().
GetConfig(context.TODO()).
Return(defaultConfig, &model.Response{}, nil).
Times(1)
s.client.
EXPECT().
PatchConfig(context.TODO(), inputConfig).
Return(inputConfig, &model.Response{}, nil).
Times(1)
err := configSetCmdF(s.client, &cobra.Command{}, args)
s.Require().Nil(err)
s.Require().Len(printer.GetLines(), 1)
s.Require().Equal(printer.GetLines()[0], inputConfig)
s.Require().Len(printer.GetErrorLines(), 0)
})
s.Run("Should get an error if a string is passed while trying to set a slice", func() {
printer.Clean()
args := []string{"SqlSettings.DataSourceReplicas", "[\"test1\", \"test2\"]"}
defaultConfig := &model.Config{}
defaultConfig.SetDefaults()
inputConfig := &model.Config{}
inputConfig.SetDefaults()
inputConfig.SqlSettings.DataSourceReplicas = []string{"test1", "test2"}
s.client.
EXPECT().
GetConfig(context.TODO()).
Return(defaultConfig, &model.Response{}, nil).
Times(1)
err := configSetCmdF(s.client, &cobra.Command{}, args)
s.Require().NotNil(err)
s.Require().Len(printer.GetLines(), 0)
})
s.Run("Get error if the key doesn't exist", func() {
printer.Clean()
defaultConfig := &model.Config{}
defaultConfig.SetDefaults()
args := []string{"SqlSettings.WrongKey", "test1"}
inputConfig := &model.Config{}
inputConfig.SetDefaults()
s.client.
EXPECT().
GetConfig(context.TODO()).
Return(defaultConfig, &model.Response{}, nil).
Times(1)
err := configSetCmdF(s.client, &cobra.Command{}, args)
s.Require().NotNil(err)
s.Require().Len(printer.GetLines(), 0)
s.Require().Len(printer.GetErrorLines(), 0)
})
s.Run("Should handle response error from the server", func() {
printer.Clean()
args := []string{"SqlSettings.DriverName", "postgres"}
defaultConfig := &model.Config{}
defaultConfig.SetDefaults()
inputConfig := &model.Config{}
inputConfig.SetDefaults()
changedValue := "postgres"
inputConfig.SqlSettings.DriverName = &changedValue
s.client.
EXPECT().
GetConfig(context.TODO()).
Return(defaultConfig, &model.Response{}, nil).
Times(1)
s.client.
EXPECT().
PatchConfig(context.TODO(), inputConfig).
Return(inputConfig, &model.Response{StatusCode: 500}, errors.New("")).
Times(1)
err := configSetCmdF(s.client, &cobra.Command{}, args)
s.Require().NotNil(err)
s.Require().Len(printer.GetLines(), 0)
s.Require().Len(printer.GetErrorLines(), 0)
})
s.Run("Set a field inside a map", func() {
defaultConfig := &model.Config{}
defaultConfig.SetDefaults()
defaultConfig.PluginSettings.PluginStates = map[string]*model.PluginState{
"com.mattermost.testplugin": {Enable: false},
}
pluginSettings := map[string]any{
"test1": 1,
"test2": []string{"a", "b"},
"test3": map[string]any{"a": "b"},
}
defaultConfig.PluginSettings.Plugins = map[string]map[string]any{
"com.mattermost.testplugin": pluginSettings,
}
inputConfig := &model.Config{}
inputConfig.SetDefaults()
inputConfig.PluginSettings.PluginStates = map[string]*model.PluginState{
"com.mattermost.testplugin": {Enable: true},
}
inputConfig.PluginSettings.Plugins = map[string]map[string]any{
"com.mattermost.testplugin": pluginSettings,
}
s.client.
EXPECT().
GetConfig(context.TODO()).
Return(defaultConfig, &model.Response{}, nil).
Times(3)
s.client.
EXPECT().
PatchConfig(context.TODO(), inputConfig).
Return(inputConfig, &model.Response{}, nil).
Times(3)
printer.Clean()
err := configSetCmdF(s.client, &cobra.Command{}, []string{"PluginSettings.PluginStates.com.mattermost.testplugin.Enable", "true"})
s.Require().Nil(err)
s.Require().Len(printer.GetLines(), 1)
s.Require().Len(printer.GetErrorLines(), 0)
printer.Clean()
err = configSetCmdF(s.client, &cobra.Command{}, []string{"PluginSettings.Plugins.com.mattermost.testplugin.test1", "123"})
s.Require().Nil(err)
s.Require().Len(printer.GetLines(), 1)
s.Require().Len(printer.GetErrorLines(), 0)
printer.Clean()
err = configSetCmdF(s.client, &cobra.Command{}, []string{"PluginSettings.Plugins.com.mattermost.testplugin.test3.a", "123"})
s.Require().Nil(err)
s.Require().Len(printer.GetLines(), 1)
s.Require().Len(printer.GetErrorLines(), 0)
})
s.Run("Try to set a field inside a map for incorrect field, get error", func() {
printer.Clean()
defaultConfig := &model.Config{}
defaultConfig.SetDefaults()
defaultConfig.PluginSettings.PluginStates = map[string]*model.PluginState{
"com.mattermost.testplugin": {Enable: true},
}
args := []string{"PluginSettings.PluginStates.com.mattermost.testplugin.x", "true"}
s.client.
EXPECT().
GetConfig(context.TODO()).
Return(defaultConfig, &model.Response{}, nil).
Times(1)
err := configSetCmdF(s.client, &cobra.Command{}, args)
s.Require().NotNil(err)
s.Require().Len(printer.GetLines(), 0)
s.Require().Len(printer.GetErrorLines(), 0)
})
s.Run("Set a config value for a cloud restricted config path", func() {
printer.Clean()
args := []string{"ServiceSettings.EnableDeveloper", "true"}
defaultConfig := &model.Config{}
defaultConfig.SetDefaults()
js, err := defaultConfig.ToJSONFiltered(model.ConfigAccessTagType, model.ConfigAccessTagCloudRestrictable)
s.Require().NoError(err)
defaultConfig = model.ConfigFromJSON(bytes.NewBuffer(js))
s.client.
EXPECT().
GetConfig(context.TODO()).
Return(defaultConfig, &model.Response{}, nil).
Times(1)
err = configSetCmdF(s.client, &cobra.Command{}, args)
s.Require().EqualError(err, fmt.Sprintf("changing this config path: %s is restricted in a cloud environment", "ServiceSettings.EnableDeveloper"))
s.Require().Len(printer.GetLines(), 0)
s.Require().Len(printer.GetErrorLines(), 0)
})
}
func (s *MmctlUnitTestSuite) TestConfigPatchCmd() {
tmpFile, err := os.CreateTemp(os.TempDir(), "config_*.json")
s.Require().NoError(err)
invalidFile, err := os.CreateTemp(os.TempDir(), "invalid_config_*.json")
s.Require().NoError(err)
pluginFile, err := os.CreateTemp(os.TempDir(), "plugin_config_*.json")
s.Require().NoError(err)
_, err = tmpFile.Write([]byte(configFilePayload))
s.Require().NoError(err)
_, err = pluginFile.Write([]byte(configFilePluginPayload))
s.Require().NoError(err)
defer func() {
os.Remove(tmpFile.Name())
os.Remove(invalidFile.Name())
os.Remove(pluginFile.Name())
}()
s.Run("Patch config with a valid file", func() {
printer.Clean()
defaultConfig := &model.Config{}
defaultConfig.SetDefaults()
brandValue := "BrandText"
defaultConfig.TeamSettings.CustomBrandText = &brandValue
inputConfig := &model.Config{}
inputConfig.SetDefaults()
changedValue := "ADifferentName"
inputConfig.TeamSettings.SiteName = &changedValue
inputConfig.TeamSettings.CustomBrandText = &brandValue
s.client.
EXPECT().
GetConfig(context.TODO()).
Return(defaultConfig, &model.Response{}, nil).
Times(1)
s.client.
EXPECT().
PatchConfig(context.TODO(), inputConfig).
Return(inputConfig, &model.Response{}, nil).
Times(1)
err = configPatchCmdF(s.client, &cobra.Command{}, []string{tmpFile.Name()})
s.Require().Nil(err)
s.Require().Len(printer.GetLines(), 1)
s.Require().Equal(printer.GetLines()[0], inputConfig)
s.Require().Len(printer.GetErrorLines(), 0)
})
s.Run("Correctly patch with a valid file that affects plugins", func() {
printer.Clean()
defaultConfig := &model.Config{}
defaultConfig.SetDefaults()
defaultConfig.PluginSettings.Plugins = map[string]map[string]any{
"plugin.1": {
"existing": "value",
},
}
expectedPluginConfig := map[string]map[string]any{
"plugin.1": {
"new": "key",
"existing": "replacement",
},
"plugin.2": {
"this is": "new",
},
}
expectedConfig := &model.Config{}
expectedConfig.SetDefaults()
expectedConfig.PluginSettings.Plugins = expectedPluginConfig
s.client.
EXPECT().
GetConfig(context.TODO()).
Return(defaultConfig, &model.Response{}, nil).
Times(1)
s.client.
EXPECT().
PatchConfig(context.TODO(), expectedConfig).
Return(expectedConfig, &model.Response{}, nil).
Times(1)
err = configPatchCmdF(s.client, &cobra.Command{}, []string{pluginFile.Name()})
s.Require().Nil(err)
s.Require().Len(printer.GetLines(), 1)
s.Require().Equal(printer.GetLines()[0], expectedConfig)
s.Require().Len(printer.GetErrorLines(), 0)
})
s.Run("Fail to patch config if file is invalid", func() {
printer.Clean()
defaultConfig := &model.Config{}
defaultConfig.SetDefaults()
s.client.
EXPECT().
GetConfig(context.TODO()).
Return(defaultConfig, &model.Response{}, nil).
Times(1)
err = configPatchCmdF(s.client, &cobra.Command{}, []string{invalidFile.Name()})
s.Require().NotNil(err)
})
s.Run("Fail to patch config if file not found", func() {
printer.Clean()
path := "/path/to/nonexistentfile"
errMsg := "open " + path + ": no such file or directory"
err = configPatchCmdF(s.client, &cobra.Command{}, []string{path})
s.Require().NotNil(err)
s.Require().EqualError(err, errMsg)
})
}
func (s *MmctlUnitTestSuite) TestConfigResetCmd() {
s.Run("Reset a single key", func() {
printer.Clean()
args := []string{"SqlSettings.DriverName"}
defaultConfig := &model.Config{}
defaultConfig.SetDefaults()
s.client.
EXPECT().
GetConfig(context.TODO()).
Return(defaultConfig, &model.Response{}, nil).
Times(1)
s.client.
EXPECT().
UpdateConfig(context.TODO(), defaultConfig).
Return(defaultConfig, &model.Response{}, nil).
Times(1)
resetCmd := &cobra.Command{}
resetCmd.Flags().Bool("confirm", true, "")
err := configResetCmdF(s.client, resetCmd, args)
s.Require().Nil(err)
s.Require().Len(printer.GetLines(), 1)
s.Require().Equal(printer.GetLines()[0], defaultConfig)
s.Require().Len(printer.GetErrorLines(), 0)
})
s.Run("Reset a whole config section", func() {
printer.Clean()
args := []string{"SqlSettings"}
defaultConfig := &model.Config{}
defaultConfig.SetDefaults()
s.client.
EXPECT().
GetConfig(context.TODO()).
Return(defaultConfig, &model.Response{}, nil).
Times(1)
s.client.
EXPECT().
UpdateConfig(context.TODO(), defaultConfig).
Return(defaultConfig, &model.Response{}, nil).
Times(1)
resetCmd := &cobra.Command{}
resetCmd.Flags().Bool("confirm", true, "")
_ = resetCmd.ParseFlags([]string{"confirm"})
err := configResetCmdF(s.client, resetCmd, args)
s.Require().Nil(err)
s.Require().Len(printer.GetLines(), 1)
s.Require().Equal(printer.GetLines()[0], defaultConfig)
s.Require().Len(printer.GetErrorLines(), 0)
})
s.Run("Should fail if the key doesn't exist", func() {
printer.Clean()
args := []string{"WrongKey"}
defaultConfig := &model.Config{}
defaultConfig.SetDefaults()
s.client.
EXPECT().
GetConfig(context.TODO()).
Return(defaultConfig, &model.Response{}, nil).
Times(1)
resetCmd := &cobra.Command{}
resetCmd.Flags().Bool("confirm", true, "")
_ = resetCmd.ParseFlags([]string{"confirm"})
err := configResetCmdF(s.client, resetCmd, args)
s.Require().NotNil(err)
s.Require().Len(printer.GetLines(), 0)
s.Require().Len(printer.GetErrorLines(), 0)
})
}
func (s *MmctlUnitTestSuite) TestConfigShowCmd() {
s.Run("Should show config", func() {
printer.Clean()
mockConfig := &model.Config{}
s.client.
EXPECT().
GetConfig(context.TODO()).
Return(mockConfig, &model.Response{}, nil).
Times(1)
err := configShowCmdF(s.client, &cobra.Command{}, []string{})
s.Require().Nil(err)
s.Len(printer.GetLines(), 1)
s.Equal(mockConfig, printer.GetLines()[0])
s.Len(printer.GetErrorLines(), 0)
})
s.Run("Should return an error", func() {
printer.Clean()
configError := errors.New("config error")
s.client.
EXPECT().
GetConfig(context.TODO()).
Return(nil, &model.Response{}, configError).
Times(1)
err := configShowCmdF(s.client, &cobra.Command{}, []string{})
s.Require().NotNil(err)
s.EqualError(err, configError.Error())
})
}
func (s *MmctlUnitTestSuite) TestConfigReloadCmd() {
s.Run("Should reload config", func() {
printer.Clean()
s.client.
EXPECT().
ReloadConfig(context.TODO()).
Return(&model.Response{StatusCode: http.StatusOK}, nil).
Times(1)
err := configReloadCmdF(s.client, &cobra.Command{}, []string{})
s.Require().Nil(err)
s.Len(printer.GetErrorLines(), 0)
})
s.Run("Should fail on error when reload config", func() {
printer.Clean()
s.client.
EXPECT().
ReloadConfig(context.TODO()).
Return(&model.Response{StatusCode: http.StatusBadRequest}, errors.New("some-error")).
Times(1)
err := configReloadCmdF(s.client, &cobra.Command{}, []string{})
s.Require().NotNil(err)
})
}
func (s *MmctlUnitTestSuite) TestConfigMigrateCmd() {
s.Run("Should fail without the --local flag", func() {
printer.Clean()
args := []string{"from", "to"}
err := configMigrateCmdF(s.client, &cobra.Command{}, args)
s.Require().Error(err)
})
s.Run("Should be able to migrate config", func() {
printer.Clean()
args := []string{"from", "to"}
s.client.
EXPECT().
MigrateConfig(context.TODO(), args[0], args[1]).
Return(&model.Response{StatusCode: http.StatusOK}, nil).
Times(1)
cmd := &cobra.Command{}
cmd.Flags().Bool("local", true, "")
err := configMigrateCmdF(s.client, cmd, args)
s.Require().Nil(err)
s.Len(printer.GetErrorLines(), 0)
})
s.Run("Should fail on error when migrating config", func() {
printer.Clean()
args := []string{"from", "to"}
s.client.
EXPECT().
MigrateConfig(context.TODO(), args[0], args[1]).
Return(&model.Response{StatusCode: http.StatusBadRequest}, errors.New("some-error")).
Times(1)
cmd := &cobra.Command{}
cmd.Flags().Bool("local", true, "")
err := configMigrateCmdF(s.client, cmd, args)
s.Require().NotNil(err)
})
}
func TestCloudRestricted(t *testing.T) {
cfg := &model.Config{
ServiceSettings: model.ServiceSettings{
GoogleDeveloperKey: model.NewPointer("test"),
SiteURL: model.NewPointer("test"),
},
}
t.Run("Should return true if the config is cloud restricted", func(t *testing.T) {
path := "ServiceSettings.GoogleDeveloperKey"
require.True(t, cloudRestricted(cfg, parseConfigPath(path)))
})
t.Run("Should return false if the config is not cloud restricted", func(t *testing.T) {
path := "ServiceSettings.SiteURL"
require.False(t, cloudRestricted(cfg, parseConfigPath(path)))
})
t.Run("Should return false if the config is not cloud restricted and the path is not found", func(t *testing.T) {
path := "ServiceSettings.Unknown"
require.False(t, cloudRestricted(cfg, parseConfigPath(path)))
})
t.Run("Should return true if the config is cloud restricted and the value is not found", func(t *testing.T) {
path := "ServiceSettings.EnableDeveloper"
require.True(t, cloudRestricted(cfg, parseConfigPath(path)))
})
}
func TestSetConfigValue(t *testing.T) {
tests := map[string]struct {
path string
config *model.Config
args []string
expectedConfig *model.Config
}{
"bool": {
path: "LogSettings.EnableConsole",
args: []string{"true"},
config: &model.Config{LogSettings: model.LogSettings{
EnableConsole: model.NewPointer(false),
}},
expectedConfig: &model.Config{LogSettings: model.LogSettings{
EnableConsole: model.NewPointer(true),
}},
},
"string": {
path: "LogSettings.ConsoleLevel",
args: []string{"foo"},
config: &model.Config{LogSettings: model.LogSettings{
ConsoleLevel: model.NewPointer("ConsoleLevel"),
}},
expectedConfig: &model.Config{LogSettings: model.LogSettings{
ConsoleLevel: model.NewPointer("foo"),
}},
},
"int": {
path: "LogSettings.MaxFieldSize",
args: []string{"123"},
config: &model.Config{LogSettings: model.LogSettings{
MaxFieldSize: model.NewPointer(0),
}},
expectedConfig: &model.Config{LogSettings: model.LogSettings{
MaxFieldSize: model.NewPointer(123),
}},
},
"int64": {
path: "ServiceSettings.TLSStrictTransportMaxAge",
config: &model.Config{ServiceSettings: model.ServiceSettings{
TLSStrictTransportMaxAge: model.NewPointer(int64(0)),
}},
args: []string{"123"},
expectedConfig: &model.Config{ServiceSettings: model.ServiceSettings{
TLSStrictTransportMaxAge: model.NewPointer(int64(123)),
}},
},
"string slice": {
path: "SqlSettings.DataSourceReplicas",
args: []string{"abc", "def"},
config: &model.Config{SqlSettings: model.SqlSettings{
DataSourceReplicas: []string{},
}},
expectedConfig: &model.Config{SqlSettings: model.SqlSettings{
DataSourceReplicas: []string{"abc", "def"},
}},
},
"json.RawMessage": {
path: "LogSettings.AdvancedLoggingJSON",
config: &model.Config{LogSettings: model.LogSettings{
AdvancedLoggingJSON: nil,
}},
args: []string{`{"console1":{"Type":"console"}}`},
expectedConfig: &model.Config{LogSettings: model.LogSettings{
AdvancedLoggingJSON: json.RawMessage(`{"console1":{"Type":"console"}}`),
}},
},
}
for name, tc := range tests {
err := setConfigValue(parseConfigPath(tc.path), tc.config, tc.args)
require.NoError(t, err)
assert.Equal(t, tc.expectedConfig, tc.config, name)
}
}
func (s *MmctlUnitTestSuite) TestConfigExportCmd() {
s.Run("Should get the config as-is", func() {
// there is not much to test as the config is returned as-is
// adding a test to make sure future changes are not breaking this
printer.Clean()
s.client.
EXPECT().
GetConfigWithOptions(context.TODO(), model.GetConfigOptions{}).
Return(map[string]any{
"SqlSettings": map[string]any{
"DriverName": "postgres",
},
}, &model.Response{}, nil).
Times(1)
err := configExportCmdF(s.client, &cobra.Command{}, nil)
s.Require().Nil(err)
s.Require().Len(printer.GetLines(), 1)
s.Require().Len(printer.GetErrorLines(), 0)
})
}