2019-11-14 03:59:41 -06:00
package cloudwatch
import (
2021-09-08 09:06:43 -05:00
"encoding/json"
2022-08-10 08:37:51 -05:00
"os"
2022-04-04 08:44:19 -05:00
"path/filepath"
2019-11-14 03:59:41 -06:00
"testing"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/cloudwatch"
2024-04-05 10:57:56 -05:00
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/features"
2022-10-20 04:21:13 -05:00
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models"
2020-10-02 12:40:15 -05:00
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
2019-11-14 03:59:41 -06:00
)
2022-04-04 08:44:19 -05:00
func loadGetMetricDataOutputsFromFile ( filePath string ) ( [ ] * cloudwatch . GetMetricDataOutput , error ) {
2021-09-08 09:06:43 -05:00
var getMetricDataOutputs [ ] * cloudwatch . GetMetricDataOutput
2022-04-04 08:44:19 -05:00
cleanFilePath := filepath . Clean ( filePath )
2022-08-10 08:37:51 -05:00
jsonBody , err := os . ReadFile ( cleanFilePath )
2021-09-08 09:06:43 -05:00
if err != nil {
return getMetricDataOutputs , err
}
err = json . Unmarshal ( jsonBody , & getMetricDataOutputs )
return getMetricDataOutputs , err
}
2019-11-14 03:59:41 -06:00
func TestCloudWatchResponseParser ( t * testing . T ) {
2022-05-08 02:27:03 -05:00
t . Run ( "when aggregating multi-outputs response" , func ( t * testing . T ) {
2022-10-18 03:21:18 -05:00
getMetricDataOutputs , err := loadGetMetricDataOutputsFromFile ( "./testdata/multiple-outputs-query-a.json" )
2021-09-08 09:06:43 -05:00
require . NoError ( t , err )
aggregatedResponse := aggregateResponse ( getMetricDataOutputs )
2022-05-08 02:27:03 -05:00
idA := "a"
t . Run ( "should have two labels" , func ( t * testing . T ) {
assert . Len ( t , aggregatedResponse [ idA ] . Metrics , 2 )
2021-09-08 09:06:43 -05:00
} )
2022-05-08 02:27:03 -05:00
t . Run ( "should have points for label1 taken from both getMetricDataOutputs" , func ( t * testing . T ) {
2022-05-18 02:16:38 -05:00
require . NotNil ( t , * aggregatedResponse [ idA ] . Metrics [ 0 ] . Label )
require . Equal ( t , "label1" , * aggregatedResponse [ idA ] . Metrics [ 0 ] . Label )
assert . Len ( t , aggregatedResponse [ idA ] . Metrics [ 0 ] . Values , 10 )
2022-05-08 02:27:03 -05:00
} )
t . Run ( "should have statuscode 'Complete'" , func ( t * testing . T ) {
assert . Equal ( t , "Complete" , aggregatedResponse [ idA ] . StatusCode )
} )
t . Run ( "should have exceeded request limit" , func ( t * testing . T ) {
assert . True ( t , aggregatedResponse [ idA ] . ErrorCodes [ "MaxMetricsExceeded" ] )
} )
t . Run ( "should have exceeded query time range" , func ( t * testing . T ) {
assert . True ( t , aggregatedResponse [ idA ] . ErrorCodes [ "MaxQueryTimeRangeExceeded" ] )
} )
t . Run ( "should have exceeded max query results" , func ( t * testing . T ) {
assert . True ( t , aggregatedResponse [ idA ] . ErrorCodes [ "MaxQueryResultsExceeded" ] )
} )
t . Run ( "should have exceeded max matching results" , func ( t * testing . T ) {
assert . True ( t , aggregatedResponse [ idA ] . ErrorCodes [ "MaxMatchingResultsExceeded" ] )
} )
} )
t . Run ( "when aggregating multi-outputs response with PartialData and ArithmeticError" , func ( t * testing . T ) {
2022-10-18 03:21:18 -05:00
getMetricDataOutputs , err := loadGetMetricDataOutputsFromFile ( "./testdata/multiple-outputs-query-b.json" )
2022-05-08 02:27:03 -05:00
require . NoError ( t , err )
aggregatedResponse := aggregateResponse ( getMetricDataOutputs )
idB := "b"
t . Run ( "should have statuscode is 'PartialData'" , func ( t * testing . T ) {
assert . Equal ( t , "PartialData" , aggregatedResponse [ idB ] . StatusCode )
} )
t . Run ( "should have an arithmetic error and an error message" , func ( t * testing . T ) {
assert . True ( t , aggregatedResponse [ idB ] . HasArithmeticError )
assert . Equal ( t , "One or more data-points have been dropped due to non-numeric values (NaN, -Infinite, +Infinite)" , aggregatedResponse [ idB ] . ArithmeticErrorMessage )
2021-09-08 09:06:43 -05:00
} )
} )
2022-05-18 02:16:38 -05:00
t . Run ( "when aggregating multi-outputs response" , func ( t * testing . T ) {
2022-10-18 03:21:18 -05:00
getMetricDataOutputs , err := loadGetMetricDataOutputsFromFile ( "./testdata/single-output-multiple-metric-data-results.json" )
2022-05-18 02:16:38 -05:00
require . NoError ( t , err )
aggregatedResponse := aggregateResponse ( getMetricDataOutputs )
idA := "a"
t . Run ( "should have one label" , func ( t * testing . T ) {
assert . Len ( t , aggregatedResponse [ idA ] . Metrics , 1 )
} )
t . Run ( "should have points for label1 taken from both MetricDataResults" , func ( t * testing . T ) {
require . NotNil ( t , * aggregatedResponse [ idA ] . Metrics [ 0 ] . Label )
require . Equal ( t , "label1" , * aggregatedResponse [ idA ] . Metrics [ 0 ] . Label )
assert . Len ( t , aggregatedResponse [ idA ] . Metrics [ 0 ] . Values , 6 )
} )
t . Run ( "should have statuscode 'Complete'" , func ( t * testing . T ) {
assert . Equal ( t , "Complete" , aggregatedResponse [ idA ] . StatusCode )
} )
} )
2022-04-04 08:44:19 -05:00
t . Run ( "when aggregating response and error codes are in first GetMetricDataOutput" , func ( t * testing . T ) {
2022-10-18 03:21:18 -05:00
getMetricDataOutputs , err := loadGetMetricDataOutputsFromFile ( "./testdata/multiple-outputs2.json" )
2022-04-04 08:44:19 -05:00
require . NoError ( t , err )
aggregatedResponse := aggregateResponse ( getMetricDataOutputs )
t . Run ( "response for id a" , func ( t * testing . T ) {
idA := "a"
t . Run ( "should have exceeded request limit" , func ( t * testing . T ) {
assert . True ( t , aggregatedResponse [ idA ] . ErrorCodes [ "MaxMetricsExceeded" ] )
} )
t . Run ( "should have exceeded query time range" , func ( t * testing . T ) {
assert . True ( t , aggregatedResponse [ idA ] . ErrorCodes [ "MaxQueryTimeRangeExceeded" ] )
} )
t . Run ( "should have exceeded max query results" , func ( t * testing . T ) {
assert . True ( t , aggregatedResponse [ idA ] . ErrorCodes [ "MaxQueryResultsExceeded" ] )
} )
t . Run ( "should have exceeded max matching results" , func ( t * testing . T ) {
assert . True ( t , aggregatedResponse [ idA ] . ErrorCodes [ "MaxMatchingResultsExceeded" ] )
} )
} )
} )
2022-12-02 03:21:46 -06:00
t . Run ( "when aggregating response and error codes are in second GetMetricDataOutput" , func ( t * testing . T ) {
getMetricDataOutputs , err := loadGetMetricDataOutputsFromFile ( "./testdata/multiple-outputs3.json" )
require . NoError ( t , err )
aggregatedResponse := aggregateResponse ( getMetricDataOutputs )
t . Run ( "response for id a" , func ( t * testing . T ) {
idA := "a"
idB := "b"
t . Run ( "should have exceeded request limit" , func ( t * testing . T ) {
assert . True ( t , aggregatedResponse [ idA ] . ErrorCodes [ "MaxMetricsExceeded" ] )
assert . True ( t , aggregatedResponse [ idB ] . ErrorCodes [ "MaxMetricsExceeded" ] )
} )
t . Run ( "should have exceeded query time range" , func ( t * testing . T ) {
assert . True ( t , aggregatedResponse [ idA ] . ErrorCodes [ "MaxQueryTimeRangeExceeded" ] )
assert . True ( t , aggregatedResponse [ idB ] . ErrorCodes [ "MaxQueryTimeRangeExceeded" ] )
} )
t . Run ( "should have exceeded max query results" , func ( t * testing . T ) {
assert . True ( t , aggregatedResponse [ idA ] . ErrorCodes [ "MaxQueryResultsExceeded" ] )
assert . True ( t , aggregatedResponse [ idB ] . ErrorCodes [ "MaxQueryResultsExceeded" ] )
} )
t . Run ( "should have exceeded max matching results" , func ( t * testing . T ) {
assert . True ( t , aggregatedResponse [ idA ] . ErrorCodes [ "MaxMatchingResultsExceeded" ] )
assert . True ( t , aggregatedResponse [ idB ] . ErrorCodes [ "MaxMatchingResultsExceeded" ] )
} )
} )
} )
2023-04-27 04:19:45 -05:00
}
2022-12-02 03:21:46 -06:00
2024-04-05 10:57:56 -05:00
func Test_buildDataFrames_parse_label_to_name_and_labels ( t * testing . T ) {
2023-04-27 04:19:45 -05:00
startTime := time . Now ( )
endTime := startTime . Add ( 2 * time . Hour )
2024-04-05 10:57:56 -05:00
t . Run ( "using multi filter" , func ( t * testing . T ) {
2020-10-02 12:40:15 -05:00
timestamp := time . Unix ( 0 , 0 )
2022-12-02 03:21:46 -06:00
response := & models . QueryRowResponse {
2022-05-18 02:16:38 -05:00
Metrics : [ ] * cloudwatch . MetricDataResult {
{
2021-09-08 09:06:43 -05:00
Id : aws . String ( "id1" ) ,
2024-04-05 10:57:56 -05:00
Label : aws . String ( "lb1|&|lb1" ) ,
2021-09-08 09:06:43 -05:00
Timestamps : [ ] * time . Time {
aws . Time ( timestamp ) ,
2022-11-22 01:09:15 -06:00
aws . Time ( timestamp . Add ( time . Minute ) ) ,
aws . Time ( timestamp . Add ( 3 * time . Minute ) ) ,
2021-09-08 09:06:43 -05:00
} ,
Values : [ ] * float64 {
aws . Float64 ( 10 ) ,
aws . Float64 ( 20 ) ,
aws . Float64 ( 30 ) ,
} ,
StatusCode : aws . String ( "Complete" ) ,
2020-01-17 05:47:40 -06:00
} ,
2022-05-18 02:16:38 -05:00
{
2021-09-08 09:06:43 -05:00
Id : aws . String ( "id2" ) ,
2024-04-05 10:57:56 -05:00
Label : aws . String ( "lb2|&|lb2" ) ,
2021-09-08 09:06:43 -05:00
Timestamps : [ ] * time . Time {
aws . Time ( timestamp ) ,
2022-11-22 01:09:15 -06:00
aws . Time ( timestamp . Add ( time . Minute ) ) ,
aws . Time ( timestamp . Add ( 3 * time . Minute ) ) ,
2021-09-08 09:06:43 -05:00
} ,
Values : [ ] * float64 {
aws . Float64 ( 10 ) ,
aws . Float64 ( 20 ) ,
aws . Float64 ( 30 ) ,
} ,
StatusCode : aws . String ( "Complete" ) ,
2020-01-17 05:47:40 -06:00
} ,
2020-10-02 12:40:15 -05:00
} ,
}
2020-09-08 06:35:17 -05:00
2022-10-20 04:21:13 -05:00
query := & models . CloudWatchQuery {
2020-10-02 12:40:15 -05:00
RefId : "refId1" ,
Region : "us-east-1" ,
Namespace : "AWS/ApplicationELB" ,
MetricName : "TargetResponseTime" ,
Dimensions : map [ string ] [ ] string {
"LoadBalancer" : { "lb1" , "lb2" } ,
"TargetGroup" : { "tg" } ,
} ,
2021-11-30 03:53:31 -06:00
Statistic : "Average" ,
Period : 60 ,
2022-10-20 04:21:13 -05:00
MetricQueryType : models . MetricQueryTypeSearch ,
MetricEditorMode : models . MetricEditorModeBuilder ,
2024-04-05 10:57:56 -05:00
MatchExact : true ,
2020-10-02 12:40:15 -05:00
}
2024-04-05 10:57:56 -05:00
frames , err := buildDataFrames ( contextWithFeaturesEnabled ( features . FlagCloudWatchNewLabelParsing ) , startTime , endTime , * response , query )
2020-10-02 12:40:15 -05:00
require . NoError ( t , err )
2019-11-14 03:59:41 -06:00
2020-10-06 06:45:58 -05:00
frame1 := frames [ 0 ]
2023-04-27 04:19:45 -05:00
assert . Equal ( t , "lb1" , frame1 . Name )
2020-10-06 06:45:58 -05:00
assert . Equal ( t , "lb1" , frame1 . Fields [ 1 ] . Labels [ "LoadBalancer" ] )
2024-04-05 10:57:56 -05:00
assert . Equal ( t , "tg" , frame1 . Fields [ 1 ] . Labels [ "TargetGroup" ] )
2020-03-10 15:14:58 -05:00
2020-10-06 06:45:58 -05:00
frame2 := frames [ 1 ]
2023-04-27 04:19:45 -05:00
assert . Equal ( t , "lb2" , frame2 . Name )
2020-10-06 06:45:58 -05:00
assert . Equal ( t , "lb2" , frame2 . Fields [ 1 ] . Labels [ "LoadBalancer" ] )
2024-04-05 10:57:56 -05:00
assert . Equal ( t , "tg" , frame2 . Fields [ 1 ] . Labels [ "TargetGroup" ] )
2020-10-02 12:40:15 -05:00
} )
2024-04-05 10:57:56 -05:00
t . Run ( "using multiple wildcard filters" , func ( t * testing . T ) {
2020-10-02 12:40:15 -05:00
timestamp := time . Unix ( 0 , 0 )
2022-12-02 03:21:46 -06:00
response := & models . QueryRowResponse {
2022-05-18 02:16:38 -05:00
Metrics : [ ] * cloudwatch . MetricDataResult {
{
2021-09-08 09:06:43 -05:00
Id : aws . String ( "lb3" ) ,
2024-04-05 10:57:56 -05:00
Label : aws . String ( "some label lb3|&|inst1|&|balancer 1" ) ,
2021-09-08 09:06:43 -05:00
Timestamps : [ ] * time . Time {
aws . Time ( timestamp ) ,
2022-11-22 01:09:15 -06:00
aws . Time ( timestamp . Add ( time . Minute ) ) ,
aws . Time ( timestamp . Add ( 3 * time . Minute ) ) ,
2021-09-08 09:06:43 -05:00
} ,
Values : [ ] * float64 {
aws . Float64 ( 10 ) ,
aws . Float64 ( 20 ) ,
aws . Float64 ( 30 ) ,
} ,
StatusCode : aws . String ( "Complete" ) ,
2020-10-02 12:40:15 -05:00
} ,
2022-05-18 02:16:38 -05:00
{
2021-09-08 09:06:43 -05:00
Id : aws . String ( "lb4" ) ,
2024-04-05 10:57:56 -05:00
Label : aws . String ( "some label lb4|&|inst2|&|balancer 2" ) ,
2021-09-08 09:06:43 -05:00
Timestamps : [ ] * time . Time {
aws . Time ( timestamp ) ,
2022-11-22 01:09:15 -06:00
aws . Time ( timestamp . Add ( time . Minute ) ) ,
aws . Time ( timestamp . Add ( 3 * time . Minute ) ) ,
2021-09-08 09:06:43 -05:00
} ,
Values : [ ] * float64 {
aws . Float64 ( 10 ) ,
aws . Float64 ( 20 ) ,
aws . Float64 ( 30 ) ,
} ,
StatusCode : aws . String ( "Complete" ) ,
2020-10-02 12:40:15 -05:00
} ,
} ,
}
2020-09-08 06:35:17 -05:00
2022-10-20 04:21:13 -05:00
query := & models . CloudWatchQuery {
2020-10-02 12:40:15 -05:00
RefId : "refId1" ,
Region : "us-east-1" ,
Namespace : "AWS/ApplicationELB" ,
MetricName : "TargetResponseTime" ,
Dimensions : map [ string ] [ ] string {
"LoadBalancer" : { "*" } ,
2024-04-05 10:57:56 -05:00
"InstanceType" : { "*" } ,
2020-10-02 12:40:15 -05:00
"TargetGroup" : { "tg" } ,
} ,
2021-11-30 03:53:31 -06:00
Statistic : "Average" ,
Period : 60 ,
2022-10-20 04:21:13 -05:00
MetricQueryType : models . MetricQueryTypeSearch ,
MetricEditorMode : models . MetricEditorModeBuilder ,
2020-10-02 12:40:15 -05:00
}
2024-04-05 10:57:56 -05:00
frames , err := buildDataFrames ( contextWithFeaturesEnabled ( features . FlagCloudWatchNewLabelParsing ) , startTime , endTime , * response , query )
2020-10-02 12:40:15 -05:00
require . NoError ( t , err )
2020-10-06 06:45:58 -05:00
2023-04-27 04:19:45 -05:00
assert . Equal ( t , "some label lb3" , frames [ 0 ] . Name )
2024-04-05 10:57:56 -05:00
assert . Equal ( t , "balancer 1" , frames [ 0 ] . Fields [ 1 ] . Labels [ "LoadBalancer" ] )
assert . Equal ( t , "inst1" , frames [ 0 ] . Fields [ 1 ] . Labels [ "InstanceType" ] )
assert . Equal ( t , "tg" , frames [ 0 ] . Fields [ 1 ] . Labels [ "TargetGroup" ] )
2023-04-27 04:19:45 -05:00
assert . Equal ( t , "some label lb4" , frames [ 1 ] . Name )
2024-04-05 10:57:56 -05:00
assert . Equal ( t , "balancer 2" , frames [ 1 ] . Fields [ 1 ] . Labels [ "LoadBalancer" ] )
assert . Equal ( t , "inst2" , frames [ 1 ] . Fields [ 1 ] . Labels [ "InstanceType" ] )
assert . Equal ( t , "tg" , frames [ 1 ] . Fields [ 1 ] . Labels [ "TargetGroup" ] )
2020-10-02 12:40:15 -05:00
} )
2020-03-10 15:14:58 -05:00
2023-04-27 04:19:45 -05:00
t . Run ( "when no values are returned and a multi-valued template variable is used" , func ( t * testing . T ) {
2020-10-02 12:40:15 -05:00
timestamp := time . Unix ( 0 , 0 )
2024-04-05 10:57:56 -05:00
// When there are no results, CloudWatch sets the label values to --
2022-12-02 03:21:46 -06:00
response := & models . QueryRowResponse {
2022-05-18 02:16:38 -05:00
Metrics : [ ] * cloudwatch . MetricDataResult {
{
2021-09-08 09:06:43 -05:00
Id : aws . String ( "lb3" ) ,
2024-04-05 10:57:56 -05:00
Label : aws . String ( "some label|&|--" ) ,
2021-09-08 09:06:43 -05:00
Timestamps : [ ] * time . Time {
aws . Time ( timestamp ) ,
2022-11-22 01:09:15 -06:00
aws . Time ( timestamp . Add ( time . Minute ) ) ,
aws . Time ( timestamp . Add ( 3 * time . Minute ) ) ,
2021-09-08 09:06:43 -05:00
} ,
Values : [ ] * float64 { } ,
StatusCode : aws . String ( "Complete" ) ,
2020-03-10 15:14:58 -05:00
} ,
2020-10-02 12:40:15 -05:00
} ,
}
2022-10-20 04:21:13 -05:00
query := & models . CloudWatchQuery {
2020-10-02 12:40:15 -05:00
RefId : "refId1" ,
Region : "us-east-1" ,
Namespace : "AWS/ApplicationELB" ,
MetricName : "TargetResponseTime" ,
Dimensions : map [ string ] [ ] string {
"LoadBalancer" : { "lb1" , "lb2" } ,
} ,
2021-11-30 03:53:31 -06:00
Statistic : "Average" ,
Period : 60 ,
2022-10-20 04:21:13 -05:00
MetricQueryType : models . MetricQueryTypeSearch ,
MetricEditorMode : models . MetricEditorModeBuilder ,
2020-10-02 12:40:15 -05:00
}
2024-04-05 10:57:56 -05:00
frames , err := buildDataFrames ( contextWithFeaturesEnabled ( features . FlagCloudWatchNewLabelParsing ) , startTime , endTime , * response , query )
2020-10-02 12:40:15 -05:00
require . NoError ( t , err )
2020-10-06 06:45:58 -05:00
assert . Len ( t , frames , 2 )
2023-04-27 04:19:45 -05:00
assert . Equal ( t , "some label" , frames [ 0 ] . Name )
2024-04-05 10:57:56 -05:00
assert . Equal ( t , "lb1" , frames [ 0 ] . Fields [ 1 ] . Labels [ "LoadBalancer" ] )
2023-04-27 04:19:45 -05:00
assert . Equal ( t , "some label" , frames [ 1 ] . Name )
2024-04-05 10:57:56 -05:00
assert . Equal ( t , "lb2" , frames [ 1 ] . Fields [ 1 ] . Labels [ "LoadBalancer" ] )
2020-10-02 12:40:15 -05:00
} )
2023-04-27 04:19:45 -05:00
t . Run ( "when no values are returned and a multi-valued template variable and two single-valued dimensions are used" , func ( t * testing . T ) {
2020-10-02 12:40:15 -05:00
timestamp := time . Unix ( 0 , 0 )
2024-04-05 10:57:56 -05:00
// When there are no results, CloudWatch sets the label values to --
2022-12-02 03:21:46 -06:00
response := & models . QueryRowResponse {
2022-05-18 02:16:38 -05:00
Metrics : [ ] * cloudwatch . MetricDataResult {
{
2021-09-08 09:06:43 -05:00
Id : aws . String ( "lb3" ) ,
2024-04-05 10:57:56 -05:00
Label : aws . String ( "some label|&|--" ) ,
2021-09-08 09:06:43 -05:00
Timestamps : [ ] * time . Time {
aws . Time ( timestamp ) ,
2022-11-22 01:09:15 -06:00
aws . Time ( timestamp . Add ( time . Minute ) ) ,
aws . Time ( timestamp . Add ( 3 * time . Minute ) ) ,
2021-09-08 09:06:43 -05:00
} ,
Values : [ ] * float64 { } ,
StatusCode : aws . String ( "Complete" ) ,
2020-03-10 15:14:58 -05:00
} ,
2020-10-02 12:40:15 -05:00
} ,
}
2020-09-08 06:35:17 -05:00
2022-10-20 04:21:13 -05:00
query := & models . CloudWatchQuery {
2020-10-02 12:40:15 -05:00
RefId : "refId1" ,
Region : "us-east-1" ,
Namespace : "AWS/ApplicationELB" ,
MetricName : "TargetResponseTime" ,
Dimensions : map [ string ] [ ] string {
"LoadBalancer" : { "lb1" , "lb2" } ,
"InstanceType" : { "micro" } ,
"Resource" : { "res" } ,
} ,
2021-11-30 03:53:31 -06:00
Statistic : "Average" ,
Period : 60 ,
2022-10-20 04:21:13 -05:00
MetricQueryType : models . MetricQueryTypeSearch ,
MetricEditorMode : models . MetricEditorModeBuilder ,
2020-10-02 12:40:15 -05:00
}
2024-04-05 10:57:56 -05:00
frames , err := buildDataFrames ( contextWithFeaturesEnabled ( features . FlagCloudWatchNewLabelParsing ) , startTime , endTime , * response , query )
2020-10-02 12:40:15 -05:00
require . NoError ( t , err )
2020-10-06 06:45:58 -05:00
assert . Len ( t , frames , 2 )
2023-04-27 04:19:45 -05:00
assert . Equal ( t , "some label" , frames [ 0 ] . Name )
2024-04-05 10:57:56 -05:00
assert . Equal ( t , "lb1" , frames [ 0 ] . Fields [ 1 ] . Labels [ "LoadBalancer" ] )
assert . Equal ( t , "micro" , frames [ 0 ] . Fields [ 1 ] . Labels [ "InstanceType" ] )
assert . Equal ( t , "res" , frames [ 0 ] . Fields [ 1 ] . Labels [ "Resource" ] )
2023-04-27 04:19:45 -05:00
assert . Equal ( t , "some label" , frames [ 1 ] . Name )
2024-04-05 10:57:56 -05:00
assert . Equal ( t , "lb2" , frames [ 1 ] . Fields [ 1 ] . Labels [ "LoadBalancer" ] )
assert . Equal ( t , "micro" , frames [ 1 ] . Fields [ 1 ] . Labels [ "InstanceType" ] )
assert . Equal ( t , "res" , frames [ 1 ] . Fields [ 1 ] . Labels [ "Resource" ] )
2020-10-02 12:40:15 -05:00
} )
2020-03-10 15:14:58 -05:00
2024-04-30 11:06:16 -05:00
t . Run ( "when not using multi-value dimension filters on a `MetricSearch` query" , func ( t * testing . T ) {
2021-11-30 03:53:31 -06:00
timestamp := time . Unix ( 0 , 0 )
2022-12-02 03:21:46 -06:00
response := & models . QueryRowResponse {
2022-05-18 02:16:38 -05:00
Metrics : [ ] * cloudwatch . MetricDataResult {
{
2021-11-30 03:53:31 -06:00
Id : aws . String ( "lb3" ) ,
2023-04-27 04:19:45 -05:00
Label : aws . String ( "some label" ) ,
2021-11-30 03:53:31 -06:00
Timestamps : [ ] * time . Time {
aws . Time ( timestamp ) ,
} ,
Values : [ ] * float64 { aws . Float64 ( 23 ) } ,
StatusCode : aws . String ( "Complete" ) ,
} ,
} ,
}
2022-10-20 04:21:13 -05:00
query := & models . CloudWatchQuery {
2021-11-30 03:53:31 -06:00
RefId : "refId1" ,
Region : "us-east-1" ,
Namespace : "AWS/ApplicationELB" ,
MetricName : "TargetResponseTime" ,
Dimensions : map [ string ] [ ] string {
"LoadBalancer" : { "lb1" } ,
"InstanceType" : { "micro" } ,
"Resource" : { "res" } ,
} ,
Statistic : "Average" ,
Period : 60 ,
2024-04-30 11:06:16 -05:00
MetricQueryType : models . MetricQueryTypeSearch ,
2022-10-20 04:21:13 -05:00
MetricEditorMode : models . MetricEditorModeRaw ,
2021-11-30 03:53:31 -06:00
}
2024-04-05 10:57:56 -05:00
frames , err := buildDataFrames ( contextWithFeaturesEnabled ( features . FlagCloudWatchNewLabelParsing ) , startTime , endTime , * response , query )
2021-11-30 03:53:31 -06:00
require . NoError ( t , err )
2023-04-27 04:19:45 -05:00
assert . Equal ( t , "some label" , frames [ 0 ] . Name )
2024-04-05 10:57:56 -05:00
assert . Equal ( t , "lb1" , frames [ 0 ] . Fields [ 1 ] . Labels [ "LoadBalancer" ] )
assert . Equal ( t , "micro" , frames [ 0 ] . Fields [ 1 ] . Labels [ "InstanceType" ] )
assert . Equal ( t , "res" , frames [ 0 ] . Fields [ 1 ] . Labels [ "Resource" ] )
2021-11-30 03:53:31 -06:00
} )
2024-04-30 11:06:16 -05:00
t . Run ( "when non-static label set on a `MetricSearch` query" , func ( t * testing . T ) {
2024-03-18 16:30:59 -05:00
timestamp := time . Unix ( 0 , 0 )
response := & models . QueryRowResponse {
Metrics : [ ] * cloudwatch . MetricDataResult {
{
Id : aws . String ( "lb3" ) ,
2024-04-05 10:57:56 -05:00
Label : aws . String ( "some label|&|res" ) ,
2024-03-18 16:30:59 -05:00
Timestamps : [ ] * time . Time {
aws . Time ( timestamp ) ,
} ,
Values : [ ] * float64 { aws . Float64 ( 23 ) } ,
StatusCode : aws . String ( "Complete" ) ,
} ,
} ,
}
query := & models . CloudWatchQuery {
RefId : "refId1" ,
Region : "us-east-1" ,
Namespace : "AWS/ApplicationELB" ,
MetricName : "TargetResponseTime" ,
Dimensions : map [ string ] [ ] string {
"LoadBalancer" : { "lb1" } ,
"InstanceType" : { "micro" } ,
2024-04-05 10:57:56 -05:00
"Resource" : { "*" } ,
2024-03-18 16:30:59 -05:00
} ,
Statistic : "Average" ,
Period : 60 ,
2024-04-30 11:06:16 -05:00
MetricQueryType : models . MetricQueryTypeSearch ,
2024-03-18 16:30:59 -05:00
MetricEditorMode : models . MetricEditorModeBuilder ,
Label : "set ${AVG} label" ,
}
2024-04-05 10:57:56 -05:00
frames , err := buildDataFrames ( contextWithFeaturesEnabled ( features . FlagCloudWatchNewLabelParsing ) , startTime , endTime , * response , query )
2024-03-18 16:30:59 -05:00
require . NoError ( t , err )
assert . Equal ( t , "some label" , frames [ 0 ] . Name )
2024-04-05 10:57:56 -05:00
assert . Equal ( t , "lb1" , frames [ 0 ] . Fields [ 1 ] . Labels [ "LoadBalancer" ] )
assert . Equal ( t , "micro" , frames [ 0 ] . Fields [ 1 ] . Labels [ "InstanceType" ] )
assert . Equal ( t , "res" , frames [ 0 ] . Fields [ 1 ] . Labels [ "Resource" ] )
2024-03-18 16:30:59 -05:00
} )
2024-04-30 11:06:16 -05:00
t . Run ( "when static label set on a `MetricSearch` query" , func ( t * testing . T ) {
2024-03-18 16:30:59 -05:00
timestamp := time . Unix ( 0 , 0 )
response := & models . QueryRowResponse {
Metrics : [ ] * cloudwatch . MetricDataResult {
{
Id : aws . String ( "lb3" ) ,
2024-04-05 10:57:56 -05:00
Label : aws . String ( "some label|&|res" ) ,
2024-03-18 16:30:59 -05:00
Timestamps : [ ] * time . Time {
aws . Time ( timestamp ) ,
} ,
Values : [ ] * float64 { aws . Float64 ( 23 ) } ,
StatusCode : aws . String ( "Complete" ) ,
} ,
} ,
}
query := & models . CloudWatchQuery {
RefId : "refId1" ,
Region : "us-east-1" ,
Namespace : "AWS/ApplicationELB" ,
MetricName : "TargetResponseTime" ,
Dimensions : map [ string ] [ ] string {
"LoadBalancer" : { "lb1" } ,
"InstanceType" : { "micro" } ,
2024-04-05 10:57:56 -05:00
"Resource" : { "*" } ,
2024-03-18 16:30:59 -05:00
} ,
Statistic : "Average" ,
Period : 60 ,
2024-04-30 11:06:16 -05:00
MetricQueryType : models . MetricQueryTypeSearch ,
2024-03-18 16:30:59 -05:00
MetricEditorMode : models . MetricEditorModeBuilder ,
Label : "actual" ,
}
2024-04-05 10:57:56 -05:00
frames , err := buildDataFrames ( contextWithFeaturesEnabled ( features . FlagCloudWatchNewLabelParsing ) , startTime , endTime , * response , query )
2024-03-18 16:30:59 -05:00
require . NoError ( t , err )
assert . Equal ( t , "actual" , frames [ 0 ] . Name )
2024-04-05 10:57:56 -05:00
assert . Equal ( t , "lb1" , frames [ 0 ] . Fields [ 1 ] . Labels [ "LoadBalancer" ] )
assert . Equal ( t , "micro" , frames [ 0 ] . Fields [ 1 ] . Labels [ "InstanceType" ] )
assert . Equal ( t , "res" , frames [ 0 ] . Fields [ 1 ] . Labels [ "Resource" ] )
2024-03-18 16:30:59 -05:00
} )
2024-04-30 11:06:16 -05:00
t . Run ( "when `MetricQuery` query has no label set and `GROUP BY` clause has multiple fields" , func ( t * testing . T ) {
timestamp := time . Unix ( 0 , 0 )
response := & models . QueryRowResponse {
Metrics : [ ] * cloudwatch . MetricDataResult {
{
Id : aws . String ( "query1" ) ,
Label : aws . String ( "EC2 vCPU" ) ,
Timestamps : [ ] * time . Time {
aws . Time ( timestamp ) ,
} ,
Values : [ ] * float64 { aws . Float64 ( 23 ) } ,
StatusCode : aws . String ( "Complete" ) ,
} ,
{
Id : aws . String ( "query2" ) ,
Label : aws . String ( "Elastic Loading Balancing ApplicationLoadBalancersPerRegion" ) ,
Timestamps : [ ] * time . Time {
aws . Time ( timestamp ) ,
} ,
Values : [ ] * float64 { aws . Float64 ( 23 ) } ,
StatusCode : aws . String ( "Complete" ) ,
} ,
} ,
}
query := & models . CloudWatchQuery {
RefId : "refId1" ,
Region : "us-east-1" ,
Statistic : "Average" ,
Period : 60 ,
MetricQueryType : models . MetricQueryTypeQuery ,
MetricEditorMode : models . MetricEditorModeBuilder ,
Dimensions : map [ string ] [ ] string { "Service" : { "EC2" , "Elastic Loading Balancing" } , "Resource" : { "vCPU" , "ApplicationLoadBalancersPerRegion" } } ,
SqlExpression : "SELECT AVG(ResourceCount) FROM SCHEMA(\"AWS/Usage\", Class, Resource, Service, Type) GROUP BY Service, Resource" ,
}
frames , err := buildDataFrames ( contextWithFeaturesEnabled ( features . FlagCloudWatchNewLabelParsing ) , startTime , endTime , * response , query )
require . NoError ( t , err )
assert . Equal ( t , "EC2 vCPU" , frames [ 0 ] . Name )
assert . Equal ( t , "EC2" , frames [ 0 ] . Fields [ 1 ] . Labels [ "Service" ] )
assert . Equal ( t , "vCPU" , frames [ 0 ] . Fields [ 1 ] . Labels [ "Resource" ] )
assert . Equal ( t , "Elastic Loading Balancing ApplicationLoadBalancersPerRegion" , frames [ 1 ] . Name )
assert . Equal ( t , "Elastic Loading Balancing" , frames [ 1 ] . Fields [ 1 ] . Labels [ "Service" ] )
assert . Equal ( t , "ApplicationLoadBalancersPerRegion" , frames [ 1 ] . Fields [ 1 ] . Labels [ "Resource" ] )
} )
t . Run ( "when `MetricQuery` query has no `GROUP BY` clause" , func ( t * testing . T ) {
timestamp := time . Unix ( 0 , 0 )
response := & models . QueryRowResponse {
Metrics : [ ] * cloudwatch . MetricDataResult {
{
Id : aws . String ( "query1" ) ,
Label : aws . String ( "cloudwatch-default-label" ) ,
Timestamps : [ ] * time . Time {
aws . Time ( timestamp ) ,
} ,
Values : [ ] * float64 { aws . Float64 ( 23 ) } ,
StatusCode : aws . String ( "Complete" ) ,
} ,
} ,
}
query := & models . CloudWatchQuery {
RefId : "refId1" ,
Region : "us-east-1" ,
Statistic : "Average" ,
Period : 60 ,
MetricQueryType : models . MetricQueryTypeQuery ,
MetricEditorMode : models . MetricEditorModeBuilder ,
SqlExpression : "SELECT AVG(ResourceCount) FROM SCHEMA(\"AWS/Usage\", Class, Resource, Service, Type)" ,
}
frames , err := buildDataFrames ( contextWithFeaturesEnabled ( features . FlagCloudWatchNewLabelParsing ) , startTime , endTime , * response , query )
require . NoError ( t , err )
assert . Equal ( t , "cloudwatch-default-label" , frames [ 0 ] . Name )
assert . Equal ( t , "cloudwatch-default-label" , frames [ 0 ] . Fields [ 1 ] . Labels [ "Series" ] )
} )
2020-10-02 12:40:15 -05:00
t . Run ( "Parse cloudwatch response" , func ( t * testing . T ) {
timestamp := time . Unix ( 0 , 0 )
2022-12-02 03:21:46 -06:00
response := & models . QueryRowResponse {
2022-05-18 02:16:38 -05:00
Metrics : [ ] * cloudwatch . MetricDataResult {
{
2021-09-08 09:06:43 -05:00
Id : aws . String ( "id1" ) ,
2023-04-27 04:19:45 -05:00
Label : aws . String ( "some label" ) ,
2021-09-08 09:06:43 -05:00
Timestamps : [ ] * time . Time {
aws . Time ( timestamp ) ,
2022-11-22 01:09:15 -06:00
aws . Time ( timestamp . Add ( time . Minute ) ) ,
aws . Time ( timestamp . Add ( 3 * time . Minute ) ) ,
2021-09-08 09:06:43 -05:00
} ,
Values : [ ] * float64 {
aws . Float64 ( 10 ) ,
aws . Float64 ( 20 ) ,
aws . Float64 ( 30 ) ,
} ,
StatusCode : aws . String ( "Complete" ) ,
2019-11-14 03:59:41 -06:00
} ,
2020-10-02 12:40:15 -05:00
} ,
}
2020-09-08 06:35:17 -05:00
2022-10-20 04:21:13 -05:00
query := & models . CloudWatchQuery {
2020-10-02 12:40:15 -05:00
RefId : "refId1" ,
Region : "us-east-1" ,
Namespace : "AWS/ApplicationELB" ,
MetricName : "TargetResponseTime" ,
Dimensions : map [ string ] [ ] string {
"LoadBalancer" : { "lb" } ,
"TargetGroup" : { "tg" } ,
} ,
2021-11-30 03:53:31 -06:00
Statistic : "Average" ,
Period : 60 ,
2022-10-20 04:21:13 -05:00
MetricQueryType : models . MetricQueryTypeSearch ,
MetricEditorMode : models . MetricEditorModeBuilder ,
2020-10-02 12:40:15 -05:00
}
2024-04-05 10:57:56 -05:00
frames , err := buildDataFrames ( contextWithFeaturesEnabled ( features . FlagCloudWatchNewLabelParsing ) , startTime , endTime , * response , query )
2020-10-02 12:40:15 -05:00
require . NoError ( t , err )
2020-10-06 06:45:58 -05:00
frame := frames [ 0 ]
2023-04-27 04:19:45 -05:00
assert . Equal ( t , "some label" , frame . Name )
2020-11-03 04:24:26 -06:00
assert . Equal ( t , "Time" , frame . Fields [ 0 ] . Name )
2020-10-06 06:45:58 -05:00
assert . Equal ( t , "lb" , frame . Fields [ 1 ] . Labels [ "LoadBalancer" ] )
assert . Equal ( t , 10.0 , * frame . Fields [ 1 ] . At ( 0 ) . ( * float64 ) )
assert . Equal ( t , 20.0 , * frame . Fields [ 1 ] . At ( 1 ) . ( * float64 ) )
2022-02-10 03:17:45 -06:00
assert . Equal ( t , 30.0 , * frame . Fields [ 1 ] . At ( 2 ) . ( * float64 ) )
2020-11-03 04:24:26 -06:00
assert . Equal ( t , "Value" , frame . Fields [ 1 ] . Name )
assert . Equal ( t , "" , frame . Fields [ 1 ] . Config . DisplayName )
2019-11-14 03:59:41 -06:00
} )
}