github.com/go-graphite/carbonapi@v0.17.0/expr/functions/sortByName/function_test.go (about) 1 package sortByName 2 3 import ( 4 "context" 5 "testing" 6 "time" 7 8 "github.com/go-graphite/carbonapi/expr/interfaces" 9 "github.com/go-graphite/carbonapi/expr/metadata" 10 "github.com/go-graphite/carbonapi/expr/types" 11 "github.com/go-graphite/carbonapi/pkg/parser" 12 th "github.com/go-graphite/carbonapi/tests" 13 ) 14 15 var ( 16 md []interfaces.FunctionMetadata = New("") 17 ) 18 19 func init() { 20 for _, m := range md { 21 metadata.RegisterFunction(m.Name, m.F) 22 } 23 } 24 25 func TestSortByName(t *testing.T) { 26 now32 := int64(time.Now().Unix()) 27 28 tests := []th.EvalTestItem{ 29 { 30 "sortByName(metric*)", 31 map[parser.MetricRequest][]*types.MetricData{ 32 {Metric: "metric*", From: 0, Until: 1}: { 33 types.MakeMetricData("metricX", []float64{0, 0, 0, 0, 0, 0}, 1, now32), 34 types.MakeMetricData("metricA", []float64{0, 1, 0, 0, 0, 0}, 1, now32), 35 types.MakeMetricData("metricB", []float64{0, 0, 2, 0, 0, 0}, 1, now32), 36 types.MakeMetricData("metricC", []float64{0, 0, 0, 3, 0, 0}, 1, now32), 37 }, 38 }, 39 []*types.MetricData{ 40 types.MakeMetricData("metricA", []float64{0, 1, 0, 0, 0, 0}, 1, now32), 41 types.MakeMetricData("metricB", []float64{0, 0, 2, 0, 0, 0}, 1, now32), 42 types.MakeMetricData("metricC", []float64{0, 0, 0, 3, 0, 0}, 1, now32), 43 types.MakeMetricData("metricX", []float64{0, 0, 0, 0, 0, 0}, 1, now32), 44 }, 45 }, 46 { 47 "sortByName(metric*,natural=true)", 48 map[parser.MetricRequest][]*types.MetricData{ 49 {Metric: "metric*", From: 0, Until: 1}: { 50 types.MakeMetricData("metric1", []float64{0, 0, 0, 0, 0, 0}, 1, now32), 51 types.MakeMetricData("metric12", []float64{0, 1, 0, 0, 0, 0}, 1, now32), 52 types.MakeMetricData("metric1234567890", []float64{0, 0, 0, 5, 0, 0}, 1, now32), 53 types.MakeMetricData("metric2", []float64{0, 0, 2, 0, 0, 0}, 1, now32), 54 types.MakeMetricData("metric11", []float64{0, 0, 0, 3, 0, 0}, 1, now32), 55 types.MakeMetricData("metric", []float64{0, 0, 0, 0, 0, 0}, 1, now32), 56 }, 57 }, 58 []*types.MetricData{ 59 types.MakeMetricData("metric", []float64{0, 0, 0, 0, 0, 0}, 1, now32), 60 types.MakeMetricData("metric1", []float64{0, 0, 0, 0, 0, 0}, 1, now32), 61 types.MakeMetricData("metric2", []float64{0, 0, 2, 0, 0, 0}, 1, now32), 62 types.MakeMetricData("metric11", []float64{0, 0, 0, 3, 0, 0}, 1, now32), 63 types.MakeMetricData("metric12", []float64{0, 1, 0, 0, 0, 0}, 1, now32), 64 types.MakeMetricData("metric1234567890", []float64{0, 0, 0, 5, 0, 0}, 1, now32), 65 }, 66 }, 67 { 68 "sortByName(metric.foo.*)", 69 map[parser.MetricRequest][]*types.MetricData{ 70 parser.MetricRequest{ 71 Metric: "metric.foo.*", 72 From: 0, 73 Until: 1, 74 }: { 75 types.MakeMetricData("metric.foo.x99", []float64{1}, 1, now32), 76 types.MakeMetricData("metric.foo.x1", []float64{1}, 1, now32), 77 types.MakeMetricData("metric.foo.x2", []float64{1}, 1, now32), 78 types.MakeMetricData("metric.foo.x100", []float64{1}, 1, now32), 79 }, 80 }, 81 []*types.MetricData{ // 100 is placed between 1 and 2 because it is alphabetical sort 82 types.MakeMetricData("metric.foo.x1", []float64{1}, 1, now32), 83 types.MakeMetricData("metric.foo.x100", []float64{1}, 1, now32), 84 types.MakeMetricData("metric.foo.x2", []float64{1}, 1, now32), 85 types.MakeMetricData("metric.foo.x99", []float64{1}, 1, now32), 86 }, 87 }, 88 { 89 "sortByName(metric.foo.*, true)", 90 map[parser.MetricRequest][]*types.MetricData{ 91 parser.MetricRequest{ 92 Metric: "metric.foo.*", 93 From: 0, 94 Until: 1, 95 }: { 96 types.MakeMetricData("metric.foo.x99", []float64{1}, 1, now32), 97 types.MakeMetricData("metric.foo.x1", []float64{1}, 1, now32), 98 types.MakeMetricData("metric.foo.x2", []float64{1}, 1, now32), 99 types.MakeMetricData("metric.foo.x100", []float64{1}, 1, now32), 100 }, 101 }, 102 []*types.MetricData{ // "natural" sort method considers that metrics contain numbers 103 types.MakeMetricData("metric.foo.x1", []float64{1}, 1, now32), 104 types.MakeMetricData("metric.foo.x2", []float64{1}, 1, now32), 105 types.MakeMetricData("metric.foo.x99", []float64{1}, 1, now32), 106 types.MakeMetricData("metric.foo.x100", []float64{1}, 1, now32), 107 }, 108 }, 109 { 110 "sortByName(metric.foo.*, natural=false, reverse=true)", 111 map[parser.MetricRequest][]*types.MetricData{ 112 parser.MetricRequest{ 113 Metric: "metric.foo.*", 114 From: 0, 115 Until: 1, 116 }: { 117 types.MakeMetricData("metric.foo.x99", []float64{1}, 1, now32), 118 types.MakeMetricData("metric.foo.x1", []float64{1}, 1, now32), 119 types.MakeMetricData("metric.foo.x2", []float64{1}, 1, now32), 120 types.MakeMetricData("metric.foo.x100", []float64{1}, 1, now32), 121 }, 122 }, 123 []*types.MetricData{ // alphabetical reverse sort 124 types.MakeMetricData("metric.foo.x99", []float64{1}, 1, now32), 125 types.MakeMetricData("metric.foo.x2", []float64{1}, 1, now32), 126 types.MakeMetricData("metric.foo.x100", []float64{1}, 1, now32), 127 types.MakeMetricData("metric.foo.x1", []float64{1}, 1, now32), 128 }, 129 }, 130 { 131 "sortByName(metric.foo.*, true, true)", 132 map[parser.MetricRequest][]*types.MetricData{ 133 parser.MetricRequest{ 134 Metric: "metric.foo.*", 135 From: 0, 136 Until: 1, 137 }: { 138 types.MakeMetricData("metric.foo.x99", []float64{1}, 1, now32), 139 types.MakeMetricData("metric.foo.x1", []float64{1}, 1, now32), 140 types.MakeMetricData("metric.foo.x2", []float64{1}, 1, now32), 141 types.MakeMetricData("metric.foo.x100", []float64{1}, 1, now32), 142 }, 143 }, 144 []*types.MetricData{ // "natural" reverse sort 145 types.MakeMetricData("metric.foo.x100", []float64{1}, 1, now32), 146 types.MakeMetricData("metric.foo.x99", []float64{1}, 1, now32), 147 types.MakeMetricData("metric.foo.x2", []float64{1}, 1, now32), 148 types.MakeMetricData("metric.foo.x1", []float64{1}, 1, now32), 149 }, 150 }, 151 } 152 153 for _, tt := range tests { 154 testName := tt.Target 155 t.Run(testName, func(t *testing.T) { 156 eval := th.EvaluatorFromFunc(md[0].F) 157 th.TestEvalExpr(t, eval, &tt) 158 }) 159 } 160 161 } 162 163 func BenchmarkSortByName(b *testing.B) { 164 benchmarks := []struct { 165 target string 166 M map[parser.MetricRequest][]*types.MetricData 167 }{ 168 { 169 target: "sortByName(metric.foo.*)", 170 M: map[parser.MetricRequest][]*types.MetricData{ 171 parser.MetricRequest{ 172 Metric: "metric.foo.*", 173 From: 0, 174 Until: 1, 175 }: { 176 types.MakeMetricData("metric.foo.x99", []float64{1}, 1, 1), 177 types.MakeMetricData("metric.foo.x1", []float64{1}, 1, 1), 178 types.MakeMetricData("metric.foo.x2", []float64{1}, 1, 1), 179 types.MakeMetricData("metric.foo.x100", []float64{1}, 1, 1), 180 }, 181 }, 182 }, 183 { 184 target: "sortByName(metric.foo.*, true)", 185 M: map[parser.MetricRequest][]*types.MetricData{ 186 parser.MetricRequest{ 187 Metric: "metric.foo.*", 188 From: 0, 189 Until: 1, 190 }: { 191 types.MakeMetricData("metric.foo.x99", []float64{1}, 1, 1), 192 types.MakeMetricData("metric.foo.x1", []float64{1}, 1, 1), 193 types.MakeMetricData("metric.foo.x2", []float64{1}, 1, 1), 194 types.MakeMetricData("metric.foo.x100", []float64{1}, 1, 1), 195 }, 196 }, 197 }, 198 { 199 target: "sortByName(metric.foo.*, natural=false, reverse=true)", 200 M: map[parser.MetricRequest][]*types.MetricData{ 201 parser.MetricRequest{ 202 Metric: "metric.foo.*", 203 From: 0, 204 Until: 1, 205 }: { 206 types.MakeMetricData("metric.foo.x99", []float64{1}, 1, 1), 207 types.MakeMetricData("metric.foo.x1", []float64{1}, 1, 1), 208 types.MakeMetricData("metric.foo.x2", []float64{1}, 1, 1), 209 types.MakeMetricData("metric.foo.x100", []float64{1}, 1, 1), 210 }, 211 }, 212 }, 213 { 214 target: "sortByName(metric.foo.*, true, true)", 215 M: map[parser.MetricRequest][]*types.MetricData{ 216 parser.MetricRequest{ 217 Metric: "metric.foo.*", 218 From: 0, 219 Until: 1, 220 }: { 221 types.MakeMetricData("metric.foo.x99", []float64{1}, 1, 1), 222 types.MakeMetricData("metric.foo.x1", []float64{1}, 1, 1), 223 types.MakeMetricData("metric.foo.x2", []float64{1}, 1, 1), 224 types.MakeMetricData("metric.foo.x100", []float64{1}, 1, 1), 225 }, 226 }, 227 }, 228 } 229 230 eval := th.EvaluatorFromFunc(md[0].F) 231 232 for _, bm := range benchmarks { 233 b.Run(bm.target, func(b *testing.B) { 234 exp, _, err := parser.ParseExpr(bm.target) 235 if err != nil { 236 b.Fatalf("failed to parse %s: %+v", bm.target, err) 237 } 238 239 b.ResetTimer() 240 241 for i := 0; i < b.N; i++ { 242 g, err := eval.Eval(context.Background(), exp, 0, 1, bm.M) 243 if err != nil { 244 b.Fatalf("failed to eval %s: %+v", bm.target, err) 245 } 246 _ = g 247 } 248 }) 249 } 250 }