diff --git a/cmd/file_convert.go b/cmd/file_convert.go index 37debd53e..f3270226c 100644 --- a/cmd/file_convert.go +++ b/cmd/file_convert.go @@ -113,6 +113,22 @@ into another compatible format. For example, a configuration for 'kong-gateway-2 can be converted into a 'kong-gateway-3.x' configuration file.`, Args: validateNoArgs, RunE: execute, + PreRunE: func(_ *cobra.Command, _ []string) error { + validSourceFormats := []string{string(convert.FormatKongGateway), string(convert.FormatKongGateway2x)} + validDestinationFormats := []string{string(convert.FormatKonnect), string(convert.FormatKongGateway3x)} + + err := validateInputFlag("from", convertCmdSourceFormat, validSourceFormats, "") + if err != nil { + return err + } + + err = validateInputFlag("to", convertCmdDestinationFormat, validDestinationFormats, "") + if err != nil { + return err + } + + return nil + }, } sourceFormats := []convert.Format{convert.FormatKongGateway, convert.FormatKongGateway2x} diff --git a/cmd/utils.go b/cmd/utils.go index 476743903..ba0c70ed0 100644 --- a/cmd/utils.go +++ b/cmd/utils.go @@ -1,6 +1,10 @@ package cmd import ( + "errors" + "fmt" + "slices" + "github.com/fatih/color" "github.com/kong/go-database-reconciler/pkg/cprint" "github.com/kong/go-database-reconciler/pkg/diff" @@ -30,3 +34,16 @@ func addSilenceEventsFlag(set *pflag.FlagSet) { set.BoolVar(&silenceEvents, "silence-events", false, "disable printing events to stdout") } + +func validateInputFlag(flagName string, flagValue string, allowedValues []string, errorMessage string) error { + if slices.Contains(allowedValues, flagValue) { + return nil + } + + if errorMessage != "" { + return errors.New(errorMessage) + } + + return fmt.Errorf("invalid value '%s' found for the '%s' flag. Allowed values: %v", + flagValue, flagName, allowedValues) +} diff --git a/tests/integration/file_convert_test.go b/tests/integration/file_convert_test.go new file mode 100644 index 000000000..c36b6515f --- /dev/null +++ b/tests/integration/file_convert_test.go @@ -0,0 +1,73 @@ +package integration + +import ( + "os" + "testing" + + "github.com/stretchr/testify/assert" + "sigs.k8s.io/yaml" +) + +func Test_FileConvert(t *testing.T) { + tests := []struct { + name string + convertCmdSourceFormat string + convertCmdDestinationFormat string + errorExpected bool + errorString string + expectedOutputFile string + }{ + { + name: "Valid source and destination format", + convertCmdSourceFormat: "kong-gateway-2.x", + convertCmdDestinationFormat: "kong-gateway-3.x", + errorExpected: false, + expectedOutputFile: "testdata/file-convert/001-kong-gateway-config/kong-gateway-3-x.yaml", + }, + { + name: "Invalid source format", + convertCmdSourceFormat: "random-value", + convertCmdDestinationFormat: "kong-gateway-3.x", + errorExpected: true, + errorString: "invalid value 'random-value' found for the 'from' flag." + + " Allowed values: [kong-gateway kong-gateway-2.x]", + }, + { + name: "Invalid destination format", + convertCmdSourceFormat: "kong-gateway-2.x", + convertCmdDestinationFormat: "random-value", + errorExpected: true, + errorString: "invalid value 'random-value' found for the 'to' flag." + + " Allowed values: [konnect kong-gateway-3.x]", + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + output, err := fileConvert( + "--from", tc.convertCmdSourceFormat, + "--to", tc.convertCmdDestinationFormat, + "--input-file", "testdata/file-convert/001-kong-gateway-config/kong-gateway-2-x.yaml", + ) + + if tc.errorExpected { + assert.Error(t, err) + assert.Contains(t, err.Error(), tc.errorString) + + return + } + + assert.NoError(t, err) + + var expectedOutput interface{} + var currentOutput interface{} + content, err := os.ReadFile(tc.expectedOutputFile) + assert.NoError(t, err) + + err = yaml.Unmarshal(content, &expectedOutput) + assert.NoError(t, err) + err = yaml.Unmarshal([]byte(output), ¤tOutput) + assert.NoError(t, err) + assert.Equal(t, expectedOutput, currentOutput) + }) + } +} diff --git a/tests/integration/test_utils.go b/tests/integration/test_utils.go index 41a23b40e..41718b7bb 100644 --- a/tests/integration/test_utils.go +++ b/tests/integration/test_utils.go @@ -342,6 +342,28 @@ func lint(opts ...string) (string, error) { return stripansi.Strip(string(out)), cmdErr } +func fileConvert(opts ...string) (string, error) { + deckCmd := cmd.NewRootCmd() + args := []string{"file", "convert"} + if len(opts) > 0 { + args = append(args, opts...) + } + deckCmd.SetArgs(args) + + // capture command output to be used during tests + rescueStdout := os.Stdout + r, w, _ := os.Pipe() + os.Stdout = w + + cmdErr := deckCmd.ExecuteContext(context.Background()) + + w.Close() + out, _ := io.ReadAll(r) + os.Stdout = rescueStdout + + return stripansi.Strip(string(out)), cmdErr +} + func ping(opts ...string) error { deckCmd := cmd.NewRootCmd() args := []string{"gateway", "ping"} diff --git a/tests/integration/testdata/file-convert/001-kong-gateway-config/kong-gateway-2-x.yaml b/tests/integration/testdata/file-convert/001-kong-gateway-config/kong-gateway-2-x.yaml new file mode 100644 index 000000000..398199a29 --- /dev/null +++ b/tests/integration/testdata/file-convert/001-kong-gateway-config/kong-gateway-2-x.yaml @@ -0,0 +1,10 @@ +_format_version: "1.1" +services: +- connect_timeout: 60000 + id: 58076db2-28b6-423b-ba39-a797193017f7 + host: mockbin.org + name: svc1 + port: 80 + protocol: http + read_timeout: 60000 + retries: 5 \ No newline at end of file diff --git a/tests/integration/testdata/file-convert/001-kong-gateway-config/kong-gateway-3-x.yaml b/tests/integration/testdata/file-convert/001-kong-gateway-config/kong-gateway-3-x.yaml new file mode 100644 index 000000000..747af52e0 --- /dev/null +++ b/tests/integration/testdata/file-convert/001-kong-gateway-config/kong-gateway-3-x.yaml @@ -0,0 +1,10 @@ +_format_version: "3.0" +services: +- connect_timeout: 60000 + id: 58076db2-28b6-423b-ba39-a797193017f7 + host: mockbin.org + name: svc1 + port: 80 + protocol: http + read_timeout: 60000 + retries: 5