diff --git a/src/lib/case-studies/eshoppen.test.ts b/src/lib/case-studies/eshoppen.test.ts index 4e4aeb0a5..41f11ed7b 100644 --- a/src/lib/case-studies/eshoppen.test.ts +++ b/src/lib/case-studies/eshoppen.test.ts @@ -1,5 +1,5 @@ import {describe, expect, jest, test} from '@jest/globals'; -import {EshoppenModel} from './eshoppen-model'; +import {EshoppenMemModel, EshoppenModel} from './eshoppen-model'; jest.setTimeout(30000); @@ -28,5 +28,30 @@ describe('eshoppen:configure test', () => { }, ]); await expect(model.calculate([{}])).rejects.toThrowError(); + await expect(model.calculate({})).rejects.toThrowError(); + expect(model.authenticate({test: 'test'})).toBe(undefined); + + const model2 = await new EshoppenMemModel().configure('eshoppen', { + type: 'e-mem', + }); + expect(model2).toBeInstanceOf(EshoppenMemModel); + await expect( + model2.calculate([ + { + 'n-hours': 1, + 'n-chips': 1, + 'tdp-mem': 1, + 'tdp-coeff': 1, + }, + ]) + ).resolves.toStrictEqual([ + { + 'e-mem': 0.001, + 'n-chips': 1, + 'n-hours': 1, + 'tdp-coeff': 1, + 'tdp-mem': 1, + }, + ]); }); }); diff --git a/src/lib/ccf/index.test.ts b/src/lib/ccf/index.test.ts index b8189acf1..eaa2a9e5b 100644 --- a/src/lib/ccf/index.test.ts +++ b/src/lib/ccf/index.test.ts @@ -6,9 +6,24 @@ jest.setTimeout(30000); describe('ccf:configure test', () => { test('initialize with params', async () => { const impactModel = new CloudCarbonFootprint(); + + await expect( + impactModel.configure('test', { + provider: 'aws2', + 'instance-type': 't2.micro', + }) + ).rejects.toThrowError(); + expect(impactModel.resolveAwsArchitecture('Graviton')).toStrictEqual( + 'Graviton' + ); + try { + impactModel.resolveAwsArchitecture('Gra2'); + } catch (e: any) { + expect(e.message).toBe('Gra2 not supported'); + } await impactModel.configure('test', { provider: 'aws', - instance_type: 't2.micro', + 'instance-type': 't2.micro', }); await expect( impactModel.calculate([ @@ -16,16 +31,39 @@ describe('ccf:configure test', () => { ]) ).resolves.toStrictEqual([ { + duration: 3600, + cpu: 0.5, + datetime: '2021-01-01T00:00:00Z', energy: 0.0023031270462730543, - embodied_emissions: 0.04216723744292237 * 1000, + 'embodied-carbon': 0.04216723744292237 * 1000, + }, + ]); + await impactModel.configure('test', { + provider: 'aws', + interpolation: 'spline', + 'instance-type': 't2.micro', + }); + await expect( + impactModel.calculate([ + {duration: 3600, cpu: 0.5, datetime: '2021-01-01T00:00:00Z'}, + ]) + ).resolves.toStrictEqual([ + { + cpu: 0.5, + datetime: '2021-01-01T00:00:00Z', + duration: 3600, + 'embodied-carbon': 42.16723744292237, + energy: 0.004900000000000001, }, ]); + await expect(impactModel.calculate(undefined)).rejects.toThrowError(); + await expect(impactModel.calculate({})).rejects.toThrowError(); }); test('initialize with params:aws', async () => { const impactModel = new CloudCarbonFootprint(); await impactModel.configure('test', { provider: 'aws', - instance_type: 'm5n.large', + 'instance-type': 'm5n.large', }); await expect( impactModel.calculate([ @@ -47,16 +85,25 @@ describe('ccf:configure test', () => { ]) ).resolves.toStrictEqual([ { + duration: 3600, + cpu: 0.1, + datetime: '2021-01-01T00:00:00Z', energy: 0.0019435697915529846, - embodied_emissions: 91.94006849315068, + 'embodied-carbon': 91.94006849315068, }, { + duration: 3600, + cpu: 0.5, + datetime: '2021-01-01T00:00:00Z', energy: 0.0046062540925461085, - embodied_emissions: 91.94006849315068, + 'embodied-carbon': 91.94006849315068, }, { + duration: 3600, + cpu: 1, + datetime: '2021-01-01T00:00:00Z', energy: 0.007934609468787513, - embodied_emissions: 91.94006849315068, + 'embodied-carbon': 91.94006849315068, }, ]); }); @@ -64,7 +111,7 @@ describe('ccf:configure test', () => { const impactModel = new CloudCarbonFootprint(); await impactModel.configure('test', { provider: 'azure', - instance_type: 'D2 v4', + 'instance-type': 'D2 v4', }); await expect( impactModel.calculate([ @@ -86,16 +133,25 @@ describe('ccf:configure test', () => { ]) ).resolves.toStrictEqual([ { + duration: 3600, + cpu: 0.1, + datetime: '2021-01-01T00:00:00Z', energy: 0.0019435697915529846, - embodied_emissions: 0.08179908675799086 * 1000, + 'embodied-carbon': 0.08179908675799086 * 1000, }, { + duration: 3600, + cpu: 0.5, + datetime: '2021-01-01T00:00:00Z', energy: 0.0046062540925461085, - embodied_emissions: 0.08179908675799086 * 1000, + 'embodied-carbon': 0.08179908675799086 * 1000, }, { + duration: 3600, + cpu: 1, + datetime: '2021-01-01T00:00:00Z', energy: 0.007934609468787513, - embodied_emissions: 0.08179908675799086 * 1000, + 'embodied-carbon': 0.08179908675799086 * 1000, }, ]); }); @@ -103,7 +159,7 @@ describe('ccf:configure test', () => { const impactModel = new CloudCarbonFootprint(); await impactModel.configure('test', { provider: 'gcp', - instance_type: 'n2-standard-2', + 'instance-type': 'n2-standard-2', }); await expect( impactModel.calculate([ @@ -125,16 +181,25 @@ describe('ccf:configure test', () => { ]) ).resolves.toStrictEqual([ { + duration: 3600, + cpu: 0.1, + datetime: '2021-01-01T00:00:00Z', energy: 0.0018785992503765141, - embodied_emissions: 0.10778881278538813 * 1000, + 'embodied-carbon': 0.10778881278538813 * 1000, }, { + duration: 3600, + cpu: 0.5, + datetime: '2021-01-01T00:00:00Z', energy: 0.004281401386663755, - embodied_emissions: 0.10778881278538813 * 1000, + 'embodied-carbon': 0.10778881278538813 * 1000, }, { + duration: 3600, + cpu: 1, + datetime: '2021-01-01T00:00:00Z', energy: 0.0072849040570228075, - embodied_emissions: 0.10778881278538813 * 1000, + 'embodied-carbon': 0.10778881278538813 * 1000, }, ]); }); @@ -144,7 +209,7 @@ describe('ccf:configure test', () => { await expect( impactModel.configure('test', { provider: 'aws', - instance_type: 't5.micro', + 'instance-type': 't5.micro', }) ).rejects.toThrowError(); await expect( @@ -158,7 +223,7 @@ describe('ccf:configure test', () => { await expect( impactModel.configure('test', { provider: 'aws2', - instance_type: 't2.micro', + 'instance-type': 't2.micro', }) ).rejects.toThrowError(); await expect( @@ -173,7 +238,7 @@ describe('ccf:configure test', () => { await expect( impactModel.configure('test', { provider: 'aws', - instance_type: 't2.micro', + 'instance-type': 't2.micro', }) ).resolves.toBeInstanceOf(CloudCarbonFootprint); await expect( diff --git a/src/lib/ccf/index.ts b/src/lib/ccf/index.ts index 6fba5a459..99537aac3 100644 --- a/src/lib/ccf/index.ts +++ b/src/lib/ccf/index.ts @@ -1,11 +1,7 @@ -import {INSTANCE_TYPE_COMPUTE_PROCESSOR_MAPPING} from '@cloud-carbon-footprint/aws/dist/lib/AWSInstanceTypes'; import Spline from 'typescript-cubic-spline'; -import { - ICcfResult, - IComputeInstance, - IImpactModelInterface, -} from '../interfaces'; +import {IComputeInstance, IImpactModelInterface} from '../interfaces'; +import {INSTANCE_TYPE_COMPUTE_PROCESSOR_MAPPING} from '@cloud-carbon-footprint/aws/dist/lib/AWSInstanceTypes'; import {CONFIG} from '../../config'; @@ -64,8 +60,8 @@ export class CloudCarbonFootprint implements IImpactModelInterface { * @param {string} name name of the resource * @param {Object} staticParams static parameters for the resource * @param {("aws"|"gcp"|"azure")} staticParams.provider aws, gcp, azure - * @param {string} staticParams.instance_type instance type from the list of supported instances - * @param {number} staticParams.expected_lifespan expected lifespan of the instance in years + * @param {string} staticParams.'instance-type' instance type from the list of supported instances + * @param {number} staticParams.'expected-lifespan' expected lifespan of the instance in years * @param {Interpolation} staticParams.interpolation linear(All Clouds), spline (only for AWS) */ async configure( @@ -89,8 +85,8 @@ export class CloudCarbonFootprint implements IImpactModelInterface { throw new Error('Provider not provided'); } - if ('instance_type' in staticParams) { - const instanceType = staticParams?.instance_type as string; + if ('instance-type' in staticParams) { + const instanceType = staticParams['instance-type'] as string; if (instanceType in this.computeInstances[this.provider]) { this.instanceType = instanceType; } else { @@ -100,8 +96,8 @@ export class CloudCarbonFootprint implements IImpactModelInterface { throw new Error('Instance Type not provided'); } - if ('expected_lifespan' in staticParams) { - this.expectedLifespan = staticParams?.expected_lifespan as number; + if ('expected-lifespan' in staticParams) { + this.expectedLifespan = staticParams['expected-lifespan'] as number; } if ('interpolation' in staticParams) { @@ -132,25 +128,20 @@ export class CloudCarbonFootprint implements IImpactModelInterface { if (observations === undefined) { throw new Error('Required Parameters not provided'); } + if (!Array.isArray(observations)) { + throw new Error('observations should be an array'); + } if (this.instanceType === '' || this.provider === '') { throw new Error('Configuration is incomplete'); } + observations.map((observation: KeyValuePair) => { + observation['energy'] = this.calculateEnergy(observation); + observation['embodied-carbon'] = this.embodiedEmissions(observation); + return observation; + }); - const results: ICcfResult[] = []; - if (Array.isArray(observations)) { - observations.forEach((observation: KeyValuePair) => { - const energy = this.calculateEnergy(observation); - const embodiedEmissions = this.embodiedEmissions(observation); - - results.push({ - energy: energy, - embodied_emissions: embodiedEmissions, - }); - }); - } - - return results; + return observations; } /** @@ -369,7 +360,7 @@ export class CloudCarbonFootprint implements IImpactModelInterface { // Architecture strings are different between Instances-Use.JSON and the bundled Typescript from CCF. // This function resolves the differences. - private resolveAwsArchitecture(architecture: string) { + resolveAwsArchitecture(architecture: string) { if (architecture.includes('AMD ')) { architecture = architecture.substring(4); } @@ -393,7 +384,7 @@ export class CloudCarbonFootprint implements IImpactModelInterface { } if (!(architecture in this.computeInstanceUsageByArchitecture['aws'])) { - console.log('ARCHITECTURE:', architecture); + throw new Error(`${architecture} not supported`); } return architecture;