grafana/pkg/tsdb/cloudwatch/metric_data_query_builder_test.go
Erik Sundell 00bef917ee
CloudWatch: Datasource improvements (#20268)
* CloudWatch: Datasource improvements

* Add statistic as template variale

* Add wildcard to list of values

* Template variable intercept dimension key

* Return row specific errors when transformation error occured

* Add meta feedback

* Make it possible to retrieve values without known metrics

* Add curated dashboard for EC2

* Fix broken tests

* Use correct dashboard name

* Display alert in case multi template var is being used for some certain props in the cloudwatch query

* Minor fixes after feedback

* Update dashboard json

* Update snapshot test

* Make sure region default is intercepted in cloudwatch link

* Update dashboards

* Include ec2 dashboard in ds

* Do not include ec2 dashboard in beta1

* Display actual region
2019-11-14 10:59:41 +01:00

216 lines
6.8 KiB
Go

package cloudwatch
import (
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestMetricDataQueryBuilder(t *testing.T) {
Convey("TestMetricDataQueryBuilder", t, func() {
Convey("buildSearchExpression", func() {
Convey("and query should be matched exact", func() {
matchExact := true
Convey("and query has three dimension values for a given dimension key", func() {
query := &cloudWatchQuery{
Namespace: "AWS/EC2",
MetricName: "CPUUtilization",
Dimensions: map[string][]string{
"LoadBalancer": {"lb1", "lb2", "lb3"},
},
Period: 300,
Identifier: "id1",
Expression: "",
MatchExact: matchExact,
}
res := buildSearchExpression(query, "Average")
So(res, ShouldEqual, `REMOVE_EMPTY(SEARCH('{AWS/EC2,LoadBalancer} MetricName="CPUUtilization" "LoadBalancer"=("lb1" OR "lb2" OR "lb3")', 'Average', 300))`)
})
Convey("and query has three dimension values for two given dimension keys", func() {
query := &cloudWatchQuery{
Namespace: "AWS/EC2",
MetricName: "CPUUtilization",
Dimensions: map[string][]string{
"LoadBalancer": {"lb1", "lb2", "lb3"},
"InstanceId": {"i-123", "i-456", "i-789"},
},
Period: 300,
Identifier: "id1",
Expression: "",
MatchExact: matchExact,
}
res := buildSearchExpression(query, "Average")
So(res, ShouldEqual, `REMOVE_EMPTY(SEARCH('{AWS/EC2,InstanceId,LoadBalancer} MetricName="CPUUtilization" "InstanceId"=("i-123" OR "i-456" OR "i-789") "LoadBalancer"=("lb1" OR "lb2" OR "lb3")', 'Average', 300))`)
})
Convey("and no OR operator was added if a star was used for dimension value", func() {
query := &cloudWatchQuery{
Namespace: "AWS/EC2",
MetricName: "CPUUtilization",
Dimensions: map[string][]string{
"LoadBalancer": {"*"},
},
Period: 300,
Identifier: "id1",
Expression: "",
MatchExact: matchExact,
}
res := buildSearchExpression(query, "Average")
So(res, ShouldNotContainSubstring, "OR")
})
Convey("and query has one dimension key with a * value", func() {
query := &cloudWatchQuery{
Namespace: "AWS/EC2",
MetricName: "CPUUtilization",
Dimensions: map[string][]string{
"LoadBalancer": {"*"},
},
Period: 300,
Identifier: "id1",
Expression: "",
MatchExact: matchExact,
}
res := buildSearchExpression(query, "Average")
So(res, ShouldEqual, `REMOVE_EMPTY(SEARCH('{AWS/EC2,LoadBalancer} MetricName="CPUUtilization"', 'Average', 300))`)
})
Convey("and query has three dimension values for two given dimension keys, and one value is a star", func() {
query := &cloudWatchQuery{
Namespace: "AWS/EC2",
MetricName: "CPUUtilization",
Dimensions: map[string][]string{
"LoadBalancer": {"lb1", "lb2", "lb3"},
"InstanceId": {"i-123", "*", "i-789"},
},
Period: 300,
Identifier: "id1",
Expression: "",
MatchExact: matchExact,
}
res := buildSearchExpression(query, "Average")
So(res, ShouldEqual, `REMOVE_EMPTY(SEARCH('{AWS/EC2,InstanceId,LoadBalancer} MetricName="CPUUtilization" "LoadBalancer"=("lb1" OR "lb2" OR "lb3")', 'Average', 300))`)
})
})
Convey("and query should not be matched exact", func() {
matchExact := false
Convey("and query has three dimension values for a given dimension key", func() {
query := &cloudWatchQuery{
Namespace: "AWS/EC2",
MetricName: "CPUUtilization",
Dimensions: map[string][]string{
"LoadBalancer": {"lb1", "lb2", "lb3"},
},
Period: 300,
Identifier: "id1",
Expression: "",
MatchExact: matchExact,
}
res := buildSearchExpression(query, "Average")
So(res, ShouldEqual, `REMOVE_EMPTY(SEARCH('Namespace="AWS/EC2" MetricName="CPUUtilization" "LoadBalancer"=("lb1" OR "lb2" OR "lb3")', 'Average', 300))`)
})
Convey("and query has three dimension values for two given dimension keys", func() {
query := &cloudWatchQuery{
Namespace: "AWS/EC2",
MetricName: "CPUUtilization",
Dimensions: map[string][]string{
"LoadBalancer": {"lb1", "lb2", "lb3"},
"InstanceId": {"i-123", "i-456", "i-789"},
},
Period: 300,
Identifier: "id1",
Expression: "",
MatchExact: matchExact,
}
res := buildSearchExpression(query, "Average")
So(res, ShouldEqual, `REMOVE_EMPTY(SEARCH('Namespace="AWS/EC2" MetricName="CPUUtilization" "InstanceId"=("i-123" OR "i-456" OR "i-789") "LoadBalancer"=("lb1" OR "lb2" OR "lb3")', 'Average', 300))`)
})
Convey("and query has one dimension key with a * value", func() {
query := &cloudWatchQuery{
Namespace: "AWS/EC2",
MetricName: "CPUUtilization",
Dimensions: map[string][]string{
"LoadBalancer": {"*"},
},
Period: 300,
Identifier: "id1",
Expression: "",
MatchExact: matchExact,
}
res := buildSearchExpression(query, "Average")
So(res, ShouldEqual, `REMOVE_EMPTY(SEARCH('Namespace="AWS/EC2" MetricName="CPUUtilization" "LoadBalancer"', 'Average', 300))`)
})
Convey("and query has three dimension values for two given dimension keys, and one value is a star", func() {
query := &cloudWatchQuery{
Namespace: "AWS/EC2",
MetricName: "CPUUtilization",
Dimensions: map[string][]string{
"LoadBalancer": {"lb1", "lb2", "lb3"},
"InstanceId": {"i-123", "*", "i-789"},
},
Period: 300,
Identifier: "id1",
Expression: "",
MatchExact: matchExact,
}
res := buildSearchExpression(query, "Average")
So(res, ShouldEqual, `REMOVE_EMPTY(SEARCH('Namespace="AWS/EC2" MetricName="CPUUtilization" "LoadBalancer"=("lb1" OR "lb2" OR "lb3") "InstanceId"', 'Average', 300))`)
})
})
})
Convey("and query has has invalid characters in dimension values", func() {
query := &cloudWatchQuery{
Namespace: "AWS/EC2",
MetricName: "CPUUtilization",
Dimensions: map[string][]string{
"lb1": {`lb\1\`},
"lb2": {`)lb2`},
"lb3": {`l(b3`},
"lb4": {`lb4""`},
"lb5": {`l\(b5"`},
"lb6": {`l\\(b5"`},
},
Period: 300,
Identifier: "id1",
Expression: "",
MatchExact: true,
}
res := buildSearchExpression(query, "Average")
Convey("it should escape backslash", func() {
So(res, ShouldContainSubstring, `"lb1"="lb\\1\\"`)
})
Convey("it should escape closing parenthesis", func() {
So(res, ShouldContainSubstring, `"lb2"="\)lb2"`)
})
Convey("it should escape open parenthesis", func() {
So(res, ShouldContainSubstring, `"lb3"="l\(b3"`)
})
Convey("it should escape double quotes", func() {
So(res, ShouldContainSubstring, `"lb6"="l\\\\\(b5\""`)
})
})
})
}