The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
grafana/pkg/tsdb/cloudwatch/services/list_metrics_test.go

199 lines
8.4 KiB

package services
import (
"context"
"testing"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/cloudwatch"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/mocks"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models/resources"
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/utils"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
)
const useLinkedAccountsId = "all"
var metricResponse = []resources.MetricResponse{
{
Metric: &cloudwatch.Metric{
MetricName: aws.String("CPUUtilization"),
Namespace: aws.String("AWS/EC2"),
Dimensions: []*cloudwatch.Dimension{
{Name: aws.String("InstanceId"), Value: aws.String("i-1234567890abcdef0")},
{Name: aws.String("InstanceType"), Value: aws.String("t2.micro")},
},
},
},
{
Metric: &cloudwatch.Metric{
MetricName: aws.String("CPUUtilization"),
Namespace: aws.String("AWS/EC2"),
Dimensions: []*cloudwatch.Dimension{
{Name: aws.String("InstanceId"), Value: aws.String("i-5234567890abcdef0")},
{Name: aws.String("InstanceType"), Value: aws.String("t2.micro")},
{Name: aws.String("AutoScalingGroupName"), Value: aws.String("my-asg")},
},
},
},
{
Metric: &cloudwatch.Metric{
MetricName: aws.String("CPUUtilization"),
Namespace: aws.String("AWS/EC2"),
Dimensions: []*cloudwatch.Dimension{
{Name: aws.String("InstanceId"), Value: aws.String("i-64234567890abcdef0")},
{Name: aws.String("InstanceType"), Value: aws.String("t3.micro")},
{Name: aws.String("AutoScalingGroupName"), Value: aws.String("my-asg2")},
},
},
},
}
type validateInputTestCase[T resources.DimensionKeysRequest | resources.DimensionValuesRequest] struct {
name string
input T
listMetricsWithPageLimitInput *cloudwatch.ListMetricsInput
}
func TestListMetricsService_GetDimensionKeysByDimensionFilter(t *testing.T) {
t.Run("Should filter out duplicates and keys matching dimension filter keys", func(t *testing.T) {
fakeMetricsClient := &mocks.FakeMetricsClient{}
fakeMetricsClient.On("ListMetricsWithPageLimit", mock.Anything).Return(metricResponse, nil)
listMetricsService := NewListMetricsService(fakeMetricsClient)
resp, err := listMetricsService.GetDimensionKeysByDimensionFilter(context.Background(), resources.DimensionKeysRequest{
ResourceRequest: &resources.ResourceRequest{Region: "us-east-1"},
Namespace: "AWS/EC2",
MetricName: "CPUUtilization",
DimensionFilter: []*resources.Dimension{{Name: "InstanceId", Value: ""}},
})
require.NoError(t, err)
assert.Equal(t, []resources.ResourceResponse[string]{{Value: "InstanceType"}, {Value: "AutoScalingGroupName"}}, resp)
})
testCases := []validateInputTestCase[resources.DimensionKeysRequest]{
{
name: "Should set account correctly on list metric input if it cross account is defined on the request",
input: resources.DimensionKeysRequest{
ResourceRequest: &resources.ResourceRequest{Region: "us-east-1", AccountId: utils.Pointer(useLinkedAccountsId)},
Namespace: "AWS/EC2",
MetricName: "CPUUtilization",
DimensionFilter: []*resources.Dimension{{Name: "InstanceId", Value: ""}},
},
listMetricsWithPageLimitInput: &cloudwatch.ListMetricsInput{
MetricName: aws.String("CPUUtilization"),
Namespace: aws.String("AWS/EC2"),
Dimensions: []*cloudwatch.DimensionFilter{{Name: aws.String("InstanceId")}},
IncludeLinkedAccounts: aws.Bool(true),
},
},
{
name: "Should set account correctly on list metric input if single account is defined on the request",
input: resources.DimensionKeysRequest{
ResourceRequest: &resources.ResourceRequest{Region: "us-east-1", AccountId: utils.Pointer("1234567890")},
Namespace: "AWS/EC2",
MetricName: "CPUUtilization",
DimensionFilter: []*resources.Dimension{{Name: "InstanceId", Value: ""}},
},
listMetricsWithPageLimitInput: &cloudwatch.ListMetricsInput{
MetricName: aws.String("CPUUtilization"),
Namespace: aws.String("AWS/EC2"),
Dimensions: []*cloudwatch.DimensionFilter{{Name: aws.String("InstanceId")}},
IncludeLinkedAccounts: aws.Bool(true),
OwningAccount: aws.String("1234567890"),
},
},
{
name: "Should not set namespace and metricName on list metric input if empty strings are set for these in the request",
input: resources.DimensionKeysRequest{
ResourceRequest: &resources.ResourceRequest{Region: "us-east-1"},
Namespace: "",
MetricName: "",
DimensionFilter: []*resources.Dimension{{Name: "InstanceId", Value: ""}},
},
listMetricsWithPageLimitInput: &cloudwatch.ListMetricsInput{Dimensions: []*cloudwatch.DimensionFilter{{Name: aws.String("InstanceId")}}},
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
fakeMetricsClient := &mocks.FakeMetricsClient{}
fakeMetricsClient.On("ListMetricsWithPageLimit", mock.Anything).Return(metricResponse, nil)
listMetricsService := NewListMetricsService(fakeMetricsClient)
res, err := listMetricsService.GetDimensionKeysByDimensionFilter(context.Background(), tc.input)
require.NoError(t, err)
require.NotEmpty(t, res)
fakeMetricsClient.AssertCalled(t, "ListMetricsWithPageLimit", tc.listMetricsWithPageLimitInput)
})
}
}
func TestListMetricsService_GetDimensionValuesByDimensionFilter(t *testing.T) {
t.Run("Should filter out duplicates and keys matching dimension filter keys", func(t *testing.T) {
fakeMetricsClient := &mocks.FakeMetricsClient{}
fakeMetricsClient.On("ListMetricsWithPageLimit", mock.Anything).Return(metricResponse, nil)
listMetricsService := NewListMetricsService(fakeMetricsClient)
resp, err := listMetricsService.GetDimensionValuesByDimensionFilter(context.Background(), resources.DimensionValuesRequest{
ResourceRequest: &resources.ResourceRequest{Region: "us-east-1"},
Namespace: "AWS/EC2",
MetricName: "CPUUtilization",
DimensionKey: "InstanceId",
DimensionFilter: []*resources.Dimension{
{Name: "InstanceId", Value: ""},
},
})
require.NoError(t, err)
assert.Equal(t, []resources.ResourceResponse[string]{{Value: "i-1234567890abcdef0"}, {Value: "i-5234567890abcdef0"}, {Value: "i-64234567890abcdef0"}}, resp)
})
testCases := []validateInputTestCase[resources.DimensionValuesRequest]{
{
name: "Should set account correctly on list metric input if it cross account is defined on the request",
input: resources.DimensionValuesRequest{
ResourceRequest: &resources.ResourceRequest{Region: "us-east-1", AccountId: utils.Pointer(useLinkedAccountsId)},
Namespace: "AWS/EC2",
MetricName: "CPUUtilization",
DimensionFilter: []*resources.Dimension{{Name: "InstanceId", Value: ""}},
},
listMetricsWithPageLimitInput: &cloudwatch.ListMetricsInput{
MetricName: aws.String("CPUUtilization"),
Namespace: aws.String("AWS/EC2"),
Dimensions: []*cloudwatch.DimensionFilter{{Name: aws.String("InstanceId")}},
IncludeLinkedAccounts: aws.Bool(true),
},
},
{
name: "Should set account correctly on list metric input if single account is defined on the request",
input: resources.DimensionValuesRequest{
ResourceRequest: &resources.ResourceRequest{Region: "us-east-1", AccountId: utils.Pointer("1234567890")},
Namespace: "AWS/EC2",
MetricName: "CPUUtilization",
DimensionFilter: []*resources.Dimension{{Name: "InstanceId", Value: ""}},
},
listMetricsWithPageLimitInput: &cloudwatch.ListMetricsInput{
MetricName: aws.String("CPUUtilization"),
Namespace: aws.String("AWS/EC2"),
Dimensions: []*cloudwatch.DimensionFilter{{Name: aws.String("InstanceId")}},
IncludeLinkedAccounts: aws.Bool(true),
OwningAccount: aws.String("1234567890"),
},
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
fakeMetricsClient := &mocks.FakeMetricsClient{}
fakeMetricsClient.On("ListMetricsWithPageLimit", mock.Anything).Return(metricResponse, nil)
listMetricsService := NewListMetricsService(fakeMetricsClient)
res, err := listMetricsService.GetDimensionValuesByDimensionFilter(context.Background(), tc.input)
require.NoError(t, err)
require.Empty(t, res)
fakeMetricsClient.AssertCalled(t, "ListMetricsWithPageLimit", tc.listMetricsWithPageLimitInput)
})
}
}