You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by ho...@apache.org on 2021/02/06 12:56:58 UTC
[skywalking-infra-e2e] 03/04: Implement the verify of actual data
file
This is an automated email from the ASF dual-hosted git repository.
hoshea pushed a commit to branch verifier
in repository https://gitbox.apache.org/repos/asf/skywalking-infra-e2e.git
commit c1f23bd9b8daaf6b0d52327ea3387260a5c154e2
Author: Hoshea <fg...@gmail.com>
AuthorDate: Sat Feb 6 20:54:59 2021 +0800
Implement the verify of actual data file
---
commands/verify/verify.go | 18 +++-
internal/components/verifier/funcs.go | 54 ++++++++++++
internal/components/verifier/verifier.go | 89 +++++++++++++++++++
internal/config/e2eConfig.go | 9 +-
internal/util/utils.go | 14 +++
test.go | 142 -------------------------------
test/verify/1.actual.yaml | 24 ++++++
test/verify/1.expected.yaml | 24 ++++++
8 files changed, 230 insertions(+), 144 deletions(-)
diff --git a/commands/verify/verify.go b/commands/verify/verify.go
index 34c122c..06b908b 100644
--- a/commands/verify/verify.go
+++ b/commands/verify/verify.go
@@ -19,14 +19,30 @@ package verify
import (
"fmt"
+ "github.com/apache/skywalking-infra-e2e/internal/components/verifier"
"github.com/spf13/cobra"
)
+var (
+ query string
+ actual string
+ expected string
+)
+
+func init() {
+ Verify.Flags().StringVarP(&query, "query", "q", "", "the query to get the actual data, the result of the query should in YAML format")
+ Verify.Flags().StringVarP(&actual, "actual", "a", "", "the actual data file, only YAML file format is supported")
+ Verify.Flags().StringVarP(&expected, "expected", "e", "", "the expected data file, only YAML file format is supported")
+}
+
var Verify = &cobra.Command{
Use: "verify",
- Short: "",
+ 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)
+ }
fmt.Println("Not implemented.")
return nil
},
diff --git a/internal/components/verifier/funcs.go b/internal/components/verifier/funcs.go
new file mode 100644
index 0000000..597bb89
--- /dev/null
+++ b/internal/components/verifier/funcs.go
@@ -0,0 +1,54 @@
+package verifier
+
+import (
+ "encoding/base64"
+ "fmt"
+ "regexp"
+ "strings"
+
+ "github.com/apache/skywalking-infra-e2e/third-party/template"
+)
+
+// funcMap produces the custom function map.
+// Use this to pass the functions into the template engine:
+// tpl := template.New("foo").Funcs(funcMap()))
+func funcMap() template.FuncMap {
+ fm := make(map[string]interface{}, len(customFuncMap))
+ for k, v := range customFuncMap {
+ fm[k] = v
+ }
+ return template.FuncMap(fm)
+}
+
+var customFuncMap = map[string]interface{}{
+ // Basic:
+ "notEmpty": notEmpty,
+
+ // Encoding:
+ "b64enc": base64encode,
+
+ // Regex:
+ "regexp": regexpMatch,
+}
+
+func base64encode(s string) string {
+ return base64.StdEncoding.EncodeToString([]byte(s))
+}
+
+func notEmpty(s string) string {
+ if len(strings.TrimSpace(s)) > 0 {
+ return s
+ }
+ return fmt.Sprintf(`<"%s" is empty, wanted is not empty>`, s)
+}
+
+func regexpMatch(s, pattern string) string {
+ matched, err := regexp.MatchString(pattern, s)
+ if err != nil {
+ return fmt.Sprintf(`<"%s">`, err)
+ }
+ if !matched {
+ return fmt.Sprintf(`<"%s" does not match the pattern %s">`, s, pattern)
+ }
+ return s
+}
diff --git a/internal/components/verifier/verifier.go b/internal/components/verifier/verifier.go
new file mode 100644
index 0000000..4c46263
--- /dev/null
+++ b/internal/components/verifier/verifier.go
@@ -0,0 +1,89 @@
+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/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.
+type MismatchError struct {
+ Err error
+}
+
+func (e *MismatchError) Unwrap() error { return e.Err }
+
+func (e *MismatchError) Error() string {
+ if e == nil {
+ return "<nil>"
+ }
+ return "the actual data does not match the expected data"
+}
+
+// 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 {
+ var actual interface{}
+ if err := yaml.Unmarshal([]byte(actualData), &actual); err != nil {
+ logger.Log.Error("failed to unmarshal actual data")
+ return err
+ }
+
+ tmpl, err := template.New("test").Funcs(funcMap()).Parse(expectedTemplate)
+ if err != nil {
+ logger.Log.Error("failed to parse template")
+ return err
+ }
+
+ var b bytes.Buffer
+ if err := tmpl.Execute(&b, actual); err != nil {
+ logger.Log.Error("failed to execute template")
+ return err
+ }
+
+ var expected interface{}
+ if err := yaml.Unmarshal(b.Bytes(), &expected); err != nil {
+ logger.Log.Error("failed to unmarshal expected data")
+ return err
+ }
+
+ if !cmp.Equal(expected, actual) {
+ diff := cmp.Diff(expected, actual)
+ fmt.Println(diff)
+ return &MismatchError{}
+ } else {
+ logger.Log.Info("the actual data matches the expected data")
+ }
+
+ return nil
+}
diff --git a/internal/config/e2eConfig.go b/internal/config/e2eConfig.go
index 836e582..c242947 100644
--- a/internal/config/e2eConfig.go
+++ b/internal/config/e2eConfig.go
@@ -20,7 +20,8 @@ package config
// E2EConfig corresponds to configuration file e2e.yaml.
type E2EConfig struct {
- Setup Setup `yaml:"setup"`
+ Setup Setup `yaml:"setup"`
+ Verify []VerifyCase `yaml:"verify"`
}
type Setup struct {
@@ -48,3 +49,9 @@ type Wait struct {
LabelSelector string `yaml:"label-selector"`
For string `yaml:"for"`
}
+
+type VerifyCase struct {
+ Query string `yaml:"query"`
+ Actual string `yaml:"actual"`
+ Expected string `yaml:"expected"`
+}
diff --git a/internal/util/utils.go b/internal/util/utils.go
index 50030d7..0c2a2f0 100644
--- a/internal/util/utils.go
+++ b/internal/util/utils.go
@@ -19,6 +19,8 @@
package util
import (
+ "errors"
+ "io/ioutil"
"os"
"os/exec"
)
@@ -38,3 +40,15 @@ func PathExist(_path string) bool {
}
return true
}
+
+// ReadFileContent reads the file content.
+func ReadFileContent(filename string) (string, error) {
+ if PathExist(filename) {
+ content, err := ioutil.ReadFile(filename)
+ if err != nil {
+ return "", err
+ }
+ return string(content), nil
+ }
+ return "", errors.New("the file does not exist")
+}
diff --git a/test.go b/test.go
deleted file mode 100644
index cbdfe8e..0000000
--- a/test.go
+++ /dev/null
@@ -1,142 +0,0 @@
-package main
-
-import (
- "bytes"
- "encoding/base64"
- "fmt"
- "github.com/apache/skywalking-infra-e2e/third-party/template"
- "github.com/google/go-cmp/cmp"
- "gopkg.in/yaml.v3"
- "log"
- "strings"
-)
-
-var funcMap = template.FuncMap{
- "b64enc": func(s string) string {
- return base64.StdEncoding.EncodeToString([]byte(s))
- },
- "notEmpty": func(s string) string {
- if len(strings.TrimSpace(s)) > 0 {
- return s
- } else {
- return fmt.Sprintf(`<"%s" is empty, wanted is not empty>`, s)
- }
- },
-}
-
-func main() {
- test(`
-nodes:
- - id: VXNlcg==.0
- name: User
- type: USER
- isReal: false
- - id: WW91cl9BcHBsaWNhdGlvbk5hbWU=.1
- name: Your_ApplicationName
- type: Tomcat
- isReal: true
- - id: bG9jYWxob3N0Oi0x.0
- name: localhost:-1
- type: H2
- isReal: false
-calls:
- - id: WW91cl9BcHBsaWNhdGlvbk5hbWU=.1-bG9jYWxob3N0Oi0x.0
- source: WW91cl9BcHBsaWNhdGlvbk5hbWU=.1
- detectPoints:
- - CLIENT
- target: bG9jYWxob3N0Oi0x.0
- - id: VXNlcg==.0-WW91cl9BcHBsaWNhdGlvbk5hbWU=.1
- source: VXNlcg==.0
- detectPoints:
- - SERVER
- target: WW91cl9BcHBsaWNhdGlvbk5hbWU=.1
-`, `
-nodes:
- - id: {{ b64enc "User" }}.0
- name: User
- type: USER
- isReal: false
- - id: {{ b64enc "Your_ApplicationName" }}.1
- name: Your_ApplicationName
- type: Tomcat
- isReal: true
- - id: {{ $h2ID := (index .nodes 2).id }}{{ notEmpty $h2ID }}
- name: localhost:-1
- type: H2
- isReal: false
-calls:
- - id: {{ notEmpty (index .calls 0).id }}
- source: {{ b64enc "Your_ApplicationName" }}.1
- target: {{ $h2ID }}
- detectPoints:
- - CLIENT
- - id: {{ b64enc "User" }}.0-{{ b64enc "Your_ApplicationName" }}.1
- source: {{ b64enc "User" }}.0
- target: {{ b64enc "Your_ApplicationName" }}.1
- detectPoints:
- - SERVER
-`)
-
- test(`
-metrics:
- - name: business-zone::projectA
- id: YnVzaW5lc3Mtem9uZTo6cHJvamVjdEE=.1
- value: 1
- - name: system::load balancer1
- id: c3lzdGVtOjpsb2FkIGJhbGFuY2VyMQ==.1
- value: 0
- - name: system::load balancer2
- id: c3lzdGVtOjpsb2FkIGJhbGFuY2VyMg==.1
- value: 0
-`, `
-metrics:
-{{- atLeastOnce .metrics }}
- name: {{ notEmpty .name }}
- id: {{ notEmpty .id }}
- value: {{ gt .value 0 }}
-{{- end }}
-`)
- test(`
-metrics:
- - name: business-zone::projectA
- id: YnVzaW5lc3Mtem9uZTo6cHJvamVjdEE=.1
- value: 0
- - name: system::load balancer1
- id: c3lzdGVtOjpsb2FkIGJhbGFuY2VyMQ==.1
- value: 0
- - name: system::load balancer2
- id: c3lzdGVtOjpsb2FkIGJhbGFuY2VyMg==.1
- value: 0
-`, `
-metrics:
-{{- atLeastOnce .metrics }}
- name: {{ notEmpty .name }}
- id: {{ notEmpty .id }}
- value: {{ gt .value 0 }}
-{{- end }}
-`)
-}
-
-func test(actualData string, expectedTemplate string) {
- var actual interface{}
- yaml.Unmarshal([]byte(actualData), &actual)
-
- tmpl, err := template.New("test").Funcs(funcMap).Parse(expectedTemplate)
- if err != nil {
- log.Fatalf("parsing: %s", err)
- }
-
- var b bytes.Buffer
- err = tmpl.Execute(&b, actual)
- if err != nil {
- log.Fatalf("execution: %s", err)
- }
-
- var expected interface{}
- yaml.Unmarshal(b.Bytes(), &expected)
-
- if !cmp.Equal(expected, actual) {
- diff := cmp.Diff(expected, actual)
- println(diff)
- }
-}
diff --git a/test/verify/1.actual.yaml b/test/verify/1.actual.yaml
new file mode 100644
index 0000000..1e3d89d
--- /dev/null
+++ b/test/verify/1.actual.yaml
@@ -0,0 +1,24 @@
+nodes:
+ - id: VXNlcg==.0
+ name: User
+ type: USER
+ isReal: false
+ - id: WW91cl9BcHBsaWNhdGlvbk5hbWU=.1
+ name: Your_ApplicationName
+ type: Tomcat
+ isReal: true
+ - id: bG9jYWxob3N0Oi0x.0
+ name: localhost:-1
+ type: H2
+ isReal: false
+calls:
+ - id: WW91cl9BcHBsaWNhdGlvbk5hbWU=.1-bG9jYWxob3N0Oi0x.0
+ source: WW91cl9BcHBsaWNhdGlvbk5hbWU=.1
+ detectPoints:
+ - CLIENT
+ target: bG9jYWxob3N0Oi0x.0
+ - id: VXNlcg==.0-WW91cl9BcHBsaWNhdGlvbk5hbWU=.1
+ source: VXNlcg==.0
+ detectPoints:
+ - SERVER
+ target: WW91cl9BcHBsaWNhdGlvbk5hbWU=.1
\ No newline at end of file
diff --git a/test/verify/1.expected.yaml b/test/verify/1.expected.yaml
new file mode 100644
index 0000000..23b8076
--- /dev/null
+++ b/test/verify/1.expected.yaml
@@ -0,0 +1,24 @@
+nodes:
+ - id: {{ b64enc "User" }}.0
+ name: User
+ type: USER
+ isReal: false
+ - id: {{ b64enc "Your_ApplicationName" }}.1
+ name: Your_ApplicationName
+ type: Tomcat
+ isReal: true
+ - id: {{ $h2ID := (index .nodes 2).id }}{{ notEmpty $h2ID }}
+ name: localhost:-1
+ type: H2
+ isReal: false
+calls:
+ - id: {{ notEmpty (index .calls 0).id }}
+ source: {{ b64enc "Your_ApplicationName" }}.1
+ target: {{ $h2ID }}
+ detectPoints:
+ - CLIENT
+ - id: {{ b64enc "User" }}.0-{{ b64enc "Your_ApplicationName" }}.1
+ source: {{ b64enc "User" }}.0
+ target: {{ b64enc "Your_ApplicationName" }}.1
+ detectPoints:
+ - SERVER
\ No newline at end of file