From 1e43a95952c0899c88dd0b47e67e690b8c80529a Mon Sep 17 00:00:00 2001 From: Rob Skillington Date: Wed, 17 Mar 2021 15:23:25 -0400 Subject: [PATCH 1/2] [query] Add Graphite sortByName natural and reverse params and generic sortBy --- .../native/aggregation_functions_test.go | 40 ++++----- .../graphite/native/builtin_functions.go | 50 ++++++++++- .../graphite/native/builtin_functions_test.go | 82 ++++++++++++++++++- src/query/graphite/ts/series.go | 62 +++++++++++++- src/query/graphite/ts/sortable_series_test.go | 28 +++++++ 5 files changed, 234 insertions(+), 28 deletions(-) diff --git a/src/query/graphite/native/aggregation_functions_test.go b/src/query/graphite/native/aggregation_functions_test.go index 9eb2cc494f..8af855de55 100644 --- a/src/query/graphite/native/aggregation_functions_test.go +++ b/src/query/graphite/native/aggregation_functions_test.go @@ -100,7 +100,7 @@ func testAggregatedSeries( } // nil input -> nil output - for _, in := range [][]*ts.Series{nil, []*ts.Series{}} { + for _, in := range [][]*ts.Series{nil, {}} { series, err := f(ctx, multiplePathSpecs(ts.SeriesList{ Values: in, })) @@ -287,7 +287,7 @@ func TestVariadicSumSeries(t *testing.T) { }, block.ResultMetadata{ Exhaustive: false, LocalOnly: false, - Warnings: []block.Warning{block.Warning{Name: "foo", Message: "bar"}}, + Warnings: []block.Warning{{Name: "foo", Message: "bar"}}, }), nil } return nil, fmt.Errorf("unexpected query: %s", query) @@ -449,14 +449,14 @@ func TestAverageSeriesWithWildcards(t *testing.T) { defer ctx.Close() input := []common.TestSeries{ - common.TestSeries{"web.host-1.avg-response.value", []float64{70.0, 20.0, 30.0, 40.0, 50.0}}, - common.TestSeries{"web.host-2.avg-response.value", []float64{20.0, 30.0, 40.0, 50.0, 60.0}}, - common.TestSeries{"web.host-3.avg-response.value", []float64{30.0, 40.0, 80.0, 60.0, 70.0}}, - common.TestSeries{"web.host-4.num-requests.value", []float64{10.0, 10.0, 15.0, 10.0, 15.0}}, + {"web.host-1.avg-response.value", []float64{70.0, 20.0, 30.0, 40.0, 50.0}}, + {"web.host-2.avg-response.value", []float64{20.0, 30.0, 40.0, 50.0, 60.0}}, + {"web.host-3.avg-response.value", []float64{30.0, 40.0, 80.0, 60.0, 70.0}}, + {"web.host-4.num-requests.value", []float64{10.0, 10.0, 15.0, 10.0, 15.0}}, } expected := []common.TestSeries{ - common.TestSeries{"web.avg-response", []float64{40.0, 30.0, 50.0, 50.0, 60.0}}, - common.TestSeries{"web.num-requests", []float64{10.0, 10.0, 15.0, 10.0, 15.0}}, + {"web.avg-response", []float64{40.0, 30.0, 50.0, 50.0, 60.0}}, + {"web.num-requests", []float64{10.0, 10.0, 15.0, 10.0, 15.0}}, } start := consolidationStartTime @@ -503,7 +503,7 @@ func TestSumSeriesWithWildcards(t *testing.T) { require.NoError(t, err) require.Equal(t, 2, len(outSeries.Values)) - outSeries, _ = sortByName(ctx, singlePathSpec(outSeries)) + outSeries, _ = sortByName(ctx, singlePathSpec(outSeries), false, false) expectedOutputs := []struct { name string @@ -619,7 +619,7 @@ func TestApplyByNode(t *testing.T) { require.NoError(t, err) require.Equal(t, len(test.expectedResults), len(outSeries.Values)) - outSeries, _ = sortByName(ctx, singlePathSpec(outSeries)) + outSeries, _ = sortByName(ctx, singlePathSpec(outSeries), false, false) common.CompareOutputsAndExpected(t, 60000, start, test.expectedResults, outSeries.Values) } } @@ -657,7 +657,7 @@ func TestAggregateWithWildcards(t *testing.T) { require.NoError(t, err) require.Equal(t, 2, len(outSeries.Values)) - outSeries, _ = sortByName(ctx, singlePathSpec(outSeries)) + outSeries, _ = sortByName(ctx, singlePathSpec(outSeries), false, false) expectedOutputs := []struct { name string @@ -732,7 +732,7 @@ func TestGroupByNode(t *testing.T) { require.NoError(t, err) require.Equal(t, len(test.expectedResults), len(outSeries.Values)) - outSeries, _ = sortByName(ctx, singlePathSpec(outSeries)) + outSeries, _ = sortByName(ctx, singlePathSpec(outSeries), false, false) for i, expected := range test.expectedResults { series := outSeries.Values[i] @@ -820,7 +820,7 @@ func TestGroupByNodes(t *testing.T) { require.NoError(t, err) require.Equal(t, len(test.expectedResults), len(outSeries.Values)) - outSeries, _ = sortByName(ctx, singlePathSpec(outSeries)) + outSeries, _ = sortByName(ctx, singlePathSpec(outSeries), false, false) for i, expected := range test.expectedResults { series := outSeries.Values[i] @@ -837,17 +837,17 @@ func TestWeightedAverage(t *testing.T) { defer ctx.Close() means := []common.TestSeries{ - common.TestSeries{"web.host-1.avg-response.mean", []float64{70.0, 20.0, 30.0, 0.0, 50.0}}, - common.TestSeries{"web.host-2.avg-response.mean", []float64{20.0, 30.0, 40.0, 50.0, 60.0}}, - common.TestSeries{"web.host-3.avg-response.mean", []float64{20.0, 30.0, 40.0, 50.0, 60.0}}, // no match + {"web.host-1.avg-response.mean", []float64{70.0, 20.0, 30.0, 0.0, 50.0}}, + {"web.host-2.avg-response.mean", []float64{20.0, 30.0, 40.0, 50.0, 60.0}}, + {"web.host-3.avg-response.mean", []float64{20.0, 30.0, 40.0, 50.0, 60.0}}, // no match } counts := []common.TestSeries{ - common.TestSeries{"web.host-1.avg-response.count", []float64{1, 2, 3, 4, 5}}, - common.TestSeries{"web.host-2.avg-response.count", []float64{10, 20, 30, 40, 50}}, - common.TestSeries{"web.host-4.avg-response.count", []float64{10, 20, 30, 40, 50}}, // no match + {"web.host-1.avg-response.count", []float64{1, 2, 3, 4, 5}}, + {"web.host-2.avg-response.count", []float64{10, 20, 30, 40, 50}}, + {"web.host-4.avg-response.count", []float64{10, 20, 30, 40, 50}}, // no match } expected := []common.TestSeries{ - common.TestSeries{"weightedAverage", []float64{24.5454, 29.0909, 39.0909, 45.4545, 59.0909}}, + {"weightedAverage", []float64{24.5454, 29.0909, 39.0909, 45.4545, 59.0909}}, } // normal series diff --git a/src/query/graphite/native/builtin_functions.go b/src/query/graphite/native/builtin_functions.go index 02be8efe67..a4d5cbc240 100644 --- a/src/query/graphite/native/builtin_functions.go +++ b/src/query/graphite/native/builtin_functions.go @@ -72,15 +72,52 @@ func joinPathExpr(series ts.SeriesList) string { return strings.Join(joined, ",") } +// sortBy allows for sorting by an aggregation function. +func sortBy(ctx *common.Context, series singlePathSpec, fn string, reverse bool) (ts.SeriesList, error) { + var ( + result ts.SeriesList + err error + ) + if strings.HasPrefix(fn, "min") { + result, err = lowest(ctx, series, len(series.Values), fn) + } else { + result, err = highest(ctx, series, len(series.Values), fn) + } + if err != nil { + return ts.SeriesList{}, err + } + if reverse { + reverseSeries(result.Values) + } + return result, nil +} + +func reverseSeries(s []*ts.Series) { + for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 { + s[i], s[j] = s[j], s[i] + } +} + // sortByName sorts timeseries results by their names -func sortByName(_ *common.Context, series singlePathSpec) (ts.SeriesList, error) { +func sortByName(_ *common.Context, series singlePathSpec, natural, reverse bool) (ts.SeriesList, error) { sorted := make([]*ts.Series, len(series.Values)) for i := range series.Values { sorted[i] = series.Values[i] } + var sortedBy sort.Interface + if natural { + sortedBy = ts.SeriesByNameAndNaturalNumbers(sorted) + } else { + sortedBy = ts.SeriesByName(sorted) + } + + if reverse { + sortedBy = sort.Reverse(sortedBy) + } + // Use sort.Stable for deterministic output. - sort.Stable(ts.SeriesByName(sorted)) + sort.Stable(sortedBy) r := ts.SeriesList(series) r.Values = sorted @@ -2514,9 +2551,16 @@ func init() { MustRegisterFunction(removeEmptySeries) MustRegisterFunction(scale) MustRegisterFunction(scaleToSeconds) + MustRegisterFunction(sortBy).WithDefaultParams(map[uint8]interface{}{ + 2: "average", // fn + 3: false, // reverse + }) MustRegisterFunction(sortByMaxima) MustRegisterFunction(sortByMinima) - MustRegisterFunction(sortByName) + MustRegisterFunction(sortByName).WithDefaultParams(map[uint8]interface{}{ + 2: false, // natural + 3: false, // reverse + }) MustRegisterFunction(sortByTotal) MustRegisterFunction(squareRoot) MustRegisterFunction(stdev).WithDefaultParams(map[uint8]interface{}{ diff --git a/src/query/graphite/native/builtin_functions_test.go b/src/query/graphite/native/builtin_functions_test.go index d9e7388efb..e799c559d0 100644 --- a/src/query/graphite/native/builtin_functions_test.go +++ b/src/query/graphite/native/builtin_functions_test.go @@ -188,14 +188,50 @@ func TestSortByName(t *testing.T) { ts.NewSeries(ctx, "a.c.d", now, values), } + // Normal. results, err := sortByName(ctx, singlePathSpec{ Values: series, - }) + }, false, false) require.Nil(t, err) require.Equal(t, len(series), results.Len()) assert.Equal(t, "a.c.d", results.Values[0].Name()) assert.Equal(t, "b.d.a", results.Values[1].Name()) assert.Equal(t, "zee", results.Values[2].Name()) + + // Reverse. + results, err = sortByName(ctx, singlePathSpec{ + Values: series, + }, false, true) + require.Nil(t, err) + require.Equal(t, len(series), results.Len()) + assert.Equal(t, "zee", results.Values[0].Name()) + assert.Equal(t, "b.d.a", results.Values[1].Name()) + assert.Equal(t, "a.c.d", results.Values[2].Name()) +} + +func TestSortByNameNatural(t *testing.T) { + ctx := common.NewTestContext() + defer ctx.Close() + + now := time.Now() + values := ts.NewConstantValues(ctx, 10.0, 1000, 10) + + series := []*ts.Series{ + ts.NewSeries(ctx, "server1", now, values), + ts.NewSeries(ctx, "server11", now, values), + ts.NewSeries(ctx, "server12", now, values), + ts.NewSeries(ctx, "server2", now, values), + } + + results, err := sortByName(ctx, singlePathSpec{ + Values: series, + }, true, false) + require.Nil(t, err) + require.Equal(t, len(series), results.Len()) + assert.Equal(t, "server1", results.Values[0].Name()) + assert.Equal(t, "server2", results.Values[1].Name()) + assert.Equal(t, "server11", results.Values[2].Name()) + assert.Equal(t, "server12", results.Values[3].Name()) } func getTestInput(ctx *common.Context) []*ts.Series { @@ -219,11 +255,55 @@ func testSortingFuncs( results, err := f(ctx, singlePathSpec{Values: input}) require.Nil(t, err) require.Equal(t, len(resultIndexes), results.Len()) + + expected := make([]string, 0, len(input)) + for _, idx := range resultIndexes { + expected = append(expected, input[idx].Name()) + } + + actual := make([]string, 0, len(input)) + for _, s := range results.Values { + actual = append(actual, s.Name()) + } + require.Equal(t, expected, actual) + for i, idx := range resultIndexes { require.Equal(t, results.Values[i], input[idx]) } } +func TestSortBy(t *testing.T) { + for _, test := range []struct { + fn string + indices []int + }{ + {fn: "average", indices: []int{4, 2, 0, 3, 1}}, + {fn: "sum", indices: []int{4, 0, 2, 3, 1}}, + {fn: "max", indices: []int{4, 0, 3, 2, 1}}, + {fn: "min", indices: []int{1, 3, 2, 4, 0}}, + } { + t.Run(test.fn, func(t *testing.T) { + // Regular. + expected := test.indices + testSortingFuncs(t, + func(ctx *common.Context, series singlePathSpec) (ts.SeriesList, error) { + return sortBy(ctx, series, test.fn, false) + }, + expected) + + // Reversed. + for i, j := 0, len(expected)-1; i < j; i, j = i+1, j-1 { + expected[i], expected[j] = expected[j], expected[i] + } + testSortingFuncs(t, + func(ctx *common.Context, series singlePathSpec) (ts.SeriesList, error) { + return sortBy(ctx, series, test.fn, true) + }, + expected) + }) + } +} + func TestSortByTotal(t *testing.T) { testSortingFuncs(t, sortByTotal, []int{4, 0, 2, 3, 1}) } diff --git a/src/query/graphite/ts/series.go b/src/query/graphite/ts/series.go index 02d88c712a..ff8dc691bd 100644 --- a/src/query/graphite/ts/series.go +++ b/src/query/graphite/ts/series.go @@ -22,8 +22,12 @@ package ts import ( "errors" + "fmt" "math" + "regexp" "sort" + "strconv" + "strings" "time" "github.com/m3db/m3/src/query/block" @@ -35,6 +39,12 @@ var ( // ErrRangeIsInvalid is returned when attempting to slice Series with invalid range // endpoints (begin is beyond end). ErrRangeIsInvalid = errors.New("requested range is invalid") + + digitsRegex = regexp.MustCompile(`\d+`) +) + +const ( + digits = "0123456789" ) // An AggregationFunc combines two data values at a given point. @@ -58,17 +68,61 @@ type Series struct { consolidationFunc ConsolidationFunc } -// SeriesByName implements sort.Interface for sorting collections of series by name +// SeriesByName implements sort.Interface for sorting collections +// of series by name. type SeriesByName []*Series // Len returns the length of the series collection -func (a SeriesByName) Len() int { return len(a) } +func (a SeriesByName) Len() int { + return len(a) +} + +// Swap swaps two series in the collection +func (a SeriesByName) Swap(i, j int) { + a[i], a[j] = a[j], a[i] +} + +// Less determines if a series is ordered before another series by name +func (a SeriesByName) Less(i, j int) bool { + return a[i].name < a[j].name +} + +// SeriesByNameAndNaturalNumbers implements sort.Interface for sorting +// collections of series by name respecting natural sort order for numbers. +type SeriesByNameAndNaturalNumbers []*Series + +// Len returns the length of the series collection +func (a SeriesByNameAndNaturalNumbers) Len() int { + return len(a) +} // Swap swaps two series in the collection -func (a SeriesByName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a SeriesByNameAndNaturalNumbers) Swap(i, j int) { + a[i], a[j] = a[j], a[i] +} // Less determines if a series is ordered before another series by name -func (a SeriesByName) Less(i, j int) bool { return a[i].name < a[j].name } +func (a SeriesByNameAndNaturalNumbers) Less(i, j int) bool { + left := a[i].name + if strings.ContainsAny(left, digits) { + left = digitsRegex.ReplaceAllStringFunc(left, digitsPrefixed) + } + + right := a[j].name + if strings.ContainsAny(right, digits) { + right = digitsRegex.ReplaceAllStringFunc(right, digitsPrefixed) + } + + return left < right +} + +func digitsPrefixed(digits string) string { + n, err := strconv.Atoi(digits) + if err != nil { + return digits + } + return fmt.Sprintf("%010d", n) +} // NewSeries creates a new Series at a given start time, backed by the provided values func NewSeries(ctx context.Context, name string, startTime time.Time, vals Values) *Series { diff --git a/src/query/graphite/ts/sortable_series_test.go b/src/query/graphite/ts/sortable_series_test.go index a260d71d66..a1cd3a6e24 100644 --- a/src/query/graphite/ts/sortable_series_test.go +++ b/src/query/graphite/ts/sortable_series_test.go @@ -23,6 +23,7 @@ package ts import ( "math" "math/rand" + "sort" "testing" "time" @@ -173,3 +174,30 @@ func TestSortSeriesStable(t *testing.T) { require.Equal(t, expectedOrder, order) } } + +func TestSortSeriesByNameAndNaturalNumbers(t *testing.T) { + ctx := context.New() + defer ctx.Close() + + constValues := newTestSeriesValues(ctx, 1000, []float64{1, 2, 3, 4}) + series := []*Series{ + NewSeries(ctx, "server1", time.Now(), constValues), + NewSeries(ctx, "server11", time.Now(), constValues), + NewSeries(ctx, "server12", time.Now(), constValues), + NewSeries(ctx, "server2", time.Now(), constValues), + } + + sort.Sort(SeriesByNameAndNaturalNumbers(series)) + + actual := make([]string, 0, len(series)) + for _, s := range series { + actual = append(actual, s.Name()) + } + + require.Equal(t, []string{ + "server1", + "server2", + "server11", + "server12", + }, actual) +} From a4f2b964fd0dbc08e9463496607dc40e1aef8ae5 Mon Sep 17 00:00:00 2001 From: Rob Skillington Date: Wed, 17 Mar 2021 15:38:07 -0400 Subject: [PATCH 2/2] Fix lint --- .../native/aggregation_functions_test.go | 16 +- .../graphite/native/builtin_functions_test.go | 150 +++++++++--------- src/query/graphite/ts/series.go | 1 + src/query/graphite/ts/sortable_series_test.go | 6 +- 4 files changed, 87 insertions(+), 86 deletions(-) diff --git a/src/query/graphite/native/aggregation_functions_test.go b/src/query/graphite/native/aggregation_functions_test.go index 8af855de55..8e9af03045 100644 --- a/src/query/graphite/native/aggregation_functions_test.go +++ b/src/query/graphite/native/aggregation_functions_test.go @@ -837,17 +837,17 @@ func TestWeightedAverage(t *testing.T) { defer ctx.Close() means := []common.TestSeries{ - {"web.host-1.avg-response.mean", []float64{70.0, 20.0, 30.0, 0.0, 50.0}}, - {"web.host-2.avg-response.mean", []float64{20.0, 30.0, 40.0, 50.0, 60.0}}, - {"web.host-3.avg-response.mean", []float64{20.0, 30.0, 40.0, 50.0, 60.0}}, // no match + {Name: "web.host-1.avg-response.mean", Data: []float64{70.0, 20.0, 30.0, 0.0, 50.0}}, + {Name: "web.host-2.avg-response.mean", Data: []float64{20.0, 30.0, 40.0, 50.0, 60.0}}, + {Name: "web.host-3.avg-response.mean", Data: []float64{20.0, 30.0, 40.0, 50.0, 60.0}}, // no match } counts := []common.TestSeries{ - {"web.host-1.avg-response.count", []float64{1, 2, 3, 4, 5}}, - {"web.host-2.avg-response.count", []float64{10, 20, 30, 40, 50}}, - {"web.host-4.avg-response.count", []float64{10, 20, 30, 40, 50}}, // no match + {Name: "web.host-1.avg-response.count", Data: []float64{1, 2, 3, 4, 5}}, + {Name: "web.host-2.avg-response.count", Data: []float64{10, 20, 30, 40, 50}}, + {Name: "web.host-4.avg-response.count", Data: []float64{10, 20, 30, 40, 50}}, // no match } expected := []common.TestSeries{ - {"weightedAverage", []float64{24.5454, 29.0909, 39.0909, 45.4545, 59.0909}}, + {Name: "weightedAverage", Data: []float64{24.5454, 29.0909, 39.0909, 45.4545, 59.0909}}, } // normal series @@ -866,7 +866,7 @@ func TestWeightedAverage(t *testing.T) { output, err = weightedAverage(ctx, singlePathSpec(values), singlePathSpec(weights), 1) require.NoError(t, err) common.CompareOutputsAndExpected(t, step, start, - []common.TestSeries{{"weightedAverage", means[0].Data}}, output.Values) + []common.TestSeries{{Name: "weightedAverage", Data: means[0].Data}}, output.Values) // different steps should lead to error -- not supported yet values = ts.SeriesList{Values: generateSeriesList(ctx, start, means, step)} diff --git a/src/query/graphite/native/builtin_functions_test.go b/src/query/graphite/native/builtin_functions_test.go index e799c559d0..b8acb6b855 100644 --- a/src/query/graphite/native/builtin_functions_test.go +++ b/src/query/graphite/native/builtin_functions_test.go @@ -70,7 +70,7 @@ var ( func TestExclude(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() now := time.Now() values := ts.NewConstantValues(ctx, 10.0, 1000, 10) @@ -122,7 +122,7 @@ func TestExclude(t *testing.T) { func TestExcludeErr(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() now := time.Now() values := ts.NewConstantValues(ctx, 10.0, 1000, 10) @@ -139,7 +139,7 @@ func TestExcludeErr(t *testing.T) { func TestGrep(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() now := time.Now() values := ts.NewConstantValues(ctx, 10.0, 5, 10) @@ -177,7 +177,7 @@ func TestGrep(t *testing.T) { func TestSortByName(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() now := time.Now() values := ts.NewConstantValues(ctx, 10.0, 1000, 10) @@ -211,7 +211,7 @@ func TestSortByName(t *testing.T) { func TestSortByNameNatural(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() now := time.Now() values := ts.NewConstantValues(ctx, 10.0, 1000, 10) @@ -249,7 +249,7 @@ func testSortingFuncs( resultIndexes []int, ) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() input := getTestInput(ctx) results, err := f(ctx, singlePathSpec{Values: input}) @@ -318,7 +318,7 @@ func TestSortByMinima(t *testing.T) { func TestAbsolute(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() inputVals := []float64{-2, 0, 42, math.NaN()} outputVals := []float64{2, 0, 42, math.NaN()} @@ -345,7 +345,7 @@ func TestAbsolute(t *testing.T) { func TestScale(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() tests := []struct { inputs []float64 @@ -399,7 +399,7 @@ func TestUseSeriesAbove(t *testing.T) { ) defer ctrl.Finish() - defer ctx.Close() + defer func() { _ = ctx.Close() }() store.EXPECT().FetchByQuery(gomock.Any(), "foo.bar.q.zed", gomock.Any()).DoAndReturn( buildTestSeriesFn(stepSize, "foo.bar.q.zed")) @@ -670,7 +670,7 @@ func TestPercentileOfSeries(t *testing.T) { func TestOffset(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() tests := []struct { inputs []float64 @@ -713,7 +713,7 @@ func TestOffset(t *testing.T) { func TestPerSecond(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() tests := []struct { millisPerStep int @@ -763,7 +763,7 @@ func TestTransformNull(t *testing.T) { ctx = common.NewTestContext() millisPerStep = 100 ) - defer ctx.Close() + defer func() { _ = ctx.Close() }() tests := []struct { inputs []*ts.Series @@ -829,7 +829,7 @@ var ( func testMovingFunction(t *testing.T, target, expectedName string, values, bootstrap, output []float64) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() engine := NewEngine(&common.MovingFunctionStorage{ StepMillis: 10000, @@ -867,7 +867,7 @@ var ( // testGeneralFunction is a copy of testMovingFunction but without any logic for bootstrapping values func testGeneralFunction(t *testing.T, target, expectedName string, values, output []float64) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() engine := NewEngine(&common.MovingFunctionStorage{ StepMillis: 60000, @@ -922,7 +922,7 @@ func TestCombineBootstrapWithOriginal(t *testing.T) { ) bootstrappedSeriesList.Values = bootstrappedSeriesListValues - defer ctx.Close() + defer func() { _ = ctx.Close() }() output, err := combineBootstrapWithOriginal(ctx, bootstrapStartTime, bootstrapEndTime, bootstrappedSeriesList, originalSeriesList) assert.Equal(t, output.Values[0], expectedSeries) @@ -983,7 +983,7 @@ func TestExponentialMovingAverageSuccess(t *testing.T) { func testMovingFunctionError(t *testing.T, target string) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() engine := NewEngine(&common.MovingFunctionStorage{ StepMillis: 10000, @@ -1067,7 +1067,7 @@ func TestMovingMinError(t *testing.T) { func TestIsNonNull(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() tests := []struct { inputs []float64 @@ -1107,7 +1107,7 @@ func TestIsNonNull(t *testing.T) { func TestKeepLastValue(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() tests := []struct { inputs []float64 @@ -1146,7 +1146,7 @@ func TestKeepLastValue(t *testing.T) { func TestSustainedAbove(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() tests := []struct { inputs []float64 @@ -1232,7 +1232,7 @@ func TestSustainedAbove(t *testing.T) { func TestSustainedAboveFail(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() input := ts.NewSeries(ctx, "foo", time.Now(), common.NewTestSeriesValues(ctx, 10000, []float64{0})) outputs, err := sustainedAbove(ctx, singlePathSpec{ @@ -1244,7 +1244,7 @@ func TestSustainedAboveFail(t *testing.T) { func TestSustainedBelow(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() tests := []struct { inputs []float64 @@ -1329,7 +1329,7 @@ func TestSustainedBelow(t *testing.T) { func TestSustainedBelowFail(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() input := ts.NewSeries(ctx, "foo", time.Now(), common.NewTestSeriesValues(ctx, 10000, []float64{0})) outputs, err := sustainedBelow(ctx, singlePathSpec{ @@ -1407,7 +1407,7 @@ func testOrderedAggregationFunc(t *testing.T, ctx *common.Context, tests []nIntP func TestHighest(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() tests := []nIntParamGoldenDataWithAgg{ { @@ -1448,7 +1448,7 @@ func TestHighest(t *testing.T) { func TestHighestCurrent(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() tests := []nIntParamGoldenData{ { @@ -1477,7 +1477,7 @@ func TestHighestCurrent(t *testing.T) { func TestHighestCurrentWithNaNSeries(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() tests := []nIntParamGoldenData{ { @@ -1511,7 +1511,7 @@ func TestHighestCurrentWithNaNSeries(t *testing.T) { func TestHighestAverage(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() tests := []nIntParamGoldenData{ { @@ -1530,7 +1530,7 @@ func TestHighestAverage(t *testing.T) { func TestHighestMax(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() tests := []nIntParamGoldenData{ { @@ -1550,7 +1550,7 @@ func TestHighestMax(t *testing.T) { //nolint:govet func TestFallbackSeries(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() tests := []struct { input []common.TestSeries @@ -1595,7 +1595,7 @@ func TestFallbackSeries(t *testing.T) { func TestMostDeviant(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() tests := []nIntParamGoldenData{ { @@ -1619,7 +1619,7 @@ func TestMostDeviant(t *testing.T) { func TestLowest(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() tests := []nIntParamGoldenDataWithAgg{ { @@ -1660,7 +1660,7 @@ func TestLowest(t *testing.T) { func TestLowestAverage(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() tests := []nIntParamGoldenData{ { @@ -1689,7 +1689,7 @@ func TestLowestAverage(t *testing.T) { func TestLowestCurrent(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() tests := []nIntParamGoldenData{ { @@ -1725,7 +1725,7 @@ func testComparatorFunc( resultIndexes []int, ) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() input := getTestInput(ctx) results, err := f(ctx, singlePathSpec{ @@ -1771,7 +1771,7 @@ func TestCurrentBelow(t *testing.T) { func TestRemoveBelowValue(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() nan := math.NaN() tests := []struct { @@ -1815,7 +1815,7 @@ func TestRemoveBelowValue(t *testing.T) { func TestRemoveAboveValue(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() nan := math.NaN() tests := []struct { @@ -1861,7 +1861,7 @@ func TestRemoveAboveValue(t *testing.T) { func TestRemoveEmptySeries(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() nan := math.NaN() tests := []struct { @@ -1903,7 +1903,7 @@ func generateSeriesList(ctx *common.Context, start time.Time, inputs []common.Te func TestScaleToSeconds(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() tests := []struct { millisPerStep int @@ -1956,7 +1956,7 @@ func TestScaleToSeconds(t *testing.T) { func TestAsPercentWithSeriesTotal(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() tests := []struct { valuesStep int @@ -2011,7 +2011,7 @@ func TestAsPercentWithSeriesTotal(t *testing.T) { func TestAsPercentWithFloatTotal(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() nan := math.NaN() tests := []struct { @@ -2061,7 +2061,7 @@ func TestAsPercentWithFloatTotal(t *testing.T) { func TestAsPercentWithNilTotal(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() nan := math.NaN() tests := []struct { @@ -2101,7 +2101,7 @@ func TestAsPercentWithNilTotal(t *testing.T) { func TestAsPercentWithSeriesList(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() nan := math.NaN() inputs := []struct { @@ -2183,7 +2183,7 @@ func TestAsPercentWithSeriesList(t *testing.T) { func testLogarithm(t *testing.T, base int, indices []int) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() invals := make([]float64, 101) for i := range invals { @@ -2219,7 +2219,7 @@ func TestLogarithm(t *testing.T) { func TestIntegral(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() invals := []float64{ 0, 1, 2, 3, 4, 5, 6, math.NaN(), 8, math.NaN(), @@ -2249,7 +2249,7 @@ func TestIntegral(t *testing.T) { func TestInterpolate(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() tests := []struct { values []float64 @@ -2310,7 +2310,7 @@ func TestInterpolate(t *testing.T) { func TestIntegralByInterval(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() invals := []float64{ math.NaN(), 1, 2, 3, 4, 5, math.NaN(), 6, 7, 8, @@ -2340,7 +2340,7 @@ func TestIntegralByInterval(t *testing.T) { func TestDerivative(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() tests := []struct { values []float64 @@ -2373,7 +2373,7 @@ func TestDerivative(t *testing.T) { func TestNonNegativeDerivative(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() tests := []struct { values []float64 @@ -2414,7 +2414,7 @@ func (o TimeSeriesPtrVector) Swap(i, j int) { o[i], o[j] = o[j], o[i] } func TestConstantLine(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() testValue := 5.0 r, err := constantLine(ctx, testValue) @@ -2432,7 +2432,7 @@ func TestConstantLine(t *testing.T) { func TestIdentity(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() testName := "testName.mytest" r, err := identity(ctx, testName) @@ -2451,7 +2451,7 @@ func TestIdentity(t *testing.T) { func TestLimit(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() // invalid input testInput := getTestInput(ctx) @@ -2477,7 +2477,7 @@ func TestLimit(t *testing.T) { func TestLimitSortStable(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() constValues := common.NewTestSeriesValues(ctx, 1000, []float64{1, 2, 3, 4}) series := []*ts.Series{ @@ -2520,7 +2520,7 @@ func TestLimitSortStable(t *testing.T) { func TestHitCount(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() now := time.Now() tests := []struct { @@ -2577,7 +2577,7 @@ func TestHitCount(t *testing.T) { func TestSubstr(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() now := ctx.StartTime input := struct { @@ -2658,7 +2658,7 @@ func (*mockStorage) CompleteTags( func TestHoltWintersForecast(t *testing.T) { ctx := common.NewTestContext() ctx.Engine = NewEngine(&mockStorage{}, CompileOptions{}) - defer ctx.Close() + defer func() { _ = ctx.Close() }() now := ctx.StartTime tests := []struct { @@ -2708,7 +2708,7 @@ func TestHoltWintersForecast(t *testing.T) { func TestHoltWintersConfidenceBands(t *testing.T) { ctx := common.NewTestContext() ctx.Engine = NewEngine(&mockStorage{}, CompileOptions{}) - defer ctx.Close() + defer func() { _ = ctx.Close() }() now := ctx.StartTime tests := []struct { @@ -2768,7 +2768,7 @@ func TestHoltWintersConfidenceBands(t *testing.T) { func TestHoltWintersAberration(t *testing.T) { ctx := common.NewTestContext() ctx.Engine = NewEngine(&mockStorage{}, CompileOptions{}) - defer ctx.Close() + defer func() { _ = ctx.Close() }() now := ctx.StartTime tests := []struct { @@ -2815,7 +2815,7 @@ func TestHoltWintersAberration(t *testing.T) { func TestSquareRoot(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() nan := math.NaN() startTime := ctx.StartTime @@ -2864,7 +2864,7 @@ func TestSquareRoot(t *testing.T) { func TestStdev(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() nan := math.NaN() startTime := ctx.StartTime @@ -2906,7 +2906,7 @@ func TestStdev(t *testing.T) { func TestRangeOfSeries(t *testing.T) { ctx, input := newConsolidationTestSeries() - defer ctx.Close() + defer func() { _ = ctx.Close() }() expectedStart := ctx.StartTime.Add(-30 * time.Second) expectedStep := 10000 @@ -2926,7 +2926,7 @@ type percentileFunction func(ctx *common.Context, seriesList singlePathSpec, per func testPercentileFunction(t *testing.T, f percentileFunction, expected []common.TestSeries) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() nan := math.NaN() startTime := ctx.StartTime @@ -3046,7 +3046,7 @@ func testRandomWalkFunctionInternal(t *testing.T, ctx *common.Context, stepSize, func TestRandomWalkFunction(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() ctx.EndTime = ctx.StartTime.Add(1100 * time.Millisecond) testRandomWalkFunctionInternal(t, ctx, 1, 2) @@ -3057,7 +3057,7 @@ func TestRandomWalkFunction(t *testing.T) { func testAggregateLineInternal(t *testing.T, f string, expectedName string, expectedVal float64) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() input := struct { name string @@ -3100,7 +3100,7 @@ func TestAggregateLine(t *testing.T) { func TestChanged(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() nan := math.NaN() startTime := ctx.StartTime @@ -3158,7 +3158,7 @@ func TestMovingMedian(t *testing.T) { startTime := now.Add(-3 * time.Minute) endTime := now.Add(-time.Minute) ctx := common.NewContext(common.ContextOptions{Start: startTime, End: endTime, Engine: engine}) - defer ctx.Close() + defer func() { _ = ctx.Close() }() stepSize := 60000 target := "movingMedian(foo.bar.q.zed, '1min')" @@ -3186,7 +3186,7 @@ func TestMovingAverage(t *testing.T) { startTime := now.Add(-3 * time.Minute) endTime := now.Add(-1 * time.Minute) ctx := common.NewContext(common.ContextOptions{Start: startTime, End: endTime, Engine: engine}) - defer ctx.Close() + defer func() { _ = ctx.Close() }() stepSize := 60000 target := `movingAverage(timeShift(foo.bar.g.zed, '-1d'), '1min', 0.7)` @@ -3206,7 +3206,7 @@ func TestMovingAverage(t *testing.T) { func TestLegendValue(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() vals := []float64{1.0, 2.0, 3.0, 4.0, math.NaN()} input := struct { @@ -3252,7 +3252,7 @@ func TestLegendValue(t *testing.T) { func TestCactiStyle(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() stepSize := 10000 inputs := []struct { @@ -3307,7 +3307,7 @@ func TestCactiStyle(t *testing.T) { func TestConsolidateBy(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() stepSize := 10000 input := struct { @@ -3386,7 +3386,7 @@ func TestPow(t *testing.T) { func TestCumulative(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() stepSize := 10000 input := struct { @@ -3419,7 +3419,7 @@ func TestCumulative(t *testing.T) { func TestOffsetToZero(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() nan := math.NaN() startTime := ctx.StartTime @@ -3472,7 +3472,7 @@ func TestTimeFunction(t *testing.T) { truncatedNow := float64(now.Truncate(time.Second).Unix()) ctx.StartTime = now ctx.EndTime = now.Add(2 * time.Minute) - defer ctx.Close() + defer func() { _ = ctx.Close() }() results, err := timeFunction(ctx, "foo", 30) require.NoError(t, err) @@ -3498,7 +3498,7 @@ func TestTimeShift(t *testing.T) { End: endTime, Engine: engine, }) - defer ctx.Close() + defer func() { _ = ctx.Close() }() stepSize := 60000 target := "timeShift(foo.bar.q.zed, '1min', false)" @@ -3543,7 +3543,7 @@ var ( func testDelay(t *testing.T, target, expectedName string, values, output []float64) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() engine := NewEngine(&common.MovingFunctionStorage{ StepMillis: 10000, @@ -3580,7 +3580,7 @@ func TestTimeSlice(t *testing.T) { func TestDashed(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() nan := math.NaN() startTime := ctx.StartTime @@ -3619,7 +3619,7 @@ func TestDashed(t *testing.T) { func TestThreshold(t *testing.T) { ctx := common.NewTestContext() - defer ctx.Close() + defer func() { _ = ctx.Close() }() r, err := threshold(ctx, 1.0, "bar", "yellow") require.NoError(t, err) diff --git a/src/query/graphite/ts/series.go b/src/query/graphite/ts/series.go index ff8dc691bd..5f5be29792 100644 --- a/src/query/graphite/ts/series.go +++ b/src/query/graphite/ts/series.go @@ -102,6 +102,7 @@ func (a SeriesByNameAndNaturalNumbers) Swap(i, j int) { } // Less determines if a series is ordered before another series by name +// nolint: ifshort func (a SeriesByNameAndNaturalNumbers) Less(i, j int) bool { left := a[i].name if strings.ContainsAny(left, digits) { diff --git a/src/query/graphite/ts/sortable_series_test.go b/src/query/graphite/ts/sortable_series_test.go index a1cd3a6e24..77b69d22b8 100644 --- a/src/query/graphite/ts/sortable_series_test.go +++ b/src/query/graphite/ts/sortable_series_test.go @@ -102,7 +102,7 @@ func testSortImpl(ctx context.Context, t *testing.T, tests []testSortData, sr Se func TestSortSeries(t *testing.T) { ctx := context.New() - defer ctx.Close() + defer func() { _ = ctx.Close() }() testInput := []testSeries{ {"foo", []float64{0, 601, 3, 4}}, @@ -136,7 +136,7 @@ func TestSortSeries(t *testing.T) { func TestSortSeriesStable(t *testing.T) { ctx := context.New() - defer ctx.Close() + defer func() { _ = ctx.Close() }() constValues := newTestSeriesValues(ctx, 1000, []float64{1, 2, 3, 4}) series := []*Series{ @@ -177,7 +177,7 @@ func TestSortSeriesStable(t *testing.T) { func TestSortSeriesByNameAndNaturalNumbers(t *testing.T) { ctx := context.New() - defer ctx.Close() + defer func() { _ = ctx.Close() }() constValues := newTestSeriesValues(ctx, 1000, []float64{1, 2, 3, 4}) series := []*Series{