github.com/go-graphite/carbonapi@v0.17.0/expr/functions/highestLowest/function_test.go (about) 1 package highestLowest 2 3 import ( 4 "math" 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 TestHighestMultiReturn(t *testing.T) { 26 now32 := int64(time.Now().Unix()) 27 28 tests := []th.MultiReturnEvalTestItem{ 29 { 30 "highestCurrent(metric1,2)", 31 map[parser.MetricRequest][]*types.MetricData{ 32 {Metric: "metric1", From: 0, Until: 1}: { 33 types.MakeMetricData("metricA", []float64{1, 1, 3, 3, 4, 12}, 1, now32), 34 types.MakeMetricData("metricB", []float64{1, 1, 3, 3, 4, 1}, 1, now32), 35 types.MakeMetricData("metricC", []float64{1, 1, 3, 3, 4, 15}, 1, now32), 36 }, 37 }, 38 "highestCurrent", 39 map[string][]*types.MetricData{ 40 "metricA": {types.MakeMetricData("metricA", []float64{1, 1, 3, 3, 4, 12}, 1, now32)}, 41 "metricC": {types.MakeMetricData("metricC", []float64{1, 1, 3, 3, 4, 15}, 1, now32)}, 42 }, 43 }, 44 { 45 "highestCurrent(metric1)", 46 map[parser.MetricRequest][]*types.MetricData{ 47 parser.MetricRequest{Metric: "metric1", From: 0, Until: 1}: { 48 types.MakeMetricData("metricA", []float64{1, 1, 3, 3, 4, 12}, 1, now32), 49 types.MakeMetricData("metricB", []float64{1, 1, 3, 3, 4, 1}, 1, now32), 50 types.MakeMetricData("metricC", []float64{1, 1, 3, 3, 4, 15}, 1, now32), 51 }, 52 }, 53 "highestCurrent", 54 map[string][]*types.MetricData{ 55 "metricC": {types.MakeMetricData("metricC", []float64{1, 1, 3, 3, 4, 15}, 1, now32)}, 56 }, 57 }, 58 { 59 "highestMax(metric1, 2)", 60 map[parser.MetricRequest][]*types.MetricData{ 61 parser.MetricRequest{Metric: "metric1", From: 0, Until: 1}: { 62 types.MakeMetricData("metricA", []float64{1, 1, 3, 3, 4, 12, 9}, 1, now32), 63 types.MakeMetricData("metricB", []float64{1, 5, 5, 5, 5, 5, 3}, 1, now32), 64 types.MakeMetricData("metricC", []float64{1, 1, 3, 3, 4, 10, 10}, 1, now32), 65 }, 66 }, 67 "highestMax", 68 map[string][]*types.MetricData{ 69 "metricA": {types.MakeMetricData("metricA", []float64{1, 1, 3, 3, 4, 12, 9}, 1, now32)}, 70 "metricC": {types.MakeMetricData("metricC", []float64{1, 1, 3, 3, 4, 10, 10}, 1, now32)}, 71 }, 72 }, 73 { 74 "highestMin(metric1, 2)", 75 map[parser.MetricRequest][]*types.MetricData{ 76 parser.MetricRequest{Metric: "metric1", From: 0, Until: 1}: { 77 types.MakeMetricData("metricA", []float64{6, 1, 3, 3, 4, 12}, 1, now32), 78 types.MakeMetricData("metricB", []float64{2, 5, 5, 5, 5, 5}, 1, now32), 79 types.MakeMetricData("metricC", []float64{3, 2, 3, 3, 4, 10}, 1, now32), 80 }, 81 }, 82 "highestMin", 83 map[string][]*types.MetricData{ 84 "metricB": {types.MakeMetricData("metricB", []float64{2, 5, 5, 5, 5, 5}, 1, now32)}, 85 "metricC": {types.MakeMetricData("metricC", []float64{3, 2, 3, 3, 4, 10}, 1, now32)}, 86 }, 87 }, 88 { 89 "highest(metric1, 2, \"max\")", 90 map[parser.MetricRequest][]*types.MetricData{ 91 {Metric: "metric1", From: 0, Until: 1}: { 92 types.MakeMetricData("metricA", []float64{1, 1, 3, 3, 12, 11}, 1, now32), 93 types.MakeMetricData("metricB", []float64{1, 1, 3, 3, 4, 1}, 1, now32), 94 types.MakeMetricData("metricC", []float64{1, 1, 3, 3, 4, 10}, 1, now32), 95 }, 96 }, 97 "highest", 98 map[string][]*types.MetricData{ 99 "metricA": {types.MakeMetricData("metricA", []float64{1, 1, 3, 3, 12, 11}, 1, now32)}, 100 "metricC": {types.MakeMetricData("metricC", []float64{1, 1, 3, 3, 4, 10}, 1, now32)}, 101 }, 102 }, 103 { 104 "lowest(metric1, 2, \"max\")", 105 map[parser.MetricRequest][]*types.MetricData{ 106 {Metric: "metric1", From: 0, Until: 1}: { 107 types.MakeMetricData("metricA", []float64{1, 1, 3, 3, 12, 11}, 1, now32), 108 types.MakeMetricData("metricB", []float64{1, 1, 3, 3, 4, 1}, 1, now32), 109 types.MakeMetricData("metricC", []float64{1, 1, 3, 3, 4, 10}, 1, now32), 110 }, 111 }, 112 "lowest", 113 map[string][]*types.MetricData{ 114 "metricB": {types.MakeMetricData("metricB", []float64{1, 1, 3, 3, 4, 1}, 1, now32)}, 115 "metricC": {types.MakeMetricData("metricC", []float64{1, 1, 3, 3, 4, 10}, 1, now32)}, 116 }, 117 }, 118 119 { 120 "lowestCurrent(metric1,3)", 121 map[parser.MetricRequest][]*types.MetricData{ 122 {Metric: "metric1", From: 0, Until: 1}: { 123 types.MakeMetricData("metricB", []float64{1, 1, 3, 3, 4, 1}, 1, now32), 124 types.MakeMetricData("metricC", []float64{1, 1, 3, 3, 4, 15}, 1, now32), 125 types.MakeMetricData("metricD", []float64{1, 1, 3, 3, 4, 3}, 1, now32), 126 types.MakeMetricData("metricA", []float64{1, 1, 3, 3, 4, 12}, 1, now32), 127 }, 128 }, 129 "lowestCurrent", 130 map[string][]*types.MetricData{ 131 "metricA": {types.MakeMetricData("metricA", []float64{1, 1, 3, 3, 4, 12}, 1, now32)}, 132 "metricB": {types.MakeMetricData("metricB", []float64{1, 1, 3, 3, 4, 1}, 1, now32)}, 133 "metricD": {types.MakeMetricData("metricD", []float64{1, 1, 3, 3, 4, 3}, 1, now32)}, 134 }, 135 }, 136 { 137 "lowestCurrent(metric1)", 138 map[parser.MetricRequest][]*types.MetricData{ 139 parser.MetricRequest{Metric: "metric1", From: 0, Until: 1}: { 140 types.MakeMetricData("metricB", []float64{1, 1, 3, 3, 4, 1}, 1, now32), 141 types.MakeMetricData("metricC", []float64{1, 1, 3, 3, 4, 15}, 1, now32), 142 types.MakeMetricData("metricD", []float64{1, 1, 3, 3, 4, 3}, 1, now32), 143 types.MakeMetricData("metricA", []float64{1, 1, 3, 3, 4, 12}, 1, now32), 144 }, 145 }, 146 "lowestCurrent", 147 map[string][]*types.MetricData{ 148 "metricB": {types.MakeMetricData("metricB", []float64{1, 1, 3, 3, 4, 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.TestMultiReturnEvalExpr(t, eval, &tt) 158 }) 159 } 160 } 161 162 func TestHighest(t *testing.T) { 163 now32 := int64(time.Now().Unix()) 164 165 tests := []th.EvalTestItem{ 166 { 167 "highestCurrent(metric1,1)", 168 map[parser.MetricRequest][]*types.MetricData{ 169 {Metric: "metric1", From: 0, Until: 1}: { 170 types.MakeMetricData("metric0", []float64{math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN()}, 1, now32), 171 types.MakeMetricData("metricA", []float64{1, 1, 3, 3, 4, 12}, 1, now32), 172 types.MakeMetricData("metricB", []float64{1, 1, 3, 3, 4, 1}, 1, now32), 173 types.MakeMetricData("metricC", []float64{1, 1, 3, 3, 4, 15}, 1, now32), 174 }, 175 }, 176 []*types.MetricData{types.MakeMetricData("metricC", // NOTE(dgryski): not sure if this matches graphite 177 []float64{1, 1, 3, 3, 4, 15}, 1, now32)}, 178 }, 179 { 180 "highestCurrent(metric1,4)", 181 map[parser.MetricRequest][]*types.MetricData{ 182 {Metric: "metric1", From: 0, Until: 1}: { 183 types.MakeMetricData("metric0", []float64{math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN()}, 1, now32), 184 types.MakeMetricData("metricA", []float64{1, 1, 3, 3, 4, 12}, 1, now32), 185 types.MakeMetricData("metricB", []float64{1, 1, 3, 3, 4, 1}, 1, now32), 186 types.MakeMetricData("metricC", []float64{1, 1, 3, 3, 4, 15}, 1, now32), 187 }, 188 }, 189 []*types.MetricData{ 190 types.MakeMetricData("metricC", []float64{1, 1, 3, 3, 4, 15}, 1, now32), 191 types.MakeMetricData("metricA", []float64{1, 1, 3, 3, 4, 12}, 1, now32), 192 types.MakeMetricData("metricB", []float64{1, 1, 3, 3, 4, 1}, 1, now32), 193 //NOTE(nnuss): highest* functions filter null-valued series as a side-effect when `n` >= number of series 194 //TODO(nnuss): bring lowest* functions into harmony with this side effect or get rid of it 195 //types.MakeMetricData("metric0", []float64{math.NaN(), math.NaN(), math.NaN(), math.NaN(), math.NaN()}, 1, now32), 196 }, 197 }, 198 { 199 "highestAverage(metric1,1)", 200 map[parser.MetricRequest][]*types.MetricData{ 201 {Metric: "metric1", From: 0, Until: 1}: { 202 types.MakeMetricData("metricA", []float64{1, 1, 3, 3, 4, 12}, 1, now32), 203 types.MakeMetricData("metricB", []float64{1, 5, 5, 5, 5, 5}, 1, now32), 204 types.MakeMetricData("metricC", []float64{1, 1, 3, 3, 4, 10}, 1, now32), 205 }, 206 }, 207 []*types.MetricData{types.MakeMetricData("metricB", // NOTE(dgryski): not sure if this matches graphite 208 []float64{1, 5, 5, 5, 5, 5}, 1, now32)}, 209 }, 210 { 211 "highestMax(metric1,1)", 212 map[parser.MetricRequest][]*types.MetricData{ 213 {Metric: "metric1", From: 0, Until: 1}: { 214 types.MakeMetricData("metricA", []float64{1, 1, 3, 3, 12, 11}, 1, now32), 215 types.MakeMetricData("metricB", []float64{1, 1, 3, 3, 4, 1}, 1, now32), 216 types.MakeMetricData("metricC", []float64{1, 1, 3, 3, 4, 10}, 1, now32), 217 }, 218 }, 219 []*types.MetricData{types.MakeMetricData("metricA", // NOTE(dgryski): not sure if this matches graphite 220 []float64{1, 1, 3, 3, 12, 11}, 1, now32)}, 221 }, 222 { 223 "highestMin(metric1,1)", 224 map[parser.MetricRequest][]*types.MetricData{ 225 {Metric: "metric1", From: 0, Until: 1}: { 226 types.MakeMetricData("metricA", []float64{6, 1, 3, 3, 4, 12}, 1, now32), 227 types.MakeMetricData("metricB", []float64{2, 5, 5, 5, 5, 5}, 1, now32), 228 types.MakeMetricData("metricC", []float64{3, 1, 3, 3, 4, 10}, 1, now32), 229 }, 230 }, 231 []*types.MetricData{types.MakeMetricData("metricB", // NOTE(dgryski): not sure if this matches graphite 232 []float64{2, 5, 5, 5, 5, 5}, 1, now32)}, 233 }, 234 { 235 "highestCurrent(metric1,0)", 236 map[parser.MetricRequest][]*types.MetricData{ 237 parser.MetricRequest{Metric: "metric1", From: 0, Until: 1}: { 238 types.MakeMetricData("metricA", []float64{1, 1, 3, 3, 4, 12}, 1, now32), 239 types.MakeMetricData("metricB", []float64{1, 1, 3, 3, 4, 1}, 1, now32), 240 types.MakeMetricData("metricC", []float64{1, 1, 3, 3, 4, 15}, 1, now32), 241 }, 242 }, 243 []*types.MetricData{}, 244 }, 245 { 246 "highest(metric1,\"max\")", 247 map[parser.MetricRequest][]*types.MetricData{ 248 {Metric: "metric1", From: 0, Until: 1}: { 249 types.MakeMetricData("metricA", []float64{1, 1, 3, 3, 12, 11}, 1, now32), 250 types.MakeMetricData("metricB", []float64{1, 1, 3, 3, 4, 1}, 1, now32), 251 types.MakeMetricData("metricC", []float64{1, 1, 3, 3, 4, 10}, 1, now32), 252 }, 253 }, 254 []*types.MetricData{types.MakeMetricData("metricA", 255 []float64{1, 1, 3, 3, 12, 11}, 1, now32)}, 256 }, 257 { 258 "highest(metric1, 0, \"max\")", 259 map[parser.MetricRequest][]*types.MetricData{ 260 {Metric: "metric1", From: 0, Until: 1}: { 261 types.MakeMetricData("metricA", []float64{1, 1, 3, 3, 12, 11}, 1, now32), 262 types.MakeMetricData("metricB", []float64{1, 1, 3, 3, 4, 1}, 1, now32), 263 types.MakeMetricData("metricC", []float64{1, 1, 3, 3, 4, 10}, 1, now32), 264 }, 265 }, 266 []*types.MetricData{}, 267 }, 268 { 269 "highest(metric1, -1, \"max\")", 270 map[parser.MetricRequest][]*types.MetricData{ 271 {Metric: "metric1", From: 0, Until: 1}: { 272 types.MakeMetricData("metricA", []float64{1, 1, 3, 3, 12, 11}, 1, now32), 273 types.MakeMetricData("metricB", []float64{1, 1, 3, 3, 4, 1}, 1, now32), 274 types.MakeMetricData("metricC", []float64{1, 1, 3, 3, 4, 10}, 1, now32), 275 }, 276 }, 277 []*types.MetricData{}, 278 }, 279 { 280 "lowest(metric1,\"max\")", 281 map[parser.MetricRequest][]*types.MetricData{ 282 {Metric: "metric1", From: 0, Until: 1}: { 283 types.MakeMetricData("metricA", []float64{1, 1, 3, 3, 12, 11}, 1, now32), 284 types.MakeMetricData("metricB", []float64{1, 1, 3, 3, 4, 1}, 1, now32), 285 types.MakeMetricData("metricC", []float64{1, 1, 3, 3, 4, 10}, 1, now32), 286 }, 287 }, 288 []*types.MetricData{ 289 types.MakeMetricData("metricB", []float64{1, 1, 3, 3, 4, 1}, 1, now32), 290 }, 291 }, 292 { 293 "lowestCurrent(metric1,1)", 294 map[parser.MetricRequest][]*types.MetricData{ 295 {Metric: "metric1", From: 0, Until: 1}: { 296 types.MakeMetricData("metricA", []float64{1, 1, 3, 3, 4, 12}, 1, now32), 297 types.MakeMetricData("metricB", []float64{1, 1, 3, 3, 4, 1}, 1, now32), 298 types.MakeMetricData("metricC", []float64{1, 1, 3, 3, 4, 15}, 1, now32), 299 }, 300 }, 301 []*types.MetricData{types.MakeMetricData("metricB", // NOTE(dgryski): not sure if this matches graphite 302 []float64{1, 1, 3, 3, 4, 1}, 1, now32)}, 303 }, 304 } 305 306 for _, tt := range tests { 307 testName := tt.Target 308 t.Run(testName, func(t *testing.T) { 309 eval := th.EvaluatorFromFunc(md[0].F) 310 th.TestEvalExpr(t, eval, &tt) 311 }) 312 } 313 }