[tests] Properly test for multiple headers with same name in probes (#9538)

Updates the `responseHeaders` probe checks to properly test for multiple headers with the same name.

Previously the probes were using `headers.get()` which concats multiple headers into a single string, which results in the test not really checking if there are in fact multiple headers with the same name. Using `headers.raw()` allows us to properly test for that.

A couple of Python tests that were already checking for multiple `set-cookie` headers needed to be updated to match the full value, since the check now properly validates the full string match of each header (before it was basically just doing a `string.includes()` check).

This is a precursor for https://github.com/vercel/vercel/pull/9533.
This commit is contained in:
Nathan Rajlich
2023-02-24 14:07:00 -08:00
committed by GitHub
parent f09d6fce85
commit 48eed7532a
2 changed files with 50 additions and 22 deletions

View File

@@ -220,26 +220,47 @@ async function runProbe(probe, deploymentId, deploymentUrl, ctx) {
hadTest = true;
}
/**
* @type Record<string, string[]>
*/
const rawHeaders = resp.headers.raw();
if (probe.responseHeaders) {
// eslint-disable-next-line no-loop-func
Object.keys(probe.responseHeaders).forEach(header => {
const actual = resp.headers.get(header);
const expected = probe.responseHeaders[header];
const isEqual = Array.isArray(expected)
? expected.every(h => actual.includes(h))
: typeof expected === 'string' &&
expected.startsWith('/') &&
expected.endsWith('/')
? new RegExp(expected.slice(1, -1)).test(actual)
: expected === actual;
if (!isEqual) {
const headers = Array.from(resp.headers.entries())
.map(([k, v]) => ` ${k}=${v}`)
.join('\n');
const actualArr = rawHeaders[header.toLowerCase()];
let expectedArr = probe.responseHeaders[header];
throw new Error(
`Page ${probeUrl} does not have expected response header ${header}.\n\nExpected: ${expected}.\n\nActual: ${headers}`
);
// Header should not exist
if (expectedArr === null) {
if (actualArr) {
throw new Error(
`Page ${probeUrl} contains response header "${header}", but probe says it should not.\n\nActual: ${formatHeaders(
rawHeaders
)}`
);
}
return;
}
if (!Array.isArray(expectedArr)) {
expectedArr = [expectedArr];
}
for (const expected of expectedArr) {
let isEqual = false;
for (const actual of actualArr) {
isEqual =
expected.startsWith('/') && expected.endsWith('/')
? new RegExp(expected.slice(1, -1)).test(actual)
: expected === actual;
if (isEqual) break;
}
if (!isEqual) {
throw new Error(
`Page ${probeUrl} does not have expected response header ${header}.\n\nExpected: ${expected}.\n\nActual: ${formatHeaders(
rawHeaders
)}`
);
}
}
});
hadTest = true;
@@ -249,12 +270,10 @@ async function runProbe(probe, deploymentId, deploymentUrl, ctx) {
const expected = probe.notResponseHeaders[header];
if (headerValue === expected) {
const headers = Array.from(resp.headers.entries())
.map(([k, v]) => ` ${k}=${v}`)
.join('\n');
throw new Error(
`Page ${probeUrl} has unexpected response header ${header}.\n\nDid not expect: ${header}=${expected}.\n\nAll: ${headers}`
`Page ${probeUrl} has unexpected response header ${header}.\n\nDid not expect: ${header}=${expected}.\n\nAll: ${formatHeaders(
rawHeaders
)}`
);
}
});
@@ -434,6 +453,15 @@ async function spawnAsync(...args) {
});
}
/**
* @param {Record<string, string[]>} headers
*/
function formatHeaders(headers) {
return Object.entries(headers)
.flatMap(([name, values]) => values.map(v => ` ${name}: ${v}`))
.join('\n');
}
module.exports = {
packAndDeploy,
testDeployment,