From c91c2bbea5e96c7a7101e4914736b854d2f1d313 Mon Sep 17 00:00:00 2001 From: David Leadbeater Date: Thu, 28 Oct 2021 22:17:18 +1100 Subject: [PATCH] promtool: Show more human readable got/exp output (#8064) Avoid using %#v, nothing needs to parse this, so escaping " and so on leads to hard to read output. Add new lines, number and indentation to each alert series output. Signed-off-by: David Leadbeater --- cmd/promtool/unittest.go | 62 ++++++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 28 deletions(-) diff --git a/cmd/promtool/unittest.go b/cmd/promtool/unittest.go index 3ddec3152..5dcc5bb56 100644 --- a/cmd/promtool/unittest.go +++ b/cmd/promtool/unittest.go @@ -47,6 +47,7 @@ func RulesUnitTest(queryOpts promql.LazyLoaderOpts, files ...string) int { fmt.Fprintln(os.Stderr, " FAILED:") for _, e := range errs { fmt.Fprintln(os.Stderr, e.Error()) + fmt.Println() } failed = true } else { @@ -313,30 +314,18 @@ func (tg *testGroup) test(evalInterval time.Duration, groupOrderMap map[string]i }) } - var sb strings.Builder - if gotAlerts.Len() != expAlerts.Len() { + sort.Sort(gotAlerts) + sort.Sort(expAlerts) + + if !reflect.DeepEqual(expAlerts, gotAlerts) { + var testName string if tg.TestGroupName != "" { - fmt.Fprintf(&sb, " name: %s,\n", tg.TestGroupName) - } - fmt.Fprintf(&sb, " alertname:%s, time:%s, \n", testcase.Alertname, testcase.EvalTime.String()) - fmt.Fprintf(&sb, " exp:%#v, \n", expAlerts.String()) - fmt.Fprintf(&sb, " got:%#v", gotAlerts.String()) - - errs = append(errs, errors.New(sb.String())) - } else { - sort.Sort(gotAlerts) - sort.Sort(expAlerts) - - if !reflect.DeepEqual(expAlerts, gotAlerts) { - if tg.TestGroupName != "" { - fmt.Fprintf(&sb, " name: %s,\n", tg.TestGroupName) - } - fmt.Fprintf(&sb, " alertname:%s, time:%s, \n", testcase.Alertname, testcase.EvalTime.String()) - fmt.Fprintf(&sb, " exp:%#v, \n", expAlerts.String()) - fmt.Fprintf(&sb, " got:%#v", gotAlerts.String()) - - errs = append(errs, errors.New(sb.String())) + testName = fmt.Sprintf(" name: %s,\n", tg.TestGroupName) } + expString := indentLines(expAlerts.String(), " ") + gotString := indentLines(gotAlerts.String(), " ") + errs = append(errs, errors.Errorf("%s alertname: %s, time: %s, \n exp:%v, \n got:%v", + testName, testcase.Alertname, testcase.EvalTime.String(), expString, gotString)) } } @@ -385,7 +374,7 @@ Outer: return labels.Compare(gotSamples[i].Labels, gotSamples[j].Labels) <= 0 }) if !reflect.DeepEqual(expSamples, gotSamples) { - errs = append(errs, errors.Errorf(" expr: %q, time: %s,\n exp:%#v\n got:%#v", testCase.Expr, + errs = append(errs, errors.Errorf(" expr: %q, time: %s,\n exp: %v\n got: %v", testCase.Expr, testCase.EvalTime.String(), parsedSamplesString(expSamples), parsedSamplesString(gotSamples))) } } @@ -468,6 +457,23 @@ func query(ctx context.Context, qs string, t time.Time, engine *promql.Engine, q } } +// indentLines prefixes each line in the supplied string with the given "indent" +// string. +func indentLines(lines, indent string) string { + sb := strings.Builder{} + n := strings.Split(lines, "\n") + for i, l := range n { + if i > 0 { + sb.WriteString(indent) + } + sb.WriteString(l) + if i != len(n)-1 { + sb.WriteRune('\n') + } + } + return sb.String() +} + type labelsAndAnnotations []labelAndAnnotation func (la labelsAndAnnotations) Len() int { return len(la) } @@ -484,11 +490,11 @@ func (la labelsAndAnnotations) String() string { if len(la) == 0 { return "[]" } - s := "[" + la[0].String() - for _, l := range la[1:] { - s += ", " + l.String() + s := "[\n0:" + indentLines("\n"+la[0].String(), " ") + for i, l := range la[1:] { + s += ",\n" + fmt.Sprintf("%d", i+1) + ":" + indentLines("\n"+l.String(), " ") } - s += "]" + s += "\n]" return s } @@ -499,7 +505,7 @@ type labelAndAnnotation struct { } func (la *labelAndAnnotation) String() string { - return "Labels:" + la.Labels.String() + " Annotations:" + la.Annotations.String() + return "Labels:" + la.Labels.String() + "\nAnnotations:" + la.Annotations.String() } type series struct {