mirror of https://github.com/grafana/grafana.git
				
				
				
			
		
			
				
	
	
		
			519 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			519 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Go
		
	
	
	
package cloudwatch
 | 
						|
 | 
						|
import (
 | 
						|
	"context"
 | 
						|
	"fmt"
 | 
						|
	"testing"
 | 
						|
	"time"
 | 
						|
 | 
						|
	"github.com/aws/aws-sdk-go/aws"
 | 
						|
	"github.com/aws/aws-sdk-go/aws/session"
 | 
						|
	"github.com/aws/aws-sdk-go/service/cloudwatchlogs"
 | 
						|
	"github.com/aws/aws-sdk-go/service/cloudwatchlogs/cloudwatchlogsiface"
 | 
						|
	"github.com/grafana/grafana-plugin-sdk-go/data"
 | 
						|
	"github.com/grafana/grafana/pkg/components/simplejson"
 | 
						|
	"github.com/grafana/grafana/pkg/tsdb"
 | 
						|
 | 
						|
	"github.com/stretchr/testify/assert"
 | 
						|
	"github.com/stretchr/testify/require"
 | 
						|
)
 | 
						|
 | 
						|
func TestQuery_DescribeLogGroups(t *testing.T) {
 | 
						|
	origNewCWLogsClient := newCWLogsClient
 | 
						|
	t.Cleanup(func() {
 | 
						|
		newCWLogsClient = origNewCWLogsClient
 | 
						|
	})
 | 
						|
 | 
						|
	var cli fakeCWLogsClient
 | 
						|
 | 
						|
	newCWLogsClient = func(sess *session.Session) cloudwatchlogsiface.CloudWatchLogsAPI {
 | 
						|
		return cli
 | 
						|
	}
 | 
						|
 | 
						|
	t.Run("Empty log group name prefix", func(t *testing.T) {
 | 
						|
		cli = fakeCWLogsClient{
 | 
						|
			logGroups: cloudwatchlogs.DescribeLogGroupsOutput{
 | 
						|
				LogGroups: []*cloudwatchlogs.LogGroup{
 | 
						|
					{
 | 
						|
						LogGroupName: aws.String("group_a"),
 | 
						|
					},
 | 
						|
					{
 | 
						|
						LogGroupName: aws.String("group_b"),
 | 
						|
					},
 | 
						|
					{
 | 
						|
						LogGroupName: aws.String("group_c"),
 | 
						|
					},
 | 
						|
				},
 | 
						|
			},
 | 
						|
		}
 | 
						|
 | 
						|
		executor := newExecutor()
 | 
						|
		resp, err := executor.Query(context.Background(), fakeDataSource(), &tsdb.TsdbQuery{
 | 
						|
			Queries: []*tsdb.Query{
 | 
						|
				{
 | 
						|
					Model: simplejson.NewFromAny(map[string]interface{}{
 | 
						|
						"type":    "logAction",
 | 
						|
						"subtype": "DescribeLogGroups",
 | 
						|
						"limit":   50,
 | 
						|
					}),
 | 
						|
				},
 | 
						|
			},
 | 
						|
		})
 | 
						|
		require.NoError(t, err)
 | 
						|
		require.NotNil(t, resp)
 | 
						|
 | 
						|
		assert.Equal(t, &tsdb.Response{
 | 
						|
			Results: map[string]*tsdb.QueryResult{
 | 
						|
				"": {
 | 
						|
					Dataframes: tsdb.NewDecodedDataFrames(data.Frames{
 | 
						|
						&data.Frame{
 | 
						|
							Name: "logGroups",
 | 
						|
							Fields: []*data.Field{
 | 
						|
								data.NewField("logGroupName", nil, []*string{
 | 
						|
									aws.String("group_a"), aws.String("group_b"), aws.String("group_c"),
 | 
						|
								}),
 | 
						|
							},
 | 
						|
							Meta: &data.FrameMeta{
 | 
						|
								PreferredVisualization: "logs",
 | 
						|
							},
 | 
						|
						},
 | 
						|
					}),
 | 
						|
				},
 | 
						|
			},
 | 
						|
		}, resp)
 | 
						|
	})
 | 
						|
 | 
						|
	t.Run("Non-empty log group name prefix", func(t *testing.T) {
 | 
						|
		cli = fakeCWLogsClient{
 | 
						|
			logGroups: cloudwatchlogs.DescribeLogGroupsOutput{
 | 
						|
				LogGroups: []*cloudwatchlogs.LogGroup{
 | 
						|
					{
 | 
						|
						LogGroupName: aws.String("group_a"),
 | 
						|
					},
 | 
						|
					{
 | 
						|
						LogGroupName: aws.String("group_b"),
 | 
						|
					},
 | 
						|
					{
 | 
						|
						LogGroupName: aws.String("group_c"),
 | 
						|
					},
 | 
						|
				},
 | 
						|
			},
 | 
						|
		}
 | 
						|
 | 
						|
		executor := newExecutor()
 | 
						|
		resp, err := executor.Query(context.Background(), fakeDataSource(), &tsdb.TsdbQuery{
 | 
						|
			Queries: []*tsdb.Query{
 | 
						|
				{
 | 
						|
					Model: simplejson.NewFromAny(map[string]interface{}{
 | 
						|
						"type":               "logAction",
 | 
						|
						"subtype":            "DescribeLogGroups",
 | 
						|
						"logGroupNamePrefix": "g",
 | 
						|
					}),
 | 
						|
				},
 | 
						|
			},
 | 
						|
		})
 | 
						|
		require.NoError(t, err)
 | 
						|
		require.NotNil(t, resp)
 | 
						|
 | 
						|
		assert.Equal(t, &tsdb.Response{
 | 
						|
			Results: map[string]*tsdb.QueryResult{
 | 
						|
				"": {
 | 
						|
					Dataframes: tsdb.NewDecodedDataFrames(data.Frames{
 | 
						|
						&data.Frame{
 | 
						|
							Name: "logGroups",
 | 
						|
							Fields: []*data.Field{
 | 
						|
								data.NewField("logGroupName", nil, []*string{
 | 
						|
									aws.String("group_a"), aws.String("group_b"), aws.String("group_c"),
 | 
						|
								}),
 | 
						|
							},
 | 
						|
							Meta: &data.FrameMeta{
 | 
						|
								PreferredVisualization: "logs",
 | 
						|
							},
 | 
						|
						},
 | 
						|
					}),
 | 
						|
				},
 | 
						|
			},
 | 
						|
		}, resp)
 | 
						|
	})
 | 
						|
}
 | 
						|
 | 
						|
