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

wusheng pushed a commit to branch feat/no-duplicates
in repository https://gitbox.apache.org/repos/asf/skywalking-infra-e2e.git

commit e2c67fb9cf7d9af2a031d6332d86ec767b13dfdf
Author: Wu Sheng <[email protected]>
AuthorDate: Tue Apr 14 06:45:25 2026 +0800

    feat: add noDuplicates pipe function for duplicate data verification
    
    Add a noDuplicates template pipe function that checks a list for
    duplicate entries. Works with contains, containsOnce, and range.
    
    Resolves apache/skywalking#12253
    
    Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
---
 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{

Reply via email to