* Added the get command to get the value of a config setting. * Depending on the config setting it can work on any depth of the setting. * Added test for the get command. * Add print tabs * Remove excess else statements * Return with the value and remove named return variable * Refactor the printMap function and return a string, remove side effects * Improve the error message, use the name argument * Use app.Config() to create our config object * Remove reading the file, make helper functions return string and perform printing inside the command * Remove the tab printing * Add extra quotes on the output * Remove extra code for checking arguments and replaced it with cobra.ExactArgs(1) * Remove buffer from printConfigValues * Add some tests to check the output of the command * Write test for the function 'structToMap' and test for complext nested structs * Write test for the function 'configToMap' and test for complext nested structs * Write test for the function 'printMap' and test for complext maps as input * Write test for the function 'printConfigValues' and test for complext maps as input * Remove commented code * Update the description of the command
Этот коммит содержится в:
коммит произвёл
Harrison Healey
родитель
43bdbb0c3a
Коммит
9385dc750d
@@ -4,12 +4,17 @@
|
|||||||
package commands
|
package commands
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
"github.com/mattermost/mattermost-server/mlog"
|
||||||
"github.com/mattermost/mattermost-server/model"
|
"github.com/mattermost/mattermost-server/model"
|
||||||
"github.com/mattermost/mattermost-server/utils"
|
"github.com/mattermost/mattermost-server/utils"
|
||||||
)
|
)
|
||||||
@@ -36,12 +41,22 @@ var ConfigSubpathCmd = &cobra.Command{
|
|||||||
RunE: configSubpathCmdF,
|
RunE: configSubpathCmdF,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ConfigGetCmd = &cobra.Command{
|
||||||
|
Use: "get",
|
||||||
|
Short: "Get config setting",
|
||||||
|
Long: "Gets the value of a config setting by its name in dot notation.",
|
||||||
|
Example: `config get SqlSettings.DriverName`,
|
||||||
|
Args: cobra.ExactArgs(1),
|
||||||
|
RunE: configGetCmdF,
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
ConfigSubpathCmd.Flags().String("path", "", "Optional subpath; defaults to value in SiteURL")
|
ConfigSubpathCmd.Flags().String("path", "", "Optional subpath; defaults to value in SiteURL")
|
||||||
|
|
||||||
ConfigCmd.AddCommand(
|
ConfigCmd.AddCommand(
|
||||||
ValidateConfigCmd,
|
ValidateConfigCmd,
|
||||||
ConfigSubpathCmd,
|
ConfigSubpathCmd,
|
||||||
|
ConfigGetCmd,
|
||||||
)
|
)
|
||||||
RootCmd.AddCommand(ConfigCmd)
|
RootCmd.AddCommand(ConfigCmd)
|
||||||
}
|
}
|
||||||
@@ -102,3 +117,120 @@ func configSubpathCmdF(command *cobra.Command, args []string) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func configGetCmdF(command *cobra.Command, args []string) error {
|
||||||
|
app, err := InitDBCommandContextCobra(command)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer app.Shutdown()
|
||||||
|
|
||||||
|
// create the model for config
|
||||||
|
// Note: app.Config() returns a pointer, make appropriate changes
|
||||||
|
config := app.Config()
|
||||||
|
|
||||||
|
// get the print config setting and any error if there is
|
||||||
|
out, err := printConfigValues(configToMap(*config), strings.Split(args[0], "."), args[0])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("%s", out)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// printConfigValues function prints out the value of the configSettings working recursively or
|
||||||
|
// gives an error if config setting is not in the file.
|
||||||
|
func printConfigValues(configMap map[string]interface{}, configSetting []string, name string) (string, error) {
|
||||||
|
|
||||||
|
res, ok := configMap[configSetting[0]]
|
||||||
|
if !ok {
|
||||||
|
return "", fmt.Errorf("%s configuration setting is not in the file", name)
|
||||||
|
}
|
||||||
|
value := reflect.ValueOf(res)
|
||||||
|
switch value.Kind() {
|
||||||
|
case reflect.Map:
|
||||||
|
if len(configSetting) == 1 {
|
||||||
|
return printMap(value, 0), nil
|
||||||
|
}
|
||||||
|
return printConfigValues(res.(map[string]interface{}), configSetting[1:], name)
|
||||||
|
default:
|
||||||
|
if len(configSetting) == 1 {
|
||||||
|
return fmt.Sprintf("%s: \"%v\"\n", name, res), nil
|
||||||
|
}
|
||||||
|
return "", fmt.Errorf("%s configuration setting is not in the file", name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// printMap takes a reflect.Value and return a string, recursively if its a map with the given tab settings.
|
||||||
|
func printMap(value reflect.Value, tabVal int) string {
|
||||||
|
|
||||||
|
// our output buffer
|
||||||
|
out := &bytes.Buffer{}
|
||||||
|
|
||||||
|
for _, key := range value.MapKeys() {
|
||||||
|
val := value.MapIndex(key)
|
||||||
|
if newVal, ok := val.Interface().(map[string]interface{}); !ok {
|
||||||
|
fmt.Fprintf(out, "%s", strings.Repeat("\t", tabVal))
|
||||||
|
fmt.Fprintf(out, "%v: \"%v\"\n", key.Interface(), val.Interface())
|
||||||
|
} else {
|
||||||
|
fmt.Fprintf(out, "%s", strings.Repeat("\t", tabVal))
|
||||||
|
fmt.Fprintf(out, "%v:\n", key.Interface())
|
||||||
|
// going one level in, increase the tab
|
||||||
|
tabVal++
|
||||||
|
fmt.Fprintf(out, "%s", printMap(reflect.ValueOf(newVal), tabVal))
|
||||||
|
// coming back one level, decrease the tab
|
||||||
|
tabVal--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return out.String()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// configToMap converts our config into a map
|
||||||
|
func configToMap(s interface{}) map[string]interface{} {
|
||||||
|
return structToMap(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// structToMap converts a struct into a map
|
||||||
|
func structToMap(t interface{}) map[string]interface{} {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
mlog.Error(fmt.Sprintf("Panicked in structToMap. This should never happen. %v", r))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
val := reflect.ValueOf(t)
|
||||||
|
|
||||||
|
if val.Kind() != reflect.Struct {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
out := map[string]interface{}{}
|
||||||
|
|
||||||
|
for i := 0; i < val.NumField(); i++ {
|
||||||
|
field := val.Field(i)
|
||||||
|
|
||||||
|
var value interface{}
|
||||||
|
|
||||||
|
switch field.Kind() {
|
||||||
|
case reflect.Struct:
|
||||||
|
value = structToMap(field.Interface())
|
||||||
|
case reflect.Ptr:
|
||||||
|
indirectType := field.Elem()
|
||||||
|
|
||||||
|
if indirectType.Kind() == reflect.Struct {
|
||||||
|
value = structToMap(indirectType.Interface())
|
||||||
|
} else {
|
||||||
|
value = indirectType.Interface()
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
value = field.Interface()
|
||||||
|
}
|
||||||
|
|
||||||
|
out[val.Type().Field(i).Name] = value
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"reflect"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@@ -15,6 +18,42 @@ import (
|
|||||||
"github.com/mattermost/mattermost-server/model"
|
"github.com/mattermost/mattermost-server/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type TestConfig struct {
|
||||||
|
TestServiceSettings TestServiceSettings
|
||||||
|
TestTeamSettings TestTeamSettings
|
||||||
|
TestClientRequirements TestClientRequirements
|
||||||
|
TestMessageExportSettings TestMessageExportSettings
|
||||||
|
}
|
||||||
|
|
||||||
|
type TestMessageExportSettings struct {
|
||||||
|
Enableexport bool
|
||||||
|
Exportformat string
|
||||||
|
TestGlobalRelaySettings TestGlobalRelaySettings
|
||||||
|
}
|
||||||
|
|
||||||
|
type TestGlobalRelaySettings struct {
|
||||||
|
Customertype string
|
||||||
|
Smtpusername string
|
||||||
|
Smtppassword string
|
||||||
|
}
|
||||||
|
|
||||||
|
type TestServiceSettings struct {
|
||||||
|
Siteurl string
|
||||||
|
Websocketurl string
|
||||||
|
Licensedfieldlocation string
|
||||||
|
}
|
||||||
|
|
||||||
|
type TestTeamSettings struct {
|
||||||
|
Sitename string
|
||||||
|
Maxuserperteam int
|
||||||
|
}
|
||||||
|
|
||||||
|
type TestClientRequirements struct {
|
||||||
|
Androidlatestversion string
|
||||||
|
Androidminversion string
|
||||||
|
Desktoplatestversion string
|
||||||
|
}
|
||||||
|
|
||||||
func TestConfigValidate(t *testing.T) {
|
func TestConfigValidate(t *testing.T) {
|
||||||
dir, err := ioutil.TempDir("", "")
|
dir, err := ioutil.TempDir("", "")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -28,3 +67,339 @@ func TestConfigValidate(t *testing.T) {
|
|||||||
assert.Error(t, RunCommand(t, "--config", "foo.json", "config", "validate"))
|
assert.Error(t, RunCommand(t, "--config", "foo.json", "config", "validate"))
|
||||||
assert.NoError(t, RunCommand(t, "--config", path, "config", "validate"))
|
assert.NoError(t, RunCommand(t, "--config", path, "config", "validate"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestConfigGet(t *testing.T) {
|
||||||
|
// Error when no arguments are given
|
||||||
|
assert.Error(t, RunCommand(t, "config", "get"))
|
||||||
|
|
||||||
|
// Error when more than one config settings are given
|
||||||
|
assert.Error(t, RunCommand(t, "config", "get", "abc", "def"))
|
||||||
|
|
||||||
|
// Error when a config setting which is not in the config.json is given
|
||||||
|
assert.Error(t, RunCommand(t, "config", "get", "abc"))
|
||||||
|
|
||||||
|
// No Error when a config setting which is in the config.json is given
|
||||||
|
assert.NoError(t, RunCommand(t, "config", "get", "MessageExportSettings"))
|
||||||
|
assert.NoError(t, RunCommand(t, "config", "get", "MessageExportSettings.GlobalRelaySettings"))
|
||||||
|
assert.NoError(t, RunCommand(t, "config", "get", "MessageExportSettings.GlobalRelaySettings.CustomerType"))
|
||||||
|
|
||||||
|
// check output
|
||||||
|
output := CheckCommand(t, "config", "get", "MessageExportSettings")
|
||||||
|
|
||||||
|
assert.Contains(t, string(output), "EnableExport")
|
||||||
|
assert.Contains(t, string(output), "ExportFormat")
|
||||||
|
assert.Contains(t, string(output), "DailyRunTime")
|
||||||
|
assert.Contains(t, string(output), "ExportFromTimestamp")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStructToMap(t *testing.T) {
|
||||||
|
|
||||||
|
cases := []struct {
|
||||||
|
Name string
|
||||||
|
Input interface{}
|
||||||
|
Expected map[string]interface{}
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
Name: "Struct with one string field",
|
||||||
|
Input: struct {
|
||||||
|
Test string
|
||||||
|
}{
|
||||||
|
Test: "test",
|
||||||
|
},
|
||||||
|
Expected: map[string]interface{}{
|
||||||
|
"Test": "test",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "String with multiple fields of different ",
|
||||||
|
Input: struct {
|
||||||
|
Test1 string
|
||||||
|
Test2 int
|
||||||
|
Test3 string
|
||||||
|
Test4 bool
|
||||||
|
}{
|
||||||
|
Test1: "test1",
|
||||||
|
Test2: 21,
|
||||||
|
Test3: "test2",
|
||||||
|
Test4: false,
|
||||||
|
},
|
||||||
|
Expected: map[string]interface{}{
|
||||||
|
"Test1": "test1",
|
||||||
|
"Test2": 21,
|
||||||
|
"Test3": "test2",
|
||||||
|
"Test4": false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Nested fields",
|
||||||
|
Input: TestConfig{
|
||||||
|
TestServiceSettings{"abc", "def", "ghi"},
|
||||||
|
TestTeamSettings{"abc", 1},
|
||||||
|
TestClientRequirements{"abc", "def", "ghi"},
|
||||||
|
TestMessageExportSettings{true, "abc", TestGlobalRelaySettings{"abc", "def", "ghi"}},
|
||||||
|
},
|
||||||
|
Expected: map[string]interface{}{
|
||||||
|
"TestServiceSettings": map[string]interface{}{
|
||||||
|
"Siteurl": "abc",
|
||||||
|
"Websocketurl": "def",
|
||||||
|
"Licensedfieldlocation": "ghi",
|
||||||
|
},
|
||||||
|
"TestTeamSettings": map[string]interface{}{
|
||||||
|
"Sitename": "abc",
|
||||||
|
"Maxuserperteam": 1,
|
||||||
|
},
|
||||||
|
"TestClientRequirements": map[string]interface{}{
|
||||||
|
"Androidlatestversion": "abc",
|
||||||
|
"Androidminversion": "def",
|
||||||
|
"Desktoplatestversion": "ghi",
|
||||||
|
},
|
||||||
|
"TestMessageExportSettings": map[string]interface{}{
|
||||||
|
"Enableexport": true,
|
||||||
|
"Exportformat": "abc",
|
||||||
|
"TestGlobalRelaySettings": map[string]interface{}{
|
||||||
|
"Customertype": "abc",
|
||||||
|
"Smtpusername": "def",
|
||||||
|
"Smtppassword": "ghi",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range cases {
|
||||||
|
t.Run(test.Name, func(t *testing.T) {
|
||||||
|
res := structToMap(test.Input)
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(res, test.Expected) {
|
||||||
|
t.Errorf("got %v want %v ", res, test.Expected)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConfigToMap(t *testing.T) {
|
||||||
|
// This test is almost the same as TestMapToStruct, but I have it here for the sake of completions
|
||||||
|
cases := []struct {
|
||||||
|
Name string
|
||||||
|
Input interface{}
|
||||||
|
Expected map[string]interface{}
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
Name: "Struct with one string field",
|
||||||
|
Input: struct {
|
||||||
|
Test string
|
||||||
|
}{
|
||||||
|
Test: "test",
|
||||||
|
},
|
||||||
|
Expected: map[string]interface{}{
|
||||||
|
"Test": "test",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "String with multiple fields of different ",
|
||||||
|
Input: struct {
|
||||||
|
Test1 string
|
||||||
|
Test2 int
|
||||||
|
Test3 string
|
||||||
|
Test4 bool
|
||||||
|
}{
|
||||||
|
Test1: "test1",
|
||||||
|
Test2: 21,
|
||||||
|
Test3: "test2",
|
||||||
|
Test4: false,
|
||||||
|
},
|
||||||
|
Expected: map[string]interface{}{
|
||||||
|
"Test1": "test1",
|
||||||
|
"Test2": 21,
|
||||||
|
"Test3": "test2",
|
||||||
|
"Test4": false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Nested fields",
|
||||||
|
Input: TestConfig{
|
||||||
|
TestServiceSettings{"abc", "def", "ghi"},
|
||||||
|
TestTeamSettings{"abc", 1},
|
||||||
|
TestClientRequirements{"abc", "def", "ghi"},
|
||||||
|
TestMessageExportSettings{true, "abc", TestGlobalRelaySettings{"abc", "def", "ghi"}},
|
||||||
|
},
|
||||||
|
Expected: map[string]interface{}{
|
||||||
|
"TestServiceSettings": map[string]interface{}{
|
||||||
|
"Siteurl": "abc",
|
||||||
|
"Websocketurl": "def",
|
||||||
|
"Licensedfieldlocation": "ghi",
|
||||||
|
},
|
||||||
|
"TestTeamSettings": map[string]interface{}{
|
||||||
|
"Sitename": "abc",
|
||||||
|
"Maxuserperteam": 1,
|
||||||
|
},
|
||||||
|
"TestClientRequirements": map[string]interface{}{
|
||||||
|
"Androidlatestversion": "abc",
|
||||||
|
"Androidminversion": "def",
|
||||||
|
"Desktoplatestversion": "ghi",
|
||||||
|
},
|
||||||
|
"TestMessageExportSettings": map[string]interface{}{
|
||||||
|
"Enableexport": true,
|
||||||
|
"Exportformat": "abc",
|
||||||
|
"TestGlobalRelaySettings": map[string]interface{}{
|
||||||
|
"Customertype": "abc",
|
||||||
|
"Smtpusername": "def",
|
||||||
|
"Smtppassword": "ghi",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range cases {
|
||||||
|
t.Run(test.Name, func(t *testing.T) {
|
||||||
|
res := configToMap(test.Input)
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(res, test.Expected) {
|
||||||
|
t.Errorf("got %v want %v ", res, test.Expected)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPrintMap(t *testing.T) {
|
||||||
|
|
||||||
|
inputCases := []interface{}{
|
||||||
|
map[string]interface{}{
|
||||||
|
"CustomerType": "A9",
|
||||||
|
"SmtpUsername": "",
|
||||||
|
"SmtpPassword": "",
|
||||||
|
"EmailAddress": "",
|
||||||
|
},
|
||||||
|
map[string]interface{}{
|
||||||
|
"EnableExport": false,
|
||||||
|
"ExportFormat": "actiance",
|
||||||
|
"DailyRunTime": "01:00",
|
||||||
|
"GlobalRelaySettings": map[string]interface{}{
|
||||||
|
"CustomerType": "A9",
|
||||||
|
"SmtpUsername": "",
|
||||||
|
"SmtpPassword": "",
|
||||||
|
"EmailAddress": "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
outputCases := []string{
|
||||||
|
"CustomerType: \"A9\"\nSmtpUsername: \"\"\nSmtpPassword: \"\"\nEmailAddress: \"\"\n",
|
||||||
|
"EnableExport: \"false\"\nExportFormat: \"actiance\"\nDailyRunTime: \"01:00\"\nGlobalRelaySettings:\n\t CustomerType: \"A9\"\n\tSmtpUsername: \"\"\n\tSmtpPassword: \"\"\n\tEmailAddress: \"\"\n",
|
||||||
|
}
|
||||||
|
|
||||||
|
cases := []struct {
|
||||||
|
Name string
|
||||||
|
Input reflect.Value
|
||||||
|
Expected string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
Name: "Basic print",
|
||||||
|
Input: reflect.ValueOf(inputCases[0]),
|
||||||
|
Expected: outputCases[0],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Complex print",
|
||||||
|
Input: reflect.ValueOf(inputCases[1]),
|
||||||
|
Expected: outputCases[1],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range cases {
|
||||||
|
t.Run(test.Name, func(t *testing.T) {
|
||||||
|
res := printMap(test.Input, 0)
|
||||||
|
|
||||||
|
// create two slice of string formed by splitting our strings on \n
|
||||||
|
slice1 := strings.Split(res, "\n")
|
||||||
|
slice2 := strings.Split(res, "\n")
|
||||||
|
|
||||||
|
sort.Strings(slice1)
|
||||||
|
sort.Strings(slice2)
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(slice1, slice2) {
|
||||||
|
t.Errorf("got '%#v' want '%#v", slice1, slice2)
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPrintConfigValues(t *testing.T) {
|
||||||
|
|
||||||
|
outputs := []string{
|
||||||
|
"Siteurl: \"abc\"\nWebsocketurl: \"def\"\nLicensedfieldlocation: \"ghi\"\n",
|
||||||
|
"Sitename: \"abc\"\nMaxuserperteam: \"1\"\n",
|
||||||
|
"Androidlatestversion: \"abc\"\nAndroidminversion: \"def\"\nDesktoplatestversion: \"ghi\"\n",
|
||||||
|
"Enableexport: \"true\"\nExportformat: \"abc\"\nTestGlobalRelaySettings:\n\tCustomertype: \"abc\"\n\tSmtpusername: \"def\"\n\tSmtppassword: \"ghi\"\n",
|
||||||
|
"Customertype: \"abc\"\nSmtpusername: \"def\"\nSmtppassword: \"ghi\"\n",
|
||||||
|
}
|
||||||
|
|
||||||
|
commands := []string{
|
||||||
|
"TestServiceSettings",
|
||||||
|
"TestTeamSettings",
|
||||||
|
"TestClientRequirements",
|
||||||
|
"TestMessageExportSettings",
|
||||||
|
"TestMessageExportSettings.TestGlobalRelaySettings",
|
||||||
|
}
|
||||||
|
|
||||||
|
input := TestConfig{
|
||||||
|
TestServiceSettings{"abc", "def", "ghi"},
|
||||||
|
TestTeamSettings{"abc", 1},
|
||||||
|
TestClientRequirements{"abc", "def", "ghi"},
|
||||||
|
TestMessageExportSettings{true, "abc", TestGlobalRelaySettings{"abc", "def", "ghi"}},
|
||||||
|
}
|
||||||
|
|
||||||
|
configMap := structToMap(input)
|
||||||
|
|
||||||
|
cases := []struct {
|
||||||
|
Name string
|
||||||
|
Command string
|
||||||
|
Expected string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
Name: "First test",
|
||||||
|
Command: commands[0],
|
||||||
|
Expected: outputs[0],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Second test",
|
||||||
|
Command: commands[1],
|
||||||
|
Expected: outputs[1],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "third test",
|
||||||
|
Command: commands[2],
|
||||||
|
Expected: outputs[2],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "fourth test",
|
||||||
|
Command: commands[3],
|
||||||
|
Expected: outputs[3],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "fifth test",
|
||||||
|
Command: commands[4],
|
||||||
|
Expected: outputs[4],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range cases {
|
||||||
|
t.Run(test.Name, func(t *testing.T) {
|
||||||
|
res, _ := printConfigValues(configMap, strings.Split(test.Command, "."), test.Command)
|
||||||
|
|
||||||
|
// create two slice of string formed by splitting our strings on \n
|
||||||
|
slice1 := strings.Split(res, "\n")
|
||||||
|
slice2 := strings.Split(test.Expected, "\n")
|
||||||
|
|
||||||
|
sort.Strings(slice1)
|
||||||
|
sort.Strings(slice2)
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(slice1, slice2) {
|
||||||
|
t.Errorf("got '%#v' want '%#v", slice1, slice2)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user