2020-04-26 04:48:20 +08:00
package cloudwatch
import (
"context"
2021-03-23 23:32:12 +08:00
"encoding/json"
2020-04-26 04:48:20 +08:00
"testing"
"time"
"github.com/aws/aws-sdk-go/aws"
2020-07-24 00:52:22 +08:00
"github.com/aws/aws-sdk-go/aws/session"
2020-04-26 04:48:20 +08:00
"github.com/aws/aws-sdk-go/service/cloudwatchlogs"
2020-07-24 00:52:22 +08:00
"github.com/aws/aws-sdk-go/service/cloudwatchlogs/cloudwatchlogsiface"
2021-03-23 23:32:12 +08:00
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana-plugin-sdk-go/backend/datasource"
"github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt"
2020-04-26 04:48:20 +08:00
"github.com/grafana/grafana-plugin-sdk-go/data"
2022-04-29 23:47:46 +08:00
"github.com/grafana/grafana/pkg/services/featuremgmt"
2023-04-14 22:21:16 +08:00
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/mocks"
2022-10-25 15:52:12 +08:00
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models"
2023-04-14 22:21:16 +08:00
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/utils"
"github.com/stretchr/testify/mock"
2020-04-26 04:48:20 +08:00
"github.com/stretchr/testify/assert"
2020-05-18 18:25:58 +08:00
"github.com/stretchr/testify/require"
2020-04-26 04:48:20 +08:00
)
2023-04-14 22:21:16 +08:00
func TestQuery_handleGetLogEvents_passes_nil_start_and_end_times_to_GetLogEvents ( t * testing . T ) {
2022-07-20 01:59:30 +08:00
origNewCWLogsClient := NewCWLogsClient
t . Cleanup ( func ( ) {
NewCWLogsClient = origNewCWLogsClient
} )
var cli fakeCWLogsClient
NewCWLogsClient = func ( sess * session . Session ) cloudwatchlogsiface . CloudWatchLogsAPI {
return & cli
}
const refID = "A"
testCases := map [ string ] struct {
query string
expectedInput [ ] * cloudwatchlogs . GetLogEventsInput
} {
"Nil startTime" : {
query : ` {
"type" : "logAction" ,
"subtype" : "GetLogEvents" ,
"logGroupName" : "foo" ,
"logStreamName" : "bar" ,
"endTime" : 1 ,
"startFromHead" : false
} ` ,
expectedInput : [ ] * cloudwatchlogs . GetLogEventsInput {
{
EndTime : aws . Int64 ( 1 ) ,
Limit : aws . Int64 ( 10 ) ,
LogGroupName : aws . String ( "foo" ) ,
LogStreamName : aws . String ( "bar" ) ,
StartFromHead : aws . Bool ( false ) ,
} ,
} ,
} ,
"Nil endTime" : {
query : ` {
"type" : "logAction" ,
"subtype" : "GetLogEvents" ,
"logGroupName" : "foo" ,
"logStreamName" : "bar" ,
"startTime" : 1 ,
"startFromHead" : true
} ` ,
expectedInput : [ ] * cloudwatchlogs . GetLogEventsInput {
{
StartTime : aws . Int64 ( 1 ) ,
Limit : aws . Int64 ( 10 ) ,
LogGroupName : aws . String ( "foo" ) ,
LogStreamName : aws . String ( "bar" ) ,
StartFromHead : aws . Bool ( true ) ,
} ,
} ,
} ,
}
for name , test := range testCases {
t . Run ( name , func ( t * testing . T ) {
cli = fakeCWLogsClient { }
im := datasource . NewInstanceManager ( func ( s backend . DataSourceInstanceSettings ) ( instancemgmt . Instance , error ) {
2022-11-22 22:59:11 +08:00
return DataSource { Settings : models . CloudWatchSettings { } } , nil
2022-07-20 01:59:30 +08:00
} )
executor := newExecutor ( im , newTestConfig ( ) , & fakeSessionCache { } , featuremgmt . WithFeatures ( ) )
_ , err := executor . QueryData ( context . Background ( ) , & backend . QueryDataRequest {
PluginContext : backend . PluginContext {
DataSourceInstanceSettings : & backend . DataSourceInstanceSettings { } ,
} ,
Queries : [ ] backend . DataQuery {
{
RefID : refID ,
TimeRange : backend . TimeRange { From : time . Unix ( 0 , 0 ) , To : time . Unix ( 1 , 0 ) } ,
JSON : json . RawMessage ( test . query ) ,
} ,
} ,
} )
require . NoError ( t , err )
require . Len ( t , cli . calls . getEventsWithContext , 1 )
assert . Equal ( t , test . expectedInput , cli . calls . getEventsWithContext )
} )
}
}
2023-04-14 22:21:16 +08:00
func TestQuery_GetLogEvents_returns_response_from_GetLogEvents_to_data_frame_field ( t * testing . T ) {
origNewCWLogsClient := NewCWLogsClient
t . Cleanup ( func ( ) {
NewCWLogsClient = origNewCWLogsClient
} )
var cli * mocks . MockLogEvents
NewCWLogsClient = func ( sess * session . Session ) cloudwatchlogsiface . CloudWatchLogsAPI {
return cli
}
im := datasource . NewInstanceManager ( func ( s backend . DataSourceInstanceSettings ) ( instancemgmt . Instance , error ) {
return DataSource { Settings : models . CloudWatchSettings { } } , nil
} )
executor := newExecutor ( im , newTestConfig ( ) , & fakeSessionCache { } , featuremgmt . WithFeatures ( ) )
cli = & mocks . MockLogEvents { }
cli . On ( "GetLogEventsWithContext" , mock . Anything , mock . Anything , mock . Anything ) . Return ( & cloudwatchlogs . GetLogEventsOutput {
Events : [ ] * cloudwatchlogs . OutputLogEvent { {
Message : utils . Pointer ( "some message" ) ,
Timestamp : utils . Pointer ( int64 ( 15 ) ) ,
} } } , nil )
resp , err := executor . QueryData ( context . Background ( ) , & backend . QueryDataRequest {
PluginContext : backend . PluginContext {
DataSourceInstanceSettings : & backend . DataSourceInstanceSettings { } ,
} ,
Queries : [ ] backend . DataQuery {
{
RefID : "A" ,
TimeRange : backend . TimeRange { From : time . Unix ( 0 , 0 ) , To : time . Unix ( 1 , 0 ) } ,
JSON : json . RawMessage ( ` {
"type" : "logAction" ,
"subtype" : "GetLogEvents" ,
"logGroupName" : "foo" ,
"logStreamName" : "bar" ,
"endTime" : 1 ,
"startFromHead" : false
} ` ) ,
} ,
} ,
} )
require . NoError ( t , err )
respA , ok := resp . Responses [ "A" ]
assert . True ( t , ok )
expectedTsField := data . NewField ( "ts" , nil , [ ] time . Time { time . UnixMilli ( 15 ) . UTC ( ) } )
expectedMessageField := data . NewField ( "line" , nil , [ ] * string { utils . Pointer ( "some message" ) } )
expectedTsField . SetConfig ( & data . FieldConfig { DisplayName : "Time" } )
assert . Equal ( t , [ ] * data . Field { expectedTsField , expectedMessageField } , respA . Frames [ 0 ] . Fields )
}
2020-07-24 00:52:22 +08:00
func TestQuery_StartQuery ( t * testing . T ) {
2021-01-07 18:36:13 +08:00
origNewCWLogsClient := NewCWLogsClient
2020-07-24 00:52:22 +08:00
t . Cleanup ( func ( ) {
2021-01-07 18:36:13 +08:00
NewCWLogsClient = origNewCWLogsClient
2020-04-26 04:48:20 +08:00
} )
2022-03-03 16:42:51 +08:00
var cli fakeCWLogsClient
2020-04-26 04:48:20 +08:00
2021-01-07 18:36:13 +08:00
NewCWLogsClient = func ( sess * session . Session ) cloudwatchlogsiface . CloudWatchLogsAPI {
2022-02-25 21:14:59 +08:00
return & cli
2020-04-26 04:48:20 +08:00
}
2020-07-24 00:52:22 +08:00
t . Run ( "invalid time range" , func ( t * testing . T ) {
2022-03-03 16:42:51 +08:00
cli = fakeCWLogsClient {
2020-07-24 00:52:22 +08:00
logGroupFields : cloudwatchlogs . GetLogGroupFieldsOutput {
LogGroupFields : [ ] * cloudwatchlogs . LogGroupField {
{
Name : aws . String ( "field_a" ) ,
Percent : aws . Int64 ( 100 ) ,
} ,
{
Name : aws . String ( "field_b" ) ,
Percent : aws . Int64 ( 30 ) ,
} ,
{
Name : aws . String ( "field_c" ) ,
Percent : aws . Int64 ( 55 ) ,
} ,
} ,
} ,
}
2021-03-23 23:32:12 +08:00
timeRange := backend . TimeRange {
From : time . Unix ( 1584873443 , 0 ) ,
To : time . Unix ( 1584700643 , 0 ) ,
2020-07-24 00:52:22 +08:00
}
2021-03-23 23:32:12 +08:00
im := datasource . NewInstanceManager ( func ( s backend . DataSourceInstanceSettings ) ( instancemgmt . Instance , error ) {
2022-11-22 22:59:11 +08:00
return DataSource { Settings : models . CloudWatchSettings { } } , nil
2021-03-23 23:32:12 +08:00
} )
2022-04-29 23:47:46 +08:00
executor := newExecutor ( im , newTestConfig ( ) , & fakeSessionCache { } , featuremgmt . WithFeatures ( ) )
2021-03-23 23:32:12 +08:00
_ , err := executor . QueryData ( context . Background ( ) , & backend . QueryDataRequest {
PluginContext : backend . PluginContext {
DataSourceInstanceSettings : & backend . DataSourceInstanceSettings { } ,
} ,
Queries : [ ] backend . DataQuery {
2020-07-24 00:52:22 +08:00
{
2021-03-23 23:32:12 +08:00
TimeRange : timeRange ,
JSON : json . RawMessage ( ` {
2020-07-24 00:52:22 +08:00
"type" : "logAction" ,
"subtype" : "StartQuery" ,
"limit" : 50 ,
"region" : "default" ,
2021-03-23 23:32:12 +08:00
"queryString" : "fields @message"
} ` ) ,
2020-07-24 00:52:22 +08:00
} ,
} ,
} )
require . Error ( t , err )
2020-04-26 04:48:20 +08:00
2021-11-18 04:46:13 +08:00
assert . Contains ( t , err . Error ( ) , "invalid time range: start time must be before end time" )
2020-04-26 04:48:20 +08:00
} )
2020-07-24 00:52:22 +08:00
t . Run ( "valid time range" , func ( t * testing . T ) {
const refID = "A"
2022-03-03 16:42:51 +08:00
cli = fakeCWLogsClient {
2020-07-24 00:52:22 +08:00
logGroupFields : cloudwatchlogs . GetLogGroupFieldsOutput {
LogGroupFields : [ ] * cloudwatchlogs . LogGroupField {
{
Name : aws . String ( "field_a" ) ,
Percent : aws . Int64 ( 100 ) ,
} ,
{
Name : aws . String ( "field_b" ) ,
Percent : aws . Int64 ( 30 ) ,
} ,
{
Name : aws . String ( "field_c" ) ,
Percent : aws . Int64 ( 55 ) ,
} ,
} ,
} ,
}
2021-03-23 23:32:12 +08:00
timeRange := backend . TimeRange {
From : time . Unix ( 1584700643000 , 0 ) ,
To : time . Unix ( 1584873443000 , 0 ) ,
2020-07-24 00:52:22 +08:00
}
2021-03-23 23:32:12 +08:00
im := datasource . NewInstanceManager ( func ( s backend . DataSourceInstanceSettings ) ( instancemgmt . Instance , error ) {
2022-11-22 22:59:11 +08:00
return DataSource { Settings : models . CloudWatchSettings { } } , nil
2021-03-23 23:32:12 +08:00
} )
2022-04-29 23:47:46 +08:00
executor := newExecutor ( im , newTestConfig ( ) , & fakeSessionCache { } , featuremgmt . WithFeatures ( ) )
2021-03-23 23:32:12 +08:00
resp , err := executor . QueryData ( context . Background ( ) , & backend . QueryDataRequest {
PluginContext : backend . PluginContext {
DataSourceInstanceSettings : & backend . DataSourceInstanceSettings { } ,
} ,
Queries : [ ] backend . DataQuery {
2020-07-24 00:52:22 +08:00
{
2021-03-23 23:32:12 +08:00
RefID : refID ,
TimeRange : timeRange ,
JSON : json . RawMessage ( ` {
2020-07-24 00:52:22 +08:00
"type" : "logAction" ,
"subtype" : "StartQuery" ,
"limit" : 50 ,
"region" : "default" ,
2021-03-23 23:32:12 +08:00
"queryString" : "fields @message"
} ` ) ,
2020-07-24 00:52:22 +08:00
} ,
} ,
} )
require . NoError ( t , err )
expFrame := data . NewFrame (
refID ,
data . NewField ( "queryId" , nil , [ ] string { "abcd-efgh-ijkl-mnop" } ) ,
)
expFrame . RefID = refID
expFrame . Meta = & data . FrameMeta {
Custom : map [ string ] interface { } {
"Region" : "default" ,
} ,
}
2021-03-23 23:32:12 +08:00
assert . Equal ( t , & backend . QueryDataResponse { Responses : backend . Responses {
refID : {
Frames : data . Frames { expFrame } ,
2020-07-24 00:52:22 +08:00
} ,
2021-03-23 23:32:12 +08:00
} ,
2020-07-24 00:52:22 +08:00
} , resp )
} )
}
2020-04-26 04:48:20 +08:00
2022-02-25 21:14:59 +08:00
func Test_executeStartQuery ( t * testing . T ) {
origNewCWLogsClient := NewCWLogsClient
t . Cleanup ( func ( ) {
NewCWLogsClient = origNewCWLogsClient
} )
2022-03-03 16:42:51 +08:00
var cli fakeCWLogsClient
2022-02-25 21:14:59 +08:00
NewCWLogsClient = func ( sess * session . Session ) cloudwatchlogsiface . CloudWatchLogsAPI {
return & cli
}
t . Run ( "successfully parses information from JSON to StartQueryWithContext" , func ( t * testing . T ) {
2022-03-03 16:42:51 +08:00
cli = fakeCWLogsClient { }
2022-02-25 21:14:59 +08:00
im := datasource . NewInstanceManager ( func ( s backend . DataSourceInstanceSettings ) ( instancemgmt . Instance , error ) {
2022-11-22 22:59:11 +08:00
return DataSource { Settings : models . CloudWatchSettings { } } , nil
2022-02-25 21:14:59 +08:00
} )
2022-04-29 23:47:46 +08:00
executor := newExecutor ( im , newTestConfig ( ) , & fakeSessionCache { } , featuremgmt . WithFeatures ( ) )
2022-02-25 21:14:59 +08:00
_ , err := executor . QueryData ( context . Background ( ) , & backend . QueryDataRequest {
PluginContext : backend . PluginContext { DataSourceInstanceSettings : & backend . DataSourceInstanceSettings { } } ,
Queries : [ ] backend . DataQuery {
{
RefID : "A" ,
TimeRange : backend . TimeRange { From : time . Unix ( 0 , 0 ) , To : time . Unix ( 1 , 0 ) } ,
JSON : json . RawMessage ( ` {
"type" : "logAction" ,
"subtype" : "StartQuery" ,
"limit" : 12 ,
"queryString" : "fields @message" ,
"logGroupNames" : [ "some name" , "another name" ]
} ` ) ,
} ,
} ,
} )
assert . NoError ( t , err )
assert . Equal ( t , [ ] * cloudwatchlogs . StartQueryInput {
{
2022-03-03 16:42:51 +08:00
StartTime : aws . Int64 ( 0 ) ,
EndTime : aws . Int64 ( 1 ) ,
Limit : aws . Int64 ( 12 ) ,
QueryString : aws . String ( "fields @timestamp,ltrim(@log) as __log__grafana_internal__,ltrim(@logStream) as __logstream__grafana_internal__|fields @message" ) ,
LogGroupNames : [ ] * string { aws . String ( "some name" ) , aws . String ( "another name" ) } ,
2022-02-25 21:14:59 +08:00
} ,
} , cli . calls . startQueryWithContext )
} )
t . Run ( "does not populate StartQueryInput.limit when no limit provided" , func ( t * testing . T ) {
2022-03-03 16:42:51 +08:00
cli = fakeCWLogsClient { }
2022-02-25 21:14:59 +08:00
im := datasource . NewInstanceManager ( func ( s backend . DataSourceInstanceSettings ) ( instancemgmt . Instance , error ) {
2022-11-22 22:59:11 +08:00
return DataSource { Settings : models . CloudWatchSettings { } } , nil
2022-02-25 21:14:59 +08:00
} )
2022-04-29 23:47:46 +08:00
executor := newExecutor ( im , newTestConfig ( ) , & fakeSessionCache { } , featuremgmt . WithFeatures ( ) )
2022-02-25 21:14:59 +08:00
_ , err := executor . QueryData ( context . Background ( ) , & backend . QueryDataRequest {
PluginContext : backend . PluginContext { DataSourceInstanceSettings : & backend . DataSourceInstanceSettings { } } ,
Queries : [ ] backend . DataQuery {
{
RefID : "A" ,
TimeRange : backend . TimeRange { From : time . Unix ( 0 , 0 ) , To : time . Unix ( 1 , 0 ) } ,
JSON : json . RawMessage ( ` {
"type" : "logAction" ,
"subtype" : "StartQuery"
} ` ) ,
} ,
} ,
} )
assert . NoError ( t , err )
require . Len ( t , cli . calls . startQueryWithContext , 1 )
assert . Nil ( t , cli . calls . startQueryWithContext [ 0 ] . Limit )
} )
2022-11-28 19:39:12 +08:00
t . Run ( "attaches logGroupIdentifiers if the crossAccount feature is enabled" , func ( t * testing . T ) {
cli = fakeCWLogsClient { }
im := datasource . NewInstanceManager ( func ( s backend . DataSourceInstanceSettings ) ( instancemgmt . Instance , error ) {
return DataSource { Settings : models . CloudWatchSettings { } } , nil
} )
executor := newExecutor ( im , newTestConfig ( ) , & fakeSessionCache { } , featuremgmt . WithFeatures ( featuremgmt . FlagCloudWatchCrossAccountQuerying ) )
_ , err := executor . QueryData ( context . Background ( ) , & backend . QueryDataRequest {
PluginContext : backend . PluginContext { DataSourceInstanceSettings : & backend . DataSourceInstanceSettings { } } ,
Queries : [ ] backend . DataQuery {
{
RefID : "A" ,
TimeRange : backend . TimeRange { From : time . Unix ( 0 , 0 ) , To : time . Unix ( 1 , 0 ) } ,
JSON : json . RawMessage ( ` {
"type" : "logAction" ,
"subtype" : "StartQuery" ,
"limit" : 12 ,
"queryString" : "fields @message" ,
2023-01-04 17:07:03 +08:00
"logGroups" : [ { "arn" : "fakeARN" } ]
2022-11-28 19:39:12 +08:00
} ` ) ,
} ,
} ,
} )
assert . NoError ( t , err )
assert . Equal ( t , [ ] * cloudwatchlogs . StartQueryInput {
{
StartTime : aws . Int64 ( 0 ) ,
EndTime : aws . Int64 ( 1 ) ,
Limit : aws . Int64 ( 12 ) ,
QueryString : aws . String ( "fields @timestamp,ltrim(@log) as __log__grafana_internal__,ltrim(@logStream) as __logstream__grafana_internal__|fields @message" ) ,
LogGroupIdentifiers : [ ] * string { aws . String ( "fakeARN" ) } ,
} ,
} , cli . calls . startQueryWithContext )
} )
t . Run ( "attaches logGroupIdentifiers if the crossAccount feature is enabled and strips out trailing *" , func ( t * testing . T ) {
cli = fakeCWLogsClient { }
im := datasource . NewInstanceManager ( func ( s backend . DataSourceInstanceSettings ) ( instancemgmt . Instance , error ) {
return DataSource { Settings : models . CloudWatchSettings { } } , nil
} )
executor := newExecutor ( im , newTestConfig ( ) , & fakeSessionCache { } , featuremgmt . WithFeatures ( featuremgmt . FlagCloudWatchCrossAccountQuerying ) )
_ , err := executor . QueryData ( context . Background ( ) , & backend . QueryDataRequest {
PluginContext : backend . PluginContext { DataSourceInstanceSettings : & backend . DataSourceInstanceSettings { } } ,
Queries : [ ] backend . DataQuery {
{
RefID : "A" ,
TimeRange : backend . TimeRange { From : time . Unix ( 0 , 0 ) , To : time . Unix ( 1 , 0 ) } ,
JSON : json . RawMessage ( ` {
"type" : "logAction" ,
"subtype" : "StartQuery" ,
"limit" : 12 ,
"queryString" : "fields @message" ,
2023-01-04 17:07:03 +08:00
"logGroups" : [ { "arn" : "*fake**ARN*" } ]
2022-11-28 19:39:12 +08:00
} ` ) ,
} ,
} ,
} )
assert . NoError ( t , err )
assert . Equal ( t , [ ] * cloudwatchlogs . StartQueryInput {
{
StartTime : aws . Int64 ( 0 ) ,
EndTime : aws . Int64 ( 1 ) ,
Limit : aws . Int64 ( 12 ) ,
QueryString : aws . String ( "fields @timestamp,ltrim(@log) as __log__grafana_internal__,ltrim(@logStream) as __logstream__grafana_internal__|fields @message" ) ,
LogGroupIdentifiers : [ ] * string { aws . String ( "*fake**ARN" ) } ,
} ,
} , cli . calls . startQueryWithContext )
} )
2022-02-25 21:14:59 +08:00
}
2020-07-24 00:52:22 +08:00
func TestQuery_StopQuery ( t * testing . T ) {
2021-01-07 18:36:13 +08:00
origNewCWLogsClient := NewCWLogsClient
2020-07-24 00:52:22 +08:00
t . Cleanup ( func ( ) {
2021-01-07 18:36:13 +08:00
NewCWLogsClient = origNewCWLogsClient
2020-07-24 00:52:22 +08:00
} )
2020-04-26 04:48:20 +08:00
2022-03-03 16:42:51 +08:00
var cli fakeCWLogsClient
2020-04-26 04:48:20 +08:00
2021-01-07 18:36:13 +08:00
NewCWLogsClient = func ( sess * session . Session ) cloudwatchlogsiface . CloudWatchLogsAPI {
2022-02-25 21:14:59 +08:00
return & cli
2020-07-24 00:52:22 +08:00
}
2020-04-26 04:48:20 +08:00
2022-03-03 16:42:51 +08:00
cli = fakeCWLogsClient {
2020-07-24 00:52:22 +08:00
logGroupFields : cloudwatchlogs . GetLogGroupFieldsOutput {
LogGroupFields : [ ] * cloudwatchlogs . LogGroupField {
{
Name : aws . String ( "field_a" ) ,
Percent : aws . Int64 ( 100 ) ,
} ,
{
Name : aws . String ( "field_b" ) ,
Percent : aws . Int64 ( 30 ) ,
} ,
{
Name : aws . String ( "field_c" ) ,
Percent : aws . Int64 ( 55 ) ,
} ,
} ,
2020-04-26 04:48:20 +08:00
} ,
}
2021-03-23 23:32:12 +08:00
im := datasource . NewInstanceManager ( func ( s backend . DataSourceInstanceSettings ) ( instancemgmt . Instance , error ) {
2022-11-22 22:59:11 +08:00
return DataSource { Settings : models . CloudWatchSettings { } } , nil
2021-03-23 23:32:12 +08:00
} )
timeRange := backend . TimeRange {
From : time . Unix ( 1584873443 , 0 ) ,
To : time . Unix ( 1584700643 , 0 ) ,
2020-04-26 04:48:20 +08:00
}
2022-04-29 23:47:46 +08:00
executor := newExecutor ( im , newTestConfig ( ) , & fakeSessionCache { } , featuremgmt . WithFeatures ( ) )
2021-03-23 23:32:12 +08:00
resp , err := executor . QueryData ( context . Background ( ) , & backend . QueryDataRequest {
PluginContext : backend . PluginContext {
DataSourceInstanceSettings : & backend . DataSourceInstanceSettings { } ,
} ,
Queries : [ ] backend . DataQuery {
2020-07-24 00:52:22 +08:00
{
2021-03-23 23:32:12 +08:00
TimeRange : timeRange ,
JSON : json . RawMessage ( ` {
2020-07-24 00:52:22 +08:00
"type" : "logAction" ,
"subtype" : "StopQuery" ,
2021-03-23 23:32:12 +08:00
"queryId" : "abcd-efgh-ijkl-mnop"
} ` ) ,
2020-07-24 00:52:22 +08:00
} ,
} ,
2020-04-26 04:48:20 +08:00
} )
2020-07-24 00:52:22 +08:00
require . NoError ( t , err )
2020-04-26 04:48:20 +08:00
2020-07-24 00:52:22 +08:00
expFrame := & data . Frame {
Name : "StopQueryResponse" ,
Fields : [ ] * data . Field {
data . NewField ( "success" , nil , [ ] bool { true } ) ,
2020-04-26 04:48:20 +08:00
} ,
}
2021-03-23 23:32:12 +08:00
assert . Equal ( t , & backend . QueryDataResponse { Responses : backend . Responses {
"" : {
Frames : data . Frames { expFrame } ,
2020-07-24 00:52:22 +08:00
} ,
2021-03-23 23:32:12 +08:00
} ,
2020-07-24 00:52:22 +08:00
} , resp )
}
2020-04-26 04:48:20 +08:00
2020-07-24 00:52:22 +08:00
func TestQuery_GetQueryResults ( t * testing . T ) {
2021-01-07 18:36:13 +08:00
origNewCWLogsClient := NewCWLogsClient
2020-07-24 00:52:22 +08:00
t . Cleanup ( func ( ) {
2021-01-07 18:36:13 +08:00
NewCWLogsClient = origNewCWLogsClient
2020-04-26 04:48:20 +08:00
} )
2022-03-03 16:42:51 +08:00
var cli fakeCWLogsClient
2020-04-26 04:48:20 +08:00
2021-01-07 18:36:13 +08:00
NewCWLogsClient = func ( sess * session . Session ) cloudwatchlogsiface . CloudWatchLogsAPI {
2022-02-25 21:14:59 +08:00
return & cli
2020-07-24 00:52:22 +08:00
}
2020-04-26 04:48:20 +08:00
2020-07-24 00:52:22 +08:00
const refID = "A"
2022-03-03 16:42:51 +08:00
cli = fakeCWLogsClient {
2020-07-24 00:52:22 +08:00
queryResults : cloudwatchlogs . GetQueryResultsOutput {
Results : [ ] [ ] * cloudwatchlogs . ResultField {
{
{
Field : aws . String ( "@timestamp" ) ,
Value : aws . String ( "2020-03-20 10:37:23.000" ) ,
} ,
{
Field : aws . String ( "field_b" ) ,
Value : aws . String ( "b_1" ) ,
} ,
{
Field : aws . String ( "@ptr" ) ,
Value : aws . String ( "abcdefg" ) ,
} ,
} ,
{
{
Field : aws . String ( "@timestamp" ) ,
Value : aws . String ( "2020-03-20 10:40:43.000" ) ,
} ,
{
Field : aws . String ( "field_b" ) ,
Value : aws . String ( "b_2" ) ,
} ,
{
Field : aws . String ( "@ptr" ) ,
Value : aws . String ( "hijklmnop" ) ,
} ,
} ,
} ,
Statistics : & cloudwatchlogs . QueryStatistics {
BytesScanned : aws . Float64 ( 512 ) ,
RecordsMatched : aws . Float64 ( 256 ) ,
RecordsScanned : aws . Float64 ( 1024 ) ,
} ,
Status : aws . String ( "Complete" ) ,
2020-04-26 04:48:20 +08:00
} ,
}
2021-03-23 23:32:12 +08:00
im := datasource . NewInstanceManager ( func ( s backend . DataSourceInstanceSettings ) ( instancemgmt . Instance , error ) {
2022-11-22 22:59:11 +08:00
return DataSource { Settings : models . CloudWatchSettings { } } , nil
2021-03-23 23:32:12 +08:00
} )
2022-04-29 23:47:46 +08:00
executor := newExecutor ( im , newTestConfig ( ) , & fakeSessionCache { } , featuremgmt . WithFeatures ( ) )
2021-03-23 23:32:12 +08:00
resp , err := executor . QueryData ( context . Background ( ) , & backend . QueryDataRequest {
PluginContext : backend . PluginContext {
DataSourceInstanceSettings : & backend . DataSourceInstanceSettings { } ,
} ,
Queries : [ ] backend . DataQuery {
2020-07-24 00:52:22 +08:00
{
2021-03-08 14:02:49 +08:00
RefID : refID ,
2021-03-23 23:32:12 +08:00
JSON : json . RawMessage ( ` {
2020-07-24 00:52:22 +08:00
"type" : "logAction" ,
"subtype" : "GetQueryResults" ,
2021-03-23 23:32:12 +08:00
"queryId" : "abcd-efgh-ijkl-mnop"
} ` ) ,
2020-07-24 00:52:22 +08:00
} ,
} ,
2020-04-26 04:48:20 +08:00
} )
2020-05-18 18:25:58 +08:00
require . NoError ( t , err )
2020-07-24 00:52:22 +08:00
time1 , err := time . Parse ( "2006-01-02 15:04:05.000" , "2020-03-20 10:37:23.000" )
2020-05-18 18:25:58 +08:00
require . NoError ( t , err )
2020-07-24 00:52:22 +08:00
time2 , err := time . Parse ( "2006-01-02 15:04:05.000" , "2020-03-20 10:40:43.000" )
2020-05-18 18:25:58 +08:00
require . NoError ( t , err )
2020-07-24 00:52:22 +08:00
expField1 := data . NewField ( "@timestamp" , nil , [ ] * time . Time {
aws . Time ( time1 ) , aws . Time ( time2 ) ,
2020-04-26 04:48:20 +08:00
} )
2020-07-24 00:52:22 +08:00
expField1 . SetConfig ( & data . FieldConfig { DisplayName : "Time" } )
expField2 := data . NewField ( "field_b" , nil , [ ] * string {
2020-04-26 04:48:20 +08:00
aws . String ( "b_1" ) , aws . String ( "b_2" ) ,
} )
2020-07-24 00:52:22 +08:00
expFrame := data . NewFrame ( refID , expField1 , expField2 )
expFrame . RefID = refID
expFrame . Meta = & data . FrameMeta {
2020-04-26 04:48:20 +08:00
Custom : map [ string ] interface { } {
"Status" : "Complete" ,
2020-08-19 22:18:04 +08:00
} ,
Stats : [ ] data . QueryStat {
{
FieldConfig : data . FieldConfig { DisplayName : "Bytes scanned" } ,
Value : 512 ,
} ,
{
FieldConfig : data . FieldConfig { DisplayName : "Records scanned" } ,
Value : 1024 ,
} ,
{
FieldConfig : data . FieldConfig { DisplayName : "Records matched" } ,
Value : 256 ,
2020-04-26 04:48:20 +08:00
} ,
} ,
2020-07-24 00:52:22 +08:00
PreferredVisualization : "logs" ,
2020-04-26 04:48:20 +08:00
}
2021-03-23 23:32:12 +08:00
assert . Equal ( t , & backend . QueryDataResponse { Responses : backend . Responses {
refID : {
Frames : data . Frames { expFrame } ,
2020-07-24 00:52:22 +08:00
} ,
2021-03-23 23:32:12 +08:00
} ,
2020-07-24 00:52:22 +08:00
} , resp )
2020-04-26 04:48:20 +08:00
}
2022-12-02 17:21:46 +08:00
func TestGroupResponseFrame ( t * testing . T ) {
t . Run ( "Doesn't group results without time field" , func ( t * testing . T ) {
frame := data . NewFrameOfFieldTypes ( "test" , 0 , data . FieldTypeString , data . FieldTypeInt32 )
frame . AppendRow ( "val1" , int32 ( 10 ) )
frame . AppendRow ( "val2" , int32 ( 20 ) )
frame . AppendRow ( "val3" , int32 ( 30 ) )
groupedFrame , err := groupResponseFrame ( frame , [ ] string { "something" } )
require . NoError ( t , err )
require . Equal ( t , 3 , groupedFrame [ 0 ] . Rows ( ) )
require . Equal ( t , [ ] interface { } { "val1" , "val2" , "val3" } , asArray ( groupedFrame [ 0 ] . Fields [ 0 ] ) )
require . Equal ( t , [ ] interface { } { int32 ( 10 ) , int32 ( 20 ) , int32 ( 30 ) } , asArray ( groupedFrame [ 0 ] . Fields [ 1 ] ) )
} )
}
func asArray ( field * data . Field ) [ ] interface { } {
var vals [ ] interface { }
for i := 0 ; i < field . Len ( ) ; i ++ {
vals = append ( vals , field . At ( i ) )
}
return vals
}