func TestQuery_GetLogGroupFields(t *testing.T) {
 | 
						|
	origNewCWLogsClient := newCWLogsClient
 | 
						|
	t.Cleanup(func() {
 | 
						|
		newCWLogsClient = origNewCWLogsClient
 | 
						|
	})
 | 
						|
 | 
						|
	var cli fakeCWLogsClient
 | 
						|
 | 
						|
	newCWLogsClient = func(sess *session.Session) cloudwatchlogsiface.CloudWatchLogsAPI {
 | 
						|
		return cli
 | 
						|
	}
 | 
						|
 | 
						|
	cli = fakeCWLogsClient{
 | 
						|
		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),
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	const refID = "A"
 | 
						|
 | 
						|
	executor := newExecutor()
 | 
						|
	resp, err := executor.Query(context.Background(), fakeDataSource(), &tsdb.TsdbQuery{
 | 
						|
		Queries: []*tsdb.Query{
 | 
						|
			{
 | 
						|
				RefId: refID,
 | 
						|
				Model: simplejson.NewFromAny(map[string]interface{}{
 | 
						|
					"type":         "logAction",
 | 
						|
					"subtype":      "GetLogGroupFields",
 | 
						|
					"logGroupName": "group_a",
 | 
						|
					"limit":        50,
 | 
						|
				}),
 | 
						|
			},
 | 
						|
		},
 | 
						|
	})
 | 
						|
	require.NoError(t, err)
 | 
						|
	require.NotNil(t, resp)
 | 
						|
 | 
						|
	expFrame := &data.Frame{
 | 
						|
		Name: refID,
 | 
						|
		Fields: []*data.Field{
 | 
						|
			data.NewField("name", nil, []*string{
 | 
						|
				aws.String("field_a"), aws.String("field_b"), aws.String("field_c"),
 | 
						|
			}),
 | 
						|
			data.NewField("percent", nil, []*int64{
 | 
						|
				aws.Int64(100), aws.Int64(30), aws.Int64(55),
 | 
						|
			}),
 | 
						|
		},
 | 
						|
		Meta: &data.FrameMeta{
 | 
						|
			PreferredVisualization: "logs",
 | 
						|
		},
 | 
						|
	}
 | 
						|
	expFrame.RefID = refID
 | 
						|
	assert.Equal(t, &tsdb.Response{
 | 
						|
		Results: map[string]*tsdb.QueryResult{
 | 
						|
			refID: {
 | 
						|
				Dataframes: tsdb.NewDecodedDataFrames(data.Frames{expFrame}),
 | 
						|
				RefId:      refID,
 | 
						|
			},
 | 
						|
		},
 | 
						|
	}, resp)
 | 
						|
}
 | 
						|
 | 
						|
