From be5db0d56ead71eb56641bdde3c6c54b75af7115 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ro=C5=BCek?= Date: Wed, 27 Nov 2024 20:43:57 +0100 Subject: [PATCH] feat(cli): support global delay range --- .../cli/src/util/__tests__/config.spec.ts | 25 +++++++++++++ packages/cli/src/util/config.ts | 35 ++++++++++++++++--- packages/cli/src/util/createServer.ts | 4 +++ test-harness/specs/config/delay_constant.txt | 33 +++++++++++++++++ test-harness/specs/config/delay_range.txt | 33 +++++++++++++++++ test-harness/specs/delay/delay_config.txt | 35 +++++++++++++++++++ 6 files changed, 161 insertions(+), 4 deletions(-) create mode 100644 test-harness/specs/config/delay_constant.txt create mode 100644 test-harness/specs/config/delay_range.txt create mode 100644 test-harness/specs/delay/delay_config.txt diff --git a/packages/cli/src/util/__tests__/config.spec.ts b/packages/cli/src/util/__tests__/config.spec.ts index 845d8b76a..66e942b5a 100644 --- a/packages/cli/src/util/__tests__/config.spec.ts +++ b/packages/cli/src/util/__tests__/config.spec.ts @@ -6,6 +6,7 @@ describe('assertValidConfig', () => { ignoreExamples: true, dynamic: false, jsonSchemaFakerFillProperties: true, + delay: [100, 200], chaos: { enabled: true, rate: 50, @@ -16,6 +17,14 @@ describe('assertValidConfig', () => { expect(assertValidConfig.bind(null, validConfig)).not.toThrow(); }); + it('should accept numeric delay', () => { + const validConfig: Config = { + delay: 100, + }; + + expect(assertValidConfig.bind(null, validConfig)).not.toThrow(); + }); + it('should throw an error for an invalid config', () => { const invalidConfig = { ignoreExamples: 'true', // invalid type @@ -75,4 +84,20 @@ describe('assertValidConfig', () => { }) ).toThrow(); }); + + it('should require upper latency bound to be higher than lower latency bound', () => { + expect( + assertValidConfig.bind(null, { + delay: [100, 50], + }) + ).toThrow(); + }); + + it('should throw an error for a config with negative delay', () => { + expect( + assertValidConfig.bind(null, { + delay: -100, + }) + ).toThrow(); + }); }); diff --git a/packages/cli/src/util/config.ts b/packages/cli/src/util/config.ts index 5b1074afd..c17b7a359 100644 --- a/packages/cli/src/util/config.ts +++ b/packages/cli/src/util/config.ts @@ -8,6 +8,7 @@ export type Config = { ignoreExamples?: boolean; dynamic?: boolean; jsonSchemaFakerFillProperties?: boolean; + delay?: number | [lowerBound: number, upperBound: number]; chaos?: { enabled?: boolean; rate?: number; @@ -26,6 +27,7 @@ export type Config = { const ajv = new Ajv.Ajv2020({ strict: true, allErrors: true, + $data: true, }); const validate = ajv.compile({ @@ -34,6 +36,34 @@ const validate = ajv.compile({ ignoreExamples: { type: 'boolean' }, dynamic: { type: 'boolean' }, jsonSchemaFakerFillProperties: { type: 'boolean' }, + delay: { + oneOf: [ + { + type: 'integer', + minimum: 0, + maximum: 5000, + }, + { + type: 'array', + prefixItems: [ + { + type: 'integer', + minimum: 0, + exclusiveMaximum: 5000, + }, + { + type: 'integer', + minimum: { + $data: '1/0', + }, + maximum: 5000, + }, + ], + minItems: 2, + items: false, + }, + ], + }, chaos: { type: 'object', unevaluatedProperties: false, @@ -102,10 +132,7 @@ export async function safeApplyConfig( try { const input = JSON.parse(content); - const valid = validate(input) as unknown as (input: unknown) => input is CreateMockServerOptions; - if (!valid) { - throw ajv.errorsText(validate.errors); - } + assertValidConfig(input); const merged = { ...defaultConfig, ...input }; for (const key of Object.keys(merged)) { diff --git a/packages/cli/src/util/createServer.ts b/packages/cli/src/util/createServer.ts index 4ab98faec..8019b9938 100644 --- a/packages/cli/src/util/createServer.ts +++ b/packages/cli/src/util/createServer.ts @@ -117,6 +117,9 @@ async function createPrismServerWithLogger(options: Observable 500 ? "Value is higher than 500" : "Value is not higher than 500"); print}' +====expect-loose==== +HTTP/1.1 200 OK + +Value is higher than 500 \ No newline at end of file diff --git a/test-harness/specs/config/delay_range.txt b/test-harness/specs/config/delay_range.txt new file mode 100644 index 000000000..49873d90a --- /dev/null +++ b/test-harness/specs/config/delay_range.txt @@ -0,0 +1,33 @@ +====test==== +Given I mock and specify a constant delay +When I send a request to an operation +Then the response should be delayed by that amount +====spec==== +openapi: "3.1.0" +info: + version: "0.0" + title: Config Test +paths: + /pets/{petId}: + get: + description: Get a pet by ID + responses: + "200": + description: A pet + content: + application/json: + schema: + type: integer + default: 0 +====config==== +{ + "delay": [300, 500] +} +====server==== +mock -p 4010 --config ${config} ${document} +====command==== +curl -i -s -w "%{time_total}" "http://127.0.0.1:4010/pets/2" | awk '{gsub(/0([0-9]+\.[0-9]+)/, $1 * 1000 > 300 ? "Value is higher than 300" : "Value is not higher than 300"); print}' +====expect-loose==== +HTTP/1.1 200 OK + +Value is higher than 300 \ No newline at end of file diff --git a/test-harness/specs/delay/delay_config.txt b/test-harness/specs/delay/delay_config.txt new file mode 100644 index 000000000..4257550b5 --- /dev/null +++ b/test-harness/specs/delay/delay_config.txt @@ -0,0 +1,35 @@ +====test==== +When I send a request to an operation +And I have a config with a delay of 2500ms +And in the headers I specify `Prefer: delay=100` +Then I get a response with a delay of 100ms +====spec==== +openapi: "3.1.1" +info: + version: "0" + title: Delays test + description: Delays test +paths: + /delay: + get: + description: widget details + responses: + "200": + description: delay response + content: + application/json: + schema: + type: integer + default: 0 +====config==== +{ + "delay": 2500 +} +====server==== +mock -p 4010 ${document} +====command==== +curl -i -s -w "%{time_total}" -H "Prefer: delay=100" "http://127.0.0.1:4010/delay" | awk '{gsub(/0([0-9]+\.[0-9]+)/, ($1 * 1000 < 2500 ? "Value is lower than 2500" : "Value is higher than 2500")); print}' +====expect-loose==== +HTTP/1.1 200 OK + +Value is lower than 2500 \ No newline at end of file