From 681453691a2f6d578dbc4ed8d064ed3ec259bef8 Mon Sep 17 00:00:00 2001 From: Jacob Marble Date: Thu, 22 Jul 2021 08:16:55 -0700 Subject: [PATCH] pdata: add [Type]Slice.Sort(func) to sort slices (#3671) * pdata: add TypeSlice.Sort(func) to sort slices Comparing two generated slices can be tedious when the slices are not ordered, and order does not matter for the test. This change adds a .Sort(func(i, j int) bool) method to generated [Type]Slice. This is similar to method StringMap.Sort(), but takes a less function because the order may differ by context, where the sort order of a map is obvious (by key). * fix: improve TypeSlice.Sort(less) signature * fix: resolve goimports CI check * chore: make genpdata --- cmd/pdatagen/internal/base_slices.go | 17 +++- cmd/pdatagen/internal/files.go | 8 +- cmd/pdatagen/internal/log_structs.go | 2 + cmd/pdatagen/internal/metrics_structs.go | 2 + cmd/pdatagen/internal/trace_structs.go | 2 + model/pdata/generated_log.go | 44 +++++++++ model/pdata/generated_metrics.go | 114 +++++++++++++++++++++++ model/pdata/generated_trace.go | 72 ++++++++++++++ 8 files changed, 258 insertions(+), 3 deletions(-) diff --git a/cmd/pdatagen/internal/base_slices.go b/cmd/pdatagen/internal/base_slices.go index 3f0dbb6b7ff..45cf6b901b4 100644 --- a/cmd/pdatagen/internal/base_slices.go +++ b/cmd/pdatagen/internal/base_slices.go @@ -200,7 +200,22 @@ func (es ${structName}) EnsureCapacity(newCap int) { func (es ${structName}) AppendEmpty() ${elementName} { *es.orig = append(*es.orig, &${originName}{}) return es.At(es.Len() - 1) -} ` +} + +// Sort sorts the ${elementName} elements within ${structName} given the +// provided less function so that two instances of ${structName} +// can be compared. +// +// Returns the same instance to allow nicer code like: +// lessFunc := func(a, b ${elementName}) bool { +// return a.Name() < b.Name() // choose any comparison here +// } +// assert.EqualValues(t, expected.Sort(lessFunc), actual.Sort(lessFunc)) +func (es ${structName}) Sort(less func(a, b ${elementName}) bool) ${structName} { + sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) + return es +} +` const slicePtrTestTemplate = `func Test${structName}(t *testing.T) { es := New${structName}() diff --git a/cmd/pdatagen/internal/files.go b/cmd/pdatagen/internal/files.go index 81485b06083..62b9b673c38 100644 --- a/cmd/pdatagen/internal/files.go +++ b/cmd/pdatagen/internal/files.go @@ -62,8 +62,12 @@ func (f *File) GenerateFile() string { sb.WriteString(newLine + newLine) // Add imports sb.WriteString("import (" + newLine) - for _, i := range f.imports { - sb.WriteString("\t" + i + newLine) + for _, imp := range f.imports { + if imp != "" { + sb.WriteString("\t" + imp + newLine) + } else { + sb.WriteString(newLine) + } } sb.WriteString(")") // Write all structs diff --git a/cmd/pdatagen/internal/log_structs.go b/cmd/pdatagen/internal/log_structs.go index 3b29744c793..fcb442902e5 100644 --- a/cmd/pdatagen/internal/log_structs.go +++ b/cmd/pdatagen/internal/log_structs.go @@ -17,6 +17,8 @@ package internal var logFile = &File{ Name: "log", imports: []string{ + `"sort"`, + ``, `otlplogs "go.opentelemetry.io/collector/model/internal/data/protogen/logs/v1"`, }, testImports: []string{ diff --git a/cmd/pdatagen/internal/metrics_structs.go b/cmd/pdatagen/internal/metrics_structs.go index 463b78eb558..bf97296d993 100644 --- a/cmd/pdatagen/internal/metrics_structs.go +++ b/cmd/pdatagen/internal/metrics_structs.go @@ -17,6 +17,8 @@ package internal var metricsFile = &File{ Name: "metrics", imports: []string{ + `"sort"`, + ``, `otlpmetrics "go.opentelemetry.io/collector/model/internal/data/protogen/metrics/v1"`, }, testImports: []string{ diff --git a/cmd/pdatagen/internal/trace_structs.go b/cmd/pdatagen/internal/trace_structs.go index 5b3cbc3802e..dd6af4ca28b 100644 --- a/cmd/pdatagen/internal/trace_structs.go +++ b/cmd/pdatagen/internal/trace_structs.go @@ -17,6 +17,8 @@ package internal var traceFile = &File{ Name: "trace", imports: []string{ + `"sort"`, + ``, `otlptrace "go.opentelemetry.io/collector/model/internal/data/protogen/trace/v1"`, }, testImports: []string{ diff --git a/model/pdata/generated_log.go b/model/pdata/generated_log.go index 70878b50b5a..a0889ee0d12 100644 --- a/model/pdata/generated_log.go +++ b/model/pdata/generated_log.go @@ -18,6 +18,8 @@ package pdata import ( + "sort" + otlplogs "go.opentelemetry.io/collector/model/internal/data/protogen/logs/v1" ) @@ -112,6 +114,20 @@ func (es ResourceLogsSlice) AppendEmpty() ResourceLogs { return es.At(es.Len() - 1) } +// Sort sorts the ResourceLogs elements within ResourceLogsSlice given the +// provided less function so that two instances of ResourceLogsSlice +// can be compared. +// +// Returns the same instance to allow nicer code like: +// lessFunc := func(a, b ResourceLogs) bool { +// return a.Name() < b.Name() // choose any comparison here +// } +// assert.EqualValues(t, expected.Sort(lessFunc), actual.Sort(lessFunc)) +func (es ResourceLogsSlice) Sort(less func(a, b ResourceLogs) bool) ResourceLogsSlice { + sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) + return es +} + // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es ResourceLogsSlice) MoveAndAppendTo(dest ResourceLogsSlice) { @@ -273,6 +289,20 @@ func (es InstrumentationLibraryLogsSlice) AppendEmpty() InstrumentationLibraryLo return es.At(es.Len() - 1) } +// Sort sorts the InstrumentationLibraryLogs elements within InstrumentationLibraryLogsSlice given the +// provided less function so that two instances of InstrumentationLibraryLogsSlice +// can be compared. +// +// Returns the same instance to allow nicer code like: +// lessFunc := func(a, b InstrumentationLibraryLogs) bool { +// return a.Name() < b.Name() // choose any comparison here +// } +// assert.EqualValues(t, expected.Sort(lessFunc), actual.Sort(lessFunc)) +func (es InstrumentationLibraryLogsSlice) Sort(less func(a, b InstrumentationLibraryLogs) bool) InstrumentationLibraryLogsSlice { + sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) + return es +} + // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es InstrumentationLibraryLogsSlice) MoveAndAppendTo(dest InstrumentationLibraryLogsSlice) { @@ -434,6 +464,20 @@ func (es LogSlice) AppendEmpty() LogRecord { return es.At(es.Len() - 1) } +// Sort sorts the LogRecord elements within LogSlice given the +// provided less function so that two instances of LogSlice +// can be compared. +// +// Returns the same instance to allow nicer code like: +// lessFunc := func(a, b LogRecord) bool { +// return a.Name() < b.Name() // choose any comparison here +// } +// assert.EqualValues(t, expected.Sort(lessFunc), actual.Sort(lessFunc)) +func (es LogSlice) Sort(less func(a, b LogRecord) bool) LogSlice { + sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) + return es +} + // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es LogSlice) MoveAndAppendTo(dest LogSlice) { diff --git a/model/pdata/generated_metrics.go b/model/pdata/generated_metrics.go index c0a3d048065..48e1ca61391 100644 --- a/model/pdata/generated_metrics.go +++ b/model/pdata/generated_metrics.go @@ -18,6 +18,8 @@ package pdata import ( + "sort" + otlpmetrics "go.opentelemetry.io/collector/model/internal/data/protogen/metrics/v1" ) @@ -112,6 +114,20 @@ func (es ResourceMetricsSlice) AppendEmpty() ResourceMetrics { return es.At(es.Len() - 1) } +// Sort sorts the ResourceMetrics elements within ResourceMetricsSlice given the +// provided less function so that two instances of ResourceMetricsSlice +// can be compared. +// +// Returns the same instance to allow nicer code like: +// lessFunc := func(a, b ResourceMetrics) bool { +// return a.Name() < b.Name() // choose any comparison here +// } +// assert.EqualValues(t, expected.Sort(lessFunc), actual.Sort(lessFunc)) +func (es ResourceMetricsSlice) Sort(less func(a, b ResourceMetrics) bool) ResourceMetricsSlice { + sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) + return es +} + // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es ResourceMetricsSlice) MoveAndAppendTo(dest ResourceMetricsSlice) { @@ -273,6 +289,20 @@ func (es InstrumentationLibraryMetricsSlice) AppendEmpty() InstrumentationLibrar return es.At(es.Len() - 1) } +// Sort sorts the InstrumentationLibraryMetrics elements within InstrumentationLibraryMetricsSlice given the +// provided less function so that two instances of InstrumentationLibraryMetricsSlice +// can be compared. +// +// Returns the same instance to allow nicer code like: +// lessFunc := func(a, b InstrumentationLibraryMetrics) bool { +// return a.Name() < b.Name() // choose any comparison here +// } +// assert.EqualValues(t, expected.Sort(lessFunc), actual.Sort(lessFunc)) +func (es InstrumentationLibraryMetricsSlice) Sort(less func(a, b InstrumentationLibraryMetrics) bool) InstrumentationLibraryMetricsSlice { + sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) + return es +} + // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es InstrumentationLibraryMetricsSlice) MoveAndAppendTo(dest InstrumentationLibraryMetricsSlice) { @@ -434,6 +464,20 @@ func (es MetricSlice) AppendEmpty() Metric { return es.At(es.Len() - 1) } +// Sort sorts the Metric elements within MetricSlice given the +// provided less function so that two instances of MetricSlice +// can be compared. +// +// Returns the same instance to allow nicer code like: +// lessFunc := func(a, b Metric) bool { +// return a.Name() < b.Name() // choose any comparison here +// } +// assert.EqualValues(t, expected.Sort(lessFunc), actual.Sort(lessFunc)) +func (es MetricSlice) Sort(less func(a, b Metric) bool) MetricSlice { + sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) + return es +} + // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es MetricSlice) MoveAndAppendTo(dest MetricSlice) { @@ -865,6 +909,20 @@ func (es IntDataPointSlice) AppendEmpty() IntDataPoint { return es.At(es.Len() - 1) } +// Sort sorts the IntDataPoint elements within IntDataPointSlice given the +// provided less function so that two instances of IntDataPointSlice +// can be compared. +// +// Returns the same instance to allow nicer code like: +// lessFunc := func(a, b IntDataPoint) bool { +// return a.Name() < b.Name() // choose any comparison here +// } +// assert.EqualValues(t, expected.Sort(lessFunc), actual.Sort(lessFunc)) +func (es IntDataPointSlice) Sort(less func(a, b IntDataPoint) bool) IntDataPointSlice { + sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) + return es +} + // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es IntDataPointSlice) MoveAndAppendTo(dest IntDataPointSlice) { @@ -1059,6 +1117,20 @@ func (es NumberDataPointSlice) AppendEmpty() NumberDataPoint { return es.At(es.Len() - 1) } +// Sort sorts the NumberDataPoint elements within NumberDataPointSlice given the +// provided less function so that two instances of NumberDataPointSlice +// can be compared. +// +// Returns the same instance to allow nicer code like: +// lessFunc := func(a, b NumberDataPoint) bool { +// return a.Name() < b.Name() // choose any comparison here +// } +// assert.EqualValues(t, expected.Sort(lessFunc), actual.Sort(lessFunc)) +func (es NumberDataPointSlice) Sort(less func(a, b NumberDataPoint) bool) NumberDataPointSlice { + sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) + return es +} + // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es NumberDataPointSlice) MoveAndAppendTo(dest NumberDataPointSlice) { @@ -1255,6 +1327,20 @@ func (es HistogramDataPointSlice) AppendEmpty() HistogramDataPoint { return es.At(es.Len() - 1) } +// Sort sorts the HistogramDataPoint elements within HistogramDataPointSlice given the +// provided less function so that two instances of HistogramDataPointSlice +// can be compared. +// +// Returns the same instance to allow nicer code like: +// lessFunc := func(a, b HistogramDataPoint) bool { +// return a.Name() < b.Name() // choose any comparison here +// } +// assert.EqualValues(t, expected.Sort(lessFunc), actual.Sort(lessFunc)) +func (es HistogramDataPointSlice) Sort(less func(a, b HistogramDataPoint) bool) HistogramDataPointSlice { + sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) + return es +} + // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es HistogramDataPointSlice) MoveAndAppendTo(dest HistogramDataPointSlice) { @@ -1482,6 +1568,20 @@ func (es SummaryDataPointSlice) AppendEmpty() SummaryDataPoint { return es.At(es.Len() - 1) } +// Sort sorts the SummaryDataPoint elements within SummaryDataPointSlice given the +// provided less function so that two instances of SummaryDataPointSlice +// can be compared. +// +// Returns the same instance to allow nicer code like: +// lessFunc := func(a, b SummaryDataPoint) bool { +// return a.Name() < b.Name() // choose any comparison here +// } +// assert.EqualValues(t, expected.Sort(lessFunc), actual.Sort(lessFunc)) +func (es SummaryDataPointSlice) Sort(less func(a, b SummaryDataPoint) bool) SummaryDataPointSlice { + sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) + return es +} + // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es SummaryDataPointSlice) MoveAndAppendTo(dest SummaryDataPointSlice) { @@ -1687,6 +1787,20 @@ func (es ValueAtQuantileSlice) AppendEmpty() ValueAtQuantile { return es.At(es.Len() - 1) } +// Sort sorts the ValueAtQuantile elements within ValueAtQuantileSlice given the +// provided less function so that two instances of ValueAtQuantileSlice +// can be compared. +// +// Returns the same instance to allow nicer code like: +// lessFunc := func(a, b ValueAtQuantile) bool { +// return a.Name() < b.Name() // choose any comparison here +// } +// assert.EqualValues(t, expected.Sort(lessFunc), actual.Sort(lessFunc)) +func (es ValueAtQuantileSlice) Sort(less func(a, b ValueAtQuantile) bool) ValueAtQuantileSlice { + sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) + return es +} + // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es ValueAtQuantileSlice) MoveAndAppendTo(dest ValueAtQuantileSlice) { diff --git a/model/pdata/generated_trace.go b/model/pdata/generated_trace.go index 845da62f448..58ccbf76d2b 100644 --- a/model/pdata/generated_trace.go +++ b/model/pdata/generated_trace.go @@ -18,6 +18,8 @@ package pdata import ( + "sort" + otlptrace "go.opentelemetry.io/collector/model/internal/data/protogen/trace/v1" ) @@ -112,6 +114,20 @@ func (es ResourceSpansSlice) AppendEmpty() ResourceSpans { return es.At(es.Len() - 1) } +// Sort sorts the ResourceSpans elements within ResourceSpansSlice given the +// provided less function so that two instances of ResourceSpansSlice +// can be compared. +// +// Returns the same instance to allow nicer code like: +// lessFunc := func(a, b ResourceSpans) bool { +// return a.Name() < b.Name() // choose any comparison here +// } +// assert.EqualValues(t, expected.Sort(lessFunc), actual.Sort(lessFunc)) +func (es ResourceSpansSlice) Sort(less func(a, b ResourceSpans) bool) ResourceSpansSlice { + sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) + return es +} + // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es ResourceSpansSlice) MoveAndAppendTo(dest ResourceSpansSlice) { @@ -273,6 +289,20 @@ func (es InstrumentationLibrarySpansSlice) AppendEmpty() InstrumentationLibraryS return es.At(es.Len() - 1) } +// Sort sorts the InstrumentationLibrarySpans elements within InstrumentationLibrarySpansSlice given the +// provided less function so that two instances of InstrumentationLibrarySpansSlice +// can be compared. +// +// Returns the same instance to allow nicer code like: +// lessFunc := func(a, b InstrumentationLibrarySpans) bool { +// return a.Name() < b.Name() // choose any comparison here +// } +// assert.EqualValues(t, expected.Sort(lessFunc), actual.Sort(lessFunc)) +func (es InstrumentationLibrarySpansSlice) Sort(less func(a, b InstrumentationLibrarySpans) bool) InstrumentationLibrarySpansSlice { + sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) + return es +} + // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es InstrumentationLibrarySpansSlice) MoveAndAppendTo(dest InstrumentationLibrarySpansSlice) { @@ -434,6 +464,20 @@ func (es SpanSlice) AppendEmpty() Span { return es.At(es.Len() - 1) } +// Sort sorts the Span elements within SpanSlice given the +// provided less function so that two instances of SpanSlice +// can be compared. +// +// Returns the same instance to allow nicer code like: +// lessFunc := func(a, b Span) bool { +// return a.Name() < b.Name() // choose any comparison here +// } +// assert.EqualValues(t, expected.Sort(lessFunc), actual.Sort(lessFunc)) +func (es SpanSlice) Sort(less func(a, b Span) bool) SpanSlice { + sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) + return es +} + // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es SpanSlice) MoveAndAppendTo(dest SpanSlice) { @@ -729,6 +773,20 @@ func (es SpanEventSlice) AppendEmpty() SpanEvent { return es.At(es.Len() - 1) } +// Sort sorts the SpanEvent elements within SpanEventSlice given the +// provided less function so that two instances of SpanEventSlice +// can be compared. +// +// Returns the same instance to allow nicer code like: +// lessFunc := func(a, b SpanEvent) bool { +// return a.Name() < b.Name() // choose any comparison here +// } +// assert.EqualValues(t, expected.Sort(lessFunc), actual.Sort(lessFunc)) +func (es SpanEventSlice) Sort(less func(a, b SpanEvent) bool) SpanEventSlice { + sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) + return es +} + // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es SpanEventSlice) MoveAndAppendTo(dest SpanEventSlice) { @@ -918,6 +976,20 @@ func (es SpanLinkSlice) AppendEmpty() SpanLink { return es.At(es.Len() - 1) } +// Sort sorts the SpanLink elements within SpanLinkSlice given the +// provided less function so that two instances of SpanLinkSlice +// can be compared. +// +// Returns the same instance to allow nicer code like: +// lessFunc := func(a, b SpanLink) bool { +// return a.Name() < b.Name() // choose any comparison here +// } +// assert.EqualValues(t, expected.Sort(lessFunc), actual.Sort(lessFunc)) +func (es SpanLinkSlice) Sort(less func(a, b SpanLink) bool) SpanLinkSlice { + sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) + return es +} + // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es SpanLinkSlice) MoveAndAppendTo(dest SpanLinkSlice) {