func TestQuery_StartQuery(t *testing.T) {
 | 
						|
	origNewCWLogsClient := newCWLogsClient
 | 
						|
	t.Cleanup(func() {
 | 
						|
		newCWLogsClient = origNewCWLogsClient
 | 
						|
	})
 | 
						|
 | 
						|
	var cli fakeCWLogsClient
 | 
						|
 | 
						|
	newCWLogsClient = func(sess *session.Session) cloudwatchlogsiface.CloudWatchLogsAPI {
 | 
						|
		return cli
 | 
						|
	}
 | 
						|
 | 
						|
	t.Run("invalid time range", func(t *testing.T) {
 | 
						|
		cli = fakeCWLogsClient{
 | 
						|
			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),
 | 
						|
					},
 | 
						|
				},
 | 
						|
			},
 | 
						|
		}
 | 
						|
 | 
						|
		timeRange := &tsdb.TimeRange{
 | 
						|
			From: "1584873443000",
 | 
						|
			To:   "1584700643000",
 | 
						|
		}
 | 
						|
 | 
						|
		executor := newExecutor()
 | 
						|
		_, err := executor.Query(context.Background(), fakeDataSource(), &tsdb.TsdbQuery{
 | 
						|
			TimeRange: timeRange,
 | 
						|
			Queries: []*tsdb.Query{
 | 
						|
				{
 | 
						|
					Model: simplejson.NewFromAny(map[string]interface{}{
 | 
						|
						"type":        "logAction",
 | 
						|
						"subtype":     "StartQuery",
 | 
						|
						"limit":       50,
 | 
						|
						"region":      "default",
 | 
						|
						"queryString": "fields @message",
 | 
						|
					}),
 | 
						|
				},
 | 
						|
			},
 | 
						|
		})
 | 
						|
		require.Error(t, err)
 | 
						|
 | 
						|
		assert.Equal(t, fmt.Errorf("invalid time range: start time must be before end time"), err)
 | 
						|
	})
 | 
						|
 | 
						|
	t.Run("valid time range", func(t *testing.T) {
 | 
						|
		const refID = "A"
 | 
						|
		cli = fakeCWLogsClient{
 | 
						|
			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),
 | 
						|
					},
 | 
						|
				},
 | 
						|
			},
 | 
						|
		}
 | 
						|
 | 
						|
		timeRange := &tsdb.TimeRange{
 | 
						|
			From: "1584700643000",
 | 
						|
			To:   "1584873443000",
 | 
						|
		}
 | 
						|
 | 
						|
		executor := newExecutor()
 | 
						|
		resp, err := executor.Query(context.Background(), fakeDataSource(), &tsdb.TsdbQuery{
 | 
						|
			TimeRange: timeRange,
 | 
						|
			Queries: []*tsdb.Query{
 | 
						|
				{
 | 
						|
					RefId: refID,
 | 
						|
					Model: simplejson.NewFromAny(map[string]interface{}{
 | 
						|
						"type":        "logAction",
 | 
						|
						"subtype":     "StartQuery",
 | 
						|
						"limit":       50,
 | 
						|
						"region":      "default",
 | 
						|
						"queryString": "fields @message",
 | 
						|
					}),
 | 
						|
				},
 | 
						|
			},
 | 
						|
		})
 | 
						|
		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",
 | 
						|
			},
 | 
						|
			PreferredVisualization: "logs",
 | 
						|
		}
 | 
						|
		assert.Equal(t, &tsdb.Response{
 | 
						|
			Results: map[string]*tsdb.QueryResult{
 | 
						|
				refID: {
 | 
						|
					Dataframes: tsdb.NewDecodedDataFrames(data.Frames{expFrame}),
 | 
						|
					RefId:      refID,
 | 
						|
				},
 | 
						|
			},
 | 
						|
		}, resp)
 | 
						|
	})
 | 
						|
}
 | 
						|
 | 
						|
