mirror of
https://github.com/usebruno/bruno.git
synced 2026-06-25 21:55:49 +00:00
fix: prevent assertions from returning wrong values during large iteration runs (#7692)
This commit is contained in:
@@ -15,10 +15,9 @@ const { marshallToVm } = require('./utils');
|
||||
const addCryptoUtilsShimToContext = require('./shims/lib/crypto-utils');
|
||||
const { wrapScriptInClosure, SANDBOX } = require('../../utils/sandbox');
|
||||
|
||||
let QuickJSSyncContext;
|
||||
let QuickJSModule;
|
||||
const loader = memoizePromiseFactory(() => newQuickJSWASMModule());
|
||||
const getContext = (opts) => loader().then((mod) => (QuickJSSyncContext = mod.newContext(opts)));
|
||||
getContext();
|
||||
loader().then((mod) => (QuickJSModule = mod));
|
||||
|
||||
const toNumber = (value) => {
|
||||
const num = Number(value);
|
||||
@@ -58,9 +57,8 @@ const executeQuickJsVm = ({ script: externalScript, context: externalContext, sc
|
||||
externalScript = removeQuotes(externalScript);
|
||||
}
|
||||
|
||||
const vm = QuickJSSyncContext;
|
||||
|
||||
try {
|
||||
const vm = QuickJSModule.newContext();
|
||||
const { bru, req, res, ...variables } = externalContext;
|
||||
|
||||
bru && addBruShimToContext(vm, bru);
|
||||
@@ -98,7 +96,7 @@ const executeQuickJsVmAsync = async ({ script: externalScript, context: external
|
||||
externalScript = externalScript?.trim();
|
||||
|
||||
try {
|
||||
const module = await newQuickJSWASMModule();
|
||||
const module = await loader();
|
||||
const vm = module.newContext();
|
||||
|
||||
// add crypto utilities required by the crypto-js library in bundledCode
|
||||
@@ -144,5 +142,6 @@ const executeQuickJsVmAsync = async ({ script: externalScript, context: external
|
||||
|
||||
module.exports = {
|
||||
executeQuickJsVm,
|
||||
executeQuickJsVmAsync
|
||||
executeQuickJsVmAsync,
|
||||
loader
|
||||
};
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
const { describe, it, expect } = require('@jest/globals');
|
||||
const { describe, it, expect, beforeAll } = require('@jest/globals');
|
||||
const TestRuntime = require('../src/runtime/test-runtime');
|
||||
const ScriptRuntime = require('../src/runtime/script-runtime');
|
||||
const AssertRuntime = require('../src/runtime/assert-runtime');
|
||||
const Bru = require('../src/bru');
|
||||
const VarsRuntime = require('../src/runtime/vars-runtime');
|
||||
const { loader: quickJsLoader } = require('../src/sandbox/quickjs');
|
||||
|
||||
describe('runtime', () => {
|
||||
describe('test-runtime', () => {
|
||||
@@ -261,6 +262,10 @@ describe('runtime', () => {
|
||||
});
|
||||
|
||||
describe('assert-runtime', () => {
|
||||
beforeAll(async () => {
|
||||
await quickJsLoader();
|
||||
});
|
||||
|
||||
const baseRequest = {
|
||||
method: 'GET',
|
||||
url: 'http://localhost:3000/',
|
||||
@@ -275,11 +280,81 @@ describe('runtime', () => {
|
||||
headers: {}
|
||||
});
|
||||
|
||||
const runAssertions = (assertions, response, runtime = 'nodevm') => {
|
||||
const runAssertions = (assertions, response, runtime = 'nodevm', runtimeVariables = {}) => {
|
||||
const assertRuntime = new AssertRuntime({ runtime });
|
||||
return assertRuntime.runAssertions(assertions, { ...baseRequest }, response, {}, {}, process.env);
|
||||
return assertRuntime.runAssertions(assertions, { ...baseRequest }, response, {}, runtimeVariables, process.env);
|
||||
};
|
||||
|
||||
// Ensures each QuickJS evaluation gets a fresh context
|
||||
describe('quickjs context isolation across iterations', () => {
|
||||
const ITERATION_COUNT = 350;
|
||||
|
||||
it('should return correct res.status on every iteration', () => {
|
||||
for (let i = 0; i < ITERATION_COUNT; i++) {
|
||||
const status = 200 + i;
|
||||
const results = runAssertions(
|
||||
[{ name: 'res.status', value: `eq ${status}`, enabled: true }],
|
||||
{ status, statusText: 'OK', data: {}, headers: {} },
|
||||
'quickjs'
|
||||
);
|
||||
expect(results[0].status).toBe('pass');
|
||||
}
|
||||
});
|
||||
|
||||
it('should return correct res.body values on every iteration', () => {
|
||||
for (let i = 0; i < ITERATION_COUNT; i++) {
|
||||
const results = runAssertions(
|
||||
[{ name: 'res.body.id', value: `eq ${i}`, enabled: true }],
|
||||
{ status: 200, statusText: 'OK', data: { id: i }, headers: {} },
|
||||
'quickjs'
|
||||
);
|
||||
expect(results[0].status).toBe('pass');
|
||||
}
|
||||
});
|
||||
|
||||
it('should not return stale data from a previous iteration', () => {
|
||||
// First call with status 200
|
||||
runAssertions(
|
||||
[{ name: 'res.status', value: 'eq 200', enabled: true }],
|
||||
{ status: 200, statusText: 'OK', data: { token: 'bearer_abc' }, headers: { authorization: 'bearer xyz' } },
|
||||
'quickjs'
|
||||
);
|
||||
|
||||
// Second call with status 404 — must not return 200 or any data from previous call
|
||||
const results = runAssertions(
|
||||
[
|
||||
{ name: 'res.status', value: 'eq 404', enabled: true },
|
||||
{ name: 'res.body.error', value: 'eq not_found', enabled: true }
|
||||
],
|
||||
{ status: 404, statusText: 'Not Found', data: { error: 'not_found' }, headers: {} },
|
||||
'quickjs'
|
||||
);
|
||||
|
||||
expect(results[0].status).toBe('pass');
|
||||
expect(results[1].status).toBe('pass');
|
||||
});
|
||||
|
||||
it('should not persist runtime variables from a previous call', () => {
|
||||
// First call with runtime variable token = "one"
|
||||
const results1 = runAssertions(
|
||||
[{ name: 'token', value: 'eq one', enabled: true }],
|
||||
{ status: 200, statusText: 'OK', data: {}, headers: {} },
|
||||
'quickjs',
|
||||
{ token: 'one' }
|
||||
);
|
||||
expect(results1[0].status).toBe('pass');
|
||||
|
||||
// Second call without token
|
||||
const results2 = runAssertions(
|
||||
[{ name: 'token', value: 'eq one', enabled: true }],
|
||||
{ status: 200, statusText: 'OK', data: {}, headers: {} },
|
||||
'quickjs'
|
||||
);
|
||||
// Must fail — token should not exist in a fresh context
|
||||
expect(results2[0].status).toBe('fail');
|
||||
});
|
||||
});
|
||||
|
||||
describe('isJson', () => {
|
||||
it('should pass for a plain object', () => {
|
||||
const results = runAssertions(
|
||||
|
||||
Reference in New Issue
Block a user