From 43b0b9eeb984e6ed278142992ba9415eab28c61a Mon Sep 17 00:00:00 2001 From: dongjiang1989 Date: Fri, 12 Apr 2024 17:28:01 +0800 Subject: [PATCH 01/10] remove go-spew package Signed-off-by: dongjiang1989 --- go.mod | 2 +- go.sum | 1 + prometheus/testutil/testutil.go | 31 ++++-------------------- prometheus/testutil/testutil_test.go | 36 ++++++++++++++++++++-------- 4 files changed, 32 insertions(+), 38 deletions(-) diff --git a/go.mod b/go.mod index 8bbcb4356..5acb0bc26 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.20 require ( github.com/beorn7/perks v1.0.1 github.com/cespare/xxhash/v2 v2.2.0 - github.com/davecgh/go-spew v1.1.1 + github.com/google/go-cmp v0.6.0 github.com/json-iterator/go v1.1.12 github.com/prometheus/client_model v0.6.0 github.com/prometheus/common v0.52.3 diff --git a/go.sum b/go.sum index 2c696c73a..bd503a1b0 100644 --- a/go.sum +++ b/go.sum @@ -12,6 +12,7 @@ github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= diff --git a/prometheus/testutil/testutil.go b/prometheus/testutil/testutil.go index 9dce15eaf..e24baf2d8 100644 --- a/prometheus/testutil/testutil.go +++ b/prometheus/testutil/testutil.go @@ -44,7 +44,7 @@ import ( "net/http" "reflect" - "github.com/davecgh/go-spew/spew" + "github.com/google/go-cmp/cmp" dto "github.com/prometheus/client_model/go" "github.com/prometheus/common/expfmt" "google.golang.org/protobuf/proto" @@ -264,6 +264,7 @@ func compareMetricFamilies(got, expected []*dto.MetricFamily, metricNames ...str // The error contains the encoded text of both the desired and the actual // result. func compare(got, want []*dto.MetricFamily) error { + var gotBuf, wantBuf bytes.Buffer enc := expfmt.NewEncoder(&gotBuf, expfmt.NewFormat(expfmt.TypeTextPlain)) for _, mf := range got { @@ -277,7 +278,7 @@ func compare(got, want []*dto.MetricFamily) error { return fmt.Errorf("encoding expected metrics failed: %w", err) } } - if diffErr := diff(wantBuf, gotBuf); diffErr != "" { + if diffErr := diff(gotBuf.String(), wantBuf.String()); diffErr != "" { return fmt.Errorf(diffErr) } return nil @@ -300,31 +301,7 @@ func diff(expected, actual interface{}) string { return "" } - var e, a string - c := spew.ConfigState{ - Indent: " ", - DisablePointerAddresses: true, - DisableCapacities: true, - SortKeys: true, - } - if et != reflect.TypeOf("") { - e = c.Sdump(expected) - a = c.Sdump(actual) - } else { - e = reflect.ValueOf(expected).String() - a = reflect.ValueOf(actual).String() - } - - diff, _ := internal.GetUnifiedDiffString(internal.UnifiedDiff{ - A: internal.SplitLines(e), - B: internal.SplitLines(a), - FromFile: "metric output does not match expectation; want", - FromDate: "", - ToFile: "got:", - ToDate: "", - Context: 1, - }) - + diff := cmp.Diff(expected, actual) if diff == "" { return "" } diff --git a/prometheus/testutil/testutil_test.go b/prometheus/testutil/testutil_test.go index f2e1cbaff..054cf6317 100644 --- a/prometheus/testutil/testutil_test.go +++ b/prometheus/testutil/testutil_test.go @@ -305,20 +305,36 @@ func TestMetricNotFound(t *testing.T) { expected := ` some_other_metric{label1="value1"} 1 ` + /* + expectedError := ` + + Diff: + --- metric output does not match expectation; want + +++ got: + @@ -1,4 +1,4 @@ + -(bytes.Buffer) # HELP some_other_metric A value that represents a counter. + -# TYPE some_other_metric counter + -some_other_metric{label1="value1"} 1 + +(bytes.Buffer) # HELP some_total A value that represents a counter. + +# TYPE some_total counter + +some_total{label1="value1"} 1 + + ` + */ expectedError := ` Diff: ---- metric output does not match expectation; want -+++ got: -@@ -1,4 +1,4 @@ --(bytes.Buffer) # HELP some_other_metric A value that represents a counter. --# TYPE some_other_metric counter --some_other_metric{label1="value1"} 1 -+(bytes.Buffer) # HELP some_total A value that represents a counter. -+# TYPE some_total counter -+some_total{label1="value1"} 1 - + ( + """ +- # HELP some_total A value that represents a counter. +- # TYPE some_total counter +- some_total{label1="value1"} 1 ++ # HELP some_other_metric A value that represents a counter. ++ # TYPE some_other_metric counter ++ some_other_metric{label1="value1"} 1 + """ + ) ` err := CollectAndCompare(c, strings.NewReader(metadata+expected)) From 49cd5c39f4fe80580a6bb15111db89a70ac39eaf Mon Sep 17 00:00:00 2001 From: dongjiang1989 Date: Fri, 12 Apr 2024 17:39:17 +0800 Subject: [PATCH 02/10] fix gofumpt lint Signed-off-by: dongjiang1989 --- prometheus/testutil/testutil.go | 1 - prometheus/testutil/testutil_test.go | 16 ---------------- 2 files changed, 17 deletions(-) diff --git a/prometheus/testutil/testutil.go b/prometheus/testutil/testutil.go index e24baf2d8..98ed75bd1 100644 --- a/prometheus/testutil/testutil.go +++ b/prometheus/testutil/testutil.go @@ -264,7 +264,6 @@ func compareMetricFamilies(got, expected []*dto.MetricFamily, metricNames ...str // The error contains the encoded text of both the desired and the actual // result. func compare(got, want []*dto.MetricFamily) error { - var gotBuf, wantBuf bytes.Buffer enc := expfmt.NewEncoder(&gotBuf, expfmt.NewFormat(expfmt.TypeTextPlain)) for _, mf := range got { diff --git a/prometheus/testutil/testutil_test.go b/prometheus/testutil/testutil_test.go index 054cf6317..12cb7a879 100644 --- a/prometheus/testutil/testutil_test.go +++ b/prometheus/testutil/testutil_test.go @@ -305,22 +305,6 @@ func TestMetricNotFound(t *testing.T) { expected := ` some_other_metric{label1="value1"} 1 ` - /* - expectedError := ` - - Diff: - --- metric output does not match expectation; want - +++ got: - @@ -1,4 +1,4 @@ - -(bytes.Buffer) # HELP some_other_metric A value that represents a counter. - -# TYPE some_other_metric counter - -some_other_metric{label1="value1"} 1 - +(bytes.Buffer) # HELP some_total A value that represents a counter. - +# TYPE some_total counter - +some_total{label1="value1"} 1 - - ` - */ expectedError := ` From 7a32d193eb2330b71b9b78d04f558a7c97363564 Mon Sep 17 00:00:00 2001 From: dongjiang1989 Date: Fri, 12 Apr 2024 18:19:37 +0800 Subject: [PATCH 03/10] fix unittest unicode Signed-off-by: dongjiang1989 --- prometheus/testutil/testutil_test.go | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/prometheus/testutil/testutil_test.go b/prometheus/testutil/testutil_test.go index 12cb7a879..8715d514b 100644 --- a/prometheus/testutil/testutil_test.go +++ b/prometheus/testutil/testutil_test.go @@ -300,34 +300,20 @@ func TestMetricNotFound(t *testing.T) { "label1": "value1", }, }) + c.Inc() expected := ` some_other_metric{label1="value1"} 1 ` - expectedError := ` - -Diff: - ( - """ -- # HELP some_total A value that represents a counter. -- # TYPE some_total counter -- some_total{label1="value1"} 1 -+ # HELP some_other_metric A value that represents a counter. -+ # TYPE some_other_metric counter -+ some_other_metric{label1="value1"} 1 - """ - ) -` - err := CollectAndCompare(c, strings.NewReader(metadata+expected)) if err == nil { t.Error("Expected error, got no error.") } - if err.Error() != expectedError { - t.Errorf("Expected\n%#+v\nGot:\n%#+v", expectedError, err.Error()) + if err.Error() == "" { + t.Errorf("Got:\n%#+v", err.Error()) } } From 638d3d40d807436418c5132b7c27c907cab5383b Mon Sep 17 00:00:00 2001 From: dongjiang1989 Date: Thu, 18 Apr 2024 20:19:10 +0800 Subject: [PATCH 04/10] dongjiang, change go-cmp to reflect Signed-off-by: dongjiang1989 --- prometheus/testutil/testutil.go | 30 ++---------------------------- 1 file changed, 2 insertions(+), 28 deletions(-) diff --git a/prometheus/testutil/testutil.go b/prometheus/testutil/testutil.go index 98ed75bd1..4babdfcb8 100644 --- a/prometheus/testutil/testutil.go +++ b/prometheus/testutil/testutil.go @@ -44,7 +44,6 @@ import ( "net/http" "reflect" - "github.com/google/go-cmp/cmp" dto "github.com/prometheus/client_model/go" "github.com/prometheus/common/expfmt" "google.golang.org/protobuf/proto" @@ -277,37 +276,12 @@ func compare(got, want []*dto.MetricFamily) error { return fmt.Errorf("encoding expected metrics failed: %w", err) } } - if diffErr := diff(gotBuf.String(), wantBuf.String()); diffErr != "" { - return fmt.Errorf(diffErr) + if diffErr := reflect.DeepEqual(gotBuf, wantBuf); !diffErr { + return fmt.Errorf("metrics diff") } return nil } -// diff returns a diff of both values as long as both are of the same type and -// are a struct, map, slice, array or string. Otherwise it returns an empty string. -func diff(expected, actual interface{}) string { - if expected == nil || actual == nil { - return "" - } - - et, ek := typeAndKind(expected) - at, _ := typeAndKind(actual) - if et != at { - return "" - } - - if ek != reflect.Struct && ek != reflect.Map && ek != reflect.Slice && ek != reflect.Array && ek != reflect.String { - return "" - } - - diff := cmp.Diff(expected, actual) - if diff == "" { - return "" - } - - return "\n\nDiff:\n" + diff -} - // typeAndKind returns the type and kind of the given interface{} func typeAndKind(v interface{}) (reflect.Type, reflect.Kind) { t := reflect.TypeOf(v) From 919eb7e6ca0bcfa9d70a34e525ee11deb4c947e6 Mon Sep 17 00:00:00 2001 From: dongjiang1989 Date: Fri, 19 Apr 2024 09:18:49 +0800 Subject: [PATCH 05/10] fix lint Signed-off-by: dongjiang1989 --- go.mod | 1 - go.sum | 1 - prometheus/testutil/testutil.go | 12 ------------ 3 files changed, 14 deletions(-) diff --git a/go.mod b/go.mod index 5acb0bc26..50378d251 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,6 @@ go 1.20 require ( github.com/beorn7/perks v1.0.1 github.com/cespare/xxhash/v2 v2.2.0 - github.com/google/go-cmp v0.6.0 github.com/json-iterator/go v1.1.12 github.com/prometheus/client_model v0.6.0 github.com/prometheus/common v0.52.3 diff --git a/go.sum b/go.sum index bd503a1b0..2c696c73a 100644 --- a/go.sum +++ b/go.sum @@ -12,7 +12,6 @@ github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= diff --git a/prometheus/testutil/testutil.go b/prometheus/testutil/testutil.go index 4babdfcb8..4471dd919 100644 --- a/prometheus/testutil/testutil.go +++ b/prometheus/testutil/testutil.go @@ -282,18 +282,6 @@ func compare(got, want []*dto.MetricFamily) error { return nil } -// typeAndKind returns the type and kind of the given interface{} -func typeAndKind(v interface{}) (reflect.Type, reflect.Kind) { - t := reflect.TypeOf(v) - k := t.Kind() - - if k == reflect.Ptr { - t = t.Elem() - k = t.Kind() - } - return t, k -} - func filterMetrics(metrics []*dto.MetricFamily, names []string) []*dto.MetricFamily { var filtered []*dto.MetricFamily for _, m := range metrics { From 00e09d54f473fa9f18a1254b1c2106dd6204ab89 Mon Sep 17 00:00:00 2001 From: dongjiang1989 Date: Fri, 19 Apr 2024 20:28:49 +0800 Subject: [PATCH 06/10] Revert "dongjiang, change go-cmp to reflect" This reverts commit bfbe25e926cbe45ed70b8e0df6ccec78c04d7247. Signed-off-by: dongjiang1989 --- go.mod | 1 + go.sum | 1 + prometheus/testutil/testutil.go | 42 +++++++++++++++++++++++++++++++-- 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 50378d251..5acb0bc26 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.20 require ( github.com/beorn7/perks v1.0.1 github.com/cespare/xxhash/v2 v2.2.0 + github.com/google/go-cmp v0.6.0 github.com/json-iterator/go v1.1.12 github.com/prometheus/client_model v0.6.0 github.com/prometheus/common v0.52.3 diff --git a/go.sum b/go.sum index 2c696c73a..bd503a1b0 100644 --- a/go.sum +++ b/go.sum @@ -12,6 +12,7 @@ github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= diff --git a/prometheus/testutil/testutil.go b/prometheus/testutil/testutil.go index 4471dd919..98ed75bd1 100644 --- a/prometheus/testutil/testutil.go +++ b/prometheus/testutil/testutil.go @@ -44,6 +44,7 @@ import ( "net/http" "reflect" + "github.com/google/go-cmp/cmp" dto "github.com/prometheus/client_model/go" "github.com/prometheus/common/expfmt" "google.golang.org/protobuf/proto" @@ -276,12 +277,49 @@ func compare(got, want []*dto.MetricFamily) error { return fmt.Errorf("encoding expected metrics failed: %w", err) } } - if diffErr := reflect.DeepEqual(gotBuf, wantBuf); !diffErr { - return fmt.Errorf("metrics diff") + if diffErr := diff(gotBuf.String(), wantBuf.String()); diffErr != "" { + return fmt.Errorf(diffErr) } return nil } +// diff returns a diff of both values as long as both are of the same type and +// are a struct, map, slice, array or string. Otherwise it returns an empty string. +func diff(expected, actual interface{}) string { + if expected == nil || actual == nil { + return "" + } + + et, ek := typeAndKind(expected) + at, _ := typeAndKind(actual) + if et != at { + return "" + } + + if ek != reflect.Struct && ek != reflect.Map && ek != reflect.Slice && ek != reflect.Array && ek != reflect.String { + return "" + } + + diff := cmp.Diff(expected, actual) + if diff == "" { + return "" + } + + return "\n\nDiff:\n" + diff +} + +// typeAndKind returns the type and kind of the given interface{} +func typeAndKind(v interface{}) (reflect.Type, reflect.Kind) { + t := reflect.TypeOf(v) + k := t.Kind() + + if k == reflect.Ptr { + t = t.Elem() + k = t.Kind() + } + return t, k +} + func filterMetrics(metrics []*dto.MetricFamily, names []string) []*dto.MetricFamily { var filtered []*dto.MetricFamily for _, m := range metrics { From a8e1df7a0bd3fe8d93875a480de3a64cada985a0 Mon Sep 17 00:00:00 2001 From: dongjiang1989 Date: Fri, 19 Apr 2024 20:41:53 +0800 Subject: [PATCH 07/10] change diff func Signed-off-by: dongjiang1989 --- go.mod | 2 +- go.sum | 3 +- prometheus/testutil/testutil.go | 42 ++-------------------------- prometheus/testutil/testutil_test.go | 12 ++++++-- 4 files changed, 15 insertions(+), 44 deletions(-) diff --git a/go.mod b/go.mod index 5acb0bc26..d9c20510e 100644 --- a/go.mod +++ b/go.mod @@ -5,8 +5,8 @@ go 1.20 require ( github.com/beorn7/perks v1.0.1 github.com/cespare/xxhash/v2 v2.2.0 - github.com/google/go-cmp v0.6.0 github.com/json-iterator/go v1.1.12 + github.com/kylelemons/godebug v1.1.0 github.com/prometheus/client_model v0.6.0 github.com/prometheus/common v0.52.3 github.com/prometheus/procfs v0.13.0 diff --git a/go.sum b/go.sum index bd503a1b0..a947a2de8 100644 --- a/go.sum +++ b/go.sum @@ -12,7 +12,6 @@ github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= @@ -22,6 +21,8 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= diff --git a/prometheus/testutil/testutil.go b/prometheus/testutil/testutil.go index 98ed75bd1..6ab370c4d 100644 --- a/prometheus/testutil/testutil.go +++ b/prometheus/testutil/testutil.go @@ -42,9 +42,8 @@ import ( "fmt" "io" "net/http" - "reflect" - "github.com/google/go-cmp/cmp" + godebug "github.com/kylelemons/godebug/diff" dto "github.com/prometheus/client_model/go" "github.com/prometheus/common/expfmt" "google.golang.org/protobuf/proto" @@ -277,49 +276,12 @@ func compare(got, want []*dto.MetricFamily) error { return fmt.Errorf("encoding expected metrics failed: %w", err) } } - if diffErr := diff(gotBuf.String(), wantBuf.String()); diffErr != "" { + if diffErr := godebug.Diff(gotBuf.String(), wantBuf.String()); diffErr != "" { return fmt.Errorf(diffErr) } return nil } -// diff returns a diff of both values as long as both are of the same type and -// are a struct, map, slice, array or string. Otherwise it returns an empty string. -func diff(expected, actual interface{}) string { - if expected == nil || actual == nil { - return "" - } - - et, ek := typeAndKind(expected) - at, _ := typeAndKind(actual) - if et != at { - return "" - } - - if ek != reflect.Struct && ek != reflect.Map && ek != reflect.Slice && ek != reflect.Array && ek != reflect.String { - return "" - } - - diff := cmp.Diff(expected, actual) - if diff == "" { - return "" - } - - return "\n\nDiff:\n" + diff -} - -// typeAndKind returns the type and kind of the given interface{} -func typeAndKind(v interface{}) (reflect.Type, reflect.Kind) { - t := reflect.TypeOf(v) - k := t.Kind() - - if k == reflect.Ptr { - t = t.Elem() - k = t.Kind() - } - return t, k -} - func filterMetrics(metrics []*dto.MetricFamily, names []string) []*dto.MetricFamily { var filtered []*dto.MetricFamily for _, m := range metrics { diff --git a/prometheus/testutil/testutil_test.go b/prometheus/testutil/testutil_test.go index 8715d514b..40374a01c 100644 --- a/prometheus/testutil/testutil_test.go +++ b/prometheus/testutil/testutil_test.go @@ -307,13 +307,21 @@ func TestMetricNotFound(t *testing.T) { some_other_metric{label1="value1"} 1 ` + expectedError := `-# HELP some_total A value that represents a counter. +-# TYPE some_total counter +-some_total{label1="value1"} 1 ++# HELP some_other_metric A value that represents a counter. ++# TYPE some_other_metric counter ++some_other_metric{label1="value1"} 1 + ` + err := CollectAndCompare(c, strings.NewReader(metadata+expected)) if err == nil { t.Error("Expected error, got no error.") } - if err.Error() == "" { - t.Errorf("Got:\n%#+v", err.Error()) + if err.Error() != expectedError { + t.Errorf("Expected\n%#+v\nGot:\n%#+v", expectedError, err.Error()) } } From d7f5c58211a68766018e49359eaf19a638726a17 Mon Sep 17 00:00:00 2001 From: dongjiang1989 Date: Mon, 22 Apr 2024 09:46:03 +0800 Subject: [PATCH 08/10] dongjiang, update diff package Signed-off-by: dongjiang1989 --- NOTICE | 5 + go.mod | 1 - go.sum | 2 - prometheus/testutil/diff/diff.go | 193 +++++++++++++++++++++ prometheus/testutil/diff/diff_test.go | 231 ++++++++++++++++++++++++++ prometheus/testutil/testutil.go | 4 +- 6 files changed, 431 insertions(+), 5 deletions(-) create mode 100644 prometheus/testutil/diff/diff.go create mode 100644 prometheus/testutil/diff/diff_test.go diff --git a/NOTICE b/NOTICE index dd878a30e..f3df630ad 100644 --- a/NOTICE +++ b/NOTICE @@ -21,3 +21,8 @@ Support for streaming Protocol Buffer messages for the Go language (golang). https://github.com/matttproud/golang_protobuf_extensions Copyright 2013 Matt T. Proud Licensed under the Apache License, Version 2.0 + +diff - a pretty-printed complete of a Go data structure +https://github.com/kylelemons/godebug +Copyright 2013 Google Inc. All rights reserved. +See source code for license details. diff --git a/go.mod b/go.mod index d9c20510e..50378d251 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,6 @@ require ( github.com/beorn7/perks v1.0.1 github.com/cespare/xxhash/v2 v2.2.0 github.com/json-iterator/go v1.1.12 - github.com/kylelemons/godebug v1.1.0 github.com/prometheus/client_model v0.6.0 github.com/prometheus/common v0.52.3 github.com/prometheus/procfs v0.13.0 diff --git a/go.sum b/go.sum index a947a2de8..2c696c73a 100644 --- a/go.sum +++ b/go.sum @@ -21,8 +21,6 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= -github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= diff --git a/prometheus/testutil/diff/diff.go b/prometheus/testutil/diff/diff.go new file mode 100644 index 000000000..b88625621 --- /dev/null +++ b/prometheus/testutil/diff/diff.go @@ -0,0 +1,193 @@ +// Copyright 2013 Google Inc. All rights reserved. +// +// Licensed 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. +// +// The code in this package is copy/paste to avoid a dependency. Hence this file +// carries the copyright of the original repo. +// https://github.com/kylelemons/godebug/tree/v1.1.0/diff +// +// Package diff implements a linewise diff algorithm. +package diff + +import ( + "fmt" + "strings" +) + +// Chunk represents a piece of the diff. A chunk will not have both added and +// deleted lines. Equal lines are always after any added or deleted lines. +// A Chunk may or may not have any lines in it, especially for the first or last +// chunk in a computation. +type Chunk struct { + Added []string + Deleted []string + Equal []string +} + +func (c *Chunk) empty() bool { + return len(c.Added) == 0 && len(c.Deleted) == 0 && len(c.Equal) == 0 +} + +// Diff returns a string containing a line-by-line unified diff of the linewise +// changes required to make A into B. Each line is prefixed with '+', '-', or +// ' ' to indicate if it should be added, removed, or is correct respectively. +func Diff(A, B string) string { + aLines := strings.Split(A, "\n") + bLines := strings.Split(B, "\n") + return Render(DiffChunks(aLines, bLines)) +} + +// Render renders the slice of chunks into a representation that prefixes +// the lines with '+', '-', or ' ' depending on whether the line was added, +// removed, or equal (respectively). +func Render(chunks []Chunk) string { + buf := new(strings.Builder) + for _, c := range chunks { + for _, line := range c.Added { + fmt.Fprintf(buf, "+%s\n", line) + } + for _, line := range c.Deleted { + fmt.Fprintf(buf, "-%s\n", line) + } + for _, line := range c.Equal { + fmt.Fprintf(buf, " %s\n", line) + } + } + return strings.TrimRight(buf.String(), "\n") +} + +// DiffChunks uses an O(D(N+M)) shortest-edit-script algorithm +// to compute the edits required from A to B and returns the +// edit chunks. +func DiffChunks(a, b []string) []Chunk { + // algorithm: http://www.xmailserver.org/diff2.pdf + + // We'll need these quantities a lot. + alen, blen := len(a), len(b) // M, N + + // At most, it will require len(a) deletions and len(b) additions + // to transform a into b. + maxPath := alen + blen // MAX + if maxPath == 0 { + // degenerate case: two empty lists are the same + return nil + } + + // Store the endpoint of the path for diagonals. + // We store only the a index, because the b index on any diagonal + // (which we know during the loop below) is aidx-diag. + // endpoint[maxPath] represents the 0 diagonal. + // + // Stated differently: + // endpoint[d] contains the aidx of a furthest reaching path in diagonal d + endpoint := make([]int, 2*maxPath+1) // V + + saved := make([][]int, 0, 8) // Vs + save := func() { + dup := make([]int, len(endpoint)) + copy(dup, endpoint) + saved = append(saved, dup) + } + + var editDistance int // D +dLoop: + for editDistance = 0; editDistance <= maxPath; editDistance++ { + // The 0 diag(onal) represents equality of a and b. Each diagonal to + // the left is numbered one lower, to the right is one higher, from + // -alen to +blen. Negative diagonals favor differences from a, + // positive diagonals favor differences from b. The edit distance to a + // diagonal d cannot be shorter than d itself. + // + // The iterations of this loop cover either odds or evens, but not both, + // If odd indices are inputs, even indices are outputs and vice versa. + for diag := -editDistance; diag <= editDistance; diag += 2 { // k + var aidx int // x + switch { + case diag == -editDistance: + // This is a new diagonal; copy from previous iter + aidx = endpoint[maxPath-editDistance+1] + 0 + case diag == editDistance: + // This is a new diagonal; copy from previous iter + aidx = endpoint[maxPath+editDistance-1] + 1 + case endpoint[maxPath+diag+1] > endpoint[maxPath+diag-1]: + // diagonal d+1 was farther along, so use that + aidx = endpoint[maxPath+diag+1] + 0 + default: + // diagonal d-1 was farther (or the same), so use that + aidx = endpoint[maxPath+diag-1] + 1 + } + // On diagonal d, we can compute bidx from aidx. + bidx := aidx - diag // y + // See how far we can go on this diagonal before we find a difference. + for aidx < alen && bidx < blen && a[aidx] == b[bidx] { + aidx++ + bidx++ + } + // Store the end of the current edit chain. + endpoint[maxPath+diag] = aidx + // If we've found the end of both inputs, we're done! + if aidx >= alen && bidx >= blen { + save() // save the final path + break dLoop + } + } + save() // save the current path + } + if editDistance == 0 { + return nil + } + chunks := make([]Chunk, editDistance+1) + + x, y := alen, blen + for d := editDistance; d > 0; d-- { + endpoint := saved[d] + diag := x - y + insert := diag == -d || (diag != d && endpoint[maxPath+diag-1] < endpoint[maxPath+diag+1]) + + x1 := endpoint[maxPath+diag] + var x0, xM, kk int + if insert { + kk = diag + 1 + x0 = endpoint[maxPath+kk] + xM = x0 + } else { + kk = diag - 1 + x0 = endpoint[maxPath+kk] + xM = x0 + 1 + } + y0 := x0 - kk + + var c Chunk + if insert { + c.Added = b[y0:][:1] + } else { + c.Deleted = a[x0:][:1] + } + if xM < x1 { + c.Equal = a[xM:][:x1-xM] + } + + x, y = x0, y0 + chunks[d] = c + } + if x > 0 { + chunks[0].Equal = a[:x] + } + if chunks[0].empty() { + chunks = chunks[1:] + } + if len(chunks) == 0 { + return nil + } + return chunks +} diff --git a/prometheus/testutil/diff/diff_test.go b/prometheus/testutil/diff/diff_test.go new file mode 100644 index 000000000..6dfba99fe --- /dev/null +++ b/prometheus/testutil/diff/diff_test.go @@ -0,0 +1,231 @@ +// Copyright 2013 Google Inc. All rights reserved. +// +// Licensed 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. +// +// The code in this package is copy/paste to avoid a dependency. Hence this file +// carries the copyright of the original repo. +// https://github.com/kylelemons/godebug/tree/v1.1.0/diff +package diff + +import ( + "fmt" + "reflect" + "strings" + "testing" +) + +func TestDiff(t *testing.T) { + tests := []struct { + desc string + A, B []string + chunks []Chunk + }{ + { + desc: "nil", + }, + { + desc: "empty", + A: []string{}, + B: []string{}, + }, + { + desc: "same", + A: []string{"foo"}, + B: []string{"foo"}, + }, + { + desc: "a empty", + A: []string{}, + }, + { + desc: "b empty", + B: []string{}, + }, + { + desc: "b nil", + A: []string{"foo"}, + chunks: []Chunk{ + 0: {Deleted: []string{"foo"}}, + }, + }, + { + desc: "a nil", + B: []string{"foo"}, + chunks: []Chunk{ + 0: {Added: []string{"foo"}}, + }, + }, + { + desc: "start with change", + A: []string{"a", "b", "c"}, + B: []string{"A", "b", "c"}, + chunks: []Chunk{ + 0: {Deleted: []string{"a"}}, + 1: {Added: []string{"A"}, Equal: []string{"b", "c"}}, + }, + }, + { + desc: "constitution", + A: []string{ + "We the People of the United States, in Order to form a more perfect Union,", + "establish Justice, insure domestic Tranquility, provide for the common defence,", + "and secure the Blessings of Liberty to ourselves", + "and our Posterity, do ordain and establish this Constitution for the United", + "States of America.", + }, + B: []string{ + "We the People of the United States, in Order to form a more perfect Union,", + "establish Justice, insure domestic Tranquility, provide for the common defence,", + "promote the general Welfare, and secure the Blessings of Liberty to ourselves", + "and our Posterity, do ordain and establish this Constitution for the United", + "States of America.", + }, + chunks: []Chunk{ + 0: { + Equal: []string{ + "We the People of the United States, in Order to form a more perfect Union,", + "establish Justice, insure domestic Tranquility, provide for the common defence,", + }, + }, + 1: { + Deleted: []string{ + "and secure the Blessings of Liberty to ourselves", + }, + }, + 2: { + Added: []string{ + "promote the general Welfare, and secure the Blessings of Liberty to ourselves", + }, + Equal: []string{ + "and our Posterity, do ordain and establish this Constitution for the United", + "States of America.", + }, + }, + }, + }, + } + + for _, test := range tests { + t.Run(test.desc, func(t *testing.T) { + got := DiffChunks(test.A, test.B) + if got, want := len(got), len(test.chunks); got != want { + t.Errorf("edit distance = %v, want %v", got-1, want-1) + return + } + for i := range got { + got, want := got[i], test.chunks[i] + if got, want := got.Added, want.Added; !reflect.DeepEqual(got, want) { + t.Errorf("chunks[%d]: Added = %v, want %v", i, got, want) + } + if got, want := got.Deleted, want.Deleted; !reflect.DeepEqual(got, want) { + t.Errorf("chunks[%d]: Deleted = %v, want %v", i, got, want) + } + if got, want := got.Equal, want.Equal; !reflect.DeepEqual(got, want) { + t.Errorf("chunks[%d]: Equal = %v, want %v", i, got, want) + } + } + }) + } +} + +func TestRender(t *testing.T) { + tests := []struct { + desc string + chunks []Chunk + out string + }{ + { + desc: "ordering", + chunks: []Chunk{ + { + Added: []string{"1"}, + Deleted: []string{"2"}, + Equal: []string{"3"}, + }, + { + Added: []string{"4"}, + Deleted: []string{"5"}, + }, + }, + out: strings.TrimSpace(` ++1 +-2 + 3 ++4 +-5 + `), + }, + { + desc: "only_added", + chunks: []Chunk{ + { + Added: []string{"1"}, + }, + }, + out: strings.TrimSpace(` ++1 + `), + }, + { + desc: "only_deleted", + chunks: []Chunk{ + { + Deleted: []string{"1"}, + }, + }, + out: strings.TrimSpace(` +-1 + `), + }, + } + + for _, test := range tests { + t.Run(test.desc, func(t *testing.T) { + if got, want := Render(test.chunks), test.out; got != want { + t.Errorf("Render(%q):", test.chunks) + t.Errorf("GOT\n%s", got) + t.Errorf("WANT\n%s", want) + } + }) + } +} + +func ExampleDiff() { + constitution := strings.TrimSpace(` +We the People of the United States, in Order to form a more perfect Union, +establish Justice, insure domestic Tranquility, provide for the common defence, +promote the general Welfare, and secure the Blessings of Liberty to ourselves +and our Posterity, do ordain and establish this Constitution for the United +States of America. +`) + + got := strings.TrimSpace(` +:wq +We the People of the United States, in Order to form a more perfect Union, +establish Justice, insure domestic Tranquility, provide for the common defence, +and secure the Blessings of Liberty to ourselves +and our Posterity, do ordain and establish this Constitution for the United +States of America. +`) + + fmt.Println(Diff(got, constitution)) + + // Output: + // -:wq + // We the People of the United States, in Order to form a more perfect Union, + // establish Justice, insure domestic Tranquility, provide for the common defence, + // -and secure the Blessings of Liberty to ourselves + // +promote the general Welfare, and secure the Blessings of Liberty to ourselves + // and our Posterity, do ordain and establish this Constitution for the United + // States of America. +} diff --git a/prometheus/testutil/testutil.go b/prometheus/testutil/testutil.go index 6ab370c4d..6ee8dd678 100644 --- a/prometheus/testutil/testutil.go +++ b/prometheus/testutil/testutil.go @@ -43,7 +43,7 @@ import ( "io" "net/http" - godebug "github.com/kylelemons/godebug/diff" + utildiff "github.com/prometheus/client_golang/prometheus/testutil/diff" dto "github.com/prometheus/client_model/go" "github.com/prometheus/common/expfmt" "google.golang.org/protobuf/proto" @@ -276,7 +276,7 @@ func compare(got, want []*dto.MetricFamily) error { return fmt.Errorf("encoding expected metrics failed: %w", err) } } - if diffErr := godebug.Diff(gotBuf.String(), wantBuf.String()); diffErr != "" { + if diffErr := utildiff.Diff(gotBuf.String(), wantBuf.String()); diffErr != "" { return fmt.Errorf(diffErr) } return nil From 23b0759843173472b3b596301f47dcffae8b279a Mon Sep 17 00:00:00 2001 From: dongjiang1989 Date: Mon, 22 Apr 2024 09:53:35 +0800 Subject: [PATCH 09/10] update testutil Signed-off-by: dongjiang1989 --- prometheus/testutil/testutil.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/prometheus/testutil/testutil.go b/prometheus/testutil/testutil.go index 6ee8dd678..f3735fbc2 100644 --- a/prometheus/testutil/testutil.go +++ b/prometheus/testutil/testutil.go @@ -43,11 +43,12 @@ import ( "io" "net/http" - utildiff "github.com/prometheus/client_golang/prometheus/testutil/diff" dto "github.com/prometheus/client_model/go" "github.com/prometheus/common/expfmt" "google.golang.org/protobuf/proto" + utildiff "github.com/prometheus/client_golang/prometheus/testutil/diff" + "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/internal" ) From 8298529f61c83dc5a87f5c447098cac2b2d14292 Mon Sep 17 00:00:00 2001 From: Kemal Akkoyun Date: Mon, 22 Apr 2024 08:48:17 +0200 Subject: [PATCH 10/10] Fix imports, goimports friendly Signed-off-by: Kemal Akkoyun --- prometheus/testutil/testutil.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/prometheus/testutil/testutil.go b/prometheus/testutil/testutil.go index f3735fbc2..7c1e905e6 100644 --- a/prometheus/testutil/testutil.go +++ b/prometheus/testutil/testutil.go @@ -47,10 +47,9 @@ import ( "github.com/prometheus/common/expfmt" "google.golang.org/protobuf/proto" - utildiff "github.com/prometheus/client_golang/prometheus/testutil/diff" - "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/internal" + "github.com/prometheus/client_golang/prometheus/testutil/diff" ) // ToFloat64 collects all Metrics from the provided Collector. It expects that @@ -277,7 +276,7 @@ func compare(got, want []*dto.MetricFamily) error { return fmt.Errorf("encoding expected metrics failed: %w", err) } } - if diffErr := utildiff.Diff(gotBuf.String(), wantBuf.String()); diffErr != "" { + if diffErr := diff.Diff(gotBuf.String(), wantBuf.String()); diffErr != "" { return fmt.Errorf(diffErr) } return nil