github.com/go-graphite/carbonapi@v0.17.0/expr/functions/aggregate/function_test.go (about) 1 package aggregate 2 3 import ( 4 "context" 5 "math" 6 "testing" 7 "time" 8 9 fconfig "github.com/go-graphite/carbonapi/expr/functions/config" 10 "github.com/go-graphite/carbonapi/expr/interfaces" 11 "github.com/go-graphite/carbonapi/expr/metadata" 12 "github.com/go-graphite/carbonapi/expr/types" 13 "github.com/go-graphite/carbonapi/pkg/parser" 14 th "github.com/go-graphite/carbonapi/tests" 15 "github.com/go-graphite/carbonapi/tests/compare" 16 ) 17 18 var ( 19 md []interfaces.FunctionMetadata = New("") 20 ) 21 22 func init() { 23 for _, m := range md { 24 metadata.RegisterFunction(m.Name, m.F) 25 } 26 } 27 28 func TestAverageSeries(t *testing.T) { 29 fconfig.Config.ExtractTagsFromArgs = false 30 31 now32 := int64(time.Now().Unix()) 32 33 tests := []th.EvalTestItem{ 34 { 35 `aggregate(metric[123], "avg")`, 36 map[parser.MetricRequest][]*types.MetricData{ 37 {"metric[123]", "", 0, 1}: {}, 38 }, 39 []*types.MetricData{}, 40 }, 41 { 42 `aggregate(metric[123], "avg")`, 43 map[parser.MetricRequest][]*types.MetricData{ 44 {"metric[123]", "", 0, 1}: { 45 types.MakeMetricData("metric1", []float64{1, math.NaN(), 2, 3, 4, 5}, 1, now32), 46 types.MakeMetricData("metric2", []float64{2, math.NaN(), 3, math.NaN(), 5, 6}, 1, now32), 47 types.MakeMetricData("metric3", []float64{3, math.NaN(), 4, 5, 6, math.NaN()}, 1, now32), 48 }, 49 }, 50 []*types.MetricData{types.MakeMetricData("avgSeries(metric[123])", 51 []float64{2, math.NaN(), 3, 4, 5, 5.5}, 1, now32).SetTag("aggregatedBy", "avg")}, 52 }, 53 { 54 `aggregate(metric[123], "avg_zero")`, 55 map[parser.MetricRequest][]*types.MetricData{ 56 {"metric[123]", "", 0, 1}: { 57 types.MakeMetricData("metric1", []float64{1, math.NaN(), 2, 4, 4, 6}, 1, now32), 58 types.MakeMetricData("metric2", []float64{2, math.NaN(), 3, math.NaN(), 5, 6}, 1, now32), 59 types.MakeMetricData("metric3", []float64{3, math.NaN(), 4, 5, 6, math.NaN()}, 1, now32), 60 }, 61 }, 62 []*types.MetricData{types.MakeMetricData("avg_zeroSeries(metric[123])", 63 []float64{2, math.NaN(), 3, 3, 5, 4}, 1, now32).SetTag("aggregatedBy", "avg_zero")}, 64 }, 65 { 66 `aggregate(metric[123], "count")`, 67 map[parser.MetricRequest][]*types.MetricData{ 68 {"metric[123]", "", 0, 1}: { 69 types.MakeMetricData("metric1", []float64{1, math.NaN(), 2, 3, 4, 5}, 1, now32), 70 types.MakeMetricData("metric2", []float64{2, math.NaN(), 3, math.NaN(), 5, 6}, 1, now32), 71 types.MakeMetricData("metric3", []float64{3, math.NaN(), 4, 5, 6, math.NaN()}, 1, now32), 72 }, 73 }, 74 []*types.MetricData{types.MakeMetricData("countSeries(metric[123])", 75 []float64{3, math.NaN(), 3, 2, 3, 2}, 1, now32).SetTag("aggregatedBy", "count")}, 76 }, 77 { 78 `aggregate(metric[123], "diff")`, 79 map[parser.MetricRequest][]*types.MetricData{ 80 {"metric[123]", "", 0, 1}: { 81 types.MakeMetricData("metric1", []float64{1, math.NaN(), 2, 3, 4, 5}, 1, now32), 82 types.MakeMetricData("metric2", []float64{2, math.NaN(), 3, math.NaN(), 5, 6}, 1, now32), 83 types.MakeMetricData("metric3", []float64{3, math.NaN(), 4, 5, 6, math.NaN()}, 1, now32), 84 }, 85 }, 86 []*types.MetricData{types.MakeMetricData("diffSeries(metric[123])", 87 []float64{-4, math.NaN(), -5, -2, -7, -1}, 1, now32).SetTag("aggregatedBy", "diff")}, 88 }, 89 { 90 `aggregate(metric[123], "last")`, 91 map[parser.MetricRequest][]*types.MetricData{ 92 {"metric[123]", "", 0, 1}: { 93 types.MakeMetricData("metric1", []float64{1, math.NaN(), 2, 3, 4, 5}, 1, now32), 94 types.MakeMetricData("metric2", []float64{2, math.NaN(), 3, math.NaN(), 5, 6}, 1, now32), 95 types.MakeMetricData("metric3", []float64{3, math.NaN(), 4, 5, 6, math.NaN()}, 1, now32), 96 }, 97 }, 98 []*types.MetricData{types.MakeMetricData("lastSeries(metric[123])", 99 []float64{3, math.NaN(), 4, 5, 6, 6}, 1, now32).SetTag("aggregatedBy", "last")}, 100 }, 101 { 102 `aggregate(metric[123], "current")`, 103 map[parser.MetricRequest][]*types.MetricData{ 104 {"metric[123]", "", 0, 1}: { 105 types.MakeMetricData("metric1", []float64{1, math.NaN(), 2, 3, 4, 5}, 1, now32), 106 types.MakeMetricData("metric2", []float64{2, math.NaN(), 3, math.NaN(), 5, 6}, 1, now32), 107 types.MakeMetricData("metric3", []float64{3, math.NaN(), 4, 5, 6, math.NaN()}, 1, now32), 108 }, 109 }, 110 []*types.MetricData{types.MakeMetricData("currentSeries(metric[123])", 111 []float64{3, math.NaN(), 4, 5, 6, 6}, 1, now32).SetTag("aggregatedBy", "current")}, 112 }, 113 { 114 `aggregate(metric[123], "max")`, 115 map[parser.MetricRequest][]*types.MetricData{ 116 {"metric[123]", "", 0, 1}: { 117 types.MakeMetricData("metric1", []float64{1, math.NaN(), 2, 3, 4, 5}, 1, now32), 118 types.MakeMetricData("metric2", []float64{2, math.NaN(), 3, math.NaN(), 5, 6}, 1, now32), 119 types.MakeMetricData("metric3", []float64{3, math.NaN(), 4, 5, 6, math.NaN()}, 1, now32), 120 }, 121 }, 122 []*types.MetricData{types.MakeMetricData("maxSeries(metric[123])", 123 []float64{3, math.NaN(), 4, 5, 6, 6}, 1, now32).SetTag("aggregatedBy", "max")}, 124 }, 125 { 126 `aggregate(metric[123], "min")`, 127 map[parser.MetricRequest][]*types.MetricData{ 128 {"metric[123]", "", 0, 1}: { 129 types.MakeMetricData("metric1", []float64{1, math.NaN(), 2, 3, 4, 6}, 1, now32), 130 types.MakeMetricData("metric2", []float64{2, math.NaN(), 3, math.NaN(), 5, 5}, 1, now32), 131 types.MakeMetricData("metric3", []float64{3, math.NaN(), 4, 5, 6, math.NaN()}, 1, now32), 132 }, 133 }, 134 []*types.MetricData{types.MakeMetricData("minSeries(metric[123])", 135 []float64{1, math.NaN(), 2, 3, 4, 5}, 1, now32).SetTag("aggregatedBy", "min")}, 136 }, 137 { 138 `aggregate(metric[123], "median")`, 139 map[parser.MetricRequest][]*types.MetricData{ 140 {"metric[123]", "", 0, 1}: { 141 types.MakeMetricData("metric1", []float64{1, math.NaN(), 2, 3, 4, 6}, 1, now32), 142 types.MakeMetricData("metric2", []float64{2, math.NaN(), 3, math.NaN(), 5, 5}, 1, now32), 143 types.MakeMetricData("metric3", []float64{3, math.NaN(), 4, 5, 6, math.NaN()}, 1, now32), 144 }, 145 }, 146 []*types.MetricData{types.MakeMetricData("medianSeries(metric[123])", 147 []float64{2, math.NaN(), 3, 4, 5, 5.5}, 1, now32).SetTag("aggregatedBy", "median")}, 148 }, 149 { 150 `aggregate(metric[123], "multiply")`, 151 map[parser.MetricRequest][]*types.MetricData{ 152 {"metric[123]", "", 0, 1}: { 153 types.MakeMetricData("metric1", []float64{1, math.NaN(), 2, 3, 4, 6}, 1, now32), 154 types.MakeMetricData("metric2", []float64{2, math.NaN(), 3, math.NaN(), 5, 5}, 1, now32), 155 types.MakeMetricData("metric3", []float64{3, math.NaN(), 4, 5, 6, math.NaN()}, 1, now32), 156 }, 157 }, 158 []*types.MetricData{types.MakeMetricData("multiplySeries(metric[123])", 159 []float64{6, math.NaN(), 24, math.NaN(), 120, math.NaN()}, 1, now32).SetTag("aggregatedBy", "multiply")}, 160 }, 161 { 162 `aggregate(metric[123], "range")`, 163 map[parser.MetricRequest][]*types.MetricData{ 164 {"metric[123]", "", 0, 1}: { 165 types.MakeMetricData("metric1", []float64{1, math.NaN(), 2, 3, 4, 6}, 1, now32), 166 types.MakeMetricData("metric2", []float64{2, math.NaN(), 3, math.NaN(), 5, 5}, 1, now32), 167 types.MakeMetricData("metric3", []float64{3, math.NaN(), 4, 5, 6, math.NaN()}, 1, now32), 168 }, 169 }, 170 []*types.MetricData{types.MakeMetricData("rangeSeries(metric[123])", 171 []float64{2, math.NaN(), 2, 2, 2, 1}, 1, now32).SetTag("aggregatedBy", "range")}, 172 }, 173 { 174 `aggregate(metric[123], "rangeOf")`, 175 map[parser.MetricRequest][]*types.MetricData{ 176 {"metric[123]", "", 0, 1}: { 177 types.MakeMetricData("metric1", []float64{1, math.NaN(), 2, 3, 4, 6}, 1, now32), 178 types.MakeMetricData("metric2", []float64{2, math.NaN(), 3, math.NaN(), 5, 5}, 1, now32), 179 types.MakeMetricData("metric3", []float64{3, math.NaN(), 4, 5, 6, math.NaN()}, 1, now32), 180 }, 181 }, 182 []*types.MetricData{types.MakeMetricData("rangeOfSeries(metric[123])", 183 []float64{2, math.NaN(), 2, 2, 2, 1}, 1, now32).SetTag("aggregatedBy", "rangeOf")}, 184 }, 185 { 186 `aggregate(metric[123], "sum")`, 187 map[parser.MetricRequest][]*types.MetricData{ 188 {"metric[123]", "", 0, 1}: { 189 types.MakeMetricData("metric1", []float64{1, math.NaN(), 2, 3, 4, 6}, 1, now32), 190 types.MakeMetricData("metric2", []float64{2, math.NaN(), 3, math.NaN(), 5, 5}, 1, now32), 191 types.MakeMetricData("metric3", []float64{3, math.NaN(), 4, 5, 6, math.NaN()}, 1, now32), 192 }, 193 }, 194 []*types.MetricData{types.MakeMetricData("sumSeries(metric[123])", 195 []float64{6, math.NaN(), 9, 8, 15, 11}, 1, now32).SetTag("aggregatedBy", "sum")}, 196 }, 197 { 198 `aggregate(metric[123], "total")`, 199 map[parser.MetricRequest][]*types.MetricData{ 200 {"metric[123]", "", 0, 1}: { 201 types.MakeMetricData("metric1", []float64{1, math.NaN(), 2, 3, 4, 6}, 1, now32), 202 types.MakeMetricData("metric2", []float64{2, math.NaN(), 3, math.NaN(), 5, 5}, 1, now32), 203 types.MakeMetricData("metric3", []float64{3, math.NaN(), 4, 5, 6, math.NaN()}, 1, now32), 204 }, 205 }, 206 []*types.MetricData{types.MakeMetricData("totalSeries(metric[123])", 207 []float64{6, math.NaN(), 9, 8, 15, 11}, 1, now32).SetTag("aggregatedBy", "total")}, 208 }, 209 { 210 `aggregate(metric[123], "avg", 0.7)`, // Test with xFilesFactor 211 map[parser.MetricRequest][]*types.MetricData{ 212 {"metric[123]", "", 0, 1}: { 213 types.MakeMetricData("metric1", []float64{1, math.NaN(), 2, math.NaN(), 4, 5}, 1, now32), 214 types.MakeMetricData("metric2", []float64{2, math.NaN(), 3, math.NaN(), 5, 6}, 1, now32), 215 types.MakeMetricData("metric3", []float64{3, math.NaN(), 4, 5, 6, math.NaN()}, 1, now32), 216 }, 217 }, 218 []*types.MetricData{types.MakeMetricData("avgSeries(metric[123])", 219 []float64{2, math.NaN(), 3, math.NaN(), 5, math.NaN()}, 1, now32).SetTag("aggregatedBy", "avg")}, 220 }, 221 { 222 `aggregate(metric[123], "sum", 0.5)`, // Test with xFilesFactor 223 map[parser.MetricRequest][]*types.MetricData{ 224 {"metric[123]", "", 0, 1}: { 225 types.MakeMetricData("metric1", []float64{1, math.NaN(), 2, 3, 4, math.NaN()}, 1, now32), 226 types.MakeMetricData("metric2", []float64{2, math.NaN(), 3, math.NaN(), 5, 5}, 1, now32), 227 types.MakeMetricData("metric3", []float64{3, math.NaN(), 4, 5, 6, math.NaN()}, 1, now32), 228 }, 229 }, 230 []*types.MetricData{types.MakeMetricData("sumSeries(metric[123])", 231 []float64{6, math.NaN(), 9, 8, 15, math.NaN()}, 1, now32).SetTag("aggregatedBy", "sum")}, 232 }, 233 { 234 `aggregate(metric[123], "max", 0.3)`, 235 map[parser.MetricRequest][]*types.MetricData{ 236 {"metric[123]", "", 0, 1}: { 237 types.MakeMetricData("metric1", []float64{1, math.NaN(), 2, math.NaN(), 4, 5}, 1, now32), 238 types.MakeMetricData("metric2", []float64{2, math.NaN(), 3, math.NaN(), 5, 6}, 1, now32), 239 types.MakeMetricData("metric3", []float64{3, math.NaN(), 4, 5, 6, math.NaN()}, 1, now32), 240 }, 241 }, 242 []*types.MetricData{types.MakeMetricData("maxSeries(metric[123])", 243 []float64{3, math.NaN(), 4, 5, 6, 6}, 1, now32).SetTag("aggregatedBy", "max")}, 244 }, 245 { 246 `stddevSeries(metric[123])`, 247 map[parser.MetricRequest][]*types.MetricData{ 248 {"metric[123]", "", 0, 1}: { 249 types.MakeMetricData("metric1", []float64{1, math.NaN(), 2, 3, 4, 6}, 1, now32), 250 types.MakeMetricData("metric2", []float64{2, math.NaN(), 3, math.NaN(), 5, 5}, 1, now32), 251 types.MakeMetricData("metric3", []float64{3, math.NaN(), 4, 5, 6, math.NaN()}, 1, now32), 252 }, 253 }, 254 []*types.MetricData{types.MakeMetricData("stddevSeries(metric[123])", 255 []float64{0.816496580927726, math.NaN(), 0.816496580927726, 1, 0.816496580927726, 0.5}, 1, now32).SetTag("aggregatedBy", "stddev")}, 256 }, 257 { 258 `stddevSeries(metric1,metric2,metric3)`, 259 map[parser.MetricRequest][]*types.MetricData{ 260 {Metric: "metric1", From: 0, Until: 1}: {types.MakeMetricData("metric1", []float64{1, 2, 3, 4, 5}, 1, now32)}, 261 {Metric: "metric2", From: 0, Until: 1}: {types.MakeMetricData("metric2", []float64{2, 4, 6, 8, 10}, 1, now32)}, 262 {Metric: "metric3", From: 0, Until: 1}: {types.MakeMetricData("metric3", []float64{1, 2, 3, 4, 5}, 1, now32)}, 263 }, 264 []*types.MetricData{types.MakeMetricData("stddevSeries(metric1,metric2,metric3)", 265 []float64{0.4714045207910317, 0.9428090415820634, 1.4142135623730951, 1.8856180831641267, 2.357022603955158}, 1, now32).SetTag("aggregatedBy", "stddev")}, 266 }, 267 { 268 `aggregate(metric[123], "stddev")`, 269 map[parser.MetricRequest][]*types.MetricData{ 270 {Metric: "metric[123]", From: 0, Until: 1}: { 271 types.MakeMetricData("metric1", []float64{1, math.NaN(), 2, 3, 4, 6}, 1, now32), 272 types.MakeMetricData("metric2", []float64{2, math.NaN(), 3, math.NaN(), 5, 5}, 1, now32), 273 types.MakeMetricData("metric3", []float64{3, math.NaN(), 4, 5, 6, math.NaN()}, 1, now32), 274 }, 275 }, 276 []*types.MetricData{types.MakeMetricData("stddevSeries(metric[123])", 277 []float64{0.816496580927726, math.NaN(), 0.816496580927726, 1, 0.816496580927726, 0.5}, 1, now32).SetTag("aggregatedBy", "stddev")}, 278 }, 279 { 280 `aggregate(metric[123], "stddev")`, 281 map[parser.MetricRequest][]*types.MetricData{ 282 {Metric: "metric[123]", From: 0, Until: 1}: { 283 types.MakeMetricData("metric1", []float64{1, 2, 3, 4, 5}, 1, now32), 284 types.MakeMetricData("metric2", []float64{2, 4, 6, 8, 10}, 1, now32), 285 types.MakeMetricData("metric3", []float64{1, 2, 3, 4, 5}, 1, now32), 286 }, 287 }, 288 []*types.MetricData{types.MakeMetricData("stddevSeries(metric[123])", 289 []float64{0.4714045207910317, 0.9428090415820634, 1.4142135623730951, 1.8856180831641267, 2.357022603955158}, 1, now32).SetTag("aggregatedBy", "stddev")}, 290 }, 291 292 // sum 293 { 294 `sum(metric1,metric2)`, 295 map[parser.MetricRequest][]*types.MetricData{ 296 {Metric: "metric1", From: 0, Until: 1}: {types.MakeMetricData("metric1", []float64{0, -1, 2, -3, 4, 5}, 1, now32)}, 297 {Metric: "metric2", From: 0, Until: 1}: {types.MakeMetricData("metric2", []float64{0, 1, -2, 3, -4, -5}, 1, now32)}, 298 }, 299 []*types.MetricData{types.MakeMetricData("sumSeries(metric1,metric2)", 300 []float64{0, 0, 0, 0, 0, 0}, 1, now32).SetTag("aggregatedBy", "sum")}, 301 }, 302 { 303 "sum(metric1,metric2,metric3)", 304 map[parser.MetricRequest][]*types.MetricData{ 305 {Metric: "metric1", From: 0, Until: 1}: {types.MakeMetricData("metric1", []float64{1, 2, 3, 4, 5, math.NaN()}, 1, now32)}, 306 {Metric: "metric2", From: 0, Until: 1}: {types.MakeMetricData("metric2", []float64{2, 3, math.NaN(), 5, 6, math.NaN()}, 1, now32)}, 307 {Metric: "metric3", From: 0, Until: 1}: {types.MakeMetricData("metric3", []float64{3, 4, 5, 6, math.NaN(), math.NaN()}, 1, now32)}, 308 }, 309 []*types.MetricData{types.MakeMetricData("sumSeries(metric1,metric2,metric3)", []float64{6, 9, 8, 15, 11, math.NaN()}, 1, now32).SetTag("aggregatedBy", "sum")}, 310 }, 311 { 312 "sum(metric1,metric2,metric3,metric4)", 313 map[parser.MetricRequest][]*types.MetricData{ 314 {Metric: "metric1", From: 0, Until: 1}: {types.MakeMetricData("metric1", []float64{1, 2, 3, 4, 5, math.NaN()}, 1, now32)}, 315 {Metric: "metric2", From: 0, Until: 1}: {types.MakeMetricData("metric2", []float64{2, 3, math.NaN(), 5, 6, math.NaN()}, 1, now32)}, 316 {Metric: "metric3", From: 0, Until: 1}: {types.MakeMetricData("metric3", []float64{3, 4, 5, 6, math.NaN(), math.NaN()}, 1, now32)}, 317 }, 318 []*types.MetricData{types.MakeMetricData("sumSeries(metric1,metric2,metric3)", []float64{6, 9, 8, 15, 11, math.NaN()}, 1, now32).SetTag("aggregatedBy", "sum")}, 319 }, 320 321 // minMax 322 { 323 "maxSeries(metric1,metric2,metric3)", 324 map[parser.MetricRequest][]*types.MetricData{ 325 {Metric: "metric1", From: 0, Until: 1}: {types.MakeMetricData("metric1", []float64{1, math.NaN(), 2, 3, 4, 5}, 1, now32)}, 326 {Metric: "metric2", From: 0, Until: 1}: {types.MakeMetricData("metric2", []float64{2, math.NaN(), 3, math.NaN(), 5, 6}, 1, now32)}, 327 {Metric: "metric3", From: 0, Until: 1}: {types.MakeMetricData("metric3", []float64{3, math.NaN(), 4, 5, 6, math.NaN()}, 1, now32)}, 328 }, 329 []*types.MetricData{types.MakeMetricData("maxSeries(metric1,metric2,metric3)", 330 []float64{3, math.NaN(), 4, 5, 6, 6}, 1, now32).SetTag("aggregatedBy", "max")}, 331 }, 332 { 333 "minSeries(metric1,metric2,metric3)", 334 map[parser.MetricRequest][]*types.MetricData{ 335 {Metric: "metric1", From: 0, Until: 1}: {types.MakeMetricData("metric1", []float64{1, math.NaN(), 2, 3, 4, 5}, 1, now32)}, 336 {Metric: "metric2", From: 0, Until: 1}: {types.MakeMetricData("metric2", []float64{2, math.NaN(), 3, math.NaN(), 5, 6}, 1, now32)}, 337 {Metric: "metric3", From: 0, Until: 1}: {types.MakeMetricData("metric3", []float64{3, math.NaN(), 4, 5, 6, math.NaN()}, 1, now32)}, 338 }, 339 []*types.MetricData{types.MakeMetricData("minSeries(metric1,metric2,metric3)", 340 []float64{1, math.NaN(), 2, 3, 4, 5}, 1, now32).SetTag("aggregatedBy", "min")}, 341 }, 342 343 // avg 344 { 345 "averageSeries(metric1,metric2,metric3)", 346 map[parser.MetricRequest][]*types.MetricData{ 347 {Metric: "metric1", From: 0, Until: 1}: {types.MakeMetricData("metric1", []float64{1, math.NaN(), 2, 3, 4, 5}, 1, now32)}, 348 {Metric: "metric2", From: 0, Until: 1}: {types.MakeMetricData("metric2", []float64{2, math.NaN(), 3, math.NaN(), 5, 6}, 1, now32)}, 349 {Metric: "metric3", From: 0, Until: 1}: {types.MakeMetricData("metric3", []float64{3, math.NaN(), 4, 5, 6, math.NaN()}, 1, now32)}, 350 }, 351 []*types.MetricData{types.MakeMetricData("averageSeries(metric1,metric2,metric3)", 352 []float64{2, math.NaN(), 3, 4, 5, 5.5}, 1, now32).SetTag("aggregatedBy", "average")}, 353 }, 354 355 // sumSeies with tags, common tags to all metrics 356 { 357 "sum(seriesByTag('tag2=value*', 'name=metric'))", 358 map[parser.MetricRequest][]*types.MetricData{ 359 {Metric: "seriesByTag('tag2=value*', 'name=metric')", From: 0, Until: 1}: { 360 // No tags in common 361 types.MakeMetricData("metric;tag1=value1;tag2=value21", []float64{1, math.NaN(), 2, 3, 4, 5}, 1, now32), 362 types.MakeMetricData("metric;tag2=value22;tag3=value3", []float64{2, math.NaN(), 3, math.NaN(), 5, 6}, 1, now32), 363 types.MakeMetricData("metric;tag2=value23;tag3=value3;tag4=val4", []float64{3, math.NaN(), 4, 5, 6, math.NaN()}, 1, now32), 364 }, 365 {Metric: "metric", From: 0, Until: 1}: {types.MakeMetricData("metric", []float64{2, math.NaN(), 3, math.NaN(), 5, 11}, 1, now32)}, 366 }, 367 []*types.MetricData{types.MakeMetricData("sumSeries(seriesByTag('tag2=value*', 'name=metric'))", 368 []float64{6, math.NaN(), 9, 8, 15, 11}, 1, now32).SetTags(map[string]string{"aggregatedBy": "sum", "name": "metric"})}, 369 }, 370 { 371 "sum(seriesByTag('tag2!=value2*', 'name=metric.name'))", 372 map[parser.MetricRequest][]*types.MetricData{ 373 {Metric: "seriesByTag('tag2!=value2*', 'name=metric.name')", From: 0, Until: 1}: { 374 // One tag in common 375 types.MakeMetricData("metric.name;tag2=value22;tag3=value3", []float64{2, math.NaN(), 3, math.NaN(), 5, 6}, 1, now32), 376 types.MakeMetricData("metric.name;tag2=value23;tag3=value3", []float64{3, math.NaN(), 4, 5, 6, math.NaN()}, 1, now32), 377 }, 378 {Metric: "metric.name", From: 0, Until: 1}: {types.MakeMetricData("metric.name", []float64{2, math.NaN(), 3, math.NaN(), 5, 11}, 1, now32)}, 379 }, 380 []*types.MetricData{types.MakeMetricData("sumSeries(seriesByTag('tag2!=value2*', 'name=metric.name'))", 381 // []float64{5, math.NaN(), 7, 5, 11, 6}, 1, now32).SetTags(map[string]string{"name": "metric.name"})}, 382 []float64{5, math.NaN(), 7, 5, 11, 6}, 1, now32).SetTags(map[string]string{"aggregatedBy": "sum", "name": "metric.name", "tag3": "value3"})}, 383 }, 384 { 385 "sum(seriesByTag('tag2=value21'))", 386 map[parser.MetricRequest][]*types.MetricData{ 387 {Metric: "seriesByTag('tag2=value21')", From: 0, Until: 1}: { 388 // All tags in common 389 types.MakeMetricData("metric;tag2=value22;tag3=value3", []float64{2, math.NaN(), 3, math.NaN(), 5, 6}, 1, now32), 390 types.MakeMetricData("metric;tag2=value22;tag3=value3", []float64{3, math.NaN(), 4, 5, 6, math.NaN()}, 1, now32), 391 }, 392 {Metric: "metric", From: 0, Until: 1}: {types.MakeMetricData("metric", []float64{2, math.NaN(), 3, math.NaN(), 5, 11}, 1, now32)}, 393 }, 394 []*types.MetricData{types.MakeMetricData("sumSeries(seriesByTag('tag2=value21'))", 395 // []float64{5, math.NaN(), 7, 5, 11, 6}, 1, now32).SetTags(map[string]string{"name": "sumSeries", "tag2": "value21"})}, 396 []float64{5, math.NaN(), 7, 5, 11, 6}, 1, now32).SetTags(map[string]string{"aggregatedBy": "sum", "name": "metric", "tag2": "value22", "tag3": "value3"})}, 397 }, 398 } 399 400 for _, tt := range tests { 401 testName := tt.Target 402 t.Run(testName, func(t *testing.T) { 403 eval := th.EvaluatorFromFunc(md[0].F) 404 th.TestEvalExpr(t, eval, &tt) 405 }) 406 } 407 408 } 409 410 func TestAverageSeriesExtractSeriesByTag(t *testing.T) { 411 fconfig.Config.ExtractTagsFromArgs = true 412 413 now32 := int64(time.Now().Unix()) 414 415 tests := []th.EvalTestItem{ 416 // sumSeies with tags, tags from first metric 417 { 418 "sum(seriesByTag('tag2=value*', 'name=metric'))", 419 map[parser.MetricRequest][]*types.MetricData{ 420 {Metric: "seriesByTag('tag2=value*', 'name=metric')", From: 0, Until: 1}: { 421 types.MakeMetricData("metric;tag1=value1;tag2=value21", []float64{1, math.NaN(), 2, 3, 4, 5}, 1, now32), 422 types.MakeMetricData("metric;tag2=value22;tag3=value3", []float64{2, math.NaN(), 3, math.NaN(), 5, 6}, 1, now32), 423 types.MakeMetricData("metric;tag2=value23;tag3=value3", []float64{3, math.NaN(), 4, 5, 6, math.NaN()}, 1, now32), 424 }, 425 {Metric: "metric", From: 0, Until: 1}: {types.MakeMetricData("metric", []float64{2, math.NaN(), 3, math.NaN(), 5, 11}, 1, now32)}, 426 }, 427 []*types.MetricData{types.MakeMetricData("sumSeries(seriesByTag('tag2=value*', 'name=metric'))", 428 []float64{6, math.NaN(), 9, 8, 15, 11}, 1, now32).SetTags(map[string]string{"name": "metric", "tag2": "value*", "aggregatedBy": "sum"})}, 429 }, 430 { 431 "sum(seriesByTag('tag2!=value2*', 'name=metric.name'))", 432 map[parser.MetricRequest][]*types.MetricData{ 433 {Metric: "seriesByTag('tag2!=value2*', 'name=metric.name')", From: 0, Until: 1}: { 434 types.MakeMetricData("metric.name;tag2=value22;tag3=value3", []float64{2, math.NaN(), 3, math.NaN(), 5, 6}, 1, now32), 435 types.MakeMetricData("metric.name;tag2=value23;tag3=value3", []float64{3, math.NaN(), 4, 5, 6, math.NaN()}, 1, now32), 436 }, 437 {Metric: "metric.name", From: 0, Until: 1}: {types.MakeMetricData("metric.name", []float64{2, math.NaN(), 3, math.NaN(), 5, 11}, 1, now32)}, 438 }, 439 []*types.MetricData{types.MakeMetricData("sumSeries(seriesByTag('tag2!=value2*', 'name=metric.name'))", 440 []float64{5, math.NaN(), 7, 5, 11, 6}, 1, now32).SetTags(map[string]string{"name": "metric.name", "aggregatedBy": "sum"})}, 441 }, 442 { 443 "sum(seriesByTag('tag2=value21'))", 444 map[parser.MetricRequest][]*types.MetricData{ 445 {Metric: "seriesByTag('tag2=value21')", From: 0, Until: 1}: { 446 types.MakeMetricData("metric;tag2=value22;tag3=value3", []float64{2, math.NaN(), 3, math.NaN(), 5, 6}, 1, now32), 447 types.MakeMetricData("metric;tag2=value23;tag3=value3", []float64{3, math.NaN(), 4, 5, 6, math.NaN()}, 1, now32), 448 }, 449 {Metric: "metric", From: 0, Until: 1}: {types.MakeMetricData("metric", []float64{2, math.NaN(), 3, math.NaN(), 5, 11}, 1, now32)}, 450 }, 451 []*types.MetricData{types.MakeMetricData("sumSeries(seriesByTag('tag2=value21'))", 452 []float64{5, math.NaN(), 7, 5, 11, 6}, 1, now32).SetTags(map[string]string{"name": "sumSeries", "tag2": "value21", "aggregatedBy": "sum"})}, 453 }, 454 } 455 456 for _, tt := range tests { 457 testName := tt.Target 458 t.Run(testName, func(t *testing.T) { 459 eval := th.EvaluatorFromFunc(md[0].F) 460 th.TestEvalExpr(t, eval, &tt) 461 }) 462 } 463 464 } 465 466 func TestAverageSeriesAlign(t *testing.T) { 467 tests := []th.EvalTestItem{ 468 // Indx | 0 | 1 | 2 | 3 | 4 | 469 // commonStep 2 470 // Start 0 (1 - 1 % 2) 471 // metric1_2 | | 1 | 3 | 5 | | 472 // metric1_2 | 1 | | 4 | | | 473 // 474 // metric2_1 | | 1 | | 5 | | 475 // metric2_1 | 1 | | 5 | | | 476 477 // sum | 2 | | 9 | | | 478 { 479 // timeseries with different length 480 Target: "sum(metric1_2,metric2_1)", 481 M: map[parser.MetricRequest][]*types.MetricData{ 482 {Metric: "metric1_2", From: 0, Until: 1}: {types.MakeMetricData("metric1", []float64{1, 3, 5}, 1, 1)}, 483 {Metric: "metric2_1", From: 0, Until: 1}: {types.MakeMetricData("metric2", []float64{1, 5}, 2, 1)}, 484 }, 485 Want: []*types.MetricData{types.MakeMetricData("sumSeries(metric1_2,metric2_1)", 486 []float64{2, 9}, 2, 0).SetTag("aggregatedBy", "sum")}, 487 }, 488 { 489 // First timeseries with broker StopTime 490 Target: "sum(metric1,metric2)", 491 M: map[parser.MetricRequest][]*types.MetricData{ 492 {Metric: "metric1", From: 0, Until: 1}: {types.MakeMetricData("metric1", []float64{1, 3, 5, 8}, 1, 1).AppendStopTime(-1)}, 493 {Metric: "metric2", From: 0, Until: 1}: {types.MakeMetricData("metric2", []float64{1, 5, 7}, 1, 1)}, 494 }, 495 Want: []*types.MetricData{types.MakeMetricData("sumSeries(metric1,metric2)", 496 []float64{2, 8, 12, 8}, 1, 1).SetTag("aggregatedBy", "sum")}, 497 }, 498 } 499 500 for _, tt := range tests { 501 testName := tt.Target 502 t.Run(testName, func(t *testing.T) { 503 eval := th.EvaluatorFromFunc(md[0].F) 504 th.TestEvalExprResult(t, eval, &tt) 505 }) 506 } 507 508 } 509 510 func BenchmarkAverageSeries(b *testing.B) { 511 target := "sum(metric*)" 512 metrics := map[parser.MetricRequest][]*types.MetricData{ 513 {Metric: "metric*", From: 0, Until: 1}: { 514 types.MakeMetricData("metric2", compare.GenerateMetrics(2046, 1, 10, 1), 2, 1), 515 types.MakeMetricData("metric1", compare.GenerateMetrics(4096, 1, 10, 1), 1, 1), 516 types.MakeMetricData("metric3", compare.GenerateMetrics(1360, 1, 10, 1), 3, 1), 517 }, 518 } 519 520 eval := th.EvaluatorFromFunc(md[0].F) 521 exp, _, err := parser.ParseExpr(target) 522 if err != nil { 523 b.Fatalf("failed to parse %s: %+v", target, err) 524 } 525 526 b.ResetTimer() 527 for n := 0; n < b.N; n++ { 528 g, err := eval.Eval(context.Background(), exp, 0, 1, metrics) 529 if err != nil { 530 b.Fatalf("failed to eval %s: %+v", target, err) 531 } 532 _ = g 533 } 534 }