Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move the divide plugin into builtins #647

Merged
merged 13 commits into from
May 24, 2024
Merged
2 changes: 1 addition & 1 deletion manifests/integrations/cloud-metadata-divide-boavizta.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ initialize:
path: "@grnsft/if-plugins"
divide:
method: Divide
path: "@grnsft/if-plugins"
path: "builtin"
global-config:
numerator: vcpus-allocated
denominator: 2
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ initialize:
path: "@grnsft/if-plugins"
divide:
method: Divide
path: "@grnsft/if-plugins"
path: "builtin"
global-config:
numerator: vcpus-allocated
denominator: 0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ initialize:
path: "@grnsft/if-plugins"
divide:
method: Divide
path: "@grnsft/if-plugins"
path: "builtin"
global-config:
numerator: vcpus-allocated
denominator: 'vcpus'
Expand Down
2 changes: 1 addition & 1 deletion manifests/plugins/divide/failure-missing-numerator.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ initialize:
path: "@grnsft/if-plugins"
divide:
method: Divide
path: "@grnsft/if-plugins"
path: "builtin"
global-config:
#numerator: vcpus-allocated
denominator: 2
Expand Down
2 changes: 1 addition & 1 deletion manifests/plugins/divide/success.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ initialize:
path: "@grnsft/if-plugins"
divide:
method: Divide
path: "@grnsft/if-plugins"
path: "builtin"
global-config:
numerator: vcpus-allocated
denominator: 2
Expand Down
175 changes: 175 additions & 0 deletions src/__tests__/unit/builtins/divide.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
import {Divide} from '../../../builtins';

import {ERRORS} from '../../../util/errors';

const {InputValidationError, ConfigNotFoundError} = ERRORS;

describe('builtins/divide: ', () => {
describe('Divide: ', () => {
const globalConfig = {
numerator: 'vcpus-allocated',
denominator: 2,
output: 'cpu/number-cores',
};
const divide = Divide(globalConfig);

describe('init: ', () => {
it('successfully initalized.', () => {
expect(divide).toHaveProperty('metadata');
expect(divide).toHaveProperty('execute');
});
});

describe('execute(): ', () => {
it('successfully applies Divide strategy to given input.', async () => {
expect.assertions(1);

const expectedResult = [
{
duration: 3600,
'vcpus-allocated': 24,
'cpu/number-cores': 12,
timestamp: '2021-01-01T00:00:00Z',
},
];

const result = await divide.execute([
{
duration: 3600,
'vcpus-allocated': 24,
timestamp: '2021-01-01T00:00:00Z',
},
]);

expect(result).toStrictEqual(expectedResult);
});

it('returns a result when `denominator` is provded in input.', async () => {
expect.assertions(1);
const globalConfig = {
numerator: 'vcpus-allocated',
denominator: 'duration',
output: 'vcpus-allocated-per-second',
};
const divide = Divide(globalConfig);

const input = [
{
timestamp: '2021-01-01T00:00:00Z',
duration: 3600,
'vcpus-allocated': 24,
},
];
const response = await divide.execute(input);

const expectedResult = [
{
timestamp: '2021-01-01T00:00:00Z',
duration: 3600,
'vcpus-allocated': 24,
'vcpus-allocated-per-second': 24 / 3600,
},
];

expect(response).toEqual(expectedResult);
});

it('throws an error on missing params in input.', async () => {
const expectedMessage =
'"vcpus-allocated" parameter is required. Error code: invalid_type.';

const globalConfig = {
numerator: 'vcpus-allocated',
denominator: 3600,
output: 'vcpus-allocated-per-second',
};
const divide = Divide(globalConfig);

expect.assertions(1);

try {
await divide.execute([
{
timestamp: '2021-01-01T00:00:00Z',
duration: 3600,
},
]);
} catch (error) {
expect(error).toStrictEqual(
new InputValidationError(expectedMessage)
);
}
});
});

it('throws an error on missing global config.', async () => {
const expectedMessage = 'Global config is not provided.';
const config = undefined;
const divide = Divide(config!);

expect.assertions(1);

try {
await divide.execute([
{
timestamp: '2021-01-01T00:00:00Z',
duration: 3600,
},
]);
} catch (error) {
expect(error).toStrictEqual(new ConfigNotFoundError(expectedMessage));
}
});

it('throws an error when `denominator` is 0.', async () => {
const expectedMessage =
'"denominator" parameter is number must be greater than 0. Error code: too_small.';

const globalConfig = {
numerator: 'vcpus-allocated',
denominator: 0,
output: 'vcpus-allocated-per-second',
};
const divide = Divide(globalConfig);

expect.assertions(1);

try {
await divide.execute([
{
timestamp: '2021-01-01T00:00:00Z',
duration: 3600,
'vcpus-allocated': 24,
},
]);
} catch (error) {
expect(error).toStrictEqual(new InputValidationError(expectedMessage));
}
});

it('throws an error when `denominator` is string.', async () => {
const expectedMessage = '`10` is missing from the input.';

const globalConfig = {
numerator: 'vcpus-allocated',
denominator: '10',
output: 'vcpus-allocated-per-second',
};
const divide = Divide(globalConfig);

expect.assertions(1);

try {
await divide.execute([
{
timestamp: '2021-01-01T00:00:00Z',
duration: 3600,
'vcpus-allocated': 24,
},
]);
} catch (error) {
expect(error).toStrictEqual(new InputValidationError(expectedMessage));
}
});
});
});
95 changes: 95 additions & 0 deletions src/builtins/divide/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# Divide

