UNPKG

@cloud-carbon-footprint/aws

Version:

The core logic to get cloud usage data and estimate energy and carbon emissions from Amazon Web Services.

179 lines (149 loc) 5.69 kB
/* * © 2021 Thoughtworks, Inc. */ import AWSMock from 'aws-sdk-mock' import AWS, { CloudWatch, CloudWatchLogs, CostExplorer, S3 } from 'aws-sdk' import path from 'path' import moment from 'moment' import * as fs from 'fs' import { ComputeEstimator, MemoryEstimator, StorageEstimator, } from '@cloud-carbon-footprint/core' import { AWS_RECOMMENDATIONS_SERVICES, configLoader, RecommendationResult, } from '@cloud-carbon-footprint/common' import { AWS_CLOUD_CONSTANTS } from '../domain' import { ServiceWrapper, ComputeOptimizerRecommendations } from '../lib' import { mockEBSComputeOptimizerBucketList, mockEC2ComputeOptimizerBucketList, mockLambdaComputeOptimizerBucketList, } from './fixtures/computeOptimizer.fixtures' describe('AWS Compute Optimizer Recommendations Service', () => { const getServiceWrapper = () => new ServiceWrapper( new CloudWatch(), new CloudWatchLogs(), new CostExplorer(), new S3(), ) const getRecommendationsService = () => new ComputeOptimizerRecommendations( new ComputeEstimator(), new MemoryEstimator(AWS_CLOUD_CONSTANTS.MEMORY_COEFFICIENT), new StorageEstimator(AWS_CLOUD_CONSTANTS.SSDCOEFFICIENT), new StorageEstimator(AWS_CLOUD_CONSTANTS.HDDCOEFFICIENT), getServiceWrapper(), ) const listBucketObjectsSpy = jest.fn() const mockBucketName = 'test-bucket' const defaultConfig = configLoader().AWS.RECOMMENDATIONS_SERVICE function mockListComputeOptimizerBucket(response: any) { listBucketObjectsSpy.mockResolvedValue(response) AWSMock.mock('S3', 'listObjectsV2', listBucketObjectsSpy) } function mockGetComputeOptimizerBucket(mockCSVFilePath: string) { const mockFilePath = path.join(process.cwd(), mockCSVFilePath) const mockFile = fs.readFileSync(mockFilePath) AWSMock.mock('S3', 'getObject', Buffer.alloc(mockFile.length, mockFile)) } beforeAll(() => { configLoader().AWS.RECOMMENDATIONS_SERVICE = AWS_RECOMMENDATIONS_SERVICES.ComputeOptimizer AWSMock.setSDKInstance(AWS) }) afterEach(() => { AWSMock.restore() jest.restoreAllMocks() configLoader().AWS.RECOMMENDATIONS_SERVICE = defaultConfig }) it('gets recommendations for only "Over Provisioned" EC2 instances ignoring AutoScalingGroup', async () => { moment.now = function () { return +new Date('2022-01-21T00:00:00.000Z') } const mockCSVFilePath = '/src/__tests__/fixtures/computeOptimizerEC2.csv' mockListComputeOptimizerBucket(mockEC2ComputeOptimizerBucketList) mockGetComputeOptimizerBucket(mockCSVFilePath) const awsRecommendationsServices = getRecommendationsService() const result = await awsRecommendationsServices.getRecommendations( mockBucketName, ) const expectedResult: RecommendationResult[] = [ { cloudProvider: 'AWS', accountId: '1234567890', accountName: '1234567890', region: 'eu-central-1', recommendationType: 'EC2-OVER_PROVISIONED', kilowattHourSavings: 9.737524749599999, resourceId: 'i-0c80d1b0f3a0c5c69', instanceName: 'PA-VM-100 | Networks', co2eSavings: 0.0030283701971256004, recommendationDetail: 'Save cost by changing instance type from m4.xlarge to t3.xlarge.', costSavings: 33.79, }, ] expect(result).toEqual(expectedResult) }) it('gets recommendations for only "Not Optimized" EBS volumes (with and without cost savings)', async () => { moment.now = function () { return +new Date('2022-01-21T00:00:00.000Z') } const mockCSVFilePath = '/src/__tests__/fixtures/computeOptimizerEBS.csv' mockListComputeOptimizerBucket(mockEBSComputeOptimizerBucketList) mockGetComputeOptimizerBucket(mockCSVFilePath) const awsRecommendationsServices = getRecommendationsService() const result = await awsRecommendationsServices.getRecommendations( mockBucketName, ) const expectedResult: RecommendationResult[] = [ { cloudProvider: 'AWS', accountId: '1234567890', accountName: '1234567890', region: 'us-west-2', recommendationType: 'EBS-NotOptimized', kilowattHourSavings: 0.0019612799999999993, resourceId: 'vol-00e39f1234a7eadfb', co2eSavings: 6.318596937599997e-7, recommendationDetail: 'Save cost by changing volume type from gp2(80GB) to gp3(50GB).', costSavings: 6.2, }, ] expect(result).toEqual(expectedResult) }) it('gets recommendations for only "Not Optimized" Lambda functions', async () => { moment.now = function () { return +new Date('2022-01-21T00:00:00.000Z') } const mockCSVFilePath = '/src/__tests__/fixtures/computeOptimizerLambda.csv' mockListComputeOptimizerBucket(mockLambdaComputeOptimizerBucketList) mockGetComputeOptimizerBucket(mockCSVFilePath) const awsRecommendationsServices = getRecommendationsService() const result = await awsRecommendationsServices.getRecommendations( mockBucketName, ) const expectedResult: RecommendationResult[] = [ { cloudProvider: 'AWS', accountId: '1234567890', accountName: '1234567890', region: 'us-east-2', recommendationType: 'Lambda-NotOptimized', kilowattHourSavings: 0.1781104877331825, resourceId: 'api-user-prod-add_user:$LATEST', co2eSavings: 0.00007313359114714655, recommendationDetail: 'Save cost by changing configuration memory size from 1024MB to 848MB.', costSavings: 2.988e-4, }, ] expect(result).toEqual(expectedResult) }) })