func TestQuery_StopQuery(t *testing.T) {
 | 
						|
	origNewCWLogsClient := newCWLogsClient
 | 
						|
	t.Cleanup(func() {
 | 
						|
		newCWLogsClient = origNewCWLogsClient
 | 
						|
	})
 | 
						|
 | 
						|
	var cli fakeCWLogsClient
 | 
						|
 | 
						|
	newCWLogsClient = func(sess *session.Session) cloudwatchlogsiface.CloudWatchLogsAPI {
 | 
						|
		return cli
 | 
						|
	}
 | 
						|
 | 
						|
	cli = fakeCWLogsClient{
 | 
						|
		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),
 | 
						|
				},
 | 
						|
			},
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	timeRange := &tsdb.TimeRange{
 | 
						|
		From: "1584873443000",
 | 
						|
		To:   "1584700643000",
 | 
						|
	}
 | 
						|
 | 
						|
	executor := newExecutor()
 | 
						|
	resp, err := executor.Query(context.Background(), fakeDataSource(), &tsdb.TsdbQuery{
 | 
						|
		TimeRange: timeRange,
 | 
						|
		Queries: []*tsdb.Query{
 | 
						|
			{
 | 
						|
				Model: simplejson.NewFromAny(map[string]interface{}{
 | 
						|
					"type":    "logAction",
 | 
						|
					"subtype": "StopQuery",
 | 
						|
					"queryId": "abcd-efgh-ijkl-mnop",
 | 
						|
				}),
 | 
						|
			},
 | 
						|
		},
 | 
						|
	})
 | 
						|
	require.NoError(t, err)
 | 
						|
 | 
						|
	expFrame := &data.Frame{
 | 
						|
		Name: "StopQueryResponse",
 | 
						|
		Fields: []*data.Field{
 | 
						|
			data.NewField("success", nil, []bool{true}),
 | 
						|
		},
 | 
						|
		Meta: &data.FrameMeta{
 | 
						|
			PreferredVisualization: "logs",
 | 
						|
		},
 | 
						|
	}
 | 
						|
	assert.Equal(t, &tsdb.Response{
 | 
						|
		Results: map[string]*tsdb.QueryResult{
 | 
						|
			"": {
 | 
						|
				Dataframes: tsdb.NewDecodedDataFrames(data.Frames{expFrame}),
 | 
						|
			},
 | 
						|
		},
 | 
						|
	}, resp)
 | 
						|
}
 | 
						|
 | 
						|
func TestQuery_GetQueryResults(t *testing.T) {
 | 
						|
	origNewCWLogsClient := newCWLogsClient
 | 
						|
	t.Cleanup(func() {
 | 
						|
		newCWLogsClient = origNewCWLogsClient
 | 
						|
	})
 | 
						|
 | 
						|
	var cli fakeCWLogsClient
 | 
						|
 | 
						|
	newCWLogsClient = func(sess *session.Session) cloudwatchlogsiface.CloudWatchLogsAPI {
 | 
						|
		return cli
 | 
						|
	}
 | 
						|
 | 
						|
	const refID = "A"
 | 
						|
	cli = fakeCWLogsClient{
 | 
						|
		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"),
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	executor := newExecutor()
 | 
						|
	resp, err := executor.Query(context.Background(), fakeDataSource(), &tsdb.TsdbQuery{
 | 
						|
		Queries: []*tsdb.Query{
 | 
						|
			{
 | 
						|
				RefId: refID,
 | 
						|
				Model: simplejson.NewFromAny(map[string]interface{}{
 | 
						|
					"type":    "logAction",
 | 
						|
					"subtype": "GetQueryResults",
 | 
						|
					"queryId": "abcd-efgh-ijkl-mnop",
 | 
						|
				}),
 | 
						|
			},
 | 
						|
		},
 | 
						|
	})
 | 
						|
	require.NoError(t, err)
 | 
						|
 | 
						|
	time1, err := time.Parse("2006-01-02 15:04:05.000", "2020-03-20 10:37:23.000")
 | 
						|
	require.NoError(t, err)
 | 
						|
	time2, err := time.Parse("2006-01-02 15:04:05.000", "2020-03-20 10:40:43.000")
 | 
						|
	require.NoError(t, err)
 | 
						|
	expField1 := data.NewField("@timestamp", nil, []*time.Time{
 | 
						|
		aws.Time(time1), aws.Time(time2),
 | 
						|
	})
 | 
						|
	expField1.SetConfig(&data.FieldConfig{DisplayName: "Time"})
 | 
						|
	expField2 := data.NewField("field_b", nil, []*string{
 | 
						|
		aws.String("b_1"), aws.String("b_2"),
 | 
						|
	})
 | 
						|
	expFrame := data.NewFrame(refID, expField1, expField2)
 | 
						|
	expFrame.RefID = refID
 | 
						|
	expFrame.Meta = &data.FrameMeta{
 | 
						|
		Custom: map[string]interface{}{
 | 
						|
			"Status": "Complete",
 | 
						|
		},
 | 
						|
		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,
 | 
						|
			},
 | 
						|
		},
 | 
						|
		PreferredVisualization: "logs",
 | 
						|
	}
 | 
						|
 | 
						|
	assert.Equal(t, &tsdb.Response{
 | 
						|
		Results: map[string]*tsdb.QueryResult{
 | 
						|
			refID: {
 | 
						|
				RefId:      refID,
 | 
						|
				Dataframes: tsdb.NewDecodedDataFrames(data.Frames{expFrame}),
 | 
						|
			},
 | 
						|
		},
 | 
						|
	}, resp)
 | 
						|
}
 |