`divide` is a generic plugin for doing arithmetic division of two values in an `input` array.

You provide the names of the values you want to divide, and a name to use to add the divide to the output array.

For example, `boavizta-cpu` need `cpu/number-cores` to work, however `cloud-metadata` returns `vcpus-allocated`, to get number of cores you divide `vcpus-allocated` by 2.

## Parameters

### Plugin config

- `numerator` - a parameter by a specific configured number
- `denominator` - a parameter by a specific configured number or the number by which `numerator` is divided
- `output` - the number to a configured output parameter

### Inputs

- `numerator` - as input parameter, must be available in the input array
- `denominator` - must be available in the input array if is an input parameter
- `output` - as input parameter, must be available in the input array

## Returns

- `output`: the division of `numerator` with the parameter name into `denominator` with the parameter name defined by `output` in global config.

The plugin throws an exception if the division result is not a number.

## Calculation

```pseudocode
output = input0 / input1
```

## Implementation

To run the plugin, you must first create an instance of `Divide`. Then, you can call `execute()`.

```typescript
const globalConfig = {
numerator: 'vcpus-allocated',
denominator: 2,
output: 'cpu/number-cores',
};
const divide = Divide(globalConfig);

const input = [
{
timestamp: '2021-01-01T00:00:00Z',
duration: 3600,
'vcpus-allocated': 24,
},
];
```

## Example manifest

IF users will typically call the plugin as part of a pipeline defined in a manifest file. In this case, instantiating the plugin is handled by `if` and does not have to be done explicitly by the user. The following is an example manifest that calls `divide`:

```yaml
name: divide-demo
description:
tags:
initialize:
outputs:
- yaml
plugins:
divide:
method: Divide
path: 'builtin'
global-config:
numerator: vcpus-allocated
denominator: 2
output: cpu/number-cores
tree:
children:
child:
pipeline:
- divide
config:
divide:
inputs:
- timestamp: 2023-08-06T00:00
duration: 3600
vcpus-allocated: 24
```

You can run this example by saving it as `./examples/manifests/divide.yml` and executing the following command from the project root:

```sh
npm i -g @grnsft/if
ie --manifest ./examples/manifests/divide.yml --output ./examples/outputs/divide.yml
```

The results will be saved to a new `yaml` file in `./examples/outputs`.
Loading