This is an automated email from the ASF dual-hosted git repository. hoshea pushed a commit to branch verifier/query in repository https://gitbox.apache.org/repos/asf/skywalking-infra-e2e.git
commit 7f00f7fa19668a84aab96dfac647bba31a5f1143 Author: Hoshea <[email protected]> AuthorDate: Tue Mar 2 21:27:19 2021 +0800 Implement the verification of query --- commands/verify/verify.go | 53 ++++++++++++++++++++++++++++---- e2e.yaml | 28 +++++++++++++++++ internal/components/verifier/verifier.go | 50 +++++++++++++----------------- internal/config/globalConfig.go | 2 ++ internal/util/utils.go | 18 +++++++++++ 5 files changed, 116 insertions(+), 35 deletions(-) diff --git a/commands/verify/verify.go b/commands/verify/verify.go index 91f37bf..3f53183 100644 --- a/commands/verify/verify.go +++ b/commands/verify/verify.go @@ -18,9 +18,10 @@ package verify import ( - "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 +42,50 @@ var Verify = &cobra.Command{ 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 { + logger.Log.Error("failed to read the expected data file") + return err + } + + if actualFile != "" { + if err = verifier.VerifyDataFile(actualFile, expectedData); err != nil { + logger.Log.Warnf("failed to verify the output: %s\n", actualFile) + } else { + logger.Log.Infof("verified the output: %s\n", actualFile) + } + } else if query != "" { + if err = verifier.VerifyQuery(query, expectedData); err != nil { + logger.Log.Warnf("failed to verify the output: %s\n", query) + } else { + logger.Log.Infof("verified the output: %s\n", query) + } + } + return nil +} + +func verifyAccordingConfig() error { + if config.GlobalConfig.Error != nil { + return config.GlobalConfig.Error + } + + e2eConfig := config.GlobalConfig.E2EConfig + + for _, v := range e2eConfig.Verify { + if v.Expected != "" { + verifySingleCase(v.Expected, v.Actual, v.Query) + } else { + logger.Log.Error("the expected data file is not specified") + } + } + return nil +} diff --git a/e2e.yaml b/e2e.yaml new file mode 100644 index 0000000..37281fa --- /dev/null +++ b/e2e.yaml @@ -0,0 +1,28 @@ +# 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. + +# This config file can be used to test. + +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 + - actual: test/verify/2.actual.yaml + expected: test/verify/1.expected.yaml \ No newline at end of file diff --git a/internal/components/verifier/verifier.go b/internal/components/verifier/verifier.go index 2f4675a..ed15361 100644 --- a/internal/components/verifier/verifier.go +++ b/internal/components/verifier/verifier.go @@ -14,14 +14,13 @@ // 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" @@ -30,9 +29,10 @@ import ( ) // MismatchError is the error type returned by the verify functions. -// Then the caller will know if there is a mismatch. +// It contains the diff content. type MismatchError struct { - Err error + Err error + diff string } func (e *MismatchError) Unwrap() error { return e.Err } @@ -41,65 +41,57 @@ func (e *MismatchError) Error() string { 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 { +func VerifyDataFile(actualFile, expectedData string) error { actualData, err := util.ReadFileContent(actualFile) if err != nil { - logger.Log.Error("failed to read the actual data file") - return err + return fmt.Errorf("failed to read the actual data file: %v", err) } - expectedTemplate, err := util.ReadFileContent(expectedFile) + return verify(actualData, expectedData) +} + +// VerifyQuery gets the actual data from the query and then verifies. +func VerifyQuery(query, expectedData string) error { + queryResult, err := util.ExecuteCommand(query) if err != nil { - logger.Log.Error("failed to read the expected data file") - return err + return fmt.Errorf("failed to execute the query: %v", err) } - return verify(actualData, expectedTemplate) -} + // TODO: ensure that the query result has the same format as expected data -// VerifyQuery gets the actual data from the query and then verifies. -func VerifyQuery(query, expectedFile string) error { - return errors.New("not implemented") + return verify(queryResult, expectedData) } // 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 { 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/config/globalConfig.go b/internal/config/globalConfig.go index f8c1334..c2bf184 100644 --- a/internal/config/globalConfig.go +++ b/internal/config/globalConfig.go @@ -20,6 +20,7 @@ package config import ( "fmt" + "github.com/apache/skywalking-infra-e2e/internal/logger" "io/ioutil" "gopkg.in/yaml.v2" @@ -57,4 +58,5 @@ func ReadGlobalConfigFile(configFilePath string) { 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..ab97c3c 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,20 @@ func ReadFileContent(filename string) (string, error) { } return "", errors.New("the file does not exist") } + +// ExecuteCommand executes the given command and returns the result. +// TODO: consider security issues. +func ExecuteCommand(cmd string) (string, error) { + command := exec.Command(cmd) + outinfo := bytes.Buffer{} + command.Stdout = &outinfo + + if err := command.Start(); err != nil { + return "", err + } + if err := command.Wait(); err != nil { + return "", err + } else { + return outinfo.String(), nil + } +}
