diff --git a/go/cmd/rulesctl/cmd/add_test.go b/go/cmd/rulesctl/cmd/add_test.go new file mode 100644 index 00000000000..54c6623dab8 --- /dev/null +++ b/go/cmd/rulesctl/cmd/add_test.go @@ -0,0 +1,133 @@ +/* +Copyright 2024 The Vitess Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cmd + +import ( + "io" + "os" + "testing" + + "github.com/spf13/cobra" + "github.com/stretchr/testify/require" +) + +func TestAdd(t *testing.T) { + cmd := Add() + require.NotNil(t, cmd) + require.Equal(t, "add-rule", cmd.Name()) + configFile = "./testdata/rules.json" + + tests := []struct { + name string + args []string + expectedOutput string + }{ + { + name: "Action fail", + args: []string{"--dry-run=true", "--name=Rule", `--description="New rules that will be added to the file"`, "--action=fail", "--plan=Select"}, + expectedOutput: `[ + { + "Description": "Some value", + "Name": "Name", + "Action": "FAIL" + }, + { + "Description": "\"New rules that will be added to the file\"", + "Name": "Rule", + "Plans": [ + "Select" + ], + "Action": "FAIL" + } +] +`, + }, + { + name: "Action fail_retry", + args: []string{"--dry-run=true", "--name=Rule", `--description="New rules that will be added to the file"`, "--action=fail_retry", "--plan=Select"}, + expectedOutput: `[ + { + "Description": "Some value", + "Name": "Name", + "Action": "FAIL" + }, + { + "Description": "\"New rules that will be added to the file\"", + "Name": "Rule", + "Plans": [ + "Select", + "Select" + ], + "Action": "FAIL_RETRY" + } +] +`, + }, + { + name: "Action continue with query", + args: []string{"--dry-run=true", "--name=Rule", `--description="New rules that will be added to the file"`, "--action=continue", "--plan=Select", "--query=secret", "--leading-comment=None", "--trailing-comment=Yoho", "--table=Temp"}, + expectedOutput: `[ + { + "Description": "Some value", + "Name": "Name", + "Action": "FAIL" + }, + { + "Description": "\"New rules that will be added to the file\"", + "Name": "Rule", + "Query": "secret", + "LeadingComment": "None", + "TrailingComment": "Yoho", + "Plans": [ + "Select", + "Select", + "Select" + ], + "TableNames": [ + "Temp" + ] + } +] +`, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if tt.args != nil { + cmd.SetArgs(tt.args) + err := cmd.Execute() + require.NoError(t, err) + } + + originalStdOut := os.Stdout + defer func() { + os.Stdout = originalStdOut + }() + // Redirect stdout to a buffer + r, w, _ := os.Pipe() + os.Stdout = w + + cmd.Run(&cobra.Command{}, []string{}) + + err := w.Close() + require.NoError(t, err) + got, err := io.ReadAll(r) + require.NoError(t, err) + require.EqualValues(t, tt.expectedOutput, string(got)) + }) + } +} diff --git a/go/cmd/rulesctl/cmd/explain_test.go b/go/cmd/rulesctl/cmd/explain_test.go new file mode 100644 index 00000000000..cc515a1eb3d --- /dev/null +++ b/go/cmd/rulesctl/cmd/explain_test.go @@ -0,0 +1,77 @@ +/* +Copyright 2024 The Vitess Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cmd + +import ( + "io" + "os" + "testing" + + "github.com/spf13/cobra" + "github.com/stretchr/testify/require" +) + +func TestExplainWithQueryPlanArguement(t *testing.T) { + explainCmd := Explain() + + require.NotNil(t, explainCmd) + require.Equal(t, "explain", explainCmd.Name()) + + originalStdOut := os.Stdout + defer func() { + os.Stdout = originalStdOut + }() + // Redirect stdout to a buffer + r, w, _ := os.Pipe() + os.Stdout = w + + explainCmd.Run(&cobra.Command{}, []string{"query-plans"}) + + err := w.Close() + require.NoError(t, err) + got, err := io.ReadAll(r) + require.NoError(t, err) + + expected := "Query Plans!" + require.Contains(t, string(got), expected) +} + +func TestExplainWithRandomArguement(t *testing.T) { + explainCmd := Explain() + + require.NotNil(t, explainCmd) + require.Equal(t, "explain", explainCmd.Name()) + + // Redirect stdout to a buffer + originalStdOut := os.Stdout + defer func() { + os.Stdout = originalStdOut + }() + // Redirect stdout to a buffer + r, w, _ := os.Pipe() + os.Stdout = w + + explainCmd.Run(&cobra.Command{}, []string{"random"}) + + err := w.Close() + require.NoError(t, err) + got, err := io.ReadAll(r) + require.NoError(t, err) + + expected := "I don't know anything about" + require.Contains(t, string(got), expected) +} diff --git a/go/cmd/rulesctl/cmd/list_test.go b/go/cmd/rulesctl/cmd/list_test.go new file mode 100644 index 00000000000..d787481165e --- /dev/null +++ b/go/cmd/rulesctl/cmd/list_test.go @@ -0,0 +1,103 @@ +/* +Copyright 2024 The Vitess Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cmd + +import ( + "io" + "os" + "testing" + + "github.com/spf13/cobra" + "github.com/stretchr/testify/require" +) + +func TestList(t *testing.T) { + cmd := List() + require.NotNil(t, cmd) + require.Equal(t, "list", cmd.Name()) + configFile = "./testdata/rules.json" + + tests := []struct { + name string + args []string + expectedOutput string + }{ + { + name: "No args", + expectedOutput: `[ + { + "Description": "Some value", + "Name": "Name", + "Action": "FAIL" + } +] +`, + }, + { + name: "Name only", + args: []string{"--names-only=true"}, + expectedOutput: `[ + "Name" +] +`, + }, + { + name: "Name flag set", + args: []string{"--name=Name"}, + expectedOutput: `"Name" +`, + }, + { + name: "Random name in name flag", + args: []string{"--name=Random"}, + expectedOutput: `"" +`, + }, + { + name: "Random name in name flag and names-only false", + args: []string{"--name=Random", "--names-only=false"}, + expectedOutput: `null +`, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if tt.args != nil { + cmd.SetArgs(tt.args) + err := cmd.Execute() + require.NoError(t, err) + } + + originalStdOut := os.Stdout + defer func() { + os.Stdout = originalStdOut + }() + // Redirect stdout to a buffer + r, w, _ := os.Pipe() + os.Stdout = w + + cmd.Run(&cobra.Command{}, []string{}) + + err := w.Close() + require.NoError(t, err) + got, err := io.ReadAll(r) + require.NoError(t, err) + + require.EqualValues(t, tt.expectedOutput, string(got)) + }) + } +} diff --git a/go/cmd/rulesctl/cmd/main_test.go b/go/cmd/rulesctl/cmd/main_test.go new file mode 100644 index 00000000000..cbdba6c00e6 --- /dev/null +++ b/go/cmd/rulesctl/cmd/main_test.go @@ -0,0 +1,60 @@ +/* +Copyright 2024 The Vitess Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cmd + +import ( + "io" + "os" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestMainFunction(t *testing.T) { + rootCmd := Main() + require.NotNil(t, rootCmd) + require.Equal(t, "rulesctl", rootCmd.Name()) + + originalStdOut := os.Stdout + defer func() { + os.Stdout = originalStdOut + }() + // Redirect stdout to a buffer + r, w, _ := os.Pipe() + os.Stdout = w + + args := os.Args + t.Cleanup(func() { os.Args = args }) + os.Args = []string{"rulesctl", "-f=testdata/rules.json", "list"} + err := rootCmd.Execute() + require.NoError(t, err) + + err = w.Close() + require.NoError(t, err) + got, err := io.ReadAll(r) + require.NoError(t, err) + + expected := `[ + { + "Description": "Some value", + "Name": "Name", + "Action": "FAIL" + } +] +` + require.EqualValues(t, expected, string(got)) +} diff --git a/go/cmd/rulesctl/cmd/remove_test.go b/go/cmd/rulesctl/cmd/remove_test.go new file mode 100644 index 00000000000..d0ee9f9880e --- /dev/null +++ b/go/cmd/rulesctl/cmd/remove_test.go @@ -0,0 +1,114 @@ +/* +Copyright 2024 The Vitess Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cmd + +import ( + "io" + "os" + "testing" + + "github.com/spf13/cobra" + "github.com/stretchr/testify/require" +) + +func TestRemoveOld(t *testing.T) { + removeCmd := Remove() + + require.NotNil(t, removeCmd) + require.Equal(t, "remove-rule", removeCmd.Name()) + + originalStdOut := os.Stdout + defer func() { + os.Stdout = originalStdOut + }() + // Redirect stdout to a buffer + r, w, _ := os.Pipe() + os.Stdout = w + + configFile = "../common/testdata/rules.json" + removeCmd.Run(&cobra.Command{}, []string{""}) + + err := w.Close() + require.NoError(t, err) + got, err := io.ReadAll(r) + require.NoError(t, err) + + expected := "No rule found:" + require.Contains(t, string(got), expected) +} + +func TestRemove(t *testing.T) { + cmd := Remove() + require.NotNil(t, cmd) + require.Equal(t, "remove-rule", cmd.Name()) + configFile = "./testdata/rules.json" + defer func() { + _ = os.WriteFile(configFile, []byte(`[ + { + "Description": "Some value", + "Name": "Name" + } +] +`), 0777) + }() + + tests := []struct { + name string + args []string + expectedOutput string + }{ + { + name: "No args", + expectedOutput: "No rule found: ''", + }, + { + name: "Dry run and name both set", + args: []string{"--dry-run=true", "--name=Name"}, + expectedOutput: "[]\n", + }, + { + name: "Dry run not set name set", + args: []string{"--dry-run=false", "--name=Name"}, + expectedOutput: "No rule found: 'Name'", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + originalStdOut := os.Stdout + defer func() { + os.Stdout = originalStdOut + }() + // Redirect stdout to a buffer + r, w, _ := os.Pipe() + os.Stdout = w + + if tt.args != nil { + cmd.SetArgs(tt.args) + err := cmd.Execute() + require.NoError(t, err) + } + cmd.Run(&cobra.Command{}, []string{}) + + err := w.Close() + require.NoError(t, err) + got, err := io.ReadAll(r) + require.NoError(t, err) + + require.Contains(t, string(got), tt.expectedOutput) + }) + } +} diff --git a/go/cmd/rulesctl/cmd/testdata/rules.json b/go/cmd/rulesctl/cmd/testdata/rules.json new file mode 100644 index 00000000000..12f0bfa0b5a --- /dev/null +++ b/go/cmd/rulesctl/cmd/testdata/rules.json @@ -0,0 +1,6 @@ +[ + { + "Description": "Some value", + "Name": "Name" + } +] diff --git a/go/cmd/rulesctl/common/common_test.go b/go/cmd/rulesctl/common/common_test.go new file mode 100644 index 00000000000..aff7f012c20 --- /dev/null +++ b/go/cmd/rulesctl/common/common_test.go @@ -0,0 +1,84 @@ +/* +Copyright 2024 The Vitess Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package common + +import ( + "io" + "os" + "path" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestGetRules(t *testing.T) { + rules := GetRules("testdata/rules.json") + require.NotEmpty(t, rules) +} + +type testStruct struct { + StringField string `yaml:"stringfield"` + IntField int `yaml:"intfield"` + BoolField bool `yaml:"boolfield"` + Float64Field float64 `yaml:"float64field"` +} + +var testData = testStruct{ + "tricky text to test text", + 32, + true, + 3.141, +} + +func TestMustPrintJSON(t *testing.T) { + originalStdOut := os.Stdout + defer func() { + os.Stdout = originalStdOut + }() + + // Redirect stdout to a buffer + r, w, _ := os.Pipe() + os.Stdout = w + MustPrintJSON(testData) + + err := w.Close() + require.NoError(t, err) + got, err := io.ReadAll(r) + require.NoError(t, err) + require.Equal(t, `{ + "StringField": "tricky text to test text", + "IntField": 32, + "BoolField": true, + "Float64Field": 3.141 +} +`, string(got)) +} + +func TestMustWriteJSON(t *testing.T) { + tmpFile := path.Join(t.TempDir(), "temp.json") + MustWriteJSON(testData, tmpFile) + + res, err := os.ReadFile(tmpFile) + require.NoError(t, err) + + require.EqualValues(t, `{ + "StringField": "tricky text to test text", + "IntField": 32, + "BoolField": true, + "Float64Field": 3.141 +}`, string(res)) +} diff --git a/go/cmd/rulesctl/common/testdata/rules.json b/go/cmd/rulesctl/common/testdata/rules.json new file mode 100644 index 00000000000..12f0bfa0b5a --- /dev/null +++ b/go/cmd/rulesctl/common/testdata/rules.json @@ -0,0 +1,6 @@ +[ + { + "Description": "Some value", + "Name": "Name" + } +]