Skip to content

Commit 3b510bf

Browse files
Add tests
1 parent c2861c4 commit 3b510bf

3 files changed

Lines changed: 84 additions & 1 deletion

File tree

pkg/aws/aws.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -384,14 +384,15 @@ func filterExcludedRegions(regions []types.Region, excludeList []string) []types
384384

385385
func newRegionClientMap(ctx context.Context, globalConfig aws.Config, pricingConfig aws.Config, regions []types.Region, profile string, roleARN string) (map[string]client.Client, error) {
386386
awsClientPerRegion := make(map[string]client.Client)
387+
pricingAPI := awsPricing.NewFromConfig(pricingConfig)
387388
for _, region := range regions {
388389
ac, err := createAWSConfig(ctx, *region.RegionName, profile, roleARN)
389390
if err != nil {
390391
return nil, err
391392
}
392393
awsClientPerRegion[*region.RegionName] = client.NewAWSClient(
393394
client.Config{
394-
PricingService: awsPricing.NewFromConfig(pricingConfig),
395+
PricingService: pricingAPI,
395396
EC2Service: ec2.NewFromConfig(ac),
396397
BillingService: costexplorer.NewFromConfig(globalConfig),
397398
RDSService: rds.NewFromConfig(ac),

pkg/aws/elb/elb_test.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,52 @@ func TestFetchRegionPricing(t *testing.T) {
152152
assert.Equal(t, 0.006, pricing.NLBHourlyRate[LCUUsage])
153153
}
154154

155+
func TestCollect_EmitsMetrics(t *testing.T) {
156+
ctrl := gomock.NewController(t)
157+
mockPricingClient := mock_client.NewMockClient(ctrl)
158+
mockRegionClient := mock_client.NewMockClient(ctrl)
159+
160+
albLBUsage := `{"Product":{"Attributes":{"usageType":"USE1-LoadBalancerUsage","operation":"LoadBalancing:Application"}},"Terms":{"OnDemand":{"t1":{"PriceDimensions":{"d1":{"pricePerUnit":{"USD":"0.0225"}}}}}}}`
161+
albLCUUsage := `{"Product":{"Attributes":{"usageType":"USE1-LCUUsage","operation":"LoadBalancing:Application"}},"Terms":{"OnDemand":{"t1":{"PriceDimensions":{"d1":{"pricePerUnit":{"USD":"0.008"}}}}}}}`
162+
mockPricingClient.EXPECT().ListELBPrices(gomock.Any(), "us-east-1").Return([]string{albLBUsage, albLCUUsage}, nil)
163+
mockRegionClient.EXPECT().DescribeLoadBalancers(gomock.Any()).Return([]elbTypes.LoadBalancer{
164+
{
165+
LoadBalancerName: utils.StringPtr("test-alb"),
166+
Type: elbTypes.LoadBalancerTypeEnumApplication,
167+
},
168+
}, nil)
169+
170+
config := &Config{
171+
ScrapeInterval: time.Minute,
172+
Regions: []ec2Types.Region{{RegionName: utils.StringPtr("us-east-1")}},
173+
PricingClient: mockPricingClient,
174+
RegionMap: map[string]client.Client{"us-east-1": mockRegionClient},
175+
AccountID: "123456789012",
176+
}
177+
178+
collector, err := New(context.Background(), config, slog.Default())
179+
require.NoError(t, err)
180+
181+
ch := make(chan prometheus.Metric, 10)
182+
err = collector.Collect(t.Context(), ch)
183+
close(ch)
184+
185+
require.NoError(t, err)
186+
187+
var metrics []prometheus.Metric
188+
for m := range ch {
189+
metrics = append(metrics, m)
190+
}
191+
require.Len(t, metrics, 2)
192+
193+
descStrings := make(map[string]struct{}, 2)
194+
for _, m := range metrics {
195+
descStrings[m.Desc().String()] = struct{}{}
196+
}
197+
assert.Contains(t, descStrings, LoadBalancerUsageHourlyCostDesc.String())
198+
assert.Contains(t, descStrings, LoadBalancerCapacityUnitsUsageHourlyCostDesc.String())
199+
}
200+
155201
func TestFetchRegionPricingError(t *testing.T) {
156202
ctrl := gomock.NewController(t)
157203
mockClient := mock_client.NewMockClient(ctrl)

pkg/aws/vpc/vpc_test.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
"github.com/prometheus/client_golang/prometheus"
1818
"github.com/stretchr/testify/assert"
1919
"github.com/stretchr/testify/mock"
20+
"github.com/stretchr/testify/require"
2021

2122
awsclient "github.com/grafana/cloudcost-exporter/pkg/aws/client"
2223
"github.com/grafana/cloudcost-exporter/pkg/utils"
@@ -155,6 +156,41 @@ func TestDescribe(t *testing.T) {
155156
assert.NoError(t, err)
156157
}
157158

159+
func TestCollect_EmitsMetrics(t *testing.T) {
160+
logger := slog.New(slog.NewTextHandler(os.Stdout, nil))
161+
mockClient := &MockClient{}
162+
163+
products := []string{
164+
`{"product":{"attributes":{"usageType":"USE1-VpcEndpoint-Hours","regionCode":"us-east-1"}},"terms":{"OnDemand":{"t1":{"priceDimensions":{"d1":{"pricePerUnit":{"USD":"0.01"}}}}}}}`,
165+
`{"product":{"attributes":{"usageType":"USE1-VpcEndpoint-Service-Hours","regionCode":"us-east-1"}},"terms":{"OnDemand":{"t1":{"priceDimensions":{"d1":{"pricePerUnit":{"USD":"0.01"}}}}}}}`,
166+
`{"product":{"attributes":{"usageType":"USE1-TransitGateway-Hours","regionCode":"us-east-1"}},"terms":{"OnDemand":{"t1":{"priceDimensions":{"d1":{"pricePerUnit":{"USD":"0.05"}}}}}}}`,
167+
`{"product":{"attributes":{"usageType":"USE1-PublicIPv4:InUseAddress","regionCode":"us-east-1"}},"terms":{"OnDemand":{"t1":{"priceDimensions":{"d1":{"pricePerUnit":{"USD":"0.005"}}}}}}}`,
168+
`{"product":{"attributes":{"usageType":"USE1-PublicIPv4:IdleAddress","regionCode":"us-east-1"}},"terms":{"OnDemand":{"t1":{"priceDimensions":{"d1":{"pricePerUnit":{"USD":"0.003"}}}}}}}`,
169+
}
170+
mockClient.On("ListVPCServicePrices", mock.Anything, mock.AnythingOfType("string"), mock.Anything).Return(products, nil)
171+
172+
collector, err := New(t.Context(), &Config{
173+
ScrapeInterval: time.Hour,
174+
Regions: []ec2Types.Region{{RegionName: utils.StringPtr("us-east-1")}},
175+
Client: mockClient,
176+
AccountID: "123456789012",
177+
}, logger)
178+
require.NoError(t, err)
179+
180+
ch := make(chan prometheus.Metric, 10)
181+
err = collector.Collect(t.Context(), ch)
182+
close(ch)
183+
184+
require.NoError(t, err)
185+
186+
var metrics []prometheus.Metric
187+
for m := range ch {
188+
metrics = append(metrics, m)
189+
}
190+
// One metric per rate type: VPC endpoint, VPC service endpoint, Transit Gateway, EIP in-use, EIP idle
191+
assert.Len(t, metrics, 5)
192+
}
193+
158194
// Test that VPC pricing map methods return errors when no data is available
159195
func TestVPCPricingMapErrors(t *testing.T) {
160196
// Use a logger that discards output to reduce test noise

0 commit comments

Comments
 (0)