2022-10-20 18:53:28 +08:00
|
|
|
package services
|
|
|
|
|
|
|
|
import (
|
2023-10-23 22:17:06 +08:00
|
|
|
"context"
|
2022-10-20 18:53:28 +08:00
|
|
|
"testing"
|
|
|
|
|
2025-09-19 18:46:40 +08:00
|
|
|
"github.com/aws/aws-sdk-go-v2/aws"
|
|
|
|
"github.com/aws/aws-sdk-go-v2/service/cloudwatch"
|
|
|
|
cloudwatchtypes "github.com/aws/aws-sdk-go-v2/service/cloudwatch/types"
|
|
|
|
|
2022-10-20 18:53:28 +08:00
|
|
|
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/mocks"
|
2022-11-22 22:59:11 +08:00
|
|
|
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/models/resources"
|
2022-11-28 19:39:12 +08:00
|
|
|
"github.com/grafana/grafana/pkg/tsdb/cloudwatch/utils"
|
2022-10-20 18:53:28 +08:00
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"github.com/stretchr/testify/mock"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
)
|
|
|
|
|
2022-11-28 19:39:12 +08:00
|
|
|
const useLinkedAccountsId = "all"
|
|
|
|
|
|
|
|
var metricResponse = []resources.MetricResponse{
|
2022-10-20 18:53:28 +08:00
|
|
|
{
|
2025-09-19 18:46:40 +08:00
|
|
|
Metric: cloudwatchtypes.Metric{
|
2022-11-28 19:39:12 +08:00
|
|
|
MetricName: aws.String("CPUUtilization"),
|
|
|
|
Namespace: aws.String("AWS/EC2"),
|
2025-09-19 18:46:40 +08:00
|
|
|
Dimensions: []cloudwatchtypes.Dimension{
|
2022-11-28 19:39:12 +08:00
|
|
|
{Name: aws.String("InstanceId"), Value: aws.String("i-1234567890abcdef0")},
|
|
|
|
{Name: aws.String("InstanceType"), Value: aws.String("t2.micro")},
|
|
|
|
},
|
2022-10-20 18:53:28 +08:00
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
2025-09-19 18:46:40 +08:00
|
|
|
Metric: cloudwatchtypes.Metric{
|
2022-11-28 19:39:12 +08:00
|
|
|
MetricName: aws.String("CPUUtilization"),
|
|
|
|
Namespace: aws.String("AWS/EC2"),
|
2025-09-19 18:46:40 +08:00
|
|
|
Dimensions: []cloudwatchtypes.Dimension{
|
2022-11-28 19:39:12 +08:00
|
|
|
{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")},
|
|
|
|
},
|
2022-10-20 18:53:28 +08:00
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
2025-09-19 18:46:40 +08:00
|
|
|
Metric: cloudwatchtypes.Metric{
|
2022-11-28 19:39:12 +08:00
|
|
|
MetricName: aws.String("CPUUtilization"),
|
|
|
|
Namespace: aws.String("AWS/EC2"),
|
2025-09-19 18:46:40 +08:00
|
|
|
Dimensions: []cloudwatchtypes.Dimension{
|
2022-11-28 19:39:12 +08:00
|
|
|
{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")},
|
|
|
|
},
|
2022-10-20 18:53:28 +08:00
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2022-11-28 19:39:12 +08:00
|
|
|
type validateInputTestCase[T resources.DimensionKeysRequest | resources.DimensionValuesRequest] struct {
|
|
|
|
name string
|
|
|
|
input T
|
|
|
|
listMetricsWithPageLimitInput *cloudwatch.ListMetricsInput
|
|
|
|
}
|
|
|
|
|
2022-10-20 18:53:28 +08:00
|
|
|
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)
|
|
|
|
|
2023-10-23 22:17:06 +08:00
|
|
|
resp, err := listMetricsService.GetDimensionKeysByDimensionFilter(context.Background(), resources.DimensionKeysRequest{
|
2022-11-22 22:59:11 +08:00
|
|
|
ResourceRequest: &resources.ResourceRequest{Region: "us-east-1"},
|
2022-10-24 21:04:25 +08:00
|
|
|
Namespace: "AWS/EC2",
|
|
|
|
MetricName: "CPUUtilization",
|
2022-11-28 19:39:12 +08:00
|
|
|
DimensionFilter: []*resources.Dimension{{Name: "InstanceId", Value: ""}},
|
2022-10-20 18:53:28 +08:00
|
|
|
})
|
|
|
|
|
|
|
|
require.NoError(t, err)
|
2022-11-28 19:39:12 +08:00
|
|
|
assert.Equal(t, []resources.ResourceResponse[string]{{Value: "InstanceType"}, {Value: "AutoScalingGroupName"}}, resp)
|
2022-10-20 18:53:28 +08:00
|
|
|
})
|
|
|
|
|
2022-11-28 19:39:12 +08:00
|
|
|
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"),
|
2025-09-19 18:46:40 +08:00
|
|
|
Dimensions: []cloudwatchtypes.DimensionFilter{{Name: aws.String("InstanceId")}},
|
2022-11-28 19:39:12 +08:00
|
|
|
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"),
|
2025-09-19 18:46:40 +08:00
|
|
|
Dimensions: []cloudwatchtypes.DimensionFilter{{Name: aws.String("InstanceId")}},
|
2022-11-28 19:39:12 +08:00
|
|
|
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: ""}},
|
|
|
|
},
|
2025-09-19 18:46:40 +08:00
|
|
|
listMetricsWithPageLimitInput: &cloudwatch.ListMetricsInput{Dimensions: []cloudwatchtypes.DimensionFilter{{Name: aws.String("InstanceId")}}},
|
2022-11-28 19:39:12 +08:00
|
|
|
},
|
|
|
|
}
|
2022-10-20 18:53:28 +08:00
|
|
|
|
2022-11-28 19:39:12 +08:00
|
|
|
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)
|
2023-10-23 22:17:06 +08:00
|
|
|
res, err := listMetricsService.GetDimensionKeysByDimensionFilter(context.Background(), tc.input)
|
2022-11-28 19:39:12 +08:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotEmpty(t, res)
|
|
|
|
fakeMetricsClient.AssertCalled(t, "ListMetricsWithPageLimit", tc.listMetricsWithPageLimitInput)
|
|
|
|
})
|
|
|
|
}
|
2022-10-20 18:53:28 +08:00
|
|
|
}
|
2022-10-24 21:04:25 +08:00
|
|
|
|
|
|
|
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)
|
|
|
|
|
2023-10-23 22:17:06 +08:00
|
|
|
resp, err := listMetricsService.GetDimensionValuesByDimensionFilter(context.Background(), resources.DimensionValuesRequest{
|
2022-11-22 22:59:11 +08:00
|
|
|
ResourceRequest: &resources.ResourceRequest{Region: "us-east-1"},
|
2022-10-24 21:04:25 +08:00
|
|
|
Namespace: "AWS/EC2",
|
|
|
|
MetricName: "CPUUtilization",
|
|
|
|
DimensionKey: "InstanceId",
|
2022-11-22 22:59:11 +08:00
|
|
|
DimensionFilter: []*resources.Dimension{
|
2022-10-24 21:04:25 +08:00
|
|
|
{Name: "InstanceId", Value: ""},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
|
|
|
require.NoError(t, err)
|
2022-11-28 19:39:12 +08:00
|
|
|
assert.Equal(t, []resources.ResourceResponse[string]{{Value: "i-1234567890abcdef0"}, {Value: "i-5234567890abcdef0"}, {Value: "i-64234567890abcdef0"}}, resp)
|
2022-10-24 21:04:25 +08:00
|
|
|
})
|
2022-11-28 19:39:12 +08:00
|
|
|
|
|
|
|
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"),
|
2025-09-19 18:46:40 +08:00
|
|
|
Dimensions: []cloudwatchtypes.DimensionFilter{{Name: aws.String("InstanceId")}},
|
2022-11-28 19:39:12 +08:00
|
|
|
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"),
|
2025-09-19 18:46:40 +08:00
|
|
|
Dimensions: []cloudwatchtypes.DimensionFilter{{Name: aws.String("InstanceId")}},
|
2022-11-28 19:39:12 +08:00
|
|
|
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)
|
2023-10-23 22:17:06 +08:00
|
|
|
res, err := listMetricsService.GetDimensionValuesByDimensionFilter(context.Background(), tc.input)
|
2022-11-28 19:39:12 +08:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Empty(t, res)
|
|
|
|
fakeMetricsClient.AssertCalled(t, "ListMetricsWithPageLimit", tc.listMetricsWithPageLimitInput)
|
|
|
|
})
|
|
|
|
}
|
2022-10-24 21:04:25 +08:00
|
|
|
}
|