From 1f317ebbe8e2bc1cd9feb5b90d375d4993b88abf Mon Sep 17 00:00:00 2001 From: Lukasz Mierzwa Date: Mon, 4 Mar 2024 13:33:28 +0000 Subject: [PATCH] Add more tests for tags --- internal/parser/parser.go | 63 ++++++------- internal/parser/parser_test.go | 158 ++++++++++++++++++++++++++++++++- 2 files changed, 189 insertions(+), 32 deletions(-) diff --git a/internal/parser/parser.go b/internal/parser/parser.go index f8f076ec..ff5b37b2 100644 --- a/internal/parser/parser.go +++ b/internal/parser/parser.go @@ -295,6 +295,38 @@ func parseRule(content []byte, node *yaml.Node, offset int) (rule Rule, _ bool, } return rule, false, err } + for key, part := range map[string]*yaml.Node{ + recordKey: recordNode, + alertKey: alertNode, + exprKey: exprNode, + forKey: forNode, + keepFiringForKey: keepFiringForNode, + } { + if part != nil && !isTag(part.ShortTag(), "!!str") { + return invalidValueError(lines, part.Line+offset, key, "string", describeTag(part.ShortTag())) + } + } + + for key, part := range map[string]*yaml.Node{ + labelsKey: labelsNode, + annotationsKey: annotationsNode, + } { + if part != nil && !isTag(part.ShortTag(), "!!map") { + return invalidValueError(lines, part.Line+offset, key, "mapping", describeTag(part.ShortTag())) + } + } + + for section, parts := range map[string]map[*yaml.Node]*yaml.Node{ + labelsKey: labelsNodes, + annotationsKey: annotationsNodes, + } { + for key, value := range parts { + if !isTag(value.ShortTag(), "!!str") { + return invalidValueError(lines, value.Line+offset, fmt.Sprintf("%s %s", section, nodeValue(key)), "string", describeTag(value.ShortTag())) + } + } + } + if r, ok := ensureRequiredKeys(lines, recordKey, recordPart, exprPart); !ok { return r, false, err } @@ -363,37 +395,6 @@ func parseRule(content []byte, node *yaml.Node, offset int) (rule Rule, _ bool, } } - for key, part := range map[string]*yaml.Node{ - recordKey: recordNode, - alertKey: alertNode, - exprKey: exprNode, - forKey: forNode, - keepFiringForKey: keepFiringForNode, - } { - if part != nil && !isTag(part.ShortTag(), "!!str") { - return invalidValueError(lines, part.Line+offset, key, "string", describeTag(part.ShortTag())) - } - } - for key, part := range map[string]*yaml.Node{ - labelsKey: labelsNode, - annotationsKey: annotationsNode, - } { - if part != nil && !isTag(part.ShortTag(), "!!map") { - return invalidValueError(lines, part.Line+offset, key, "mapping", describeTag(part.ShortTag())) - } - } - - for section, parts := range map[string]map[*yaml.Node]*yaml.Node{ - labelsKey: labelsNodes, - annotationsKey: annotationsNodes, - } { - for key, value := range parts { - if !isTag(value.ShortTag(), "!!str") { - return invalidValueError(lines, value.Line+offset, fmt.Sprintf("%s %s", section, nodeValue(key)), "string", describeTag(value.ShortTag())) - } - } - } - if recordPart != nil && exprPart != nil { rule = Rule{ Lines: lines, diff --git a/internal/parser/parser_test.go b/internal/parser/parser_test.go index 719ae660..dbee94e4 100644 --- a/internal/parser/parser_test.go +++ b/internal/parser/parser_test.go @@ -1539,7 +1539,7 @@ data: output: []parser.Rule{ { Lines: parser.LineRange{First: 2, Last: 3}, - Error: parser.ParseError{Err: fmt.Errorf("invalid recording rule name: 5"), Line: 2}, + Error: parser.ParseError{Err: fmt.Errorf("record value must be a YAML string, got integer instead"), Line: 2}, }, }, }, @@ -1652,6 +1652,162 @@ data: }, }, }, + { + content: []byte(` +- record: foo + expr: bar + labels: 4 +`), + output: []parser.Rule{ + { + Lines: parser.LineRange{First: 2, Last: 4}, + Error: parser.ParseError{Err: fmt.Errorf("labels value must be a YAML mapping, got integer instead"), Line: 4}, + }, + }, + }, + { + content: []byte(` +- record: foo + expr: bar + labels: true +`), + output: []parser.Rule{ + { + Lines: parser.LineRange{First: 2, Last: 4}, + Error: parser.ParseError{Err: fmt.Errorf("labels value must be a YAML mapping, got bool instead"), Line: 4}, + }, + }, + }, + { + content: []byte(` +- record: foo + expr: bar + labels: null +`), + output: []parser.Rule{ + { + Lines: parser.LineRange{First: 2, Last: 4}, + RecordingRule: &parser.RecordingRule{ + Record: parser.YamlNode{ + Lines: parser.LineRange{First: 2, Last: 2}, + Value: "foo", + }, + Expr: parser.PromQLExpr{ + Value: &parser.YamlNode{ + Lines: parser.LineRange{First: 3, Last: 3}, + Value: "bar", + }, + Query: &parser.PromQLNode{Expr: "bar"}, + }, + Labels: &parser.YamlMap{ + Lines: parser.LineRange{First: 4, Last: 4}, + Key: &parser.YamlNode{ + Lines: parser.LineRange{First: 4, Last: 4}, + Value: "labels", + }, + }, + }, + }, + }, + }, + { + content: []byte(` +- record: true + expr: bar +`), + output: []parser.Rule{ + { + Lines: parser.LineRange{First: 2, Last: 3}, + Error: parser.ParseError{Err: fmt.Errorf("record value must be a YAML string, got bool instead"), Line: 2}, + }, + }, + }, + { + content: []byte(` +- record: + query: foo + expr: bar +`), + output: []parser.Rule{ + { + Lines: parser.LineRange{First: 2, Last: 4}, + Error: parser.ParseError{Err: fmt.Errorf("record value must be a YAML string, got mapping instead"), Line: 3}, + }, + }, + }, + { + content: []byte(` +- record: foo + expr: bar + labels: some +`), + output: []parser.Rule{ + { + Lines: parser.LineRange{First: 2, Last: 4}, + Error: parser.ParseError{Err: fmt.Errorf("labels value must be a YAML mapping, got string instead"), Line: 4}, + }, + }, + }, + { + content: []byte(` +- record: foo + expr: bar + labels: !!binary "SGVsbG8sIFdvcmxkIQ==" +`), + output: []parser.Rule{ + { + Lines: parser.LineRange{First: 2, Last: 4}, + Error: parser.ParseError{Err: fmt.Errorf("labels value must be a YAML mapping, got binary data instead"), Line: 4}, + }, + }, + }, + { + content: []byte(` +- alert: foo + expr: bar + for: 1.23 +`), + output: []parser.Rule{ + { + Lines: parser.LineRange{First: 2, Last: 4}, + Error: parser.ParseError{Err: fmt.Errorf("for value must be a YAML string, got float instead"), Line: 4}, + }, + }, + }, + { + content: []byte(` +- record: foo + expr: bar + labels: !!garbage "SGVsbG8sIFdvcmxkIQ==" +`), + output: []parser.Rule{ + { + Lines: parser.LineRange{First: 2, Last: 4}, + Error: parser.ParseError{Err: fmt.Errorf("labels value must be a YAML mapping, got garbage instead"), Line: 4}, + }, + }, + }, + { + content: []byte(` +- record: foo + expr: bar + labels: !! "SGVsbG8sIFdvcmxkIQ==" +`), + err: "yaml: line 4: did not find expected tag URI", + }, + { + content: []byte(` +- record: &foo foo + expr: bar + labels: *foo +`), + output: []parser.Rule{ + { + Lines: parser.LineRange{First: 2, Last: 4}, + Error: parser.ParseError{Err: fmt.Errorf("labels value must be a YAML mapping, got string instead"), Line: 4}, + }, + }, + }, // Multi-document tests { content: []byte("---\n- expr: foo\n record: foo\n---\n- expr: bar\n"),