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/28 08:49:23 UTC

[skywalking-infra-e2e] 01/01: implement the `contains` action

This is an automated email from the ASF dual-hosted git repository.

hoshea pushed a commit to branch verifier/action
in repository https://gitbox.apache.org/repos/asf/skywalking-infra-e2e.git

commit fc27a2cda657f5a5a3b2e654cc0522a302cf206b
Author: Hoshea <fg...@gmail.com>
AuthorDate: Sun Feb 28 16:48:46 2021 +0800

    implement the `contains` action
---
 internal/components/verifier/verifier.go |  1 +
 test/verify/2.actual.yaml                | 10 ++++++
 test/verify/2.expected.yaml              |  5 +++
 third-party/go/template/exec.go          | 48 +++++++++++++------------
 third-party/go/template/parse/lex.go     | 46 ++++++++++++------------
 third-party/go/template/parse/node.go    | 62 ++++++++++++++++----------------
 third-party/go/template/parse/parse.go   | 12 +++----
 7 files changed, 101 insertions(+), 83 deletions(-)

diff --git a/internal/components/verifier/verifier.go b/internal/components/verifier/verifier.go
index 84150c1..2f4675a 100644
--- a/internal/components/verifier/verifier.go
+++ b/internal/components/verifier/verifier.go
@@ -94,6 +94,7 @@ func verify(actualData, expectedTemplate string) error {
 	}
 
 	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{}
diff --git a/test/verify/2.actual.yaml b/test/verify/2.actual.yaml
new file mode 100644
index 0000000..521f4a1
--- /dev/null
+++ b/test/verify/2.actual.yaml
@@ -0,0 +1,10 @@
+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
\ No newline at end of file
diff --git a/test/verify/2.expected.yaml b/test/verify/2.expected.yaml
new file mode 100644
index 0000000..30819b0
--- /dev/null
+++ b/test/verify/2.expected.yaml
@@ -0,0 +1,5 @@
+metrics:
+{{- contains .metrics }}
+  - name: {{ notEmpty .name }}
+    value: {{ gt .value 0 }}
+{{- end }}
\ No newline at end of file
diff --git a/third-party/go/template/exec.go b/third-party/go/template/exec.go
index b4af1ad..6eca6a7 100644
--- a/third-party/go/template/exec.go
+++ b/third-party/go/template/exec.go
@@ -7,13 +7,16 @@ package template
 import (
 	"bytes"
 	"fmt"
-	"github.com/apache/skywalking-infra-e2e/third-party/go/internal/fmtsort"
-	"github.com/apache/skywalking-infra-e2e/third-party/go/template/parse"
-	"gopkg.in/yaml.v3"
 	"io"
+	"os"
 	"reflect"
 	"runtime"
 	"strings"
+
+	"github.com/apache/skywalking-infra-e2e/third-party/go/internal/fmtsort"
+	"github.com/apache/skywalking-infra-e2e/third-party/go/template/parse"
+
+	"gopkg.in/yaml.v2"
 )
 
 // maxExecDepth specifies the maximum stack depth of templates within
@@ -274,8 +277,8 @@ func (s *state) walk(dot reflect.Value, node parse.Node) {
 		}
 	case *parse.WithNode:
 		s.walkIfOrWith(parse.NodeWith, dot, node.Pipe, node.List, node.ElseList)
-	case *parse.AtLeastOnceNode:
-		s.walkAtLeastOnce(dot, node)
+	case *parse.ContainsNode:
+		s.walkContains(dot, node)
 	default:
 		s.errorf("unknown node: %s", node)
 	}
@@ -398,7 +401,7 @@ func (s *state) walkRange(dot reflect.Value, r *parse.RangeNode) {
 	}
 }
 
