diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 50c9aabaf..9254fe1fd 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -4,11 +4,8 @@ - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) -- [ ] My code follows the code style of this project. -- [ ] My change requires a change to the documentation. - [ ] I have updated the documentation accordingly. - [ ] I have added tests to cover my changes. -- [ ] All new and existing tests passed. ### A description of the changes proposed in the Pull Request diff --git a/manifests/examples/builtins/interpolation/success-with-off.yml b/manifests/examples/builtins/interpolation/success-with-off.yml new file mode 100644 index 000000000..0aebabbf4 --- /dev/null +++ b/manifests/examples/builtins/interpolation/success-with-off.yml @@ -0,0 +1,24 @@ +name: interpolation-demo +description: simple demo of interpolation plugin +tags: +initialize: + plugins: + interpolation: + method: Interpolation + path: "builtin" + config: + method: linear + x: [0, 10, 50, 100] + y: [0.12, 0.32, 0.75, 1.02] + input-parameter: "cpu/utilization" + output-parameter: "result" +tree: + children: + child: + pipeline: + compute: + - interpolation + inputs: + - timestamp: 2023-07-06T00:00 + duration: 3600 + cpu/utilization: off diff --git a/package-lock.json b/package-lock.json index 177c80514..ded744c52 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "@commitlint/cli": "^18.6.0", "@commitlint/config-conventional": "^18.6.0", - "@grnsft/if-core": "^0.0.25", + "@grnsft/if-core": "^0.0.28", "axios": "^1.7.2", "csv-parse": "^5.5.6", "csv-stringify": "^6.4.6", @@ -1186,9 +1186,9 @@ } }, "node_modules/@grnsft/if-core": { - "version": "0.0.25", - "resolved": "https://registry.npmjs.org/@grnsft/if-core/-/if-core-0.0.25.tgz", - "integrity": "sha512-1W4SXsXhXos06q4SBPc8QpgQPDhHEc03njrGcd/X2UiJyh0ycBKTqGCjuRPRipEayGgUxO0DwRNOgNcgzzcDkA==", + "version": "0.0.28", + "resolved": "https://registry.npmjs.org/@grnsft/if-core/-/if-core-0.0.28.tgz", + "integrity": "sha512-DM88HFeBbR1yl3bU0vFRgy6FnmUiyP4KhmtXp7HK1tMQHtnuKxzdPSxbfdpHsnUuHlvgDG7R/dI67/PmQD4U5w==", "dependencies": { "typescript": "^5.1.6", "zod": "^3.23.8" diff --git a/package.json b/package.json index 343382e78..7a05f5742 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "dependencies": { "@commitlint/cli": "^18.6.0", "@commitlint/config-conventional": "^18.6.0", - "@grnsft/if-core": "^0.0.25", + "@grnsft/if-core": "^0.0.28", "axios": "^1.7.2", "csv-parse": "^5.5.6", "csv-stringify": "^6.4.6", diff --git a/src/__tests__/if-run/builtins/interpolation.test.ts b/src/__tests__/if-run/builtins/interpolation.test.ts index be379b3d3..dd5381529 100644 --- a/src/__tests__/if-run/builtins/interpolation.test.ts +++ b/src/__tests__/if-run/builtins/interpolation.test.ts @@ -55,6 +55,50 @@ describe('builtins/interpolation: ', () => { expect(result).toEqual(outputs); }); + it('returns valid output parameter if input parameter is 0.', async () => { + const inputs = [ + { + timestamp: '2023-07-06T00:00', + duration: 3600, + 'cpu/utilization': 0, + }, + ]; + const outputs = [ + { + timestamp: '2023-07-06T00:00', + duration: 3600, + 'cpu/utilization': 0, + 'interpolation-result': 0.12, + }, + ]; + + const result = await plugin.execute(inputs); + + expect(result).toEqual(outputs); + }); + + it('returns no output parameter if input parameter is `off`.', async () => { + const inputs = [ + { + timestamp: '2023-07-06T00:00', + duration: 3600, + 'cpu/utilization': 'off', + }, + ]; + const outputs = [ + { + timestamp: '2023-07-06T00:00', + duration: 3600, + 'cpu/utilization': 0, + 'interpolation-result': 0, + }, + ]; + + const result = await plugin.execute(inputs); + + expect(result).toEqual(outputs); + }); + it('returns result when `mapping` has valid data.', async () => { const mapping = { 'cpu/utilization': 'cpu/util', diff --git a/src/if-run/builtins/interpolation/README.md b/src/if-run/builtins/interpolation/README.md index d328dc9aa..9b62e7000 100644 --- a/src/if-run/builtins/interpolation/README.md +++ b/src/if-run/builtins/interpolation/README.md @@ -62,7 +62,7 @@ The plugin expects the following input parameters: - `timestamp`: a timestamp for the input (required) - `duration`: the amount of time, in seconds, that the input covers. (required) -- `[input-parameter]` - a field whose name matches the string provided to input-parameter in config (i.e. if the input-parameter in config is cpu/utilisation then cpu-utilisation must exist in the input data) +- `[input-parameter]` - a field whose name matches the string provided to input-parameter in config (i.e. if the input-parameter in config is cpu/utilisation then cpu-utilisation must exist in the input data). Value can be greater or equal to 0. For modeling server which totally turned off, `off` value can be used. ## Output diff --git a/src/if-run/builtins/interpolation/index.ts b/src/if-run/builtins/interpolation/index.ts index 30226e5a6..bfc39e3c8 100644 --- a/src/if-run/builtins/interpolation/index.ts +++ b/src/if-run/builtins/interpolation/index.ts @@ -54,12 +54,13 @@ export const Interpolation = PluginFactory({ .object({ timestamp: z.string().or(z.date()), duration: z.number(), - [inputParameter]: z.number().gt(0), + [inputParameter]: z.number().gte(0).or(z.literal('off')), }) .refine( data => - data[inputParameter] >= config.x[0] && - data[inputParameter] <= config.x[config.x.length - 1], + (data[inputParameter] >= config.x[0] && + data[inputParameter] <= config.x[config.x.length - 1]) || + data[inputParameter] === 'off', { message: WITHIN_THE_RANGE, } @@ -68,14 +69,23 @@ export const Interpolation = PluginFactory({ return validate>(schema, input, index); }, implementation: async (inputs: PluginParams[], config: ConfigParams) => { - const {'output-parameter': outputParameter} = config; + const { + 'input-parameter': inputParameter, + 'output-parameter': outputParameter, + } = config; return inputs.map(input => { - const calculatedResult = calculateResult(config, input); + if (input[inputParameter] === 'off') { + return { + ...input, + [inputParameter]: 0, + [outputParameter]: 0, + }; + } return { ...input, - [outputParameter]: calculatedResult, + [outputParameter]: calculateResult(config, input), }; }); }, @@ -169,7 +179,8 @@ const getPolynomialInterpolation = ( return result; }; +/** + * Sorts given point items in ascending order. + */ const sortPoints = (items: number[]) => - items.sort((a: number, b: number) => { - return a - b; - }); + items.sort((a: number, b: number) => a - b); diff --git a/src/if-run/lib/compute.ts b/src/if-run/lib/compute.ts index 5e73cbbb4..81bc768e1 100644 --- a/src/if-run/lib/compute.ts +++ b/src/if-run/lib/compute.ts @@ -99,8 +99,8 @@ const computeNode = async (node: Node, params: ComputeParams): Promise => { }); } - let inputStorage = structuredClone(node.inputs) as PluginParams[]; - inputStorage = mergeDefaults(inputStorage, defaults); + let outputStorage = structuredClone(node.inputs) as PluginParams[]; + outputStorage = mergeDefaults(outputStorage, defaults); const pipelineCopy = structuredClone(pipeline) || {}; /** Checks if pipeline is not an array or empty object. */ @@ -125,8 +125,8 @@ const computeNode = async (node: Node, params: ComputeParams): Promise => { const plugin = params.pluginStorage.get(pluginName); const nodeConfig = config && config[pluginName]; - inputStorage = await plugin.execute(inputStorage, nodeConfig); - node.inputs = inputStorage; + outputStorage = await plugin.execute(outputStorage, nodeConfig); + node.inputs = outputStorage; if (params.context.explainer) { addExplainData({ @@ -145,7 +145,7 @@ const computeNode = async (node: Node, params: ComputeParams): Promise => { const originalOutputs = params.append ? node.outputs || [] : []; node.children = Regroup( - inputStorage, + outputStorage, originalOutputs, pipelineCopy.regroup ); @@ -183,10 +183,11 @@ const computeNode = async (node: Node, params: ComputeParams): Promise => { console.debug(COMPUTING_PIPELINE_FOR_NODE(pluginName)); debugLogger.setExecutingPluginName(pluginName); - inputStorage = await plugin.execute(inputStorage, nodeConfig); + outputStorage = await plugin.execute(outputStorage, nodeConfig); + console.log(outputStorage); debugLogger.setExecutingPluginName(); - node.outputs = inputStorage; + node.outputs = outputStorage; if (params.context.explainer) { addExplainData({