This is an automated email from the ASF dual-hosted git repository.
wusheng pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/skywalking-infra-e2e.git
The following commit(s) were added to refs/heads/main by this push:
new ef073ad feat: add noDuplicates pipe function for duplicate data
verification (#145)
ef073ad is described below
commit ef073adb8b9e148e4eaf3f905fa4e238ee5cc7d6
Author: 吴晟 Wu Sheng <[email protected]>
AuthorDate: Tue Apr 14 08:19:32 2026 +0800
feat: add noDuplicates pipe function for duplicate data verification (#145)
---
docs/en/setup/Configuration-File.md | 13 +++++
internal/components/verifier/funcs.go | 18 +++++++
internal/components/verifier/verifier_test.go | 77 +++++++++++++++++++++++++++
3 files changed, 108 insertions(+)
diff --git a/docs/en/setup/Configuration-File.md
b/docs/en/setup/Configuration-File.md
index fd4c77a..fa5104d 100644
--- a/docs/en/setup/Configuration-File.md
+++ b/docs/en/setup/Configuration-File.md
@@ -248,6 +248,19 @@ For example, if a generic expected entry (e.g.,
`notEmpty`) appears before a spe
{{- end }}
```
+##### Duplicate Detection
+
+`noDuplicates` is a pipe function that verifies a list contains no duplicate
items. Two items are considered duplicates when all their fields are equal. It
can be combined with `contains`, `containsOnce`, or `range`.
+
+```yaml
+{{- contains (.metrics | noDuplicates) }}
+- name: {{ notEmpty .name }}
+ value: {{ notEmpty .value }}
+{{- end }}
+```
+
+When duplicates exist in the actual data, verification will fail with an error
indicating the duplicated item.
+
##### Encoding
In order to make the program easier for users to read and use, some code
conversions are provided.
diff --git a/internal/components/verifier/funcs.go
b/internal/components/verifier/funcs.go
index f0ca3d4..caffc0a 100644
--- a/internal/components/verifier/funcs.go
+++ b/internal/components/verifier/funcs.go
@@ -54,6 +54,9 @@ var customFuncMap = map[string]any{
// Calculation:
"subtractor": subtractor,
+
+ // List:
+ "noDuplicates": noDuplicates,
}
func base64encode(s string) string {
@@ -103,3 +106,18 @@ func subtractor(total int, nums ...int) int {
}
return total
}
+
+func noDuplicates(list any) any {
+ items, ok := list.([]any)
+ if !ok {
+ return list
+ }
+ for i := 0; i < len(items); i++ {
+ for j := i + 1; j < len(items); j++ {
+ if fmt.Sprint(items[i]) == fmt.Sprint(items[j]) {
+ return fmt.Sprintf("<duplicate found: %v>",
items[i])
+ }
+ }
+ }
+ return list
+}
diff --git a/internal/components/verifier/verifier_test.go
b/internal/components/verifier/verifier_test.go
index dfa5634..01aa3b5 100644
--- a/internal/components/verifier/verifier_test.go
+++ b/internal/components/verifier/verifier_test.go
@@ -501,6 +501,83 @@ metrics:
},
wantErr: true, // service-A does not exist in actual
},
+ {
+ name: "noDuplicates should pass when list has no
duplicates",
+ args: args{
+ actualData: `
+metrics:
+ - name: service-A
+ value: "100"
+ - name: service-B
+ value: "200"
+`,
+ expectedTemplate: `
+metrics:
+{{- contains (.metrics | noDuplicates) }}
+ - name: {{ notEmpty .name }}
+ value: {{ notEmpty .value }}
+{{- end }}
+`,
+ },
+ wantErr: false,
+ },
+ {
+ name: "noDuplicates should fail when list has duplicate
items",
+ args: args{
+ actualData: `
+metrics:
+ - name: service-A
+ value: "100"
+ - name: service-A
+ value: "100"
+`,
+ expectedTemplate: `
+metrics:
+{{- contains (.metrics | noDuplicates) }}
+ - name: {{ notEmpty .name }}
+ value: {{ notEmpty .value }}
+{{- end }}
+`,
+ },
+ wantErr: true, // duplicate entry exists
+ },
+ {
+ name: "noDuplicates should work with containsOnce",
+ args: args{
+ actualData: `
+- name: service-A
+ value: "100"
+- name: service-B
+ value: "200"
+- name: service-A
+ value: "100"
+`,
+ expectedTemplate: `
+{{- containsOnce (. | noDuplicates) }}
+- name: {{ notEmpty .name }}
+ value: {{ notEmpty .value }}
+{{- end }}
+`,
+ },
+ wantErr: true, // duplicate entry exists even though
containsOnce would pass
+ },
+ {
+ name: "noDuplicates should pass with range and no
duplicates",
+ args: args{
+ actualData: `
+metrics:
+ - name: service-A
+ - name: service-B
+`,
+ expectedTemplate: `
+metrics:
+{{- range (.metrics | noDuplicates) }}
+ - name: {{ notEmpty .name }}
+{{- end }}
+`,
+ },
+ wantErr: false,
+ },
{
name: "notEmpty with nil",
args: args{