diff --git a/x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/AgentConfigurationCreateEdit/SettingsPage/SettingFormRow.tsx b/x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/AgentConfigurationCreateEdit/SettingsPage/SettingFormRow.tsx index 75caed4ae480f..8b1590245f681 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/AgentConfigurationCreateEdit/SettingsPage/SettingFormRow.tsx +++ b/x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/AgentConfigurationCreateEdit/SettingsPage/SettingFormRow.tsx @@ -92,15 +92,14 @@ function FormRow({ onChange( setting.key, - amountAndUnitToString({ amount: e.target.value, unit }) + amountAndUnitToString({ + amount: parseInt(e.target.value, 10), + unit + }) ) } /> diff --git a/x-pack/plugins/apm/common/agent_configuration/amount_and_unit.ts b/x-pack/plugins/apm/common/agent_configuration/amount_and_unit.ts index d6520ae150539..53d6ea49af8e0 100644 --- a/x-pack/plugins/apm/common/agent_configuration/amount_and_unit.ts +++ b/x-pack/plugins/apm/common/agent_configuration/amount_and_unit.ts @@ -4,15 +4,15 @@ * you may not use this file except in compliance with the Elastic License. */ -interface AmountAndUnit { - amount: string; +export interface AmountAndUnit { + amount: number; unit: string; } export function amountAndUnitToObject(value: string): AmountAndUnit { // matches any postive and negative number and its unit. const [, amount = '', unit = ''] = value.match(/(^-?\d+)?(\w+)?/) || []; - return { amount, unit }; + return { amount: parseInt(amount, 10), unit }; } export function amountAndUnitToString({ amount, unit }: AmountAndUnit) { diff --git a/x-pack/plugins/apm/common/agent_configuration/runtime_types/bytes_rt.test.ts b/x-pack/plugins/apm/common/agent_configuration/runtime_types/bytes_rt.test.ts index 4df6128f248ac..180637f08a84a 100644 --- a/x-pack/plugins/apm/common/agent_configuration/runtime_types/bytes_rt.test.ts +++ b/x-pack/plugins/apm/common/agent_configuration/runtime_types/bytes_rt.test.ts @@ -8,23 +8,66 @@ import { getBytesRt } from './bytes_rt'; import { isRight } from 'fp-ts/lib/Either'; describe('bytesRt', () => { - const bytesRt = getBytesRt({ - min: 0, - units: ['b', 'mb', 'kb'] - }); + describe('must accept any amount and unit', () => { + const bytesRt = getBytesRt({ + units: ['b', 'mb', 'kb'] + }); + describe('it should not accept', () => { + ['mb', 1, '1', '5gb', '6tb'].map(input => { + it(`${JSON.stringify(input)}`, () => { + expect(isRight(bytesRt.decode(input))).toBe(false); + }); + }); + }); - describe('it should not accept', () => { - ['mb', '-1kb', '5gb', '6tb'].map(input => { - it(`${JSON.stringify(input)}`, () => { - expect(isRight(bytesRt.decode(input))).toBe(false); + describe('it should accept', () => { + ['-1b', '0mb', '1b', '2kb', '3mb', '1000mb'].map(input => { + it(`${JSON.stringify(input)}`, () => { + expect(isRight(bytesRt.decode(input))).toBe(true); + }); }); }); }); + describe('must be at least 0b', () => { + const bytesRt = getBytesRt({ + min: '0b', + units: ['b', 'mb', 'kb'] + }); + + describe('it should not accept', () => { + ['mb', '-1kb', '5gb', '6tb'].map(input => { + it(`${JSON.stringify(input)}`, () => { + expect(isRight(bytesRt.decode(input))).toBe(false); + }); + }); + }); - describe('it should accept', () => { - ['1b', '2kb', '3mb'].map(input => { - it(`${JSON.stringify(input)}`, () => { - expect(isRight(bytesRt.decode(input))).toBe(true); + describe('it should accept', () => { + ['1b', '2kb', '3mb'].map(input => { + it(`${JSON.stringify(input)}`, () => { + expect(isRight(bytesRt.decode(input))).toBe(true); + }); + }); + }); + }); + describe('must be between 500b and 1mb', () => { + const bytesRt = getBytesRt({ + min: '500b', + max: '1kb', + units: ['b', 'mb', 'kb'] + }); + describe('it should not accept', () => { + ['mb', '-1b', '1b', '499b', '1025b', '2kb', '1mb'].map(input => { + it(`${JSON.stringify(input)}`, () => { + expect(isRight(bytesRt.decode(input))).toBe(false); + }); + }); + }); + describe('it should accept', () => { + ['500b', '1024b', '1kb'].map(input => { + it(`${JSON.stringify(input)}`, () => { + expect(isRight(bytesRt.decode(input))).toBe(true); + }); }); }); }); diff --git a/x-pack/plugins/apm/common/agent_configuration/runtime_types/bytes_rt.ts b/x-pack/plugins/apm/common/agent_configuration/runtime_types/bytes_rt.ts index 99c8e2dfbe412..01a4afdcebb5b 100644 --- a/x-pack/plugins/apm/common/agent_configuration/runtime_types/bytes_rt.ts +++ b/x-pack/plugins/apm/common/agent_configuration/runtime_types/bytes_rt.ts @@ -10,17 +10,35 @@ import { i18n } from '@kbn/i18n'; import { amountAndUnitToObject } from '../amount_and_unit'; import { getRangeType } from './get_range_type'; -export const BYTE_UNITS = ['b', 'kb', 'mb']; +function toBytes(amount: number, unit: string) { + switch (unit) { + case 'kb': + return amount * 2 ** 10; + case 'mb': + return amount * 2 ** 20; + case 'b': + default: + return amount; + } +} export function getBytesRt({ - min = -Infinity, - max = Infinity, + min, + max, units }: { - min?: number; - max?: number; + min?: string; + max?: string; units: string[]; }) { + const { amount: minAmount, unit: minUnit } = min + ? amountAndUnitToObject(min) + : { amount: -Infinity, unit: 'b' }; + + const { amount: maxAmount, unit: maxUnit } = max + ? amountAndUnitToObject(max) + : { amount: Infinity, unit: 'b' }; + const message = i18n.translate('xpack.apm.agentConfig.bytes.errorText', { defaultMessage: `{rangeType, select, between {Must be between {min} and {max} with unit: {units}} @@ -32,7 +50,7 @@ export function getBytesRt({ min, max, units: units.join(', '), - rangeType: getRangeType(min, max) + rangeType: getRangeType(minAmount, maxAmount) } }); @@ -42,11 +60,16 @@ export function getBytesRt({ (input, context) => { return either.chain(t.string.validate(input, context), inputAsString => { const { amount, unit } = amountAndUnitToObject(inputAsString); - const amountAsInt = parseInt(amount, 10); const isValidUnit = units.includes(unit); - const isValid = amountAsInt >= min && amountAsInt <= max && isValidUnit; - return isValid + const inputAsBytes = toBytes(amount, unit); + const minAsBytes = toBytes(minAmount, minUnit); + const maxAsBytes = toBytes(maxAmount, maxUnit); + + const isValidAmount = + inputAsBytes >= minAsBytes && inputAsBytes <= maxAsBytes; + + return isValidUnit && isValidAmount ? t.success(inputAsString) : t.failure(input, context, message); }); diff --git a/x-pack/plugins/apm/common/agent_configuration/runtime_types/duration_rt.ts b/x-pack/plugins/apm/common/agent_configuration/runtime_types/duration_rt.ts index 39ba4c28cdf53..86e1f2d77e75d 100644 --- a/x-pack/plugins/apm/common/agent_configuration/runtime_types/duration_rt.ts +++ b/x-pack/plugins/apm/common/agent_configuration/runtime_types/duration_rt.ts @@ -8,11 +8,11 @@ import * as t from 'io-ts'; import { either } from 'fp-ts/lib/Either'; import moment, { unitOfTime } from 'moment'; import { i18n } from '@kbn/i18n'; -import { amountAndUnitToObject } from '../amount_and_unit'; +import { amountAndUnitToObject, AmountAndUnit } from '../amount_and_unit'; import { getRangeType } from './get_range_type'; -function getDuration({ amount, unit }: { amount: string; unit: string }) { - return moment.duration(parseInt(amount, 10), unit as unitOfTime.Base); +function getDuration({ amount, unit }: AmountAndUnit) { + return moment.duration(amount, unit as unitOfTime.Base); } export function getDurationRt({ @@ -38,8 +38,8 @@ export function getDurationRt({ min, max, rangeType: getRangeType( - minAmountAndUnit ? parseInt(minAmountAndUnit.amount, 10) : undefined, - maxAmountAndUnit ? parseInt(maxAmountAndUnit.amount, 10) : undefined + minAmountAndUnit ? minAmountAndUnit.amount : undefined, + maxAmountAndUnit ? maxAmountAndUnit.amount : undefined ) } }); diff --git a/x-pack/plugins/apm/common/agent_configuration/setting_definitions/__snapshots__/index.test.ts.snap b/x-pack/plugins/apm/common/agent_configuration/setting_definitions/__snapshots__/index.test.ts.snap index 92aa0e438d97b..4f5763dcde582 100644 --- a/x-pack/plugins/apm/common/agent_configuration/setting_definitions/__snapshots__/index.test.ts.snap +++ b/x-pack/plugins/apm/common/agent_configuration/setting_definitions/__snapshots__/index.test.ts.snap @@ -4,7 +4,7 @@ exports[`settingDefinitions should have correct default values 1`] = ` Array [ Object { "key": "api_request_size", - "min": 0, + "min": "0b", "type": "bytes", "units": Array [ "b", diff --git a/x-pack/plugins/apm/common/agent_configuration/setting_definitions/index.ts b/x-pack/plugins/apm/common/agent_configuration/setting_definitions/index.ts index f7760aaafc0f2..8a8f726c61f76 100644 --- a/x-pack/plugins/apm/common/agent_configuration/setting_definitions/index.ts +++ b/x-pack/plugins/apm/common/agent_configuration/setting_definitions/index.ts @@ -50,7 +50,7 @@ function getSettingDefaults(setting: RawSettingDefinition): SettingDefinition { case 'bytes': { const units = setting.units ?? ['b', 'kb', 'mb']; - const min = setting.min ?? 0; + const min = setting.min ?? '0b'; const max = setting.max; return { diff --git a/x-pack/plugins/apm/common/agent_configuration/setting_definitions/types.d.ts b/x-pack/plugins/apm/common/agent_configuration/setting_definitions/types.d.ts index 29125193edfb6..85a454b5f256a 100644 --- a/x-pack/plugins/apm/common/agent_configuration/setting_definitions/types.d.ts +++ b/x-pack/plugins/apm/common/agent_configuration/setting_definitions/types.d.ts @@ -80,8 +80,8 @@ interface IntegerSetting extends BaseSetting { interface BytesSetting extends BaseSetting { type: 'bytes'; - min?: number; - max?: number; + min?: string; + max?: string; units?: string[]; }