From 209ffa55bfd3532b2771e3bfb03ef771d1a05eed Mon Sep 17 00:00:00 2001 From: Jacob Bolda Date: Wed, 28 Aug 2024 12:30:04 -0500 Subject: [PATCH 1/2] foundation simulator delay response API --- .changes/foundation-delay.md | 5 ++ packages/foundation/src/index.ts | 4 ++ packages/foundation/src/middleware/delay.ts | 61 +++++++++++++++++++++ 3 files changed, 70 insertions(+) create mode 100644 .changes/foundation-delay.md create mode 100644 packages/foundation/src/middleware/delay.ts diff --git a/.changes/foundation-delay.md b/.changes/foundation-delay.md new file mode 100644 index 00000000..48f324f9 --- /dev/null +++ b/.changes/foundation-delay.md @@ -0,0 +1,5 @@ +--- +"@simulacrum/foundation-simulator": minor:enhance +--- + +Add API to configure a delay of all responses with a set interval. Using this in a simulator would enable a feel closer to a real external endpoint. diff --git a/packages/foundation/src/index.ts b/packages/foundation/src/index.ts index aa2febda..5ef77cd7 100644 --- a/packages/foundation/src/index.ts +++ b/packages/foundation/src/index.ts @@ -28,6 +28,7 @@ import type { ExtendSimulationSchema, } from "./store/schema"; import type { RecursivePartial } from "./store/types"; +import { delayMiddleware } from "./middleware/delay"; type SimulationHandlerFunctions = ( context: OpenAPIBackendContext, @@ -50,12 +51,14 @@ export function createFoundationSimulationServer< ExtendedSimulationSelectors >({ port = 9000, + delayResponses, serveJsonFiles, openapi, extendStore, extendRouter, }: { port: number; + delayResponses?: number | { minimum: number; maximum: number }; serveJsonFiles?: string; openapi?: { document: Document | (Document | RecursivePartial)[]; @@ -93,6 +96,7 @@ export function createFoundationSimulationServer< let app = express(); app.use(express.json()); let simulationStore = createSimulationStore(extendStore); + app.use(delayMiddleware(delayResponses)); if (serveJsonFiles) { const jsonFiles = new fdir() diff --git a/packages/foundation/src/middleware/delay.ts b/packages/foundation/src/middleware/delay.ts new file mode 100644 index 00000000..519d0834 --- /dev/null +++ b/packages/foundation/src/middleware/delay.ts @@ -0,0 +1,61 @@ +import type { Request, Response, NextFunction } from "express"; + +export function delayMiddleware( + delayResponses?: number | { minimum: number; maximum: number } +) { + const delayMin = + typeof delayResponses === "number" + ? delayResponses + : delayResponses?.minimum; + const delayMax = + typeof delayResponses === "number" ? undefined : delayResponses?.maximum; + + const minFromProcess = process.env.SIM_RESPONSE_DELAY_MIN + ? process.env.SIM_RESPONSE_DELAY_MIN + : process.env.SIM_RESPONSE_DELAY; + const min = minFromProcess ? parseInt(minFromProcess, 10) : delayMin; + + const maxFromProcess = process.env.SIM_RESPONSE_DELAY_MAX; + const max = maxFromProcess ? parseInt(maxFromProcess, 10) : delayMax; + + return async function delayHandler( + request: Request, + response: Response, + next: NextFunction + ) { + if (min || max) { + let timeoutDuration = calculateTimeoutDuration(min, max); + await new Promise((resolve) => { + let timeoutHandle: NodeJS.Timeout | undefined = undefined; + + const done = () => { + if (timeoutHandle) { + clearTimeout(timeoutHandle); + } + resolve(); + }; + + timeoutHandle = setTimeout(done, timeoutDuration); + }); + } + next(); + }; +} + +function calculateTimeoutDuration( + min: number | undefined, + max: number | undefined +): number { + if (max && !min) { + // sets the timeout at +/- 20% of configured max + return max * 0.8 + max * 0.4 * Math.random(); + } else if (min && !max) { + // sets the timeout at +/- 20% of configured max + return min * 0.8 + min * 0.4 * Math.random(); + } else if (max && min) { + const timeoutRange = max - min; + return min + timeoutRange * Math.random(); + } + + return 0; +} From 1254deeddf49d2b16beab283bc8b9f165c3519ff Mon Sep 17 00:00:00 2001 From: Jacob Bolda Date: Thu, 12 Sep 2024 14:55:26 -0500 Subject: [PATCH 2/2] remove process --- packages/foundation/src/middleware/delay.ts | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/packages/foundation/src/middleware/delay.ts b/packages/foundation/src/middleware/delay.ts index 519d0834..29e9fb1c 100644 --- a/packages/foundation/src/middleware/delay.ts +++ b/packages/foundation/src/middleware/delay.ts @@ -10,21 +10,13 @@ export function delayMiddleware( const delayMax = typeof delayResponses === "number" ? undefined : delayResponses?.maximum; - const minFromProcess = process.env.SIM_RESPONSE_DELAY_MIN - ? process.env.SIM_RESPONSE_DELAY_MIN - : process.env.SIM_RESPONSE_DELAY; - const min = minFromProcess ? parseInt(minFromProcess, 10) : delayMin; - - const maxFromProcess = process.env.SIM_RESPONSE_DELAY_MAX; - const max = maxFromProcess ? parseInt(maxFromProcess, 10) : delayMax; - return async function delayHandler( request: Request, response: Response, next: NextFunction ) { - if (min || max) { - let timeoutDuration = calculateTimeoutDuration(min, max); + if (delayMin || delayMax) { + let timeoutDuration = calculateTimeoutDuration(delayMin, delayMax); await new Promise((resolve) => { let timeoutHandle: NodeJS.Timeout | undefined = undefined;