-func (s *state) walkAtLeastOnce(dot reflect.Value, r *parse.AtLeastOnceNode) {
+func (s *state) walkContains(dot reflect.Value, r *parse.ContainsNode) {
 	s.at(r)
 	defer s.pop(s.mark())
 	val, _ := indirect(s.evalPipeline(dot, r.Pipe))
@@ -431,25 +434,27 @@ func (s *state) walkAtLeastOnce(dot reflect.Value, r *parse.AtLeastOnceNode) {
 		if val.Len() == 0 {
 			break
 		}
-		match := false
+		//match := false
 		sss := make([]interface{}, val.Len())
 		for i := 0; i < val.Len(); i++ {
 			actual := oneIteration(reflect.ValueOf(i), val.Index(i))
 			sss[i] = actual
 			value, _ := printableValue(val.Index(i))
-			if fmt.Sprint(value) == fmt.Sprint(actual) {
-				match = true
-				break
-			}
-		}
-		var marshal []byte
-		if match {
-			value, _ := printableValue(val)
-			marshal, _ = yaml.Marshal(value)
-		} else {
-			marshal, _ = yaml.Marshal(sss)
+			io.WriteString(os.Stdout, fmt.Sprintln(actual))
+			io.WriteString(os.Stdout, fmt.Sprintln(value))
+			//if fmt.Sprint(value) == fmt.Sprint(actual) {
+			//	match = true
+			//	break
+			//}
 		}
-		s.wr.Write(append([]byte("\n"), marshal...))
+		//var marshal []byte
+		//if match {
+		//	value, _ := printableValue(val)
+		//	marshal, _ = yaml.Marshal(value)
+		//} else {
+		//	marshal, _ = yaml.Marshal(sss)
+		//}
+		//s.wr.Write(append([]byte("\n"), marshal...))
 		return
 	case reflect.Map:
 		if val.Len() == 0 {
@@ -479,10 +484,7 @@ func (s *state) walkAtLeastOnce(dot reflect.Value, r *parse.AtLeastOnceNode) {
 	case reflect.Invalid:
 		break // An invalid value is likely a nil map, etc. and acts like an empty map.
 	default:
-		s.errorf("range can't iterate over %v", val)
-	}
-	if r.ElseList != nil {
-		s.walk(dot, r.ElseList)
+		s.errorf("contains can't iterate over %v", val)
 	}
 }
 
diff --git a/third-party/go/template/parse/lex.go b/third-party/go/template/parse/lex.go
index 8ebb789..19eed9a 100644
--- a/third-party/go/template/parse/lex.go
+++ b/third-party/go/template/parse/lex.go
@@ -59,32 +59,32 @@ const (
 	itemText       // plain text
 	itemVariable   // variable starting with '$', such as '$' or  '$1' or '$hello'
 	// Keywords appear after all the rest.
-	itemKeyword     // used only to delimit the keywords
-	itemBlock       // block keyword
-	itemDot         // the cursor, spelled '.'
-	itemDefine      // define keyword
-	itemElse        // else keyword
-	itemEnd         // end keyword
-	itemIf          // if keyword
-	itemNil         // the untyped nil constant, easiest to treat as a keyword
-	itemRange       // range keyword
-	itemTemplate    // template keyword
-	itemWith        // with keyword
-	itemAtLeastOnce // atLeastOnce keyword
+	itemKeyword  // used only to delimit the keywords
+	itemBlock    // block keyword
+	itemDot      // the cursor, spelled '.'
+	itemDefine   // define keyword
+	itemElse     // else keyword
+	itemEnd      // end keyword
+	itemIf       // if keyword
+	itemNil      // the untyped nil constant, easiest to treat as a keyword
+	itemRange    // range keyword
+	itemTemplate // template keyword
+	itemWith     // with keyword
+	itemContains // contains keyword
 )
 
 var key = map[string]itemType{
-	".":           itemDot,
-	"block":       itemBlock,
-	"define":      itemDefine,
-	"else":        itemElse,
-	"end":         itemEnd,
-	"if":          itemIf,
-	"range":       itemRange,
-	"nil":         itemNil,
-	"template":    itemTemplate,
-	"with":        itemWith,
-	"atLeastOnce": itemAtLeastOnce,
+	".":        itemDot,
+	"block":    itemBlock,
+	"define":   itemDefine,
+	"else":     itemElse,
+	"end":      itemEnd,
+	"if":       itemIf,
+	"range":    itemRange,
+	"nil":      itemNil,
+	"template": itemTemplate,
+	"with":     itemWith,
+	"contains": itemContains,
 }
 
 const eof = -1
diff --git a/third-party/go/template/parse/node.go b/third-party/go/template/parse/node.go
index 57ca52c..938d5bf 100644
--- a/third-party/go/template/parse/node.go
+++ b/third-party/go/template/parse/node.go
@@ -50,27 +50,27 @@ func (t NodeType) Type() NodeType {
 }
 
 const (
-	NodeText        NodeType = iota // Plain text.
-	NodeAction                      // A non-control action such as a field evaluation.
-	NodeBool                        // A boolean constant.
-	NodeChain                       // A sequence of field accesses.
-	NodeCommand                     // An element of a pipeline.
-	NodeDot                         // The cursor, dot.
-	nodeElse                        // An else action. Not added to tree.
-	nodeEnd                         // An end action. Not added to tree.
-	NodeField                       // A field or method name.
-	NodeIdentifier                  // An identifier; always a function name.
-	NodeIf                          // An if action.
-	NodeList                        // A list of Nodes.
-	NodeNil                         // An untyped nil constant.
-	NodeNumber                      // A numerical constant.
-	NodePipe                        // A pipeline of commands.
-	NodeRange                       // A range action.
-	NodeString                      // A string constant.
-	NodeTemplate                    // A template invocation action.
-	NodeVariable                    // A $ variable.
-	NodeWith                        // A with action.
-	NodeAtLeastOnce                 // An atLeastOnce action.
+	NodeText       NodeType = iota // Plain text.
+	NodeAction                     // A non-control action such as a field evaluation.
+	NodeBool                       // A boolean constant.
+	NodeChain                      // A sequence of field accesses.
+	NodeCommand                    // An element of a pipeline.
+	NodeDot                        // The cursor, dot.
+	nodeElse                       // An else action. Not added to tree.
+	nodeEnd                        // An end action. Not added to tree.
+	NodeField                      // A field or method name.
+	NodeIdentifier                 // An identifier; always a function name.
+	NodeIf                         // An if action.
+	NodeList                       // A list of Nodes.
+	NodeNil                        // An untyped nil constant.
+	NodeNumber                     // A numerical constant.
+	NodePipe                       // A pipeline of commands.
+	NodeRange                      // A range action.
+	NodeString                     // A string constant.
+	NodeTemplate                   // A template invocation action.
+	NodeVariable                   // A $ variable.
+	NodeWith                       // A with action.
+	NodeContains                   // A contains action.
 )
 
 // Nodes.
@@ -829,8 +829,8 @@ func (b *BranchNode) writeTo(sb *strings.Builder) {
 		name = "range"
 	case NodeWith:
 		name = "with"
-	case NodeAtLeastOnce:
-		name = "atLeastOnce"
+	case NodeContains:
+		name = "contains"
 	default:
 		panic("unknown branch type")
 	}
@@ -859,8 +859,8 @@ func (b *BranchNode) Copy() Node {
 		return b.tr.newRange(b.Pos, b.Line, b.Pipe, b.List, b.ElseList)
 	case NodeWith:
 		return b.tr.newWith(b.Pos, b.Line, b.Pipe, b.List, b.ElseList)
-	case NodeAtLeastOnce:
-		return b.tr.newAtLeastOnce(b.Pos, b.Line, b.Pipe, b.List, b.ElseList)
+	case NodeContains:
+		return b.tr.newContains(b.Pos, b.Line, b.Pipe, b.List, b.ElseList)
 	default:
 		panic("unknown branch type")
 	}
@@ -905,17 +905,17 @@ func (w *WithNode) Copy() Node {
 	return w.tr.newWith(w.Pos, w.Line, w.Pipe.CopyPipe(), w.List.CopyList(), w.ElseList.CopyList())
 }
 
-// AtLeastOnce represents a {{atLeastOnce}} action and its commands.
-type AtLeastOnceNode struct {
+// Contains represents a {{contains}} action and its commands.
+type ContainsNode struct {
 	BranchNode
 }
 
-func (t *Tree) newAtLeastOnce(pos Pos, line int, pipe *PipeNode, list *ListNode, elseList *ListNode) *AtLeastOnceNode {
-	return &AtLeastOnceNode{BranchNode{tr: t, NodeType: NodeAtLeastOnce, Pos: pos, Line: line, Pipe: pipe, List: list}}
+func (t *Tree) newContains(pos Pos, line int, pipe *PipeNode, list *ListNode, elseList *ListNode) *ContainsNode {
+	return &ContainsNode{BranchNode{tr: t, NodeType: NodeContains, Pos: pos, Line: line, Pipe: pipe, List: list}}
 }
 
-func (w *AtLeastOnceNode) Copy() Node {
-	return w.tr.newAtLeastOnce(w.Pos, w.Line, w.Pipe.CopyPipe(), w.List.CopyList(), w.ElseList.CopyList())
+func (w *ContainsNode) Copy() Node {
+	return w.tr.newContains(w.Pos, w.Line, w.Pipe.CopyPipe(), w.List.CopyList(), w.ElseList.CopyList())
 }
 
 // TemplateNode represents a {{template}} action.
diff --git a/third-party/go/template/parse/parse.go b/third-party/go/template/parse/parse.go
index 6698aaf..ce46c8b 100644
--- a/third-party/go/template/parse/parse.go
+++ b/third-party/go/template/parse/parse.go
@@ -365,8 +365,8 @@ func (t *Tree) action() (n Node) {
 		return t.templateControl()
 	case itemWith:
 		return t.withControl()
-	case itemAtLeastOnce:
-		return t.atLeastOnceControl()
+	case itemContains:
+		return t.containsControl()
 	}
 	t.backup()
 	token := t.peek()
@@ -506,11 +506,11 @@ func (t *Tree) withControl() Node {
 	return t.newWith(t.parseControl(false, "with"))
 }
 
-// AtLeastOnce:
-//	{{atLeastOnce number}} itemList {{end}}
+// Contains:
+//	{{contains number}} itemList {{end}}
 // If keyword is past.
-func (t *Tree) atLeastOnceControl() Node {
-	return t.newAtLeastOnce(t.parseControl(false, "atLeastOnce"))
+func (t *Tree) containsControl() Node {
+	return t.newContains(t.parseControl(false, "contains"))
 }
 
 // End: