From 6904da52814d04c3bf40e394b5b5968840718450 Mon Sep 17 00:00:00 2001 From: manushak Date: Fri, 26 Jul 2024 17:53:14 +0400 Subject: [PATCH] test(builtins): update test corespondingly --- .../if-run/builtins/coefficient.test.ts | 28 +- .../if-run/builtins/copy-param.test.ts | 28 +- .../if-run/builtins/csv-lookup.test.ts | 101 +- src/__tests__/if-run/builtins/divide.test.ts | 44 +- .../if-run/builtins/exponent.test.ts | 16 +- .../if-run/builtins/interpolation.test.ts | 58 +- .../if-run/builtins/mock-observations.test.ts | 82 +- .../if-run/builtins/multiply.test.ts | 12 +- src/__tests__/if-run/builtins/regex.test.ts | 21 +- .../if-run/builtins/sci-embodied.test.ts | 8 +- src/__tests__/if-run/builtins/sci.test.ts | 48 +- src/__tests__/if-run/builtins/shell.test.ts | 12 +- .../if-run/builtins/subtract.test.ts | 12 +- src/__tests__/if-run/builtins/sum.test.ts | 48 +- .../if-run/builtins/time-sync.test.ts | 1396 +++++++++-------- 15 files changed, 1096 insertions(+), 818 deletions(-) diff --git a/src/__tests__/if-run/builtins/coefficient.test.ts b/src/__tests__/if-run/builtins/coefficient.test.ts index 8d99c3e87..453f6954a 100644 --- a/src/__tests__/if-run/builtins/coefficient.test.ts +++ b/src/__tests__/if-run/builtins/coefficient.test.ts @@ -18,7 +18,12 @@ describe('builtins/coefficient: ', () => { inputs: {}, outputs: {}, }; - const coefficient = Coefficient(globalConfig, parametersMetadata); + const pluginSettings = { + 'global-config': globalConfig, + 'parameter-metadata': parametersMetadata, + mapping: {}, + }; + const coefficient = Coefficient(pluginSettings); describe('init: ', () => { it('successfully initalized.', () => { @@ -55,7 +60,12 @@ describe('builtins/coefficient: ', () => { it('throws an error when global config is not provided.', () => { const config = undefined; - const coefficient = Coefficient(config!, parametersMetadata); + const pluginSettings = { + 'global-config': config!, + 'parameter-metadata': parametersMetadata, + mapping: {}, + }; + const coefficient = Coefficient(pluginSettings); expect.assertions(1); @@ -80,7 +90,12 @@ describe('builtins/coefficient: ', () => { coefficient: 3, 'output-parameter': 'carbon-product', }; - const coefficient = Coefficient(invalidConfig, parametersMetadata); + const pluginSettings = { + 'global-config': invalidConfig, + 'parameter-metadata': parametersMetadata, + mapping: {}, + }; + const coefficient = Coefficient(pluginSettings); const expectedMessage = '"input-parameter" parameter is string must contain at least 1 character(s). Error code: too_small.'; @@ -107,7 +122,12 @@ describe('builtins/coefficient: ', () => { coefficient: 10, 'output-parameter': '', }; - const coefficient = Coefficient(invalidConfig, parametersMetadata); + const pluginSettings = { + 'global-config': invalidConfig, + 'parameter-metadata': parametersMetadata, + mapping: {}, + }; + const coefficient = Coefficient(pluginSettings); const expectedMessage = '"output-parameter" parameter is string must contain at least 1 character(s). Error code: too_small.'; diff --git a/src/__tests__/if-run/builtins/copy-param.test.ts b/src/__tests__/if-run/builtins/copy-param.test.ts index 952546505..7b8e2ffa3 100644 --- a/src/__tests__/if-run/builtins/copy-param.test.ts +++ b/src/__tests__/if-run/builtins/copy-param.test.ts @@ -18,7 +18,12 @@ describe('builtins/copy: ', () => { inputs: {}, outputs: {}, }; - const copy = Copy(globalConfig, parametersMetadata); + const pluginSettings = { + 'global-config': globalConfig, + 'parameter-metadata': parametersMetadata, + mapping: {}, + }; + const copy = Copy(pluginSettings); describe('init: ', () => { it('successfully initalized.', () => { @@ -53,7 +58,12 @@ describe('builtins/copy: ', () => { it('throws an error when global config is not provided.', () => { const config = undefined; - const copy = Copy(config!, parametersMetadata); + const pluginSettings = { + 'global-config': config!, + 'parameter-metadata': parametersMetadata, + mapping: {}, + }; + const copy = Copy(pluginSettings); expect.assertions(1); @@ -78,7 +88,12 @@ describe('builtins/copy: ', () => { from: 'original', to: 'copy', }; - const copy = Copy(globalConfig, parametersMetadata); + const pluginSettings = { + 'global-config': globalConfig, + 'parameter-metadata': parametersMetadata, + mapping: {}, + }; + const copy = Copy(pluginSettings); expect.assertions(1); try { @@ -103,7 +118,12 @@ describe('builtins/copy: ', () => { from: 'original', to: 'copy', }; - const copy = Copy(globalConfig, parametersMetadata); + const pluginSettings = { + 'global-config': globalConfig, + 'parameter-metadata': parametersMetadata, + mapping: {}, + }; + const copy = Copy(pluginSettings); const expectedResult = [ { diff --git a/src/__tests__/if-run/builtins/csv-lookup.test.ts b/src/__tests__/if-run/builtins/csv-lookup.test.ts index b89c7572e..18270fa11 100644 --- a/src/__tests__/if-run/builtins/csv-lookup.test.ts +++ b/src/__tests__/if-run/builtins/csv-lookup.test.ts @@ -35,7 +35,12 @@ describe('builtins/CSVLookup: ', () => { }, output: ['cpu-tdp', 'tdp'], }; - const csvLookup = CSVLookup(globalConfig); + const pluginSettings = { + 'global-config': globalConfig, + 'parameter-metadata': {}, + mapping: {}, + }; + const csvLookup = CSVLookup(pluginSettings); expect(csvLookup).toHaveProperty('metadata'); expect(csvLookup).toHaveProperty('execute'); }); @@ -54,7 +59,12 @@ describe('builtins/CSVLookup: ', () => { }, output: ['cpu-tdp', 'tdp'], }; - const csvLookup = CSVLookup(globalConfig); + const pluginSettings = { + 'global-config': globalConfig, + 'parameter-metadata': {}, + mapping: {}, + }; + const csvLookup = CSVLookup(pluginSettings); const responseData = `cpu-cores-available,cpu-cores-utilized,cpu-manufacturer,cpu-model-name,cpu-tdp,gpu-count,gpu-model-name,Hardware Information on AWS Documentation & Comments,instance-class,instance-storage,memory-available,platform-memory,release-date,storage-drives 16,8,AWS,AWS Graviton,150.00,N/A,N/A,AWS Graviton (ARM),a1.2xlarge,EBS-Only,16,32,November 2018,0 @@ -93,7 +103,12 @@ describe('builtins/CSVLookup: ', () => { }, output: ['cpu-tdp', 'tdp'], }; - const csvLookup = CSVLookup(globalConfig); + const pluginSettings = { + 'global-config': globalConfig, + 'parameter-metadata': {}, + mapping: {}, + }; + const csvLookup = CSVLookup(pluginSettings); const result = await csvLookup.execute([ { @@ -126,7 +141,12 @@ describe('builtins/CSVLookup: ', () => { }, output: ['cpu-tdp', 'tdp'], }; - const csvLookup = CSVLookup(globalConfig); + const pluginSettings = { + 'global-config': globalConfig, + 'parameter-metadata': {}, + mapping: {}, + }; + const csvLookup = CSVLookup(pluginSettings); const input = [ { timestamp: '2024-03-01', @@ -155,7 +175,12 @@ describe('builtins/CSVLookup: ', () => { }, output: ['cpu-tdp', 'tdp'], }; - const csvLookup = CSVLookup(globalConfig); + const pluginSettings = { + 'global-config': globalConfig, + 'parameter-metadata': {}, + mapping: {}, + }; + const csvLookup = CSVLookup(pluginSettings); const input = [ { timestamp: '2024-03-01', @@ -187,7 +212,12 @@ describe('builtins/CSVLookup: ', () => { }; mock.onGet(globalConfig.filepath).reply(404); - const csvLookup = CSVLookup(globalConfig); + const pluginSettings = { + 'global-config': globalConfig, + 'parameter-metadata': {}, + mapping: {}, + }; + const csvLookup = CSVLookup(pluginSettings); const input = [ { timestamp: '2024-03-01', @@ -217,7 +247,12 @@ describe('builtins/CSVLookup: ', () => { }, output: '*', }; - const csvLookup = CSVLookup(globalConfig); + const pluginSettings = { + 'global-config': globalConfig, + 'parameter-metadata': {}, + mapping: {}, + }; + const csvLookup = CSVLookup(pluginSettings); const result = await csvLookup.execute([ { @@ -265,7 +300,12 @@ describe('builtins/CSVLookup: ', () => { ['gpu-model-name', 'gpumodel'], ], }; - const csvLookup = CSVLookup(globalConfig); + const pluginSettings = { + 'global-config': globalConfig, + 'parameter-metadata': {}, + mapping: {}, + }; + const csvLookup = CSVLookup(pluginSettings); const result = await csvLookup.execute([ { @@ -300,7 +340,12 @@ describe('builtins/CSVLookup: ', () => { }, output: 'gpu-count', }; - const csvLookup = CSVLookup(globalConfig); + const pluginSettings = { + 'global-config': globalConfig, + 'parameter-metadata': {}, + mapping: {}, + }; + const csvLookup = CSVLookup(pluginSettings); const result = await csvLookup.execute([ { @@ -334,8 +379,12 @@ describe('builtins/CSVLookup: ', () => { }, output: ['cpu-tdp', 'tdp'], }; - - const csvLookup = CSVLookup(globalConfig); + const pluginSettings = { + 'global-config': globalConfig, + 'parameter-metadata': {}, + mapping: {}, + }; + const csvLookup = CSVLookup(pluginSettings); const input = [ { timestamp: '2024-03-01', @@ -360,7 +409,7 @@ describe('builtins/CSVLookup: ', () => { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore - const csvLookup = CSVLookup(); + const csvLookup = CSVLookup({}); const input = [ { timestamp: '2024-03-01', @@ -392,7 +441,12 @@ describe('builtins/CSVLookup: ', () => { }, output: 'mock', }; - const csvLookup = CSVLookup(globalConfig); + const pluginSettings = { + 'global-config': globalConfig, + 'parameter-metadata': {}, + mapping: {}, + }; + const csvLookup = CSVLookup(pluginSettings); const input = [ { timestamp: '2024-03-01', @@ -425,7 +479,12 @@ describe('builtins/CSVLookup: ', () => { }, output: ['gpu-count'], }; - const csvLookup = CSVLookup(globalConfig); + const pluginSettings = { + 'global-config': globalConfig, + 'parameter-metadata': {}, + mapping: {}, + }; + const csvLookup = CSVLookup(pluginSettings); const result = await csvLookup.execute([ { @@ -459,7 +518,12 @@ describe('builtins/CSVLookup: ', () => { }, output: [['gpu-count']], }; - const csvLookup = CSVLookup(globalConfig); + const pluginSettings = { + 'global-config': globalConfig, + 'parameter-metadata': {}, + mapping: {}, + }; + const csvLookup = CSVLookup(pluginSettings); const result = await csvLookup.execute([ { @@ -495,7 +559,12 @@ describe('builtins/CSVLookup: ', () => { }, output: [['gpu-count']], }; - const csvLookup = CSVLookup(globalConfig); + const pluginSettings = { + 'global-config': globalConfig, + 'parameter-metadata': {}, + mapping: {}, + }; + const csvLookup = CSVLookup(pluginSettings); try { await csvLookup.execute([ diff --git a/src/__tests__/if-run/builtins/divide.test.ts b/src/__tests__/if-run/builtins/divide.test.ts index e0a472998..3f5bc78a8 100644 --- a/src/__tests__/if-run/builtins/divide.test.ts +++ b/src/__tests__/if-run/builtins/divide.test.ts @@ -14,11 +14,12 @@ describe('builtins/divide: ', () => { denominator: 2, output: 'cpu/number-cores', }; - const parametersMetadata = { - inputs: {}, - outputs: {}, + const pluginSettings = { + 'global-config': globalConfig, + 'parameter-metadata': {}, + mapping: {}, }; - const divide = Divide(globalConfig, parametersMetadata); + const divide = Divide(pluginSettings); describe('init: ', () => { it('successfully initalized.', () => { @@ -58,7 +59,12 @@ describe('builtins/divide: ', () => { denominator: 'duration', output: 'vcpus-allocated-per-second', }; - const divide = Divide(globalConfig, parametersMetadata); + const pluginSettings = { + 'global-config': globalConfig, + 'parameter-metadata': {}, + mapping: {}, + }; + const divide = Divide(pluginSettings); const input = [ { @@ -90,7 +96,12 @@ describe('builtins/divide: ', () => { denominator: 3600, output: 'vcpus-allocated-per-second', }; - const divide = Divide(globalConfig, parametersMetadata); + const pluginSettings = { + 'global-config': globalConfig, + 'parameter-metadata': {}, + mapping: {}, + }; + const divide = Divide(pluginSettings); expect.assertions(1); @@ -111,7 +122,12 @@ describe('builtins/divide: ', () => { it('throws an error on missing global config.', async () => { const config = undefined; - const divide = Divide(config!, parametersMetadata); + const pluginSettings = { + 'global-config': config!, + 'parameter-metadata': {}, + mapping: {}, + }; + const divide = Divide(pluginSettings); expect.assertions(1); @@ -135,7 +151,12 @@ describe('builtins/divide: ', () => { denominator: 0, output: 'vcpus-allocated-per-second', }; - const divide = Divide(globalConfig, parametersMetadata); + const pluginSettings = { + 'global-config': globalConfig, + 'parameter-metadata': {}, + mapping: {}, + }; + const divide = Divide(pluginSettings); expect.assertions(1); @@ -163,7 +184,12 @@ describe('builtins/divide: ', () => { denominator: '10', output: 'vcpus-allocated-per-second', }; - const divide = Divide(globalConfig, parametersMetadata); + const pluginSettings = { + 'global-config': globalConfig, + 'parameter-metadata': {}, + mapping: {}, + }; + const divide = Divide(pluginSettings); expect.assertions(1); diff --git a/src/__tests__/if-run/builtins/exponent.test.ts b/src/__tests__/if-run/builtins/exponent.test.ts index 2e0419686..c8d00a255 100644 --- a/src/__tests__/if-run/builtins/exponent.test.ts +++ b/src/__tests__/if-run/builtins/exponent.test.ts @@ -11,11 +11,12 @@ describe('builtins/exponent: ', () => { exponent: 3, 'output-parameter': 'energy', }; - const parametersMetadata = { - inputs: {}, - outputs: {}, + const pluginSettings = { + 'global-config': globalConfig, + 'parameter-metadata': {}, + mapping: {}, }; - const exponent = Exponent(globalConfig, parametersMetadata); + const exponent = Exponent(pluginSettings); describe('init: ', () => { it('successfully initalized.', () => { @@ -95,7 +96,12 @@ describe('builtins/exponent: ', () => { exponent: 4, 'output-parameter': 'carbon', }; - const exponent = Exponent(newConfig, parametersMetadata); + const pluginSettings = { + 'global-config': newConfig, + 'parameter-metadata': {}, + mapping: {}, + }; + const exponent = Exponent(pluginSettings); const data = [ { diff --git a/src/__tests__/if-run/builtins/interpolation.test.ts b/src/__tests__/if-run/builtins/interpolation.test.ts index 6634556dd..1bd135aaa 100644 --- a/src/__tests__/if-run/builtins/interpolation.test.ts +++ b/src/__tests__/if-run/builtins/interpolation.test.ts @@ -22,9 +22,10 @@ describe('builtins/interpolation: ', () => { 'input-parameter': 'cpu/utilization', 'output-parameter': 'interpolation-result', }; - const parametersMetadata = { - inputs: {}, - outputs: {}, + const pluginSettings = { + 'global-config': globalConfig, + 'parameter-metadata': {}, + mapping: {}, }; const inputs = [ { @@ -33,7 +34,7 @@ describe('builtins/interpolation: ', () => { 'cpu/utilization': 45, }, ]; - const plugin = Interpolation(globalConfig, parametersMetadata); + const plugin = Interpolation(pluginSettings); describe('init Interpolation: ', () => { it('initalizes object with properties.', async () => { @@ -63,7 +64,12 @@ describe('builtins/interpolation: ', () => { 'input-parameter': 'cpu/utilization', 'output-parameter': 'interpolation-result', }; - const plugin = Interpolation(globalConfig, parametersMetadata); + const pluginSettings = { + 'global-config': globalConfig, + 'parameter-metadata': {}, + mapping: {}, + }; + const plugin = Interpolation(pluginSettings); const outputs = [ { @@ -79,7 +85,12 @@ describe('builtins/interpolation: ', () => { it('returns result when the `method` is `spline`.', () => { const config = Object.assign({}, globalConfig, {method: Method.SPLINE}); - const plugin = Interpolation(config, parametersMetadata); + const pluginSettings = { + 'global-config': config, + 'parameter-metadata': {}, + mapping: {}, + }; + const plugin = Interpolation(pluginSettings); const outputs = [ { @@ -97,7 +108,12 @@ describe('builtins/interpolation: ', () => { const config = Object.assign({}, globalConfig, { method: Method.POLYNOMIAL, }); - const plugin = Interpolation(config, parametersMetadata); + const pluginSettings = { + 'global-config': config, + 'parameter-metadata': {}, + mapping: {}, + }; + const plugin = Interpolation(pluginSettings); const outputs = [ { @@ -115,7 +131,12 @@ describe('builtins/interpolation: ', () => { const config = Object.assign({}, globalConfig, { x: [0, 10, 100, 50], }); - const plugin = Interpolation(config, parametersMetadata); + const pluginSettings = { + 'global-config': config, + 'parameter-metadata': {}, + mapping: {}, + }; + const plugin = Interpolation(pluginSettings); const outputs = [ { @@ -151,7 +172,12 @@ describe('builtins/interpolation: ', () => { it('throws an when the global config is not provided.', () => { const config = undefined; - const plugin = Interpolation(config!, parametersMetadata); + const pluginSettings = { + 'global-config': config!, + 'parameter-metadata': {}, + mapping: {}, + }; + const plugin = Interpolation(pluginSettings); expect.assertions(2); try { @@ -167,7 +193,12 @@ describe('builtins/interpolation: ', () => { x: [0, 10, 100], }); - const plugin = Interpolation(config, parametersMetadata); + const pluginSettings = { + 'global-config': config, + 'parameter-metadata': {}, + mapping: {}, + }; + const plugin = Interpolation(pluginSettings); expect.assertions(2); try { @@ -202,7 +233,12 @@ describe('builtins/interpolation: ', () => { 'output-parameter': 'interpolation-result', }; const config = Object.assign({}, globalConfig, {method: Method.SPLINE}); - const plugin = Interpolation(config, parametersMetadata); + const pluginSettings = { + 'global-config': config, + 'parameter-metadata': {}, + mapping: {}, + }; + const plugin = Interpolation(pluginSettings); const inputs = [ { timestamp: '2023-07-06T00:00', diff --git a/src/__tests__/if-run/builtins/mock-observations.test.ts b/src/__tests__/if-run/builtins/mock-observations.test.ts index 6b0fb22bd..ac2f2409a 100644 --- a/src/__tests__/if-run/builtins/mock-observations.test.ts +++ b/src/__tests__/if-run/builtins/mock-observations.test.ts @@ -10,7 +10,7 @@ const {INVALID_MIN_MAX} = STRINGS; describe('builtins/mock-observations: ', () => { describe('init: ', () => { it('successfully initalized.', () => { - const mockObservations = MockObservations({ + const globalConfig = { 'timestamp-from': '2023-07-06T00:00', 'timestamp-to': '2023-07-06T00:01', duration: 5, @@ -25,7 +25,13 @@ describe('builtins/mock-observations: ', () => { 'memory/utilization': {min: 10, max: 85}, }, }, - }); + }; + const pluginSettings = { + 'global-config': globalConfig, + 'parameter-metadata': {}, + mapping: {}, + }; + const mockObservations = MockObservations(pluginSettings); expect(mockObservations).toHaveProperty('metadata'); expect(mockObservations).toHaveProperty('execute'); @@ -49,7 +55,12 @@ describe('builtins/mock-observations: ', () => { }, }, }; - const mockObservations = MockObservations(config); + const pluginSettings = { + 'global-config': config, + 'parameter-metadata': {}, + mapping: {}, + }; + const mockObservations = MockObservations(pluginSettings); const result = await mockObservations.execute([]); expect.assertions(1); @@ -106,10 +117,15 @@ describe('builtins/mock-observations: ', () => { }, }, }; + const pluginSettings = { + 'global-config': config, + 'parameter-metadata': {}, + mapping: {}, + }; expect.assertions(2); - const mockObservations = MockObservations(config); + const mockObservations = MockObservations(pluginSettings); try { await mockObservations.execute([]); } catch (error) { @@ -127,11 +143,16 @@ describe('builtins/mock-observations: ', () => { duration: 5, components: [{'instance-type': 'A1'}, {'instance-type': 'B1'}], }; + const pluginSettings = { + 'global-config': config, + 'parameter-metadata': {}, + mapping: {}, + }; expect.assertions(2); try { - const mockObservations = MockObservations(config); + const mockObservations = MockObservations(pluginSettings); await mockObservations.execute([]); } catch (error) { expect(error).toBeInstanceOf(InputValidationError); @@ -161,11 +182,16 @@ describe('builtins/mock-observations: ', () => { }, }, }; + const pluginSettings = { + 'global-config': config, + 'parameter-metadata': {}, + mapping: {}, + }; expect.assertions(2); try { - const mockObservations = MockObservations(config); + const mockObservations = MockObservations(pluginSettings); await mockObservations.execute([]); } catch (error) { expect(error).toBeInstanceOf(InputValidationError); @@ -177,7 +203,7 @@ describe('builtins/mock-observations: ', () => { expect.assertions(2); try { - const mockObservations = MockObservations({ + const globalConfig = { 'timestamp-from': '2023-07-06T00:00', 'timestamp-to': '2023-07-06T00:01', components: [{'instance-type': 'A1'}, {'instance-type': 'B1'}], @@ -191,7 +217,13 @@ describe('builtins/mock-observations: ', () => { 'memory/utilization': {min: 10, max: 85}, }, }, - }); + }; + const pluginSettings = { + 'global-config': globalConfig, + 'parameter-metadata': {}, + mapping: {}, + }; + const mockObservations = MockObservations(pluginSettings); await mockObservations.execute([]); } catch (error) { expect(error).toBeInstanceOf(InputValidationError); @@ -207,7 +239,7 @@ describe('builtins/mock-observations: ', () => { expect.assertions(2); try { - const mockObservations = MockObservations({ + const globalConfig = { 'timestamp-from': '2023-07-06T00:00', duration: 5, components: [{'instance-type': 'A1'}, {'instance-type': 'B1'}], @@ -221,7 +253,13 @@ describe('builtins/mock-observations: ', () => { 'memory/utilization': {min: 10, max: 85}, }, }, - }); + }; + const pluginSettings = { + 'global-config': globalConfig, + 'parameter-metadata': {}, + mapping: {}, + }; + const mockObservations = MockObservations(pluginSettings); await mockObservations.execute([]); } catch (error) { expect(error).toBeInstanceOf(InputValidationError); @@ -237,7 +275,7 @@ describe('builtins/mock-observations: ', () => { expect.assertions(2); try { - const mockObservations = MockObservations({ + const globalConfig = { 'timestamp-to': '2023-07-06T00:01', duration: 5, components: [{'instance-type': 'A1'}, {'instance-type': 'B1'}], @@ -251,7 +289,13 @@ describe('builtins/mock-observations: ', () => { 'memory/utilization': {min: 10, max: 85}, }, }, - }); + }; + const pluginSettings = { + 'global-config': globalConfig, + 'parameter-metadata': {}, + mapping: {}, + }; + const mockObservations = MockObservations(pluginSettings); await mockObservations.execute([]); } catch (error) { expect(error).toBeInstanceOf(InputValidationError); @@ -277,7 +321,12 @@ describe('builtins/mock-observations: ', () => { randint: null, }, }; - const mockObservations = MockObservations(config); + const pluginSettings = { + 'global-config': config, + 'parameter-metadata': {}, + mapping: {}, + }; + const mockObservations = MockObservations(pluginSettings); expect.assertions(2); @@ -307,7 +356,12 @@ describe('builtins/mock-observations: ', () => { }, }, }; - const mockObservations = MockObservations(config); + const pluginSettings = { + 'global-config': config, + 'parameter-metadata': {}, + mapping: {}, + }; + const mockObservations = MockObservations(pluginSettings); expect.assertions(2); diff --git a/src/__tests__/if-run/builtins/multiply.test.ts b/src/__tests__/if-run/builtins/multiply.test.ts index b3856dfd4..b07ff7734 100644 --- a/src/__tests__/if-run/builtins/multiply.test.ts +++ b/src/__tests__/if-run/builtins/multiply.test.ts @@ -10,11 +10,12 @@ describe('builtins/multiply: ', () => { 'input-parameters': ['cpu/energy', 'network/energy', 'memory/energy'], 'output-parameter': 'energy', }; - const parametersMetadata = { - inputs: {}, - outputs: {}, + const pluginSettings = { + 'global-config': globalConfig, + 'parameter-metadata': {}, + mapping: {}, }; - const multiply = Multiply(globalConfig, parametersMetadata); + const multiply = Multiply(pluginSettings); describe('init: ', () => { it('successfully initalized.', () => { @@ -76,7 +77,8 @@ describe('builtins/multiply: ', () => { 'input-parameters': ['carbon', 'other-carbon'], 'output-parameter': 'carbon-product', }; - const multiply = Multiply(newConfig, parametersMetadata); + pluginSettings['global-config'] = newConfig; + const multiply = Multiply(pluginSettings); const data = [ { diff --git a/src/__tests__/if-run/builtins/regex.test.ts b/src/__tests__/if-run/builtins/regex.test.ts index ea45c49d1..df0383d89 100644 --- a/src/__tests__/if-run/builtins/regex.test.ts +++ b/src/__tests__/if-run/builtins/regex.test.ts @@ -14,11 +14,12 @@ describe('builtins/regex: ', () => { match: '^[^,]+', output: 'cpu/name', }; - const parametersMetadata = { - inputs: {}, - outputs: {}, + const pluginSettings = { + 'global-config': globalConfig, + 'parameter-metadata': {}, + mapping: {}, }; - const regex = Regex(globalConfig, parametersMetadata); + const regex = Regex(pluginSettings); describe('init: ', () => { it('successfully initalized.', () => { @@ -59,7 +60,8 @@ describe('builtins/regex: ', () => { match: '/(?<=_)[^_]+?(?=_|$)/g', output: 'cloud/instance-type', }; - const regex = Regex(globalConfig, parametersMetadata); + pluginSettings['global-config'] = globalConfig; + const regex = Regex(pluginSettings); const expectedResult = [ { @@ -90,7 +92,8 @@ describe('builtins/regex: ', () => { match: '[^,]+/', output: 'cpu/name', }; - const regex = Regex(globalConfig, parametersMetadata); + pluginSettings['global-config'] = globalConfig; + const regex = Regex(pluginSettings); const expectedResult = [ { @@ -121,7 +124,8 @@ describe('builtins/regex: ', () => { match: '^(^:)+', output: 'cpu/name', }; - const regex = Regex(globalConfig, parametersMetadata); + pluginSettings['global-config'] = globalConfig; + const regex = Regex(pluginSettings); expect.assertions(1); @@ -144,7 +148,8 @@ describe('builtins/regex: ', () => { it('throws an error on missing global config.', async () => { const config = undefined; - const regex = Regex(config!, parametersMetadata); + pluginSettings['global-config'] = config!; + const regex = Regex(pluginSettings); expect.assertions(1); diff --git a/src/__tests__/if-run/builtins/sci-embodied.test.ts b/src/__tests__/if-run/builtins/sci-embodied.test.ts index 0e2c234f7..9daef9288 100644 --- a/src/__tests__/if-run/builtins/sci-embodied.test.ts +++ b/src/__tests__/if-run/builtins/sci-embodied.test.ts @@ -9,11 +9,11 @@ const {SCI_EMBODIED_ERROR} = STRINGS; describe('builtins/sci-embodied:', () => { describe('SciEmbodied: ', () => { - const parametersMetadata = { - inputs: {}, - outputs: {}, + const pluginSettings = { + 'parameter-metadata': {}, + mapping: {}, }; - const sciEmbodied = SciEmbodied(parametersMetadata); + const sciEmbodied = SciEmbodied(pluginSettings); describe('init: ', () => { it('successfully initalized.', () => { diff --git a/src/__tests__/if-run/builtins/sci.test.ts b/src/__tests__/if-run/builtins/sci.test.ts index 0360149a9..1c74ec4fc 100644 --- a/src/__tests__/if-run/builtins/sci.test.ts +++ b/src/__tests__/if-run/builtins/sci.test.ts @@ -6,11 +6,12 @@ const {MissingInputDataError} = ERRORS; describe('builtins/sci:', () => { describe('Sci: ', () => { - const parametersMetadata = { - inputs: {}, - outputs: {}, + const pluginSettings = { + 'global-config': {'functional-unit': 'users'}, + 'parameter-metadata': {}, + mapping: {}, }; - const sci = Sci({'functional-unit': 'users'}, parametersMetadata); + const sci = Sci(pluginSettings); describe('init: ', () => { it('successfully initalized.', () => { @@ -21,12 +22,7 @@ describe('builtins/sci:', () => { describe('execute():', () => { it('returns a result with valid inputs.', async () => { - const sci = Sci( - { - 'functional-unit': 'users', - }, - parametersMetadata - ); + const sci = Sci(pluginSettings); const inputs = [ { timestamp: '2021-01-01T00:00:00Z', @@ -55,12 +51,8 @@ describe('builtins/sci:', () => { }); it('returns the same result regardless of input duration.', async () => { - const sci = Sci( - { - 'functional-unit': 'requests', - }, - parametersMetadata - ); + pluginSettings['global-config'] = {'functional-unit': 'requests'}; + const sci = Sci(pluginSettings); const inputs = [ { timestamp: '2021-01-01T00:00:00Z', @@ -106,12 +98,8 @@ describe('builtins/sci:', () => { }); it('throws exception on invalid functional unit data.', async () => { - const sci = Sci( - { - 'functional-unit': 'requests', - }, - parametersMetadata - ); + pluginSettings['global-config'] = {'functional-unit': 'requests'}; + const sci = Sci(pluginSettings); const inputs = [ { timestamp: '2021-01-01T00:00:00Z', @@ -131,12 +119,8 @@ describe('builtins/sci:', () => { }); it('throws exception if functional unit value is not positive integer.', async () => { - const sci = Sci( - { - 'functional-unit': 'requests', - }, - parametersMetadata - ); + pluginSettings['global-config'] = {'functional-unit': 'requests'}; + const sci = Sci(pluginSettings); const inputs = [ { timestamp: '2021-01-01T00:00:00Z', @@ -158,12 +142,8 @@ describe('builtins/sci:', () => { }); it('fallbacks to carbon value, if functional unit is 0.', async () => { - const sci = Sci( - { - 'functional-unit': 'requests', - }, - parametersMetadata - ); + pluginSettings['global-config'] = {'functional-unit': 'requests'}; + const sci = Sci(pluginSettings); const inputs = [ { timestamp: '2021-01-01T00:00:00Z', diff --git a/src/__tests__/if-run/builtins/shell.test.ts b/src/__tests__/if-run/builtins/shell.test.ts index 379863052..ad5ce6689 100644 --- a/src/__tests__/if-run/builtins/shell.test.ts +++ b/src/__tests__/if-run/builtins/shell.test.ts @@ -11,7 +11,12 @@ jest.mock('js-yaml'); describe('builtins/shell', () => { describe('Shell', () => { - const shell = Shell({}); + const pluginSettings = { + 'global-config': {command: 'python3 /path/to/script.py'}, + 'parameter-metadata': {}, + mapping: {}, + }; + const shell = Shell({'global-config': {}}); describe('init: ', () => { it('successfully initalized.', () => { @@ -22,7 +27,7 @@ describe('builtins/shell', () => { describe('execute(): ', () => { it('execute with valid inputs and command', async () => { - const shell = Shell({command: 'python3 /path/to/script.py'}); + const shell = Shell(pluginSettings); const mockSpawnSync = spawnSync as jest.MockedFunction< typeof spawnSync >; @@ -57,6 +62,7 @@ describe('builtins/shell', () => { {duration: 3600, timestamp: '2022-01-01T00:00:00Z', command: 123}, ]; + expect.assertions(2); try { await shell.execute(invalidInputs); } catch (error) { @@ -70,7 +76,7 @@ describe('builtins/shell', () => { }); it('throw an error when shell could not run command.', async () => { - const shell = Shell({command: 'python3 /path/to/script.py'}); + const shell = Shell(pluginSettings); (spawnSync as jest.Mock).mockImplementation(() => { throw new InputValidationError('Could not run the command'); }); diff --git a/src/__tests__/if-run/builtins/subtract.test.ts b/src/__tests__/if-run/builtins/subtract.test.ts index 134cebfa7..bd4b50e9e 100644 --- a/src/__tests__/if-run/builtins/subtract.test.ts +++ b/src/__tests__/if-run/builtins/subtract.test.ts @@ -10,11 +10,12 @@ describe('builtins/subtract: ', () => { 'input-parameters': ['cpu/energy', 'network/energy', 'memory/energy'], 'output-parameter': 'energy/diff', }; - const parametersMetadata = { - inputs: {}, - outputs: {}, + const pluginSettings = { + 'global-config': globalConfig, + 'parameter-metadata': {}, + mapping: {}, }; - const subtract = Subtract(globalConfig, parametersMetadata); + const subtract = Subtract(pluginSettings); describe('init: ', () => { it('successfully initalized.', () => { @@ -76,7 +77,8 @@ describe('builtins/subtract: ', () => { 'input-parameters': ['carbon', 'other-carbon'], 'output-parameter': 'carbon-diff', }; - const subtract = Subtract(newConfig, parametersMetadata); + pluginSettings['global-config'] = newConfig; + const subtract = Subtract(pluginSettings); const data = [ { diff --git a/src/__tests__/if-run/builtins/sum.test.ts b/src/__tests__/if-run/builtins/sum.test.ts index 9ccc64378..10686471c 100644 --- a/src/__tests__/if-run/builtins/sum.test.ts +++ b/src/__tests__/if-run/builtins/sum.test.ts @@ -13,11 +13,12 @@ describe('builtins/sum: ', () => { 'input-parameters': ['cpu/energy', 'network/energy', 'memory/energy'], 'output-parameter': 'energy', }; - const parametersMetadata = { - inputs: {}, - outputs: {}, + const pluginSettings = { + 'global-config': globalConfig, + 'parameter-metadata': {}, + mapping: {}, }; - const sum = Sum(globalConfig, parametersMetadata); + const sum = Sum(pluginSettings); describe('init: ', () => { it('successfully initalized.', () => { @@ -54,9 +55,43 @@ describe('builtins/sum: ', () => { expect(result).toStrictEqual(expectedResult); }); + it('successfully executes when mapping has valid data.', () => { + expect.assertions(1); + pluginSettings.mapping = { + 'cpu/energy': 'energy-from-cpu', + 'network/energy': 'energy-from-network', + }; + + const sum = Sum(pluginSettings); + + const expectedResult = [ + { + timestamp: '2021-01-01T00:00:00Z', + duration: 3600, + 'energy-from-cpu': 1, + 'energy-from-network': 1, + 'memory/energy': 1, + energy: 3, + }, + ]; + + const result = sum.execute([ + { + timestamp: '2021-01-01T00:00:00Z', + duration: 3600, + 'cpu/energy': 1, + 'network/energy': 1, + 'memory/energy': 1, + }, + ]); + + expect(result).toStrictEqual(expectedResult); + }); + it('throws an error when global config is not provided.', () => { const config = undefined; - const sum = Sum(config!, parametersMetadata); + pluginSettings['global-config'] = config!; + const sum = Sum(pluginSettings); expect.assertions(1); @@ -102,7 +137,8 @@ describe('builtins/sum: ', () => { 'input-parameters': ['carbon', 'other-carbon'], 'output-parameter': 'carbon-sum', }; - const sum = Sum(newConfig, parametersMetadata); + pluginSettings['global-config'] = newConfig; + const sum = Sum(pluginSettings); const data = [ { diff --git a/src/__tests__/if-run/builtins/time-sync.test.ts b/src/__tests__/if-run/builtins/time-sync.test.ts index e216690df..10a2e3489 100644 --- a/src/__tests__/if-run/builtins/time-sync.test.ts +++ b/src/__tests__/if-run/builtins/time-sync.test.ts @@ -76,7 +76,12 @@ describe('builtins/time-sync:', () => { 'allow-padding': true, }; - const timeSync = TimeSync(basicConfig); + const pluginSettings = { + 'global-config': basicConfig, + 'parameter-metadata': {}, + mapping: {}, + }; + const timeSync = TimeSync(pluginSettings); describe('init: ', () => { it('successfully initalized.', () => { @@ -84,715 +89,726 @@ describe('builtins/time-sync:', () => { expect(timeSync).toHaveProperty('execute'); }); }); - }); -}); - -describe('execute(): ', () => { - it('throws error if `start-time` is missing.', async () => { - const invalidStartTimeConfig = { - 'start-time': '', - 'end-time': '2023-12-12T00:01:00.000Z', - interval: 5, - 'allow-padding': true, - }; - - const timeModel = TimeSync(invalidStartTimeConfig); - - expect.assertions(1); - - try { - await timeModel.execute([ - { - timestamp: '2023-12-12T00:00:00.000Z', - duration: 10, - 'cpu/utilization': 10, - }, - { - timestamp: '2023-12-12T00:00:10.000Z', - duration: 30, - 'cpu/utilization': 20, - }, - ]); - } catch (error) { - expect(error).toStrictEqual( - new InputValidationError( - '"start-time" parameter is invalid datetime. Error code: invalid_string.' - ) - ); - } - }); - - it('throws error if `end-time` is missing.', async () => { - const errorMessage = - '"end-time" parameter is invalid datetime. Error code: invalid_string.,`start-time` should be lower than `end-time`'; - const invalidEndTimeConfig = { - 'start-time': '2023-12-12T00:01:00.000Z', - 'end-time': '', - interval: 5, - 'allow-padding': true, - }; - const timeModel = TimeSync(invalidEndTimeConfig); - - expect.assertions(1); - - try { - await timeModel.execute([ - { - timestamp: '2023-12-12T00:00:00.000Z', - duration: 10, - 'cpu/utilization': 10, - }, - { - timestamp: '2023-12-12T00:00:10.000Z', - duration: 30, - 'cpu/utilization': 20, - }, - ]); - } catch (error) { - expect(error).toStrictEqual(new InputValidationError(errorMessage)); - } - }); - - it('fails if `start-time` is not a valid ISO date.', async () => { - const invalidStartTimeConfig = { - 'start-time': '0023-X', - 'end-time': '2023-12-12T00:01:00.000Z', - interval: 5, - 'allow-padding': true, - }; - const timeModel = TimeSync(invalidStartTimeConfig); - expect.assertions(1); - try { - await timeModel.execute([ - { - timestamp: '2023-12-12T00:00:00.000Z', - duration: 10, - 'cpu/utilization': 10, - }, - ]); - } catch (error) { - expect(error).toStrictEqual( - new InputValidationError( - '"start-time" parameter is invalid datetime. Error code: invalid_string.' - ) - ); - } - }); - - it('fails if `end-time` is not a valid ISO date.', async () => { - const invalidEndTimeConfig = { - 'start-time': '2023-12-12T00:01:00.000Z', - 'end-time': '20XX', - interval: 5, - 'allow-padding': true, - }; - const timeModel = TimeSync(invalidEndTimeConfig); - - expect.assertions(1); - try { - await timeModel.execute([ - { - timestamp: '2023-12-12T00:00:00.000Z', - duration: 10, - 'cpu/utilization': 10, - }, - ]); - } catch (error) { - expect(error).toStrictEqual( - new InputValidationError( - '"end-time" parameter is invalid datetime. Error code: invalid_string.' - ) - ); - } - }); - - it('throws error on missing global config.', async () => { - const config = undefined; - const timeModel = TimeSync(config!); - - expect.assertions(1); - - try { - await timeModel.execute([ - { - timestamp: '2023-12-12T00:00:00.000Z', - duration: 15, - 'cpu/utilization': 10, - }, - { - timestamp: '2023-12-12T00:00:10.000Z', - duration: 30, - 'cpu/utilization': 20, - }, - ]); - } catch (error) { - expect(error).toStrictEqual( - new GlobalConfigError(INVALID_TIME_NORMALIZATION) - ); - } - }); - - it('throws error if interval is invalid.', async () => { - const invalidIntervalConfig = { - 'start-time': '2023-12-12T00:00:00.000Z', - 'end-time': '2023-12-12T00:01:00.000Z', - interval: 0, - 'allow-padding': true, - }; - - const timeModel = TimeSync(invalidIntervalConfig); - - expect.assertions(1); - - try { - await timeModel.execute([ - { - timestamp: '2023-12-12T00:00:00.000Z', - duration: 15, - 'cpu/utilization': 10, - }, - { - timestamp: '2023-12-12T00:00:10.000Z', - duration: 30, - 'cpu/utilization': 20, - }, - ]); - } catch (error) { - expect(error).toStrictEqual( - new InvalidInputError(INVALID_OBSERVATION_OVERLAP) - ); - } - }); - - it('throws error if timestamps overlap.', async () => { - const basicConfig = { - 'start-time': '2023-12-12T00:00:00.000Z', - 'end-time': '2023-12-12T00:01:00.000Z', - interval: 5, - 'allow-padding': true, - }; - - const timeModel = TimeSync(basicConfig); - - try { - await timeModel.execute([ - { - timestamp: '2023-12-12T00:00:00.000Z', - duration: 15, - 'cpu/utilization': 10, - }, - { - timestamp: '2023-12-12T00:00:10.000Z', - duration: 30, - 'cpu/utilization': 20, - }, - ]); - } catch (error) { - expect(error).toStrictEqual( - new InvalidInputError(INVALID_OBSERVATION_OVERLAP) - ); - } - }); - - it('throws error if `timestamp` is missing.', async () => { - const basicConfig = { - 'start-time': '2023-12-12T00:00:00.000Z', - 'end-time': '2023-12-12T00:01:00.000Z', - interval: 5, - 'allow-padding': true, - }; - - const timeModel = TimeSync(basicConfig); - - try { - await timeModel.execute([ - { - duration: 15, - 'cpu/utilization': 10, - }, - { - timestamp: '2023-12-12T00:00:10.000Z', - duration: 30, - 'cpu/utilization': 20, - }, - ]); - } catch (error) { - expect(error).toBeInstanceOf(InputValidationError); - expect(error).toStrictEqual( - new InputValidationError( - '"timestamp" parameter is required in input[0]. Error code: invalid_union.' - ) - ); - } - }); - - it('throws error if the seconds `timestamp` is above 60.', async () => { - const basicConfig = { - 'start-time': '2023-12-12T00:00:00.000Z', - 'end-time': '2023-12-12T00:01:00.000Z', - interval: 5, - 'allow-padding': true, - }; - - const timeModel = TimeSync(basicConfig); - - try { - await timeModel.execute([ - { - timestamp: '2023-12-12T00:00:90.000Z', - duration: 15, - 'cpu/utilization': 10, - }, - { - timestamp: '2023-12-12T00:00:10.000Z', - duration: 30, - 'cpu/utilization': 20, - }, - ]); - } catch (error) { - expect(error).toBeInstanceOf(InputValidationError); - expect(error).toStrictEqual( - new InputValidationError( - '"timestamp" parameter is required in input[0]. Error code: invalid_union.' - ) - ); - } - }); - - it('throws an error if the `timestamp` is not valid date.', async () => { - const basicConfig = { - 'start-time': '2023-12-12T00:00:00.000Z', - 'end-time': '2023-12-12T00:01:00.000Z', - interval: 10, - 'allow-padding': true, - }; - const data = [ - { - timestamp: 45, - duration: 10, - 'cpu/utilization': 10, - }, - ]; - - const timeModel = TimeSync(basicConfig); - expect.assertions(2); - - try { - await timeModel.execute(data); - } catch (error) { - expect(error).toBeInstanceOf(InvalidDateInInputError); - expect(error).toStrictEqual( - new InvalidDateInInputError(INVALID_DATE_TYPE(data[0].timestamp)) - ); - } - }); - - it('throws error if end is before start in global config.', async () => { - const basicConfig = { - 'start-time': '2023-12-12T00:00:10.000Z', - 'end-time': '2023-12-12T00:00:00.000Z', - interval: 5, - 'allow-padding': true, - }; - - const timeModel = TimeSync(basicConfig); - - try { - await timeModel.execute([ - { - timestamp: '2023-12-12T00:00:00.000Z', - duration: 15, - 'cpu/utilization': 10, - }, - { - timestamp: '2023-12-12T00:00:10.000Z', - duration: 30, - 'cpu/utilization': 20, - }, - ]); - } catch (error) { - expect(error).toStrictEqual( - new InputValidationError('`start-time` should be lower than `end-time`') - ); - } - }); - - it('converts Date objects to string outputs.', async () => { - const basicConfig = { - 'start-time': '2023-12-12T00:00:00.000Z', - 'end-time': '2023-12-12T00:00:01.000Z', - interval: 1, - 'allow-padding': false, - }; - - const timeModel = TimeSync(basicConfig); - - const result = await timeModel.execute([ - { - timestamp: '2023-12-12T00:00:00.000Z', - duration: 1, - 'cpu/utilization': 10, - }, - { - timestamp: new Date('2023-12-12T00:00:01.000Z'), - duration: 1, - 'cpu/utilization': 10, - }, - ]); - - const expectedResult = [ - { - timestamp: '2023-12-12T00:00:00.000Z', - duration: 1, - 'cpu/utilization': 10, - }, - { - timestamp: '2023-12-12T00:00:01.000Z', - duration: 1, - 'cpu/utilization': 10, - }, - ]; - - expect(result).toStrictEqual(expectedResult); - }); - - it('checks that metric (carbon) with aggregation-method == sum is properly spread over interpolated time points.', async () => { - const basicConfig = { - 'start-time': '2023-12-12T00:00:00.000Z', - 'end-time': '2023-12-12T00:00:10.000Z', - interval: 1, - 'allow-padding': true, - }; - - const timeModel = TimeSync(basicConfig); - - const result = await timeModel.execute([ - { - timestamp: '2023-12-12T00:00:00.000Z', - duration: 10, - carbon: 10, - }, - ]); - - const expectedResult = [ - { - timestamp: '2023-12-12T00:00:00.000Z', - duration: 1, - carbon: 1, - }, - { - timestamp: '2023-12-12T00:00:01.000Z', - duration: 1, - carbon: 1, - }, - { - timestamp: '2023-12-12T00:00:02.000Z', - duration: 1, - carbon: 1, - }, - { - timestamp: '2023-12-12T00:00:03.000Z', - duration: 1, - carbon: 1, - }, - { - timestamp: '2023-12-12T00:00:04.000Z', - duration: 1, - carbon: 1, - }, - { - timestamp: '2023-12-12T00:00:05.000Z', - duration: 1, - carbon: 1, - }, - { - timestamp: '2023-12-12T00:00:06.000Z', - duration: 1, - carbon: 1, - }, - { - timestamp: '2023-12-12T00:00:07.000Z', - duration: 1, - carbon: 1, - }, - { - timestamp: '2023-12-12T00:00:08.000Z', - duration: 1, - carbon: 1, - }, - { - timestamp: '2023-12-12T00:00:09.000Z', - duration: 1, - carbon: 1, - }, - ]; - - expect(result).toStrictEqual(expectedResult); - }); - - it('checks that constants are copied to results unchanged.', async () => { - const basicConfig = { - 'start-time': '2023-12-12T00:00:00.000Z', - 'end-time': '2023-12-12T00:00:09.000Z', - interval: 5, - 'allow-padding': true, - }; - - const timeModel = TimeSync(basicConfig); - const result = await timeModel.execute([ - { - timestamp: '2023-12-12T00:00:00.000Z', - duration: 3, - 'resources-total': 10, - }, - { - timestamp: '2023-12-12T00:00:05.000Z', - duration: 3, - 'resources-total': 10, - }, - ]); - - /**In each 5 second interval, 60% of the time cpu/utilization = 10, 40% of the time it is 0, so cpu/utilization in the averaged result be 6 */ - const expectedResult = [ - { - timestamp: '2023-12-12T00:00:00.000Z', - duration: 5, - 'resources-total': 10, - }, - { - timestamp: '2023-12-12T00:00:05.000Z', - duration: 5, - 'resources-total': 10, - }, - ]; + describe('execute(): ', () => { + it('throws error if `start-time` is missing.', async () => { + const invalidStartTimeConfig = { + 'start-time': '', + 'end-time': '2023-12-12T00:01:00.000Z', + interval: 5, + 'allow-padding': true, + }; + pluginSettings['global-config'] = invalidStartTimeConfig; + const timeModel = TimeSync(pluginSettings); + + expect.assertions(1); + + try { + await timeModel.execute([ + { + timestamp: '2023-12-12T00:00:00.000Z', + duration: 10, + 'cpu/utilization': 10, + }, + { + timestamp: '2023-12-12T00:00:10.000Z', + duration: 30, + 'cpu/utilization': 20, + }, + ]); + } catch (error) { + expect(error).toStrictEqual( + new InputValidationError( + '"start-time" parameter is invalid datetime. Error code: invalid_string.' + ) + ); + } + }); - expect(result).toStrictEqual(expectedResult); - }); + it('throws error if `end-time` is missing.', async () => { + const errorMessage = + '"end-time" parameter is invalid datetime. Error code: invalid_string.,`start-time` should be lower than `end-time`'; + const invalidEndTimeConfig = { + 'start-time': '2023-12-12T00:01:00.000Z', + 'end-time': '', + interval: 5, + 'allow-padding': true, + }; + pluginSettings['global-config'] = invalidEndTimeConfig; + const timeModel = TimeSync(pluginSettings); + + expect.assertions(1); + + try { + await timeModel.execute([ + { + timestamp: '2023-12-12T00:00:00.000Z', + duration: 10, + 'cpu/utilization': 10, + }, + { + timestamp: '2023-12-12T00:00:10.000Z', + duration: 30, + 'cpu/utilization': 20, + }, + ]); + } catch (error) { + expect(error).toStrictEqual(new InputValidationError(errorMessage)); + } + }); - it('returns a result when `time-reserved` persists.', async () => { - const basicConfig = { - 'start-time': '2023-12-12T00:00:00.000Z', - 'end-time': '2023-12-12T00:00:09.000Z', - interval: 5, - 'allow-padding': true, - }; + it('fails if `start-time` is not a valid ISO date.', async () => { + const invalidStartTimeConfig = { + 'start-time': '0023-X', + 'end-time': '2023-12-12T00:01:00.000Z', + interval: 5, + 'allow-padding': true, + }; + pluginSettings['global-config'] = invalidStartTimeConfig; + const timeModel = TimeSync(pluginSettings); + expect.assertions(1); + try { + await timeModel.execute([ + { + timestamp: '2023-12-12T00:00:00.000Z', + duration: 10, + 'cpu/utilization': 10, + }, + ]); + } catch (error) { + expect(error).toStrictEqual( + new InputValidationError( + '"start-time" parameter is invalid datetime. Error code: invalid_string.' + ) + ); + } + }); - const timeModel = TimeSync(basicConfig); + it('fails if `end-time` is not a valid ISO date.', async () => { + const invalidEndTimeConfig = { + 'start-time': '2023-12-12T00:01:00.000Z', + 'end-time': '20XX', + interval: 5, + 'allow-padding': true, + }; + pluginSettings['global-config'] = invalidEndTimeConfig; + const timeModel = TimeSync(pluginSettings); + + expect.assertions(1); + try { + await timeModel.execute([ + { + timestamp: '2023-12-12T00:00:00.000Z', + duration: 10, + 'cpu/utilization': 10, + }, + ]); + } catch (error) { + expect(error).toStrictEqual( + new InputValidationError( + '"end-time" parameter is invalid datetime. Error code: invalid_string.' + ) + ); + } + }); - const result = await timeModel.execute([ - { - timestamp: '2023-12-12T00:00:00.000Z', - duration: 3, - 'time-reserved': 5, - 'resources-total': 10, - }, - { - timestamp: '2023-12-12T00:00:05.000Z', - duration: 3, - 'time-reserved': 5, - 'resources-total': 10, - }, - ]); - - const expectedResult = [ - { - timestamp: '2023-12-12T00:00:00.000Z', - duration: 5, - 'resources-total': 10, - 'time-reserved': 3.2, - }, - { - timestamp: '2023-12-12T00:00:05.000Z', - duration: 5, - 'resources-total': 10, - 'time-reserved': 3.2, - }, - ]; + it('throws error on missing global config.', async () => { + const config = undefined; + pluginSettings['global-config'] = config!; + const timeModel = TimeSync(pluginSettings); + + expect.assertions(1); + + try { + await timeModel.execute([ + { + timestamp: '2023-12-12T00:00:00.000Z', + duration: 15, + 'cpu/utilization': 10, + }, + { + timestamp: '2023-12-12T00:00:10.000Z', + duration: 30, + 'cpu/utilization': 20, + }, + ]); + } catch (error) { + expect(error).toStrictEqual( + new GlobalConfigError(INVALID_TIME_NORMALIZATION) + ); + } + }); - expect(result).toStrictEqual(expectedResult); - }); + it('throws error if interval is invalid.', async () => { + const invalidIntervalConfig = { + 'start-time': '2023-12-12T00:00:00.000Z', + 'end-time': '2023-12-12T00:01:00.000Z', + interval: 0, + 'allow-padding': true, + }; + pluginSettings['global-config'] = invalidIntervalConfig; + const timeModel = TimeSync(pluginSettings); + + expect.assertions(1); + + try { + await timeModel.execute([ + { + timestamp: '2023-12-12T00:00:00.000Z', + duration: 15, + 'cpu/utilization': 10, + }, + { + timestamp: '2023-12-12T00:00:10.000Z', + duration: 30, + 'cpu/utilization': 20, + }, + ]); + } catch (error) { + expect(error).toStrictEqual( + new InvalidInputError(INVALID_OBSERVATION_OVERLAP) + ); + } + }); - it('throws an error when `start-time` is wrong.', async () => { - process.env.MOCK_INTERVAL = 'true'; - const basicConfig = { - 'start-time': '2023-12-12T00:00:90.000Z', - 'end-time': '2023-12-12T00:01:09.000Z', - interval: 5, - 'allow-padding': true, - }; + it('throws error if timestamps overlap.', async () => { + const basicConfig = { + 'start-time': '2023-12-12T00:00:00.000Z', + 'end-time': '2023-12-12T00:01:00.000Z', + interval: 5, + 'allow-padding': true, + }; + + pluginSettings['global-config'] = basicConfig; + const timeModel = TimeSync(pluginSettings); + + try { + await timeModel.execute([ + { + timestamp: '2023-12-12T00:00:00.000Z', + duration: 15, + 'cpu/utilization': 10, + }, + { + timestamp: '2023-12-12T00:00:10.000Z', + duration: 30, + 'cpu/utilization': 20, + }, + ]); + } catch (error) { + expect(error).toStrictEqual( + new InvalidInputError(INVALID_OBSERVATION_OVERLAP) + ); + } + }); - const timeModel = TimeSync(basicConfig); - - try { - await timeModel.execute([ - { - timestamp: '2023-12-12T00:00:00.000Z', - duration: 30, - 'cpu/utilization': 20, - }, - ]); - } catch (error) { - expect(error).toBeInstanceOf(InputValidationError); - expect(error).toStrictEqual( - new InputValidationError( - '"timestamp" parameter is invalid datetime in input[1]. Error code: invalid_string.' - ) - ); - } - }); + it('throws error if `timestamp` is missing.', async () => { + const basicConfig = { + 'start-time': '2023-12-12T00:00:00.000Z', + 'end-time': '2023-12-12T00:01:00.000Z', + interval: 5, + 'allow-padding': true, + }; + + pluginSettings['global-config'] = basicConfig; + const timeModel = TimeSync(pluginSettings); + + try { + await timeModel.execute([ + { + duration: 15, + 'cpu/utilization': 10, + }, + { + timestamp: '2023-12-12T00:00:10.000Z', + duration: 30, + 'cpu/utilization': 20, + }, + ]); + } catch (error) { + expect(error).toBeInstanceOf(InputValidationError); + expect(error).toStrictEqual( + new InputValidationError( + '"timestamp" parameter is required in input[0]. Error code: invalid_union.' + ) + ); + } + }); - it('returns a result when the first timestamp in the input has time padding.', async () => { - process.env.MOCK_INTERVAL = 'false'; - const basicConfig = { - 'start-time': '2023-12-12T00:00:00.000Z', - 'end-time': '2023-12-12T00:00:09.000Z', - interval: 5, - 'allow-padding': true, - }; + it('throws error if the seconds `timestamp` is above 60.', async () => { + const basicConfig = { + 'start-time': '2023-12-12T00:00:00.000Z', + 'end-time': '2023-12-12T00:01:00.000Z', + interval: 5, + 'allow-padding': true, + }; + pluginSettings['global-config'] = basicConfig; + const timeModel = TimeSync(pluginSettings); + + try { + await timeModel.execute([ + { + timestamp: '2023-12-12T00:00:90.000Z', + duration: 15, + 'cpu/utilization': 10, + }, + { + timestamp: '2023-12-12T00:00:10.000Z', + duration: 30, + 'cpu/utilization': 20, + }, + ]); + } catch (error) { + expect(error).toBeInstanceOf(InputValidationError); + expect(error).toStrictEqual( + new InputValidationError( + '"timestamp" parameter is invalid datetime in input[0]. Error code: invalid_string.' + ) + ); + } + }); - const timeModel = TimeSync(basicConfig); + it('throws an error if the `timestamp` is not valid date.', async () => { + const basicConfig = { + 'start-time': '2023-12-12T00:00:00.000Z', + 'end-time': '2023-12-12T00:01:00.000Z', + interval: 10, + 'allow-padding': true, + }; + const data = [ + { + timestamp: 45, + duration: 10, + 'cpu/utilization': 10, + }, + ]; + pluginSettings['global-config'] = basicConfig; + const timeModel = TimeSync(pluginSettings); + expect.assertions(2); + + try { + await timeModel.execute(data); + } catch (error) { + expect(error).toBeInstanceOf(InvalidDateInInputError); + expect(error).toStrictEqual( + new InvalidDateInInputError(INVALID_DATE_TYPE(data[0].timestamp)) + ); + } + }); - const result = await timeModel.execute([ - { - timestamp: '2023-12-12T00:00:05.000Z', - duration: 3, - 'resources-total': 10, - }, - { - timestamp: '2023-12-12T00:00:10.000Z', - duration: 3, - 'resources-total': 10, - }, - ]); + it('throws error if end is before start in global config.', async () => { + const basicConfig = { + 'start-time': '2023-12-12T00:00:10.000Z', + 'end-time': '2023-12-12T00:00:00.000Z', + interval: 5, + 'allow-padding': true, + }; + + pluginSettings['global-config'] = basicConfig; + const timeModel = TimeSync(pluginSettings); + + try { + await timeModel.execute([ + { + timestamp: '2023-12-12T00:00:00.000Z', + duration: 15, + 'cpu/utilization': 10, + }, + { + timestamp: '2023-12-12T00:00:10.000Z', + duration: 30, + 'cpu/utilization': 20, + }, + ]); + } catch (error) { + expect(error).toStrictEqual( + new InputValidationError( + '`start-time` should be lower than `end-time`' + ) + ); + } + }); - const expectedResult = [ - { - timestamp: '2023-12-12T00:00:00.000Z', - duration: 5, - 'resources-total': 10, - }, - { - timestamp: '2023-12-12T00:00:05.000Z', - duration: 5, - 'resources-total': 10, - }, - ]; + it('converts Date objects to string outputs.', async () => { + const basicConfig = { + 'start-time': '2023-12-12T00:00:00.000Z', + 'end-time': '2023-12-12T00:00:01.000Z', + interval: 1, + 'allow-padding': false, + }; + + pluginSettings['global-config'] = basicConfig; + const timeModel = TimeSync(pluginSettings); + + const result = await timeModel.execute([ + { + timestamp: '2023-12-12T00:00:00.000Z', + duration: 1, + 'cpu/utilization': 10, + }, + { + timestamp: new Date('2023-12-12T00:00:01.000Z'), + duration: 1, + 'cpu/utilization': 10, + }, + ]); + + const expectedResult = [ + { + timestamp: '2023-12-12T00:00:00.000Z', + duration: 1, + 'cpu/utilization': 10, + }, + { + timestamp: '2023-12-12T00:00:01.000Z', + duration: 1, + 'cpu/utilization': 10, + }, + ]; + + expect(result).toStrictEqual(expectedResult); + }); - expect(result).toStrictEqual(expectedResult); - }); + it('checks that metric (carbon) with aggregation-method == sum is properly spread over interpolated time points.', async () => { + const basicConfig = { + 'start-time': '2023-12-12T00:00:00.000Z', + 'end-time': '2023-12-12T00:00:10.000Z', + interval: 1, + 'allow-padding': true, + }; + pluginSettings['global-config'] = basicConfig; + const timeModel = TimeSync(pluginSettings); + + const result = await timeModel.execute([ + { + timestamp: '2023-12-12T00:00:00.000Z', + duration: 10, + carbon: 10, + }, + ]); + + const expectedResult = [ + { + timestamp: '2023-12-12T00:00:00.000Z', + duration: 1, + carbon: 1, + }, + { + timestamp: '2023-12-12T00:00:01.000Z', + duration: 1, + carbon: 1, + }, + { + timestamp: '2023-12-12T00:00:02.000Z', + duration: 1, + carbon: 1, + }, + { + timestamp: '2023-12-12T00:00:03.000Z', + duration: 1, + carbon: 1, + }, + { + timestamp: '2023-12-12T00:00:04.000Z', + duration: 1, + carbon: 1, + }, + { + timestamp: '2023-12-12T00:00:05.000Z', + duration: 1, + carbon: 1, + }, + { + timestamp: '2023-12-12T00:00:06.000Z', + duration: 1, + carbon: 1, + }, + { + timestamp: '2023-12-12T00:00:07.000Z', + duration: 1, + carbon: 1, + }, + { + timestamp: '2023-12-12T00:00:08.000Z', + duration: 1, + carbon: 1, + }, + { + timestamp: '2023-12-12T00:00:09.000Z', + duration: 1, + carbon: 1, + }, + ]; + + expect(result).toStrictEqual(expectedResult); + }); - it('throws error if padding is required at start while allow-padding = false.', async () => { - const basicConfig = { - 'start-time': '2023-12-12T00:00:00.000Z', - 'end-time': '2023-12-12T00:00:10.000Z', - interval: 5, - 'allow-padding': false, - }; + it('checks that constants are copied to results unchanged.', async () => { + const basicConfig = { + 'start-time': '2023-12-12T00:00:00.000Z', + 'end-time': '2023-12-12T00:00:09.000Z', + interval: 5, + 'allow-padding': true, + }; + pluginSettings['global-config'] = basicConfig; + const timeModel = TimeSync(pluginSettings); + + const result = await timeModel.execute([ + { + timestamp: '2023-12-12T00:00:00.000Z', + duration: 3, + 'resources-total': 10, + }, + { + timestamp: '2023-12-12T00:00:05.000Z', + duration: 3, + 'resources-total': 10, + }, + ]); + + /**In each 5 second interval, 60% of the time cpu/utilization = 10, 40% of the time it is 0, so cpu/utilization in the averaged result be 6 */ + const expectedResult = [ + { + timestamp: '2023-12-12T00:00:00.000Z', + duration: 5, + 'resources-total': 10, + }, + { + timestamp: '2023-12-12T00:00:05.000Z', + duration: 5, + 'resources-total': 10, + }, + ]; + + expect(result).toStrictEqual(expectedResult); + }); - const timeModel = TimeSync(basicConfig); - - try { - await timeModel.execute([ - { - timestamp: '2023-12-12T00:00:02.000Z', - duration: 15, - 'cpu/utilization': 10, - }, - { - timestamp: '2023-12-12T00:00:10.000Z', - duration: 30, - 'cpu/utilization': 20, - }, - ]); - } catch (error) { - expect(error).toStrictEqual( - new InvalidPaddingError(AVOIDING_PADDING_BY_EDGES(true, false)) - ); - } - }); + it('returns a result when `time-reserved` persists.', async () => { + const basicConfig = { + 'start-time': '2023-12-12T00:00:00.000Z', + 'end-time': '2023-12-12T00:00:09.000Z', + interval: 5, + 'allow-padding': true, + }; + + pluginSettings['global-config'] = basicConfig; + const timeModel = TimeSync(pluginSettings); + + const result = await timeModel.execute([ + { + timestamp: '2023-12-12T00:00:00.000Z', + duration: 3, + 'time-reserved': 5, + 'resources-total': 10, + }, + { + timestamp: '2023-12-12T00:00:05.000Z', + duration: 3, + 'time-reserved': 5, + 'resources-total': 10, + }, + ]); + + const expectedResult = [ + { + timestamp: '2023-12-12T00:00:00.000Z', + duration: 5, + 'resources-total': 10, + 'time-reserved': 3.2, + }, + { + timestamp: '2023-12-12T00:00:05.000Z', + duration: 5, + 'resources-total': 10, + 'time-reserved': 3.2, + }, + ]; + + expect(result).toStrictEqual(expectedResult); + }); - it('throws error if padding is required at end while allow-padding = false.', async () => { - const basicConfig = { - 'start-time': '2023-12-12T00:00:00.000Z', - 'end-time': '2023-12-12T00:00:10.000Z', - interval: 5, - 'allow-padding': false, - }; + it('throws an error when `start-time` is wrong.', async () => { + process.env.MOCK_INTERVAL = 'true'; + const basicConfig = { + 'start-time': '2023-12-12T00:00:90.000Z', + 'end-time': '2023-12-12T00:01:09.000Z', + interval: 5, + 'allow-padding': true, + }; + pluginSettings['global-config'] = basicConfig; + const timeModel = TimeSync(pluginSettings); + + try { + await timeModel.execute([ + { + timestamp: '2023-12-12T00:00:00.000Z', + duration: 30, + 'cpu/utilization': 20, + }, + ]); + } catch (error) { + expect(error).toBeInstanceOf(InputValidationError); + expect(error).toStrictEqual( + new InputValidationError( + '"start-time" parameter is invalid datetime. Error code: invalid_string.' + ) + ); + } + }); - const timeModel = TimeSync(basicConfig); - - try { - await timeModel.execute([ - { - timestamp: '2023-12-12T00:00:00.000Z', - duration: 10, - 'cpu/utilization': 10, - }, - { - timestamp: '2023-12-12T00:00:10.000Z', - duration: 30, - 'cpu/utilization': 20, - }, - ]); - } catch (error) { - expect(error).toStrictEqual( - new InputValidationError('Avoiding padding at end') - ); - } - }); + it('returns a result when the first timestamp in the input has time padding.', async () => { + process.env.MOCK_INTERVAL = 'false'; + const basicConfig = { + 'start-time': '2023-12-12T00:00:00.000Z', + 'end-time': '2023-12-12T00:00:09.000Z', + interval: 5, + 'allow-padding': true, + }; + pluginSettings['global-config'] = basicConfig; + const timeModel = TimeSync(pluginSettings); + + const result = await timeModel.execute([ + { + timestamp: '2023-12-12T00:00:05.000Z', + duration: 3, + 'resources-total': 10, + }, + { + timestamp: '2023-12-12T00:00:10.000Z', + duration: 3, + 'resources-total': 10, + }, + ]); + + const expectedResult = [ + { + timestamp: '2023-12-12T00:00:00.000Z', + duration: 5, + 'resources-total': 10, + }, + { + timestamp: '2023-12-12T00:00:05.000Z', + duration: 5, + 'resources-total': 10, + }, + ]; + + expect(result).toStrictEqual(expectedResult); + }); - it('throws error if padding is required at start and end while allow-padding = false.', async () => { - const basicConfig = { - 'start-time': '2023-12-12T00:00:00.000Z', - 'end-time': '2023-12-12T00:00:10.000Z', - interval: 5, - 'allow-padding': false, - }; + it('throws error if padding is required at start while allow-padding = false.', async () => { + const basicConfig = { + 'start-time': '2023-12-12T00:00:00.000Z', + 'end-time': '2023-12-12T00:00:10.000Z', + interval: 5, + 'allow-padding': false, + }; + pluginSettings['global-config'] = basicConfig; + const timeModel = TimeSync(pluginSettings); + + try { + await timeModel.execute([ + { + timestamp: '2023-12-12T00:00:02.000Z', + duration: 15, + 'cpu/utilization': 10, + }, + { + timestamp: '2023-12-12T00:00:10.000Z', + duration: 30, + 'cpu/utilization': 20, + }, + ]); + } catch (error) { + expect(error).toStrictEqual( + new InvalidPaddingError(AVOIDING_PADDING_BY_EDGES(true, false)) + ); + } + }); - const timeModel = TimeSync(basicConfig); - - try { - await timeModel.execute([ - { - timestamp: '2023-12-12T00:00:02.000Z', - duration: 10, - 'cpu/utilization': 10, - }, - { - timestamp: '2023-12-12T00:00:08.000Z', - duration: 1, - 'cpu/utilization': 20, - }, - ]); - } catch (error) { - expect(error).toStrictEqual( - new InvalidPaddingError(AVOIDING_PADDING_BY_EDGES(true, true)) - ); - } - }); + it('throws error if padding is required at end while allow-padding = false.', async () => { + const basicConfig = { + 'start-time': '2023-12-12T00:00:00.000Z', + 'end-time': '2023-12-12T00:00:10.000Z', + interval: 5, + 'allow-padding': false, + }; + pluginSettings['global-config'] = basicConfig; + const timeModel = TimeSync(pluginSettings); + + try { + await timeModel.execute([ + { + timestamp: '2023-12-12T00:00:00.000Z', + duration: 10, + 'cpu/utilization': 10, + }, + { + timestamp: '2023-12-12T00:00:10.000Z', + duration: 30, + 'cpu/utilization': 20, + }, + ]); + } catch (error) { + expect(error).toStrictEqual( + new InputValidationError('Avoiding padding at end') + ); + } + }); - it('checks that timestamps in return object are ISO 8061 and timezone UTC.', async () => { - process.env.MOCK_INTERVAL = 'false'; - const basicConfig = { - 'start-time': '2023-12-12T00:00:00.000Z', - 'end-time': '2023-12-12T00:00:03.000Z', - interval: 1, - 'allow-padding': true, - }; + it('throws error if padding is required at start and end while allow-padding = false.', async () => { + const basicConfig = { + 'start-time': '2023-12-12T00:00:00.000Z', + 'end-time': '2023-12-12T00:00:10.000Z', + interval: 5, + 'allow-padding': false, + }; + pluginSettings['global-config'] = basicConfig; + const timeModel = TimeSync(pluginSettings); + + try { + await timeModel.execute([ + { + timestamp: '2023-12-12T00:00:02.000Z', + duration: 10, + 'cpu/utilization': 10, + }, + { + timestamp: '2023-12-12T00:00:08.000Z', + duration: 1, + 'cpu/utilization': 20, + }, + ]); + } catch (error) { + expect(error).toStrictEqual( + new InvalidPaddingError(AVOIDING_PADDING_BY_EDGES(true, true)) + ); + } + }); - const timeModel = TimeSync(basicConfig); - const result = await timeModel.execute([ - { - timestamp: '2023-12-12T00:00:00.000Z', - duration: 1, - carbon: 1, - }, - ]); - expect( - DateTime.fromISO(result[0].timestamp).zone.valueOf() === - 'FixedOffsetZone { fixed: 0 }' - ); - expect(DateTime.fromISO(result[0].timestamp).offset === 0); + it('checks that timestamps in return object are ISO 8061 and timezone UTC.', async () => { + process.env.MOCK_INTERVAL = 'false'; + const basicConfig = { + 'start-time': '2023-12-12T00:00:00.000Z', + 'end-time': '2023-12-12T00:00:03.000Z', + interval: 1, + 'allow-padding': true, + }; + pluginSettings['global-config'] = basicConfig; + const timeModel = TimeSync(pluginSettings); + const result = await timeModel.execute([ + { + timestamp: '2023-12-12T00:00:00.000Z', + duration: 1, + carbon: 1, + }, + ]); + expect( + DateTime.fromISO(result[0].timestamp).zone.valueOf() === + 'FixedOffsetZone { fixed: 0 }' + ); + expect(DateTime.fromISO(result[0].timestamp).offset === 0); + }); + }); }); });