Implement the verification of query (#10)
diff --git a/commands/root.go b/commands/root.go
index 8493e0d..d378f0c 100644
--- a/commands/root.go
+++ b/commands/root.go
@@ -29,6 +29,8 @@
"github.com/apache/skywalking-infra-e2e/internal/constant"
)
+var cfg string
+
// Root represents the base command when called without any subcommands
var Root = &cobra.Command{
Use: "e2e command [flags]",
@@ -37,7 +39,7 @@
SilenceErrors: true,
SilenceUsage: true,
PersistentPreRun: func(cmd *cobra.Command, args []string) {
- config.ReadGlobalConfigFile(constant.E2EDefaultFile)
+ config.ReadGlobalConfigFile(cfg)
},
}
@@ -50,5 +52,7 @@
Root.AddCommand(verify.Verify)
Root.AddCommand(cleanup.Cleanup)
+ Root.PersistentFlags().StringVarP(&cfg, "config", "c", constant.E2EDefaultFile, "the config file")
+
return Root.Execute()
}
diff --git a/commands/verify/verify.go b/commands/verify/verify.go
index 91f37bf..05ccbe0 100644
--- a/commands/verify/verify.go
+++ b/commands/verify/verify.go
@@ -21,6 +21,9 @@
"fmt"
"github.com/apache/skywalking-infra-e2e/internal/components/verifier"
+ "github.com/apache/skywalking-infra-e2e/internal/config"
+ "github.com/apache/skywalking-infra-e2e/internal/logger"
+ "github.com/apache/skywalking-infra-e2e/internal/util"
"github.com/spf13/cobra"
)
@@ -41,10 +44,62 @@
Use: "verify",
Short: "verify if the actual data match the expected data",
RunE: func(cmd *cobra.Command, args []string) error {
- if actual != "" && expected != "" {
- return verifier.VerifyDataFile(actual, expected)
+ if expected != "" {
+ return verifySingleCase(expected, actual, query)
}
- fmt.Println("Not implemented.")
- return nil
+ // If there is no given flags.
+ return verifyAccordingConfig()
},
}
+
+func verifySingleCase(expectedFile, actualFile, query string) error {
+ expectedData, err := util.ReadFileContent(expectedFile)
+ if err != nil {
+ return fmt.Errorf("failed to read the expected data file: %v", err)
+ }
+
+ var actualData, sourceName string
+ if actualFile != "" {
+ sourceName = actualFile
+ actualData, err = util.ReadFileContent(actualFile)
+ if err != nil {
+ return fmt.Errorf("failed to read the actual data file: %v", err)
+ }
+ } else if query != "" {
+ sourceName = query
+ actualData, err = util.ExecuteCommand(query)
+ if err != nil {
+ return fmt.Errorf("failed to execute the query: %v", err)
+ }
+ }
+
+ if err = verifier.Verify(actualData, expectedData); err != nil {
+ logger.Log.Warnf("failed to verify the output: %s\n", sourceName)
+ if me, ok := err.(*verifier.MismatchError); ok {
+ fmt.Println(me.Error())
+ }
+ } else {
+ logger.Log.Infof("verified the output: %s\n", sourceName)
+ }
+ return nil
+}
+
+// verifyAccordingConfig reads cases from the config file and verifies them.
+func verifyAccordingConfig() error {
+ if config.GlobalConfig.Error != nil {
+ return config.GlobalConfig.Error
+ }
+
+ e2eConfig := config.GlobalConfig.E2EConfig
+
+ for _, v := range e2eConfig.Verify {
+ if v.Expected != "" {
+ if err := verifySingleCase(v.Expected, v.Actual, v.Query); err != nil {
+ logger.Log.Errorf("%v", err)
+ }
+ } else {
+ logger.Log.Error("the expected data file is not specified")
+ }
+ }
+ return nil
+}
diff --git a/examples/simple/e2e.yaml b/examples/simple/e2e.yaml
index 181cd9c..721d446 100644
--- a/examples/simple/e2e.yaml
+++ b/examples/simple/e2e.yaml
@@ -13,6 +13,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+# This file is used to show how to write configuration files and can be used to test.
+
setup:
env: kind
file: kind.yaml
@@ -32,3 +34,13 @@
resource: pod
for: condition=Ready
timeout: 600
+
+verify:
+ - actual: ../../test/verify/1.actual.yaml
+ expected: ../../test/verify/1.expected.yaml
+ - actual: ../../test/verify/2.actual.yaml
+ expected: ../../test/verify/2.expected.yaml
+ - actual: ../../test/verify/1.actual.yaml
+ expected: ../../test/verify/2.expected.yaml
+ - query: swctl --display yaml service ls
+ expected: ../../test/verify/3.expected.yaml
diff --git a/internal/components/verifier/verifier.go b/internal/components/verifier/verifier.go
index 2f4675a..866b063 100644
--- a/internal/components/verifier/verifier.go
+++ b/internal/components/verifier/verifier.go
@@ -14,25 +14,24 @@
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
+
package verifier
import (
"bytes"
- "errors"
"fmt"
- "github.com/apache/skywalking-infra-e2e/internal/logger"
- "github.com/apache/skywalking-infra-e2e/internal/util"
"github.com/apache/skywalking-infra-e2e/third-party/go/template"
"github.com/google/go-cmp/cmp"
"gopkg.in/yaml.v2"
)
-// MismatchError is the error type returned by the verify functions.
-// Then the caller will know if there is a mismatch.
+// MismatchError is the error type returned by the Verify functions.
+// It contains the diff content.
type MismatchError struct {
- Err error
+ Err error
+ diff string
}
func (e *MismatchError) Unwrap() error { return e.Err }
@@ -41,65 +40,35 @@
if e == nil {
return "<nil>"
}
- return "the actual data does not match the expected data"
+ return e.diff
}
-// VerifyDataFile reads the actual data from the file and verifies.
-func VerifyDataFile(actualFile, expectedFile string) error {
- actualData, err := util.ReadFileContent(actualFile)
- if err != nil {
- logger.Log.Error("failed to read the actual data file")
- return err
- }
-
- expectedTemplate, err := util.ReadFileContent(expectedFile)
- if err != nil {
- logger.Log.Error("failed to read the expected data file")
- return err
- }
-
- return verify(actualData, expectedTemplate)
-}
-
-// VerifyQuery gets the actual data from the query and then verifies.
-func VerifyQuery(query, expectedFile string) error {
- return errors.New("not implemented")
-}
-
-// verify checks if the actual data match the expected template.
-// It will print the diff if the actual data does not match.
-func verify(actualData, expectedTemplate string) error {
+// Verify checks if the actual data match the expected template.
+func Verify(actualData, expectedTemplate string) error {
var actual interface{}
if err := yaml.Unmarshal([]byte(actualData), &actual); err != nil {
- logger.Log.Error("failed to unmarshal actual data")
- return err
+ return fmt.Errorf("failed to unmarshal actual data: %v", err)
}
tmpl, err := template.New("test").Funcs(funcMap()).Parse(expectedTemplate)
if err != nil {
- logger.Log.Error("failed to parse template")
- return err
+ return fmt.Errorf("failed to parse template: %v", err)
}
var b bytes.Buffer
if err := tmpl.Execute(&b, actual); err != nil {
- logger.Log.Error("failed to execute template")
- return err
+ return fmt.Errorf("failed to execute template: %v", err)
}
var expected interface{}
if err := yaml.Unmarshal(b.Bytes(), &expected); err != nil {
- logger.Log.Error("failed to unmarshal expected data")
- return err
+ return fmt.Errorf("failed to unmarshal expected data: %v", err)
}
if !cmp.Equal(expected, actual) {
// TODO: use a custom Reporter (suggested by the comment of cmp.Diff)
diff := cmp.Diff(expected, actual)
- fmt.Println(diff)
- return &MismatchError{}
+ return &MismatchError{diff: diff}
}
-
- logger.Log.Info("the actual data matches the expected data")
return nil
}
diff --git a/internal/components/verifier/verifier_test.go b/internal/components/verifier/verifier_test.go
index f7d073a..0d6b7e7 100644
--- a/internal/components/verifier/verifier_test.go
+++ b/internal/components/verifier/verifier_test.go
@@ -142,8 +142,8 @@
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
- if err := verify(tt.args.actualData, tt.args.expectedTemplate); (err != nil) != tt.wantErr {
- t.Errorf("verify() error = %v, wantErr %v", err, tt.wantErr)
+ if err := Verify(tt.args.actualData, tt.args.expectedTemplate); (err != nil) != tt.wantErr {
+ t.Errorf("Verify() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
diff --git a/internal/config/globalConfig.go b/internal/config/globalConfig.go
index f8c1334..c796962 100644
--- a/internal/config/globalConfig.go
+++ b/internal/config/globalConfig.go
@@ -22,9 +22,10 @@
"fmt"
"io/ioutil"
- "gopkg.in/yaml.v2"
-
+ "github.com/apache/skywalking-infra-e2e/internal/logger"
"github.com/apache/skywalking-infra-e2e/internal/util"
+
+ "gopkg.in/yaml.v2"
)
// GlobalE2EConfig store E2EConfig which can be used globally.
@@ -57,4 +58,5 @@
GlobalConfig.E2EConfig = e2eConfigObject
GlobalConfig.Error = nil
+ logger.Log.Info("load the e2e config successfully")
}
diff --git a/internal/util/utils.go b/internal/util/utils.go
index 0c2a2f0..fc5bda4 100644
--- a/internal/util/utils.go
+++ b/internal/util/utils.go
@@ -19,6 +19,7 @@
package util
import (
+ "bytes"
"errors"
"io/ioutil"
"os"
@@ -52,3 +53,18 @@
}
return "", errors.New("the file does not exist")
}
+
+// ExecuteCommand executes the given command and returns the result.
+func ExecuteCommand(cmd string) (string, error) {
+ command := exec.Command("bash", "-c", cmd)
+ outinfo := bytes.Buffer{}
+ command.Stdout = &outinfo
+
+ if err := command.Start(); err != nil {
+ return "", err
+ }
+ if err := command.Wait(); err != nil {
+ return "", err
+ }
+ return outinfo.String(), nil
+}
diff --git a/test/verify/3.expected.yaml b/test/verify/3.expected.yaml
new file mode 100644
index 0000000..40f5133
--- /dev/null
+++ b/test/verify/3.expected.yaml
@@ -0,0 +1,22 @@
+# Licensed to Apache Software Foundation (ASF) under one or more contributor
+# license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright
+# ownership. Apache Software Foundation (ASF) licenses this file to you 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.
+
+{{- contains . }}
+- id: {{ notEmpty .id }}
+ name: {{ notEmpty .name }}
+ group: ""
+{{- end }}