github.com/muhammadn/cortex@v1.9.1-0.20220510110439-46bb7000d03d/pkg/configs/legacy_promql/parse_test.go (about) 1 // Copyright 2015 The Prometheus Authors 2 // Licensed under the Apache License, Version 2.0 (the "License"); 3 // you may not use this file except in compliance with the License. 4 // You may obtain a copy of the License at 5 // 6 // http://www.apache.org/licenses/LICENSE-2.0 7 // 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package promql 15 16 import ( 17 "fmt" 18 "math" 19 "reflect" 20 "strings" 21 "testing" 22 "time" 23 24 "github.com/prometheus/common/model" 25 "github.com/prometheus/prometheus/pkg/labels" 26 "github.com/stretchr/testify/require" 27 ) 28 29 var testExpr = []struct { 30 input string // The input to be parsed. 31 expected Expr // The expected expression AST. 32 fail bool // Whether parsing is supposed to fail. 33 errMsg string // If not empty the parsing error has to contain this string. 34 }{ 35 // Scalars and scalar-to-scalar operations. 36 { 37 input: "1", 38 expected: &NumberLiteral{1}, 39 }, { 40 input: "+Inf", 41 expected: &NumberLiteral{math.Inf(1)}, 42 }, { 43 input: "-Inf", 44 expected: &NumberLiteral{math.Inf(-1)}, 45 }, { 46 input: ".5", 47 expected: &NumberLiteral{0.5}, 48 }, { 49 input: "5.", 50 expected: &NumberLiteral{5}, 51 }, { 52 input: "123.4567", 53 expected: &NumberLiteral{123.4567}, 54 }, { 55 input: "5e-3", 56 expected: &NumberLiteral{0.005}, 57 }, { 58 input: "5e3", 59 expected: &NumberLiteral{5000}, 60 }, { 61 input: "0xc", 62 expected: &NumberLiteral{12}, 63 }, { 64 input: "0755", 65 expected: &NumberLiteral{493}, 66 }, { 67 input: "+5.5e-3", 68 expected: &NumberLiteral{0.0055}, 69 }, { 70 input: "-0755", 71 expected: &NumberLiteral{-493}, 72 }, { 73 input: "1 + 1", 74 expected: &BinaryExpr{itemADD, &NumberLiteral{1}, &NumberLiteral{1}, nil, false}, 75 }, { 76 input: "1 - 1", 77 expected: &BinaryExpr{itemSUB, &NumberLiteral{1}, &NumberLiteral{1}, nil, false}, 78 }, { 79 input: "1 * 1", 80 expected: &BinaryExpr{itemMUL, &NumberLiteral{1}, &NumberLiteral{1}, nil, false}, 81 }, { 82 input: "1 % 1", 83 expected: &BinaryExpr{itemMOD, &NumberLiteral{1}, &NumberLiteral{1}, nil, false}, 84 }, { 85 input: "1 / 1", 86 expected: &BinaryExpr{itemDIV, &NumberLiteral{1}, &NumberLiteral{1}, nil, false}, 87 }, { 88 input: "1 == bool 1", 89 expected: &BinaryExpr{itemEQL, &NumberLiteral{1}, &NumberLiteral{1}, nil, true}, 90 }, { 91 input: "1 != bool 1", 92 expected: &BinaryExpr{itemNEQ, &NumberLiteral{1}, &NumberLiteral{1}, nil, true}, 93 }, { 94 input: "1 > bool 1", 95 expected: &BinaryExpr{itemGTR, &NumberLiteral{1}, &NumberLiteral{1}, nil, true}, 96 }, { 97 input: "1 >= bool 1", 98 expected: &BinaryExpr{itemGTE, &NumberLiteral{1}, &NumberLiteral{1}, nil, true}, 99 }, { 100 input: "1 < bool 1", 101 expected: &BinaryExpr{itemLSS, &NumberLiteral{1}, &NumberLiteral{1}, nil, true}, 102 }, { 103 input: "1 <= bool 1", 104 expected: &BinaryExpr{itemLTE, &NumberLiteral{1}, &NumberLiteral{1}, nil, true}, 105 }, { 106 input: "+1 + -2 * 1", 107 expected: &BinaryExpr{ 108 Op: itemADD, 109 LHS: &NumberLiteral{1}, 110 RHS: &BinaryExpr{ 111 Op: itemMUL, LHS: &NumberLiteral{-2}, RHS: &NumberLiteral{1}, 112 }, 113 }, 114 }, { 115 input: "1 + 2/(3*1)", 116 expected: &BinaryExpr{ 117 Op: itemADD, 118 LHS: &NumberLiteral{1}, 119 RHS: &BinaryExpr{ 120 Op: itemDIV, 121 LHS: &NumberLiteral{2}, 122 RHS: &ParenExpr{&BinaryExpr{ 123 Op: itemMUL, LHS: &NumberLiteral{3}, RHS: &NumberLiteral{1}, 124 }}, 125 }, 126 }, 127 }, { 128 input: "1 < bool 2 - 1 * 2", 129 expected: &BinaryExpr{ 130 Op: itemLSS, 131 ReturnBool: true, 132 LHS: &NumberLiteral{1}, 133 RHS: &BinaryExpr{ 134 Op: itemSUB, 135 LHS: &NumberLiteral{2}, 136 RHS: &BinaryExpr{ 137 Op: itemMUL, LHS: &NumberLiteral{1}, RHS: &NumberLiteral{2}, 138 }, 139 }, 140 }, 141 }, { 142 input: "-some_metric", 143 expected: &UnaryExpr{ 144 Op: itemSUB, 145 Expr: &VectorSelector{ 146 Name: "some_metric", 147 LabelMatchers: []*labels.Matcher{ 148 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "some_metric"), 149 }, 150 }, 151 }, 152 }, { 153 input: "+some_metric", 154 expected: &UnaryExpr{ 155 Op: itemADD, 156 Expr: &VectorSelector{ 157 Name: "some_metric", 158 LabelMatchers: []*labels.Matcher{ 159 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "some_metric"), 160 }, 161 }, 162 }, 163 }, { 164 input: "", 165 fail: true, 166 errMsg: "no expression found in input", 167 }, { 168 input: "# just a comment\n\n", 169 fail: true, 170 errMsg: "no expression found in input", 171 }, { 172 input: "1+", 173 fail: true, 174 errMsg: "no valid expression found", 175 }, { 176 input: ".", 177 fail: true, 178 errMsg: "unexpected character: '.'", 179 }, { 180 input: "2.5.", 181 fail: true, 182 errMsg: "could not parse remaining input \".\"...", 183 }, { 184 input: "100..4", 185 fail: true, 186 errMsg: "could not parse remaining input \".4\"...", 187 }, { 188 input: "0deadbeef", 189 fail: true, 190 errMsg: "bad number or duration syntax: \"0de\"", 191 }, { 192 input: "1 /", 193 fail: true, 194 errMsg: "no valid expression found", 195 }, { 196 input: "*1", 197 fail: true, 198 errMsg: "no valid expression found", 199 }, { 200 input: "(1))", 201 fail: true, 202 errMsg: "could not parse remaining input \")\"...", 203 }, { 204 input: "((1)", 205 fail: true, 206 errMsg: "unclosed left parenthesis", 207 }, { 208 input: "999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999", 209 fail: true, 210 errMsg: "out of range", 211 }, { 212 input: "(", 213 fail: true, 214 errMsg: "unclosed left parenthesis", 215 }, { 216 input: "1 and 1", 217 fail: true, 218 errMsg: "set operator \"and\" not allowed in binary scalar expression", 219 }, { 220 input: "1 == 1", 221 fail: true, 222 errMsg: "parse error at char 7: comparisons between scalars must use BOOL modifier", 223 }, { 224 input: "1 or 1", 225 fail: true, 226 errMsg: "set operator \"or\" not allowed in binary scalar expression", 227 }, { 228 input: "1 unless 1", 229 fail: true, 230 errMsg: "set operator \"unless\" not allowed in binary scalar expression", 231 }, { 232 input: "1 !~ 1", 233 fail: true, 234 errMsg: "could not parse remaining input \"!~ 1\"...", 235 }, { 236 input: "1 =~ 1", 237 fail: true, 238 errMsg: "could not parse remaining input \"=~ 1\"...", 239 }, { 240 input: `-"string"`, 241 fail: true, 242 errMsg: `unary expression only allowed on expressions of type scalar or instant vector, got "string"`, 243 }, { 244 input: `-test[5m]`, 245 fail: true, 246 errMsg: `unary expression only allowed on expressions of type scalar or instant vector, got "range vector"`, 247 }, { 248 input: `*test`, 249 fail: true, 250 errMsg: "no valid expression found", 251 }, { 252 input: "1 offset 1d", 253 fail: true, 254 errMsg: "offset modifier must be preceded by an instant or range selector", 255 }, { 256 input: "a - on(b) ignoring(c) d", 257 fail: true, 258 errMsg: "parse error at char 11: no valid expression found", 259 }, 260 // Vector binary operations. 261 { 262 input: "foo * bar", 263 expected: &BinaryExpr{ 264 Op: itemMUL, 265 LHS: &VectorSelector{ 266 Name: "foo", 267 LabelMatchers: []*labels.Matcher{ 268 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "foo"), 269 }, 270 }, 271 RHS: &VectorSelector{ 272 Name: "bar", 273 LabelMatchers: []*labels.Matcher{ 274 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "bar"), 275 }, 276 }, 277 VectorMatching: &VectorMatching{Card: CardOneToOne}, 278 }, 279 }, { 280 input: "foo == 1", 281 expected: &BinaryExpr{ 282 Op: itemEQL, 283 LHS: &VectorSelector{ 284 Name: "foo", 285 LabelMatchers: []*labels.Matcher{ 286 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "foo"), 287 }, 288 }, 289 RHS: &NumberLiteral{1}, 290 }, 291 }, { 292 input: "foo == bool 1", 293 expected: &BinaryExpr{ 294 Op: itemEQL, 295 LHS: &VectorSelector{ 296 Name: "foo", 297 LabelMatchers: []*labels.Matcher{ 298 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "foo"), 299 }, 300 }, 301 RHS: &NumberLiteral{1}, 302 ReturnBool: true, 303 }, 304 }, { 305 input: "2.5 / bar", 306 expected: &BinaryExpr{ 307 Op: itemDIV, 308 LHS: &NumberLiteral{2.5}, 309 RHS: &VectorSelector{ 310 Name: "bar", 311 LabelMatchers: []*labels.Matcher{ 312 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "bar"), 313 }, 314 }, 315 }, 316 }, { 317 input: "foo and bar", 318 expected: &BinaryExpr{ 319 Op: itemLAND, 320 LHS: &VectorSelector{ 321 Name: "foo", 322 LabelMatchers: []*labels.Matcher{ 323 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "foo"), 324 }, 325 }, 326 RHS: &VectorSelector{ 327 Name: "bar", 328 LabelMatchers: []*labels.Matcher{ 329 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "bar"), 330 }, 331 }, 332 VectorMatching: &VectorMatching{Card: CardManyToMany}, 333 }, 334 }, { 335 input: "foo or bar", 336 expected: &BinaryExpr{ 337 Op: itemLOR, 338 LHS: &VectorSelector{ 339 Name: "foo", 340 LabelMatchers: []*labels.Matcher{ 341 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "foo"), 342 }, 343 }, 344 RHS: &VectorSelector{ 345 Name: "bar", 346 LabelMatchers: []*labels.Matcher{ 347 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "bar"), 348 }, 349 }, 350 VectorMatching: &VectorMatching{Card: CardManyToMany}, 351 }, 352 }, { 353 input: "foo unless bar", 354 expected: &BinaryExpr{ 355 Op: itemLUnless, 356 LHS: &VectorSelector{ 357 Name: "foo", 358 LabelMatchers: []*labels.Matcher{ 359 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "foo"), 360 }, 361 }, 362 RHS: &VectorSelector{ 363 Name: "bar", 364 LabelMatchers: []*labels.Matcher{ 365 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "bar"), 366 }, 367 }, 368 VectorMatching: &VectorMatching{Card: CardManyToMany}, 369 }, 370 }, { 371 // Test and/or precedence and reassigning of operands. 372 input: "foo + bar or bla and blub", 373 expected: &BinaryExpr{ 374 Op: itemLOR, 375 LHS: &BinaryExpr{ 376 Op: itemADD, 377 LHS: &VectorSelector{ 378 Name: "foo", 379 LabelMatchers: []*labels.Matcher{ 380 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "foo"), 381 }, 382 }, 383 RHS: &VectorSelector{ 384 Name: "bar", 385 LabelMatchers: []*labels.Matcher{ 386 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "bar"), 387 }, 388 }, 389 VectorMatching: &VectorMatching{Card: CardOneToOne}, 390 }, 391 RHS: &BinaryExpr{ 392 Op: itemLAND, 393 LHS: &VectorSelector{ 394 Name: "bla", 395 LabelMatchers: []*labels.Matcher{ 396 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "bla"), 397 }, 398 }, 399 RHS: &VectorSelector{ 400 Name: "blub", 401 LabelMatchers: []*labels.Matcher{ 402 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "blub"), 403 }, 404 }, 405 VectorMatching: &VectorMatching{Card: CardManyToMany}, 406 }, 407 VectorMatching: &VectorMatching{Card: CardManyToMany}, 408 }, 409 }, { 410 // Test and/or/unless precedence. 411 input: "foo and bar unless baz or qux", 412 expected: &BinaryExpr{ 413 Op: itemLOR, 414 LHS: &BinaryExpr{ 415 Op: itemLUnless, 416 LHS: &BinaryExpr{ 417 Op: itemLAND, 418 LHS: &VectorSelector{ 419 Name: "foo", 420 LabelMatchers: []*labels.Matcher{ 421 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "foo"), 422 }, 423 }, 424 RHS: &VectorSelector{ 425 Name: "bar", 426 LabelMatchers: []*labels.Matcher{ 427 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "bar"), 428 }, 429 }, 430 VectorMatching: &VectorMatching{Card: CardManyToMany}, 431 }, 432 RHS: &VectorSelector{ 433 Name: "baz", 434 LabelMatchers: []*labels.Matcher{ 435 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "baz"), 436 }, 437 }, 438 VectorMatching: &VectorMatching{Card: CardManyToMany}, 439 }, 440 RHS: &VectorSelector{ 441 Name: "qux", 442 LabelMatchers: []*labels.Matcher{ 443 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "qux"), 444 }, 445 }, 446 VectorMatching: &VectorMatching{Card: CardManyToMany}, 447 }, 448 }, { 449 // Test precedence and reassigning of operands. 450 input: "bar + on(foo) bla / on(baz, buz) group_right(test) blub", 451 expected: &BinaryExpr{ 452 Op: itemADD, 453 LHS: &VectorSelector{ 454 Name: "bar", 455 LabelMatchers: []*labels.Matcher{ 456 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "bar"), 457 }, 458 }, 459 RHS: &BinaryExpr{ 460 Op: itemDIV, 461 LHS: &VectorSelector{ 462 Name: "bla", 463 LabelMatchers: []*labels.Matcher{ 464 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "bla"), 465 }, 466 }, 467 RHS: &VectorSelector{ 468 Name: "blub", 469 LabelMatchers: []*labels.Matcher{ 470 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "blub"), 471 }, 472 }, 473 VectorMatching: &VectorMatching{ 474 Card: CardOneToMany, 475 MatchingLabels: []string{"baz", "buz"}, 476 On: true, 477 Include: []string{"test"}, 478 }, 479 }, 480 VectorMatching: &VectorMatching{ 481 Card: CardOneToOne, 482 MatchingLabels: []string{"foo"}, 483 On: true, 484 }, 485 }, 486 }, { 487 input: "foo * on(test,blub) bar", 488 expected: &BinaryExpr{ 489 Op: itemMUL, 490 LHS: &VectorSelector{ 491 Name: "foo", 492 LabelMatchers: []*labels.Matcher{ 493 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "foo"), 494 }, 495 }, 496 RHS: &VectorSelector{ 497 Name: "bar", 498 LabelMatchers: []*labels.Matcher{ 499 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "bar"), 500 }, 501 }, 502 VectorMatching: &VectorMatching{ 503 Card: CardOneToOne, 504 MatchingLabels: []string{"test", "blub"}, 505 On: true, 506 }, 507 }, 508 }, { 509 input: "foo * on(test,blub) group_left bar", 510 expected: &BinaryExpr{ 511 Op: itemMUL, 512 LHS: &VectorSelector{ 513 Name: "foo", 514 LabelMatchers: []*labels.Matcher{ 515 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "foo"), 516 }, 517 }, 518 RHS: &VectorSelector{ 519 Name: "bar", 520 LabelMatchers: []*labels.Matcher{ 521 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "bar"), 522 }, 523 }, 524 VectorMatching: &VectorMatching{ 525 Card: CardManyToOne, 526 MatchingLabels: []string{"test", "blub"}, 527 On: true, 528 }, 529 }, 530 }, { 531 input: "foo and on(test,blub) bar", 532 expected: &BinaryExpr{ 533 Op: itemLAND, 534 LHS: &VectorSelector{ 535 Name: "foo", 536 LabelMatchers: []*labels.Matcher{ 537 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "foo"), 538 }, 539 }, 540 RHS: &VectorSelector{ 541 Name: "bar", 542 LabelMatchers: []*labels.Matcher{ 543 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "bar"), 544 }, 545 }, 546 VectorMatching: &VectorMatching{ 547 Card: CardManyToMany, 548 MatchingLabels: []string{"test", "blub"}, 549 On: true, 550 }, 551 }, 552 }, { 553 input: "foo and on() bar", 554 expected: &BinaryExpr{ 555 Op: itemLAND, 556 LHS: &VectorSelector{ 557 Name: "foo", 558 LabelMatchers: []*labels.Matcher{ 559 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "foo"), 560 }, 561 }, 562 RHS: &VectorSelector{ 563 Name: "bar", 564 LabelMatchers: []*labels.Matcher{ 565 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "bar"), 566 }, 567 }, 568 VectorMatching: &VectorMatching{ 569 Card: CardManyToMany, 570 MatchingLabels: []string{}, 571 On: true, 572 }, 573 }, 574 }, { 575 input: "foo and ignoring(test,blub) bar", 576 expected: &BinaryExpr{ 577 Op: itemLAND, 578 LHS: &VectorSelector{ 579 Name: "foo", 580 LabelMatchers: []*labels.Matcher{ 581 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "foo"), 582 }, 583 }, 584 RHS: &VectorSelector{ 585 Name: "bar", 586 LabelMatchers: []*labels.Matcher{ 587 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "bar"), 588 }, 589 }, 590 VectorMatching: &VectorMatching{ 591 Card: CardManyToMany, 592 MatchingLabels: []string{"test", "blub"}, 593 }, 594 }, 595 }, { 596 input: "foo and ignoring() bar", 597 expected: &BinaryExpr{ 598 Op: itemLAND, 599 LHS: &VectorSelector{ 600 Name: "foo", 601 LabelMatchers: []*labels.Matcher{ 602 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "foo"), 603 }, 604 }, 605 RHS: &VectorSelector{ 606 Name: "bar", 607 LabelMatchers: []*labels.Matcher{ 608 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "bar"), 609 }, 610 }, 611 VectorMatching: &VectorMatching{ 612 Card: CardManyToMany, 613 MatchingLabels: []string{}, 614 }, 615 }, 616 }, { 617 input: "foo unless on(bar) baz", 618 expected: &BinaryExpr{ 619 Op: itemLUnless, 620 LHS: &VectorSelector{ 621 Name: "foo", 622 LabelMatchers: []*labels.Matcher{ 623 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "foo"), 624 }, 625 }, 626 RHS: &VectorSelector{ 627 Name: "baz", 628 LabelMatchers: []*labels.Matcher{ 629 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "baz"), 630 }, 631 }, 632 VectorMatching: &VectorMatching{ 633 Card: CardManyToMany, 634 MatchingLabels: []string{"bar"}, 635 On: true, 636 }, 637 }, 638 }, { 639 input: "foo / on(test,blub) group_left(bar) bar", 640 expected: &BinaryExpr{ 641 Op: itemDIV, 642 LHS: &VectorSelector{ 643 Name: "foo", 644 LabelMatchers: []*labels.Matcher{ 645 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "foo"), 646 }, 647 }, 648 RHS: &VectorSelector{ 649 Name: "bar", 650 LabelMatchers: []*labels.Matcher{ 651 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "bar"), 652 }, 653 }, 654 VectorMatching: &VectorMatching{ 655 Card: CardManyToOne, 656 MatchingLabels: []string{"test", "blub"}, 657 On: true, 658 Include: []string{"bar"}, 659 }, 660 }, 661 }, { 662 input: "foo / ignoring(test,blub) group_left(blub) bar", 663 expected: &BinaryExpr{ 664 Op: itemDIV, 665 LHS: &VectorSelector{ 666 Name: "foo", 667 LabelMatchers: []*labels.Matcher{ 668 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "foo"), 669 }, 670 }, 671 RHS: &VectorSelector{ 672 Name: "bar", 673 LabelMatchers: []*labels.Matcher{ 674 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "bar"), 675 }, 676 }, 677 VectorMatching: &VectorMatching{ 678 Card: CardManyToOne, 679 MatchingLabels: []string{"test", "blub"}, 680 Include: []string{"blub"}, 681 }, 682 }, 683 }, { 684 input: "foo / ignoring(test,blub) group_left(bar) bar", 685 expected: &BinaryExpr{ 686 Op: itemDIV, 687 LHS: &VectorSelector{ 688 Name: "foo", 689 LabelMatchers: []*labels.Matcher{ 690 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "foo"), 691 }, 692 }, 693 RHS: &VectorSelector{ 694 Name: "bar", 695 LabelMatchers: []*labels.Matcher{ 696 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "bar"), 697 }, 698 }, 699 VectorMatching: &VectorMatching{ 700 Card: CardManyToOne, 701 MatchingLabels: []string{"test", "blub"}, 702 Include: []string{"bar"}, 703 }, 704 }, 705 }, { 706 input: "foo - on(test,blub) group_right(bar,foo) bar", 707 expected: &BinaryExpr{ 708 Op: itemSUB, 709 LHS: &VectorSelector{ 710 Name: "foo", 711 LabelMatchers: []*labels.Matcher{ 712 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "foo"), 713 }, 714 }, 715 RHS: &VectorSelector{ 716 Name: "bar", 717 LabelMatchers: []*labels.Matcher{ 718 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "bar"), 719 }, 720 }, 721 VectorMatching: &VectorMatching{ 722 Card: CardOneToMany, 723 MatchingLabels: []string{"test", "blub"}, 724 Include: []string{"bar", "foo"}, 725 On: true, 726 }, 727 }, 728 }, { 729 input: "foo - ignoring(test,blub) group_right(bar,foo) bar", 730 expected: &BinaryExpr{ 731 Op: itemSUB, 732 LHS: &VectorSelector{ 733 Name: "foo", 734 LabelMatchers: []*labels.Matcher{ 735 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "foo"), 736 }, 737 }, 738 RHS: &VectorSelector{ 739 Name: "bar", 740 LabelMatchers: []*labels.Matcher{ 741 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "bar"), 742 }, 743 }, 744 VectorMatching: &VectorMatching{ 745 Card: CardOneToMany, 746 MatchingLabels: []string{"test", "blub"}, 747 Include: []string{"bar", "foo"}, 748 }, 749 }, 750 }, { 751 input: "foo and 1", 752 fail: true, 753 errMsg: "set operator \"and\" not allowed in binary scalar expression", 754 }, { 755 input: "1 and foo", 756 fail: true, 757 errMsg: "set operator \"and\" not allowed in binary scalar expression", 758 }, { 759 input: "foo or 1", 760 fail: true, 761 errMsg: "set operator \"or\" not allowed in binary scalar expression", 762 }, { 763 input: "1 or foo", 764 fail: true, 765 errMsg: "set operator \"or\" not allowed in binary scalar expression", 766 }, { 767 input: "foo unless 1", 768 fail: true, 769 errMsg: "set operator \"unless\" not allowed in binary scalar expression", 770 }, { 771 input: "1 unless foo", 772 fail: true, 773 errMsg: "set operator \"unless\" not allowed in binary scalar expression", 774 }, { 775 input: "1 or on(bar) foo", 776 fail: true, 777 errMsg: "vector matching only allowed between instant vectors", 778 }, { 779 input: "foo == on(bar) 10", 780 fail: true, 781 errMsg: "vector matching only allowed between instant vectors", 782 }, { 783 input: "foo and on(bar) group_left(baz) bar", 784 fail: true, 785 errMsg: "no grouping allowed for \"and\" operation", 786 }, { 787 input: "foo and on(bar) group_right(baz) bar", 788 fail: true, 789 errMsg: "no grouping allowed for \"and\" operation", 790 }, { 791 input: "foo or on(bar) group_left(baz) bar", 792 fail: true, 793 errMsg: "no grouping allowed for \"or\" operation", 794 }, { 795 input: "foo or on(bar) group_right(baz) bar", 796 fail: true, 797 errMsg: "no grouping allowed for \"or\" operation", 798 }, { 799 input: "foo unless on(bar) group_left(baz) bar", 800 fail: true, 801 errMsg: "no grouping allowed for \"unless\" operation", 802 }, { 803 input: "foo unless on(bar) group_right(baz) bar", 804 fail: true, 805 errMsg: "no grouping allowed for \"unless\" operation", 806 }, { 807 input: `http_requests{group="production"} + on(instance) group_left(job,instance) cpu_count{type="smp"}`, 808 fail: true, 809 errMsg: "label \"instance\" must not occur in ON and GROUP clause at once", 810 }, { 811 input: "foo + bool bar", 812 fail: true, 813 errMsg: "bool modifier can only be used on comparison operators", 814 }, { 815 input: "foo + bool 10", 816 fail: true, 817 errMsg: "bool modifier can only be used on comparison operators", 818 }, { 819 input: "foo and bool 10", 820 fail: true, 821 errMsg: "bool modifier can only be used on comparison operators", 822 }, 823 // Test Vector selector. 824 { 825 input: "foo", 826 expected: &VectorSelector{ 827 Name: "foo", 828 Offset: 0, 829 LabelMatchers: []*labels.Matcher{ 830 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "foo"), 831 }, 832 }, 833 }, { 834 input: "foo offset 5m", 835 expected: &VectorSelector{ 836 Name: "foo", 837 Offset: 5 * time.Minute, 838 LabelMatchers: []*labels.Matcher{ 839 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "foo"), 840 }, 841 }, 842 }, { 843 input: `foo:bar{a="bc"}`, 844 expected: &VectorSelector{ 845 Name: "foo:bar", 846 Offset: 0, 847 LabelMatchers: []*labels.Matcher{ 848 mustLabelMatcher(labels.MatchEqual, "a", "bc"), 849 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "foo:bar"), 850 }, 851 }, 852 }, { 853 input: `foo{NaN='bc'}`, 854 expected: &VectorSelector{ 855 Name: "foo", 856 Offset: 0, 857 LabelMatchers: []*labels.Matcher{ 858 mustLabelMatcher(labels.MatchEqual, "NaN", "bc"), 859 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "foo"), 860 }, 861 }, 862 }, { 863 input: `foo{a="b", foo!="bar", test=~"test", bar!~"baz"}`, 864 expected: &VectorSelector{ 865 Name: "foo", 866 Offset: 0, 867 LabelMatchers: []*labels.Matcher{ 868 mustLabelMatcher(labels.MatchEqual, "a", "b"), 869 mustLabelMatcher(labels.MatchNotEqual, "foo", "bar"), 870 mustLabelMatcher(labels.MatchRegexp, "test", "test"), 871 mustLabelMatcher(labels.MatchNotRegexp, "bar", "baz"), 872 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "foo"), 873 }, 874 }, 875 }, { 876 input: `{`, 877 fail: true, 878 errMsg: "unexpected end of input inside braces", 879 }, { 880 input: `}`, 881 fail: true, 882 errMsg: "unexpected character: '}'", 883 }, { 884 input: `some{`, 885 fail: true, 886 errMsg: "unexpected end of input inside braces", 887 }, { 888 input: `some}`, 889 fail: true, 890 errMsg: "could not parse remaining input \"}\"...", 891 }, { 892 input: `some_metric{a=b}`, 893 fail: true, 894 errMsg: "unexpected identifier \"b\" in label matching, expected string", 895 }, { 896 input: `some_metric{a:b="b"}`, 897 fail: true, 898 errMsg: "unexpected character inside braces: ':'", 899 }, { 900 input: `foo{a*"b"}`, 901 fail: true, 902 errMsg: "unexpected character inside braces: '*'", 903 }, { 904 input: `foo{a>="b"}`, 905 fail: true, 906 // TODO(fabxc): willingly lexing wrong tokens allows for more precrise error 907 // messages from the parser - consider if this is an option. 908 errMsg: "unexpected character inside braces: '>'", 909 }, { 910 input: "some_metric{a=\"\xff\"}", 911 fail: true, 912 errMsg: "parse error at char 15: invalid UTF-8 rune", 913 }, { 914 input: `foo{gibberish}`, 915 fail: true, 916 errMsg: "expected label matching operator but got }", 917 }, { 918 input: `foo{1}`, 919 fail: true, 920 errMsg: "unexpected character inside braces: '1'", 921 }, { 922 input: `{}`, 923 fail: true, 924 errMsg: "vector selector must contain label matchers or metric name", 925 }, { 926 input: `{x=""}`, 927 fail: true, 928 errMsg: "vector selector must contain at least one non-empty matcher", 929 }, { 930 input: `{x=~".*"}`, 931 fail: true, 932 errMsg: "vector selector must contain at least one non-empty matcher", 933 }, { 934 input: `{x!~".+"}`, 935 fail: true, 936 errMsg: "vector selector must contain at least one non-empty matcher", 937 }, { 938 input: `{x!="a"}`, 939 fail: true, 940 errMsg: "vector selector must contain at least one non-empty matcher", 941 }, { 942 input: `foo{__name__="bar"}`, 943 fail: true, 944 errMsg: "metric name must not be set twice: \"foo\" or \"bar\"", 945 // }, { 946 // input: `:foo`, 947 // fail: true, 948 // errMsg: "bla", 949 }, 950 // Test matrix selector. 951 { 952 input: "test[5s]", 953 expected: &MatrixSelector{ 954 Name: "test", 955 Offset: 0, 956 Range: 5 * time.Second, 957 LabelMatchers: []*labels.Matcher{ 958 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "test"), 959 }, 960 }, 961 }, { 962 input: "test[5m]", 963 expected: &MatrixSelector{ 964 Name: "test", 965 Offset: 0, 966 Range: 5 * time.Minute, 967 LabelMatchers: []*labels.Matcher{ 968 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "test"), 969 }, 970 }, 971 }, { 972 input: "test[5h] OFFSET 5m", 973 expected: &MatrixSelector{ 974 Name: "test", 975 Offset: 5 * time.Minute, 976 Range: 5 * time.Hour, 977 LabelMatchers: []*labels.Matcher{ 978 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "test"), 979 }, 980 }, 981 }, { 982 input: "test[5d] OFFSET 10s", 983 expected: &MatrixSelector{ 984 Name: "test", 985 Offset: 10 * time.Second, 986 Range: 5 * 24 * time.Hour, 987 LabelMatchers: []*labels.Matcher{ 988 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "test"), 989 }, 990 }, 991 }, { 992 input: "test[5w] offset 2w", 993 expected: &MatrixSelector{ 994 Name: "test", 995 Offset: 14 * 24 * time.Hour, 996 Range: 5 * 7 * 24 * time.Hour, 997 LabelMatchers: []*labels.Matcher{ 998 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "test"), 999 }, 1000 }, 1001 }, { 1002 input: `test{a="b"}[5y] OFFSET 3d`, 1003 expected: &MatrixSelector{ 1004 Name: "test", 1005 Offset: 3 * 24 * time.Hour, 1006 Range: 5 * 365 * 24 * time.Hour, 1007 LabelMatchers: []*labels.Matcher{ 1008 mustLabelMatcher(labels.MatchEqual, "a", "b"), 1009 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "test"), 1010 }, 1011 }, 1012 }, { 1013 input: `foo[5mm]`, 1014 fail: true, 1015 errMsg: "bad duration syntax: \"5mm\"", 1016 }, { 1017 input: `foo[0m]`, 1018 fail: true, 1019 errMsg: "duration must be greater than 0", 1020 }, { 1021 input: `foo[5m30s]`, 1022 fail: true, 1023 errMsg: "bad duration syntax: \"5m3\"", 1024 }, { 1025 input: `foo[5m] OFFSET 1h30m`, 1026 fail: true, 1027 errMsg: "bad number or duration syntax: \"1h3\"", 1028 }, { 1029 input: `foo["5m"]`, 1030 fail: true, 1031 }, { 1032 input: `foo[]`, 1033 fail: true, 1034 errMsg: "missing unit character in duration", 1035 }, { 1036 input: `foo[1]`, 1037 fail: true, 1038 errMsg: "missing unit character in duration", 1039 }, { 1040 input: `some_metric[5m] OFFSET 1`, 1041 fail: true, 1042 errMsg: "unexpected number \"1\" in offset, expected duration", 1043 }, { 1044 input: `some_metric[5m] OFFSET 1mm`, 1045 fail: true, 1046 errMsg: "bad number or duration syntax: \"1mm\"", 1047 }, { 1048 input: `some_metric[5m] OFFSET`, 1049 fail: true, 1050 errMsg: "unexpected end of input in offset, expected duration", 1051 }, { 1052 input: `some_metric OFFSET 1m[5m]`, 1053 fail: true, 1054 errMsg: "could not parse remaining input \"[5m]\"...", 1055 }, { 1056 input: `(foo + bar)[5m]`, 1057 fail: true, 1058 errMsg: "could not parse remaining input \"[5m]\"...", 1059 }, 1060 // Test aggregation. 1061 { 1062 input: "sum by (foo)(some_metric)", 1063 expected: &AggregateExpr{ 1064 Op: itemSum, 1065 Expr: &VectorSelector{ 1066 Name: "some_metric", 1067 LabelMatchers: []*labels.Matcher{ 1068 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "some_metric"), 1069 }, 1070 }, 1071 Grouping: []string{"foo"}, 1072 }, 1073 }, { 1074 input: "avg by (foo)(some_metric)", 1075 expected: &AggregateExpr{ 1076 Op: itemAvg, 1077 Expr: &VectorSelector{ 1078 Name: "some_metric", 1079 LabelMatchers: []*labels.Matcher{ 1080 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "some_metric"), 1081 }, 1082 }, 1083 Grouping: []string{"foo"}, 1084 }, 1085 }, { 1086 input: "max by (foo)(some_metric)", 1087 expected: &AggregateExpr{ 1088 Op: itemMax, 1089 Expr: &VectorSelector{ 1090 Name: "some_metric", 1091 LabelMatchers: []*labels.Matcher{ 1092 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "some_metric"), 1093 }, 1094 }, 1095 Grouping: []string{"foo"}, 1096 }, 1097 }, { 1098 input: "sum without (foo) (some_metric)", 1099 expected: &AggregateExpr{ 1100 Op: itemSum, 1101 Without: true, 1102 Expr: &VectorSelector{ 1103 Name: "some_metric", 1104 LabelMatchers: []*labels.Matcher{ 1105 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "some_metric"), 1106 }, 1107 }, 1108 Grouping: []string{"foo"}, 1109 }, 1110 }, { 1111 input: "sum (some_metric) without (foo)", 1112 expected: &AggregateExpr{ 1113 Op: itemSum, 1114 Without: true, 1115 Expr: &VectorSelector{ 1116 Name: "some_metric", 1117 LabelMatchers: []*labels.Matcher{ 1118 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "some_metric"), 1119 }, 1120 }, 1121 Grouping: []string{"foo"}, 1122 }, 1123 }, { 1124 input: "stddev(some_metric)", 1125 expected: &AggregateExpr{ 1126 Op: itemStddev, 1127 Expr: &VectorSelector{ 1128 Name: "some_metric", 1129 LabelMatchers: []*labels.Matcher{ 1130 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "some_metric"), 1131 }, 1132 }, 1133 }, 1134 }, { 1135 input: "stdvar by (foo)(some_metric)", 1136 expected: &AggregateExpr{ 1137 Op: itemStdvar, 1138 Expr: &VectorSelector{ 1139 Name: "some_metric", 1140 LabelMatchers: []*labels.Matcher{ 1141 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "some_metric"), 1142 }, 1143 }, 1144 Grouping: []string{"foo"}, 1145 }, 1146 }, { 1147 input: "sum by ()(some_metric)", 1148 expected: &AggregateExpr{ 1149 Op: itemSum, 1150 Expr: &VectorSelector{ 1151 Name: "some_metric", 1152 LabelMatchers: []*labels.Matcher{ 1153 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "some_metric"), 1154 }, 1155 }, 1156 Grouping: []string{}, 1157 }, 1158 }, { 1159 input: "topk(5, some_metric)", 1160 expected: &AggregateExpr{ 1161 Op: itemTopK, 1162 Expr: &VectorSelector{ 1163 Name: "some_metric", 1164 LabelMatchers: []*labels.Matcher{ 1165 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "some_metric"), 1166 }, 1167 }, 1168 Param: &NumberLiteral{5}, 1169 }, 1170 }, { 1171 input: "count_values(\"value\", some_metric)", 1172 expected: &AggregateExpr{ 1173 Op: itemCountValues, 1174 Expr: &VectorSelector{ 1175 Name: "some_metric", 1176 LabelMatchers: []*labels.Matcher{ 1177 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "some_metric"), 1178 }, 1179 }, 1180 Param: &StringLiteral{"value"}, 1181 }, 1182 }, { 1183 // Test usage of keywords as label names. 1184 input: "sum without(and, by, avg, count, alert, annotations)(some_metric)", 1185 expected: &AggregateExpr{ 1186 Op: itemSum, 1187 Without: true, 1188 Expr: &VectorSelector{ 1189 Name: "some_metric", 1190 LabelMatchers: []*labels.Matcher{ 1191 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "some_metric"), 1192 }, 1193 }, 1194 Grouping: []string{"and", "by", "avg", "count", "alert", "annotations"}, 1195 }, 1196 }, { 1197 input: "sum without(==)(some_metric)", 1198 fail: true, 1199 errMsg: "unexpected <op:==> in grouping opts, expected label", 1200 }, { 1201 input: `sum some_metric by (test)`, 1202 fail: true, 1203 errMsg: "unexpected identifier \"some_metric\" in aggregation, expected \"(\"", 1204 }, { 1205 input: `sum (some_metric) by test`, 1206 fail: true, 1207 errMsg: "unexpected identifier \"test\" in grouping opts, expected \"(\"", 1208 }, { 1209 input: `sum (some_metric) by test`, 1210 fail: true, 1211 errMsg: "unexpected identifier \"test\" in grouping opts, expected \"(\"", 1212 }, { 1213 input: `sum () by (test)`, 1214 fail: true, 1215 errMsg: "no valid expression found", 1216 }, { 1217 input: "MIN keep_common (some_metric)", 1218 fail: true, 1219 errMsg: "parse error at char 5: unexpected identifier \"keep_common\" in aggregation, expected \"(\"", 1220 }, { 1221 input: "MIN (some_metric) keep_common", 1222 fail: true, 1223 errMsg: "could not parse remaining input \"keep_common\"...", 1224 }, { 1225 input: `sum (some_metric) without (test) by (test)`, 1226 fail: true, 1227 errMsg: "could not parse remaining input \"by (test)\"...", 1228 }, { 1229 input: `sum without (test) (some_metric) by (test)`, 1230 fail: true, 1231 errMsg: "could not parse remaining input \"by (test)\"...", 1232 }, { 1233 input: `topk(some_metric)`, 1234 fail: true, 1235 errMsg: "parse error at char 17: unexpected \")\" in aggregation, expected \",\"", 1236 }, { 1237 input: `topk(some_metric, other_metric)`, 1238 fail: true, 1239 errMsg: "parse error at char 32: expected type scalar in aggregation parameter, got instant vector", 1240 }, { 1241 input: `count_values(5, other_metric)`, 1242 fail: true, 1243 errMsg: "parse error at char 30: expected type string in aggregation parameter, got scalar", 1244 }, 1245 // Test function calls. 1246 { 1247 input: "time()", 1248 expected: &Call{ 1249 Func: mustGetFunction("time"), 1250 }, 1251 }, { 1252 input: `floor(some_metric{foo!="bar"})`, 1253 expected: &Call{ 1254 Func: mustGetFunction("floor"), 1255 Args: Expressions{ 1256 &VectorSelector{ 1257 Name: "some_metric", 1258 LabelMatchers: []*labels.Matcher{ 1259 mustLabelMatcher(labels.MatchNotEqual, "foo", "bar"), 1260 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "some_metric"), 1261 }, 1262 }, 1263 }, 1264 }, 1265 }, { 1266 input: "rate(some_metric[5m])", 1267 expected: &Call{ 1268 Func: mustGetFunction("rate"), 1269 Args: Expressions{ 1270 &MatrixSelector{ 1271 Name: "some_metric", 1272 LabelMatchers: []*labels.Matcher{ 1273 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "some_metric"), 1274 }, 1275 Range: 5 * time.Minute, 1276 }, 1277 }, 1278 }, 1279 }, { 1280 input: "round(some_metric)", 1281 expected: &Call{ 1282 Func: mustGetFunction("round"), 1283 Args: Expressions{ 1284 &VectorSelector{ 1285 Name: "some_metric", 1286 LabelMatchers: []*labels.Matcher{ 1287 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "some_metric"), 1288 }, 1289 }, 1290 }, 1291 }, 1292 }, { 1293 input: "round(some_metric, 5)", 1294 expected: &Call{ 1295 Func: mustGetFunction("round"), 1296 Args: Expressions{ 1297 &VectorSelector{ 1298 Name: "some_metric", 1299 LabelMatchers: []*labels.Matcher{ 1300 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "some_metric"), 1301 }, 1302 }, 1303 &NumberLiteral{5}, 1304 }, 1305 }, 1306 }, { 1307 input: "floor()", 1308 fail: true, 1309 errMsg: "expected 1 argument(s) in call to \"floor\", got 0", 1310 }, { 1311 input: "floor(some_metric, other_metric)", 1312 fail: true, 1313 errMsg: "expected 1 argument(s) in call to \"floor\", got 2", 1314 }, { 1315 input: "floor(1)", 1316 fail: true, 1317 errMsg: "expected type instant vector in call to function \"floor\", got scalar", 1318 }, { 1319 input: "non_existent_function_far_bar()", 1320 fail: true, 1321 errMsg: "unknown function with name \"non_existent_function_far_bar\"", 1322 }, { 1323 input: "rate(some_metric)", 1324 fail: true, 1325 errMsg: "expected type range vector in call to function \"rate\", got instant vector", 1326 }, { 1327 input: "label_replace(a, `b`, `c\xff`, `d`, `.*`)", 1328 fail: true, 1329 errMsg: "parse error at char 23: invalid UTF-8 rune", 1330 }, 1331 // Fuzzing regression tests. 1332 { 1333 input: "-=", 1334 fail: true, 1335 errMsg: `no valid expression found`, 1336 }, { 1337 input: "++-++-+-+-<", 1338 fail: true, 1339 errMsg: `no valid expression found`, 1340 }, { 1341 input: "e-+=/(0)", 1342 fail: true, 1343 errMsg: `no valid expression found`, 1344 }, { 1345 input: "-If", 1346 fail: true, 1347 errMsg: `no valid expression found`, 1348 }, 1349 // String quoting and escape sequence interpretation tests. 1350 { 1351 input: `"double-quoted string \" with escaped quote"`, 1352 expected: &StringLiteral{ 1353 Val: "double-quoted string \" with escaped quote", 1354 }, 1355 }, { 1356 input: `'single-quoted string \' with escaped quote'`, 1357 expected: &StringLiteral{ 1358 Val: "single-quoted string ' with escaped quote", 1359 }, 1360 }, { 1361 input: "`backtick-quoted string`", 1362 expected: &StringLiteral{ 1363 Val: "backtick-quoted string", 1364 }, 1365 }, { 1366 input: `"\a\b\f\n\r\t\v\\\" - \xFF\377\u1234\U00010111\U0001011111☺"`, 1367 expected: &StringLiteral{ 1368 Val: "\a\b\f\n\r\t\v\\\" - \xFF\377\u1234\U00010111\U0001011111☺", 1369 }, 1370 }, { 1371 input: `'\a\b\f\n\r\t\v\\\' - \xFF\377\u1234\U00010111\U0001011111☺'`, 1372 expected: &StringLiteral{ 1373 Val: "\a\b\f\n\r\t\v\\' - \xFF\377\u1234\U00010111\U0001011111☺", 1374 }, 1375 }, { 1376 input: "`" + `\a\b\f\n\r\t\v\\\"\' - \xFF\377\u1234\U00010111\U0001011111☺` + "`", 1377 expected: &StringLiteral{ 1378 Val: `\a\b\f\n\r\t\v\\\"\' - \xFF\377\u1234\U00010111\U0001011111☺`, 1379 }, 1380 }, { 1381 input: "`\\``", 1382 fail: true, 1383 errMsg: "could not parse remaining input", 1384 }, { 1385 input: `"\`, 1386 fail: true, 1387 errMsg: "escape sequence not terminated", 1388 }, { 1389 input: `"\c"`, 1390 fail: true, 1391 errMsg: "unknown escape sequence U+0063 'c'", 1392 }, { 1393 input: `"\x."`, 1394 fail: true, 1395 errMsg: "illegal character U+002E '.' in escape sequence", 1396 }, 1397 } 1398 1399 func TestParseExpressions(t *testing.T) { 1400 for _, test := range testExpr { 1401 expr, err := ParseExpr(test.input) 1402 1403 // Unexpected errors are always caused by a bug. 1404 if err == errUnexpected { 1405 t.Fatalf("unexpected error occurred") 1406 } 1407 1408 if !test.fail && err != nil { 1409 t.Errorf("error in input '%s'", test.input) 1410 t.Fatalf("could not parse: %s", err) 1411 } 1412 1413 if test.fail && err != nil { 1414 if !strings.Contains(err.Error(), test.errMsg) { 1415 t.Errorf("unexpected error on input '%s'", test.input) 1416 t.Fatalf("expected error to contain %q but got %q", test.errMsg, err) 1417 } 1418 continue 1419 } 1420 1421 if !reflect.DeepEqual(expr, test.expected) { 1422 t.Errorf("error on input '%s'", test.input) 1423 t.Fatalf("no match\n\nexpected:\n%s\ngot: \n%s\n", Tree(test.expected), Tree(expr)) 1424 } 1425 } 1426 } 1427 1428 // NaN has no equality. Thus, we need a separate test for it. 1429 func TestNaNExpression(t *testing.T) { 1430 expr, err := ParseExpr("NaN") 1431 if err != nil { 1432 t.Errorf("error on input 'NaN'") 1433 t.Fatalf("could not parse: %s", err) 1434 } 1435 1436 nl, ok := expr.(*NumberLiteral) 1437 if !ok { 1438 t.Errorf("error on input 'NaN'") 1439 t.Fatalf("expected number literal but got %T", expr) 1440 } 1441 1442 if !math.IsNaN(float64(nl.Val)) { 1443 t.Errorf("error on input 'NaN'") 1444 t.Fatalf("expected 'NaN' in number literal but got %v", nl.Val) 1445 } 1446 } 1447 1448 var testStatement = []struct { 1449 input string 1450 expected Statements 1451 fail bool 1452 }{ 1453 { 1454 // Test a file-like input. 1455 input: ` 1456 # A simple test recording rule. 1457 dc:http_request:rate5m = sum(rate(http_request_count[5m])) by (dc) 1458 1459 # A simple test alerting rule. 1460 ALERT GlobalRequestRateLow IF(dc:http_request:rate5m < 10000) FOR 5m 1461 LABELS { 1462 service = "testservice" 1463 # ... more fields here ... 1464 } 1465 ANNOTATIONS { 1466 summary = "Global request rate low", 1467 description = "The global request rate is low" 1468 } 1469 1470 foo = bar{label1="value1"} 1471 1472 ALERT BazAlert IF foo > 10 1473 ANNOTATIONS { 1474 description = "BazAlert", 1475 runbook = "http://my.url", 1476 summary = "Baz", 1477 } 1478 `, 1479 expected: Statements{ 1480 &RecordStmt{ 1481 Name: "dc:http_request:rate5m", 1482 Expr: &AggregateExpr{ 1483 Op: itemSum, 1484 Grouping: []string{"dc"}, 1485 Expr: &Call{ 1486 Func: mustGetFunction("rate"), 1487 Args: Expressions{ 1488 &MatrixSelector{ 1489 Name: "http_request_count", 1490 LabelMatchers: []*labels.Matcher{ 1491 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "http_request_count"), 1492 }, 1493 Range: 5 * time.Minute, 1494 }, 1495 }, 1496 }, 1497 }, 1498 Labels: nil, 1499 }, 1500 &AlertStmt{ 1501 Name: "GlobalRequestRateLow", 1502 Expr: &ParenExpr{&BinaryExpr{ 1503 Op: itemLSS, 1504 LHS: &VectorSelector{ 1505 Name: "dc:http_request:rate5m", 1506 LabelMatchers: []*labels.Matcher{ 1507 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "dc:http_request:rate5m"), 1508 }, 1509 }, 1510 RHS: &NumberLiteral{10000}, 1511 }}, 1512 Labels: labels.FromStrings("service", "testservice"), 1513 Duration: 5 * time.Minute, 1514 Annotations: labels.FromStrings( 1515 "summary", "Global request rate low", 1516 "description", "The global request rate is low", 1517 ), 1518 }, 1519 &RecordStmt{ 1520 Name: "foo", 1521 Expr: &VectorSelector{ 1522 Name: "bar", 1523 LabelMatchers: []*labels.Matcher{ 1524 mustLabelMatcher(labels.MatchEqual, "label1", "value1"), 1525 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "bar"), 1526 }, 1527 }, 1528 }, 1529 &AlertStmt{ 1530 Name: "BazAlert", 1531 Expr: &BinaryExpr{ 1532 Op: itemGTR, 1533 LHS: &VectorSelector{ 1534 Name: "foo", 1535 LabelMatchers: []*labels.Matcher{ 1536 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "foo"), 1537 }, 1538 }, 1539 RHS: &NumberLiteral{10}, 1540 }, 1541 Annotations: labels.FromStrings( 1542 "summary", "Baz", 1543 "description", "BazAlert", 1544 "runbook", "http://my.url", 1545 ), 1546 }, 1547 }, 1548 }, { 1549 input: `foo{x="", a="z"} = bar{a="b", x=~"y"}`, 1550 expected: Statements{ 1551 &RecordStmt{ 1552 Name: "foo", 1553 Expr: &VectorSelector{ 1554 Name: "bar", 1555 LabelMatchers: []*labels.Matcher{ 1556 mustLabelMatcher(labels.MatchEqual, "a", "b"), 1557 mustLabelMatcher(labels.MatchRegexp, "x", "y"), 1558 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "bar"), 1559 }, 1560 }, 1561 Labels: labels.FromStrings("x", "", "a", "z"), 1562 }, 1563 }, 1564 }, { 1565 input: `ALERT SomeName IF some_metric > 1 1566 LABELS {} 1567 ANNOTATIONS { 1568 summary = "Global request rate low", 1569 description = "The global request rate is low", 1570 } 1571 `, 1572 expected: Statements{ 1573 &AlertStmt{ 1574 Name: "SomeName", 1575 Expr: &BinaryExpr{ 1576 Op: itemGTR, 1577 LHS: &VectorSelector{ 1578 Name: "some_metric", 1579 LabelMatchers: []*labels.Matcher{ 1580 mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "some_metric"), 1581 }, 1582 }, 1583 RHS: &NumberLiteral{1}, 1584 }, 1585 Labels: labels.Labels{}, 1586 Annotations: labels.FromStrings( 1587 "summary", "Global request rate low", 1588 "description", "The global request rate is low", 1589 ), 1590 }, 1591 }, 1592 }, { 1593 input: ` 1594 # A simple test alerting rule. 1595 ALERT GlobalRequestRateLow IF(dc:http_request:rate5m < 10000) FOR 5 1596 LABELS { 1597 service = "testservice" 1598 # ... more fields here ... 1599 } 1600 ANNOTATIONS { 1601 summary = "Global request rate low" 1602 description = "The global request rate is low" 1603 } 1604 `, 1605 fail: true, 1606 }, { 1607 input: "", 1608 expected: Statements{}, 1609 }, { 1610 input: "foo = time()", 1611 expected: Statements{ 1612 &RecordStmt{ 1613 Name: "foo", 1614 Expr: &Call{Func: mustGetFunction("time")}, 1615 Labels: nil, 1616 }}, 1617 }, { 1618 input: "foo = 1", 1619 expected: Statements{ 1620 &RecordStmt{ 1621 Name: "foo", 1622 Expr: &NumberLiteral{1}, 1623 Labels: nil, 1624 }}, 1625 }, { 1626 input: "foo = bar[5m]", 1627 fail: true, 1628 }, { 1629 input: `foo = "test"`, 1630 fail: true, 1631 }, { 1632 input: `foo = `, 1633 fail: true, 1634 }, { 1635 input: `foo{a!="b"} = bar`, 1636 fail: true, 1637 }, { 1638 input: `foo{a=~"b"} = bar`, 1639 fail: true, 1640 }, { 1641 input: `foo{a!~"b"} = bar`, 1642 fail: true, 1643 }, 1644 // Fuzzing regression tests. 1645 { 1646 input: `I=-/`, 1647 fail: true, 1648 }, 1649 { 1650 input: `I=3E8/-=`, 1651 fail: true, 1652 }, 1653 { 1654 input: `M=-=-0-0`, 1655 fail: true, 1656 }, 1657 } 1658 1659 func TestParseStatements(t *testing.T) { 1660 for _, test := range testStatement { 1661 stmts, err := ParseStmts(test.input) 1662 1663 // Unexpected errors are always caused by a bug. 1664 if err == errUnexpected { 1665 t.Fatalf("unexpected error occurred") 1666 } 1667 1668 if !test.fail && err != nil { 1669 t.Errorf("error in input: \n\n%s\n", test.input) 1670 t.Fatalf("could not parse: %s", err) 1671 } 1672 if test.fail && err != nil { 1673 continue 1674 } 1675 1676 if !reflect.DeepEqual(stmts, test.expected) { 1677 t.Errorf("error in input: \n\n%s\n", test.input) 1678 t.Fatalf("no match\n\nexpected:\n%s\ngot: \n%s\n", Tree(test.expected), Tree(stmts)) 1679 } 1680 } 1681 } 1682 1683 func mustLabelMatcher(mt labels.MatchType, name, val string) *labels.Matcher { 1684 m, err := labels.NewMatcher(mt, name, val) 1685 if err != nil { 1686 panic(err) 1687 } 1688 return m 1689 } 1690 1691 func mustGetFunction(name string) *Function { 1692 f, ok := getFunction(name) 1693 if !ok { 1694 panic(fmt.Errorf("function %q does not exist", name)) 1695 } 1696 return f 1697 } 1698 1699 var testSeries = []struct { 1700 input string 1701 expectedMetric labels.Labels 1702 expectedValues []sequenceValue 1703 fail bool 1704 }{ 1705 { 1706 input: `{} 1 2 3`, 1707 expectedMetric: labels.Labels{}, 1708 expectedValues: newSeq(1, 2, 3), 1709 }, { 1710 input: `{a="b"} -1 2 3`, 1711 expectedMetric: labels.FromStrings("a", "b"), 1712 expectedValues: newSeq(-1, 2, 3), 1713 }, { 1714 input: `my_metric 1 2 3`, 1715 expectedMetric: labels.FromStrings(labels.MetricName, "my_metric"), 1716 expectedValues: newSeq(1, 2, 3), 1717 }, { 1718 input: `my_metric{} 1 2 3`, 1719 expectedMetric: labels.FromStrings(labels.MetricName, "my_metric"), 1720 expectedValues: newSeq(1, 2, 3), 1721 }, { 1722 input: `my_metric{a="b"} 1 2 3`, 1723 expectedMetric: labels.FromStrings(labels.MetricName, "my_metric", "a", "b"), 1724 expectedValues: newSeq(1, 2, 3), 1725 }, { 1726 input: `my_metric{a="b"} 1 2 3-10x4`, 1727 expectedMetric: labels.FromStrings(labels.MetricName, "my_metric", "a", "b"), 1728 expectedValues: newSeq(1, 2, 3, -7, -17, -27, -37), 1729 }, { 1730 input: `my_metric{a="b"} 1 2 3-0x4`, 1731 expectedMetric: labels.FromStrings(labels.MetricName, "my_metric", "a", "b"), 1732 expectedValues: newSeq(1, 2, 3, 3, 3, 3, 3), 1733 }, { 1734 input: `my_metric{a="b"} 1 3 _ 5 _x4`, 1735 expectedMetric: labels.FromStrings(labels.MetricName, "my_metric", "a", "b"), 1736 expectedValues: newSeq(1, 3, none, 5, none, none, none, none), 1737 }, { 1738 input: `my_metric{a="b"} 1 3 _ 5 _a4`, 1739 fail: true, 1740 }, 1741 } 1742 1743 // For these tests only, we use the smallest float64 to signal an omitted value. 1744 const none = math.SmallestNonzeroFloat64 1745 1746 func newSeq(vals ...float64) (res []sequenceValue) { 1747 for _, v := range vals { 1748 if v == none { 1749 res = append(res, sequenceValue{omitted: true}) 1750 } else { 1751 res = append(res, sequenceValue{value: v}) 1752 } 1753 } 1754 return res 1755 } 1756 1757 func TestParseSeries(t *testing.T) { 1758 for _, test := range testSeries { 1759 metric, vals, err := parseSeriesDesc(test.input) 1760 1761 // Unexpected errors are always caused by a bug. 1762 if err == errUnexpected { 1763 t.Fatalf("unexpected error occurred") 1764 } 1765 1766 if test.fail { 1767 if err != nil { 1768 continue 1769 } 1770 t.Errorf("error in input: \n\n%s\n", test.input) 1771 t.Fatalf("failure expected, but passed") 1772 } else { 1773 if err != nil { 1774 t.Errorf("error in input: \n\n%s\n", test.input) 1775 t.Fatalf("could not parse: %s", err) 1776 } 1777 } 1778 1779 require.Equal(t, test.expectedMetric, metric) 1780 require.Equal(t, test.expectedValues, vals) 1781 1782 if !reflect.DeepEqual(vals, test.expectedValues) || !reflect.DeepEqual(metric, test.expectedMetric) { 1783 t.Errorf("error in input: \n\n%s\n", test.input) 1784 t.Fatalf("no match\n\nexpected:\n%s %s\ngot: \n%s %s\n", test.expectedMetric, test.expectedValues, metric, vals) 1785 } 1786 } 1787 } 1788 1789 func TestRecoverParserRuntime(t *testing.T) { 1790 var p *parser 1791 var err error 1792 defer p.recover(&err) 1793 1794 // Cause a runtime panic. 1795 var a []int 1796 a[123] = 1 1797 1798 if err != errUnexpected { 1799 t.Fatalf("wrong error message: %q, expected %q", err, errUnexpected) 1800 } 1801 } 1802 1803 func TestRecoverParserError(t *testing.T) { 1804 var p *parser 1805 var err error 1806 1807 e := fmt.Errorf("custom error") 1808 1809 defer func() { 1810 if err.Error() != e.Error() { 1811 t.Fatalf("wrong error message: %q, expected %q", err, e) 1812 } 1813 }() 1814 defer p.recover(&err) 1815 1816 panic(e) 1817 }