From bbf6d75cfffadd379f60c045c930ac64e7664eea Mon Sep 17 00:00:00 2001 From: jackkav Date: Sun, 27 Oct 2024 00:15:50 +0200 Subject: [PATCH 1/5] untested poc --- packages/insomnia-inso/src/cli.ts | 80 +++++++++++++------- packages/insomnia/src/common/send-request.ts | 11 ++- 2 files changed, 58 insertions(+), 33 deletions(-) diff --git a/packages/insomnia-inso/src/cli.ts b/packages/insomnia-inso/src/cli.ts index cf4df8bb022..6d8ecbf9786 100644 --- a/packages/insomnia-inso/src/cli.ts +++ b/packages/insomnia-inso/src/cli.ts @@ -7,8 +7,9 @@ import consola, { BasicReporter, FancyReporter, LogLevel, logType } from 'consol import { cosmiconfig } from 'cosmiconfig'; import fs from 'fs'; import { JSON_ORDER_PREFIX, JSON_ORDER_SEPARATOR } from 'insomnia/src/common/constants'; -import { getSendRequestCallbackMemDb } from 'insomnia/src/common/send-request'; +import { getSendRequestCallbackMemDb, wrapAroundIterationOverIterationData } from 'insomnia/src/common/send-request'; import { UserUploadEnvironment } from 'insomnia/src/models/environment'; +import { invariant } from 'insomnia/src/utils/invariant'; import { deserializeNDJSON } from 'insomnia/src/utils/ndjson'; import { type RequestTestResult } from 'insomnia-sdk'; import { generate, runTestsCli } from 'insomnia-testing'; @@ -23,6 +24,7 @@ import { Database, isFile, loadDb } from './db'; import { insomniaExportAdapter } from './db/adapters/insomnia-adapter'; import { loadApiSpec, promptApiSpec } from './db/models/api-spec'; import { loadEnvironment, promptEnvironment } from './db/models/environment'; +import { BaseModel } from './db/models/types'; import { loadTestSuites, promptTestSuites } from './db/models/unit-test-suite'; import { matchIdIsh } from './db/models/util'; import { loadWorkspace, promptWorkspace } from './db/models/workspace'; @@ -534,39 +536,63 @@ export const go = (args?: string[]) => { const iterationCount = parseInt(options.iterationCount, 10); const iterationData = await pathToIterationData(options.iterationData, options.envVar); - const sendRequest = await getSendRequestCallbackMemDb(environment._id, db, { validateSSL: !options.disableCertValidation }, iterationData, iterationCount); - let success = true; - for (let i = 0; i < iterationCount; i++) { + const sendRequest = await getSendRequestCallbackMemDb(environment._id, db, { validateSSL: !options.disableCertValidation }, iterationCount); + let requestOrTestFailed = false; + let workflowQueue: { req: BaseModel; iteration: number; iterationData?: UserUploadEnvironment }[] = []; + // build a workflow queue of requests to run and approriate iteration data + for (let iteration = 0; iteration < iterationCount; iteration++) { for (const req of requestsToRun) { - if (options.bail && !success) { - return; + const getCurrentRowOfIterationData = wrapAroundIterationOverIterationData(iterationData, iteration); + workflowQueue.push({ req, iteration, iterationData: getCurrentRowOfIterationData }); + } + } + // loop over workflow queue and if nextrequest exists drop the queue and add it to run next with the same iteration data + // if bail is true, exit on first request or test failure + while (workflowQueue.length) { + // remove the first element in the queue + const current = workflowQueue.shift(); + invariant(current, 'something went wrong with the workflow current item should be defined'); + logger.log(`Running request: ${current.req.name} ${current.req._id}`); + const res = await sendRequest(current.req._id, current.iteration, current.iterationData); + if (!res) { + logger.error('Timed out while running script'); + requestOrTestFailed = true; + if (options.bail) { + return process.exit(1); } - logger.log(`Running request: ${req.name} ${req._id}`); - const res = await sendRequest(req._id, i); - if (!res) { - logger.error('Timed out while running script'); - success = false; - continue; + // continue to next in workflow queue + continue; + } + if (res.nextRequestIdOrName) { + const nextRequest = requestsToRun.find(r => r.name === res.nextRequestIdOrName || r._id === res.nextRequestIdOrName); + if (nextRequest) { + workflowQueue = []; + workflowQueue.push({ req: nextRequest, iteration: current.iteration, iterationData: current.iterationData }); } - // logger.debug(res); - const timelineString = await readFile(res.timelinePath, 'utf8'); - const appendNewLineIfNeeded = (str: string) => str.endsWith('\n') ? str : str + '\n'; - const timeline = deserializeNDJSON(timelineString).map(e => appendNewLineIfNeeded(e.value)).join(''); - logger.trace(timeline); - if (res.testResults?.length) { - console.log(` -Test results:`); - console.log(logTestResult(options.reporter, res.testResults)); - const hasFailedTests = res.testResults.some(t => t.status === 'failed'); - if (hasFailedTests) { - success = false; + } + // Log timeline in --verbose + const timelineString = await readFile(res.timelinePath, 'utf8'); + const appendNewLineIfNeeded = (str: string) => str.endsWith('\n') ? str : str + '\n'; + const timeline = deserializeNDJSON(timelineString).map(e => appendNewLineIfNeeded(e.value)).join(''); + logger.trace(timeline); + // Log test results + if (res.testResults?.length) { + console.log(` + Test results:`); + console.log(logTestResult(options.reporter, res.testResults)); + const hasFailedTests = res.testResults.some(t => t.status === 'failed'); + if (hasFailedTests) { + requestOrTestFailed = true; + if (options.bail) { + return process.exit(1); } } - - await new Promise(r => setTimeout(r, parseInt(options.delayRequest, 10))); } + // Delay between requests + await new Promise(r => setTimeout(r, parseInt(options.delayRequest, 10))); } - return process.exit(success ? 0 : 1); + // Exit with 1 if any request or test failed + return process.exit(requestOrTestFailed ? 1 : 0); } catch (error) { logErrorAndExit(error); } diff --git a/packages/insomnia/src/common/send-request.ts b/packages/insomnia/src/common/send-request.ts index 74c0b0326dc..2ce9a2508bd 100644 --- a/packages/insomnia/src/common/send-request.ts +++ b/packages/insomnia/src/common/send-request.ts @@ -24,7 +24,7 @@ import { generateId } from './misc'; // The network layer uses settings from the settings model // We want to give consumers the ability to override certain settings type SettingsOverride = Pick; -const wrapAroundIterationOverIterationData = (list?: UserUploadEnvironment[], currentIteration?: number): UserUploadEnvironment | undefined => { +export const wrapAroundIterationOverIterationData = (list?: UserUploadEnvironment[], currentIteration?: number): UserUploadEnvironment | undefined => { if (currentIteration === undefined || !Array.isArray(list) || list.length === 0) { return undefined; } @@ -33,7 +33,7 @@ const wrapAroundIterationOverIterationData = (list?: UserUploadEnvironment[], cu }; return list[(currentIteration + 1) % list.length]; }; -export async function getSendRequestCallbackMemDb(environmentId: string, memDB: any, settingsOverrides?: SettingsOverride, iterationData?: UserUploadEnvironment[], iterationCount?: number) { +export async function getSendRequestCallbackMemDb(environmentId: string, memDB: any, settingsOverrides?: SettingsOverride, iterationTotal?: number) { // Initialize the DB in-memory and fill it with data if we're given one await database.init( modelTypes(), @@ -118,10 +118,9 @@ export async function getSendRequestCallbackMemDb(environmentId: string, memDB: }; // Return callback helper to send requests - return async function sendRequest(requestId: string, iteration?: number) { + return async function sendRequest(requestId: string, iteration?: number, iterationDataRow?: UserUploadEnvironment) { const requestData = await fetchInsoRequestData(requestId, environmentId); - const getCurrentRowOfIterationData = wrapAroundIterationOverIterationData(iterationData, iteration); - const mutatedContext = await tryToExecutePreRequestScript(requestData, getCurrentRowOfIterationData, iteration, iterationCount); + const mutatedContext = await tryToExecutePreRequestScript(requestData, iterationDataRow, iteration, iterationTotal); if (mutatedContext === null) { console.error('Time out while executing pre-request script'); return null; @@ -168,6 +167,6 @@ export async function getSendRequestCallbackMemDb(environmentId: string, memDB: const bodyBuffer = await getBodyBuffer(res) as Buffer; const data = bodyBuffer ? bodyBuffer.toString('utf8') : undefined; - return { status, statusMessage, data, headers, responseTime, timelinePath: requestData.timelinePath, testResults: postMutatedContext.requestTestResults }; + return { status, statusMessage, data, headers, responseTime, timelinePath: requestData.timelinePath, testResults: postMutatedContext.requestTestResults, nextRequestIdOrName: postMutatedContext?.execution?.nextRequestIdOrName }; }; } From 992d016c269c0904b7c0c87a1ee1925c01025181 Mon Sep 17 00:00:00 2001 From: jackkav Date: Sun, 27 Oct 2024 00:47:45 +0200 Subject: [PATCH 2/5] add failing tests --- packages/insomnia-inso/src/cli.test.ts | 4 + .../src/examples/set-next-request.yml | 113 ++++++++++++++++++ 2 files changed, 117 insertions(+) create mode 100644 packages/insomnia-inso/src/examples/set-next-request.yml diff --git a/packages/insomnia-inso/src/cli.test.ts b/packages/insomnia-inso/src/cli.test.ts index 158d3b187fb..db630968644 100644 --- a/packages/insomnia-inso/src/cli.test.ts +++ b/packages/insomnia-inso/src/cli.test.ts @@ -43,6 +43,8 @@ const shouldReturnSuccessCode = [ '$PWD/packages/insomnia-inso/bin/inso run collection -w packages/insomnia-inso/src/examples/after-response.yml wrk_616795 --verbose', // select request by id '$PWD/packages/insomnia-inso/bin/inso run collection -w packages/insomnia-inso/src/examples/three-requests.yml -i req_3fd28aabbb18447abab1f45e6ee4bdc1 -i req_6063adcdab5b409e9b4f00f47322df4a', + // setNextRequest runs the next request then ends + '$PWD/packages/insomnia-inso/bin/inso run collection -w packages/insomnia-inso/src/examples/set-next-request.yml wrk_cbc89e', // multiple --env-var overrides '$PWD/packages/insomnia-inso/bin/inso run collection -w packages/insomnia-inso/src/examples/with-missing-env-vars.yml -i req_3fd28aabbb18447abab1f45e6ee4bdc1 --env-var firstkey=first --env-var secondkey=second', // globals file path env overrides @@ -56,6 +58,8 @@ const shouldReturnErrorCode = [ '$PWD/packages/insomnia-inso/bin/inso lint spec packages/insomnia-inso/src/db/fixtures/insomnia-v4/malformed.yaml', // after-response script and test '$PWD/packages/insomnia-inso/bin/inso run collection -w packages/insomnia-inso/src/examples/after-response-failed-test.yml wrk_616795 --verbose', + // failing test + '$PWD/packages/insomnia-inso/bin/inso run collection -w packages/insomnia-inso/src/examples/set-next-request.yml -i req_6a0343d51ca74de7a2c73e34211354ab', ]; describe('inso dev bundle', () => { diff --git a/packages/insomnia-inso/src/examples/set-next-request.yml b/packages/insomnia-inso/src/examples/set-next-request.yml new file mode 100644 index 00000000000..06d82757705 --- /dev/null +++ b/packages/insomnia-inso/src/examples/set-next-request.yml @@ -0,0 +1,113 @@ +_type: export +__export_format: 4 +__export_date: 2024-10-26T22:34:07.758Z +__export_source: insomnia.desktop.app:v10.1.1 +resources: + - _id: req_5b004a6d43ef4e62a9117b9e08daa61e + parentId: wrk_cbc89ea8669648b8970ae684f9ff08b8 + modified: 1729982030396 + created: 1729981763331 + url: localhost:4010/echo + name: setNextRequest + description: "" + method: GET + body: {} + parameters: [] + headers: + - name: User-Agent + value: insomnia/10.1.1 + authentication: {} + metaSortKey: -1729981822482 + isPrivate: false + pathParameters: [] + afterResponseScript: |+ + insomnia.execution.setNextRequest("Passing Request"); + settingStoreCookies: true + settingSendCookies: true + settingDisableRenderRequestBody: false + settingEncodeUrl: true + settingRebuildPath: true + settingFollowRedirects: global + _type: request + - _id: wrk_cbc89ea8669648b8970ae684f9ff08b8 + parentId: null + modified: 1729981758905 + created: 1729981758905 + name: test next request + description: "" + scope: collection + _type: workspace + - _id: req_6a0343d51ca74de7a2c73e34211354ab + parentId: wrk_cbc89ea8669648b8970ae684f9ff08b8 + modified: 1729981999436 + created: 1729981846012 + url: localhost:4010/echo + name: Failing Request + description: "" + method: GET + body: {} + parameters: [] + headers: + - name: User-Agent + value: insomnia/10.1.1 + authentication: {} + preRequestScript: |- + insomnia.test('Failing test', () => { + insomnia.expect(true).to.eql(false); + }); + metaSortKey: -1729981763231 + isPrivate: false + pathParameters: [] + settingStoreCookies: true + settingSendCookies: true + settingDisableRenderRequestBody: false + settingEncodeUrl: true + settingRebuildPath: true + settingFollowRedirects: global + _type: request + - _id: req_704fcb5bf8e047cbaee4f8ca23a97249 + parentId: wrk_cbc89ea8669648b8970ae684f9ff08b8 + modified: 1729982010136 + created: 1729981822432 + url: localhost:4010/echo + name: Passing Request + description: "" + method: GET + body: {} + parameters: [] + headers: + - name: User-Agent + value: insomnia/10.1.1 + authentication: {} + preRequestScript: |- + insomnia.test('Passing test', () => { + insomnia.expect(true).to.eql(true); + }); + metaSortKey: -1729981763131 + isPrivate: false + pathParameters: [] + settingStoreCookies: true + settingSendCookies: true + settingDisableRenderRequestBody: false + settingEncodeUrl: true + settingRebuildPath: true + settingFollowRedirects: global + _type: request + - _id: env_6d416edc2e4fd8b59c75eae67c16f3b21e1e2de2 + parentId: wrk_cbc89ea8669648b8970ae684f9ff08b8 + modified: 1729982036362 + created: 1729981758906 + name: Base Environment + data: {} + dataPropertyOrder: {} + color: null + isPrivate: false + metaSortKey: 1729981758906 + _type: environment + - _id: jar_6d416edc2e4fd8b59c75eae67c16f3b21e1e2de2 + parentId: wrk_cbc89ea8669648b8970ae684f9ff08b8 + modified: 1729982036362 + created: 1729981758906 + name: Default Jar + cookies: [] + _type: cookie_jar From dfcd652ea01240c161f80fe4dcf7a610a16669ad Mon Sep 17 00:00:00 2001 From: jackkav Date: Sun, 27 Oct 2024 00:55:18 +0200 Subject: [PATCH 3/5] fix test results bug --- packages/insomnia/src/common/send-request.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/insomnia/src/common/send-request.ts b/packages/insomnia/src/common/send-request.ts index 2ce9a2508bd..9e4cc8d6243 100644 --- a/packages/insomnia/src/common/send-request.ts +++ b/packages/insomnia/src/common/send-request.ts @@ -166,7 +166,8 @@ export async function getSendRequestCallbackMemDb(environmentId: string, memDB: const headers = headerArray?.reduce((acc, { name, value }) => ({ ...acc, [name.toLowerCase() || '']: value || '' }), []); const bodyBuffer = await getBodyBuffer(res) as Buffer; const data = bodyBuffer ? bodyBuffer.toString('utf8') : undefined; - - return { status, statusMessage, data, headers, responseTime, timelinePath: requestData.timelinePath, testResults: postMutatedContext.requestTestResults, nextRequestIdOrName: postMutatedContext?.execution?.nextRequestIdOrName }; + // TODO: find out why requestTestResults can be undefined and eliminate the case so its always an array + const testResults = [...(mutatedContext.requestTestResults || []), ...(postMutatedContext.requestTestResults || [])]; + return { status, statusMessage, data, headers, responseTime, timelinePath: requestData.timelinePath, testResults, nextRequestIdOrName: postMutatedContext?.execution?.nextRequestIdOrName }; }; } From ec3eb66b773dddd78006c5db9696c226af34cbd1 Mon Sep 17 00:00:00 2001 From: jackkav Date: Sun, 27 Oct 2024 01:00:42 +0200 Subject: [PATCH 4/5] leave todos --- packages/insomnia-inso/src/cli.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/insomnia-inso/src/cli.ts b/packages/insomnia-inso/src/cli.ts index 6d8ecbf9786..e16006faf4f 100644 --- a/packages/insomnia-inso/src/cli.ts +++ b/packages/insomnia-inso/src/cli.ts @@ -563,7 +563,9 @@ export const go = (args?: string[]) => { // continue to next in workflow queue continue; } + // TODO: add support for skipRequest if (res.nextRequestIdOrName) { + // TODO: add support for null input to exit 0 const nextRequest = requestsToRun.find(r => r.name === res.nextRequestIdOrName || r._id === res.nextRequestIdOrName); if (nextRequest) { workflowQueue = []; From eb826ff48e35e15a6d0b85bbd9ccbe51aeda4c98 Mon Sep 17 00:00:00 2001 From: jackkav Date: Sun, 27 Oct 2024 01:09:11 +0200 Subject: [PATCH 5/5] add logs --- packages/insomnia-inso/src/cli.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/insomnia-inso/src/cli.ts b/packages/insomnia-inso/src/cli.ts index e16006faf4f..3ccf8b70240 100644 --- a/packages/insomnia-inso/src/cli.ts +++ b/packages/insomnia-inso/src/cli.ts @@ -565,10 +565,13 @@ export const go = (args?: string[]) => { } // TODO: add support for skipRequest if (res.nextRequestIdOrName) { + logger.trace(`setNextRequest(${res.nextRequestIdOrName}) found, adding to workflow queue, and removing any others`); + // TODO: add support for null input to exit 0 const nextRequest = requestsToRun.find(r => r.name === res.nextRequestIdOrName || r._id === res.nextRequestIdOrName); if (nextRequest) { workflowQueue = []; + // TODO: should we use the same iteration data as previous or next in list? workflowQueue.push({ req: nextRequest, iteration: current.iteration, iterationData: current.iterationData }); } }