177 lines
5.2 KiB
JavaScript
177 lines
5.2 KiB
JavaScript
const assert = require("node:assert/strict");
|
|
const vm = require("node:vm");
|
|
const { composeScript } = require("./support/application.cjs");
|
|
|
|
|
|
function createResponse(body, contentType) {
|
|
return {
|
|
ok: true,
|
|
status: 200,
|
|
statusText: "OK",
|
|
headers: {
|
|
get(name) {
|
|
return name.toLowerCase() === "content-type" ? contentType : null;
|
|
},
|
|
forEach(callback) {
|
|
callback(contentType, "content-type");
|
|
}
|
|
},
|
|
text: async () => body
|
|
};
|
|
}
|
|
|
|
function loadBackground(responses, createdTabs, removedTabs, options = {}) {
|
|
let listener;
|
|
const source = composeScript("background");
|
|
const context = {
|
|
chrome: {
|
|
runtime: {
|
|
onMessage: {
|
|
addListener(callback) {
|
|
listener = callback;
|
|
}
|
|
}
|
|
},
|
|
tabs: {
|
|
async create(details) {
|
|
createdTabs.push(details);
|
|
if (options.createTab) {
|
|
return options.createTab(details);
|
|
}
|
|
return { id: 27 };
|
|
},
|
|
async remove(tabId) {
|
|
removedTabs.push(tabId);
|
|
}
|
|
}
|
|
},
|
|
fetch: async () => {
|
|
if (options.onFetch) {
|
|
options.onFetch();
|
|
}
|
|
const response = responses.shift();
|
|
|
|
if (!response) {
|
|
throw new Error("Unexpected fetch call.");
|
|
}
|
|
|
|
return response;
|
|
},
|
|
Date,
|
|
Error,
|
|
JSON,
|
|
Map,
|
|
Set,
|
|
Promise,
|
|
String,
|
|
Array,
|
|
Object,
|
|
Number,
|
|
Math,
|
|
setTimeout: options.setTimeout || setTimeout,
|
|
clearTimeout
|
|
};
|
|
|
|
vm.runInNewContext(source, context);
|
|
return listener;
|
|
}
|
|
|
|
function dispatch(listener) {
|
|
return new Promise((resolve) => {
|
|
assert.equal(listener({ type: "opportunitiesExtension.requestConsumerTokenService" }, {
|
|
tab: { windowId: 1 }
|
|
}, resolve), true);
|
|
});
|
|
}
|
|
|
|
async function run() {
|
|
const createdTabs = [];
|
|
const removedTabs = [];
|
|
const listener = loadBackground([
|
|
createResponse("<html><body>Fallback</body></html>", "text/html"),
|
|
createResponse(JSON.stringify([
|
|
{
|
|
tokenService: "ACCP-TS",
|
|
uiaasHeader: { label: "Account-Ti-Authorization", value: "account-token" }
|
|
},
|
|
{
|
|
tokenService: "OCICONS-TS",
|
|
uiaasHeader: { label: "G2m-Authorization", value: "consumption-token" }
|
|
}
|
|
]), "application/json")
|
|
], createdTabs, removedTabs);
|
|
const response = await dispatch(listener);
|
|
|
|
assert.equal(response.ok, true);
|
|
assert.equal(response.authorizations.accountSummary.value, "account-token");
|
|
assert.equal(response.authorizations.accountPlans.value, "consumption-token");
|
|
assert.equal(createdTabs.length, 1);
|
|
assert.equal(createdTabs[0].active, false);
|
|
assert.equal(
|
|
createdTabs[0].url,
|
|
"https://spa.oracle.com/"
|
|
);
|
|
assert.deepEqual(removedTabs, [27]);
|
|
assert.equal(response.debugRequests.length, 2);
|
|
assert.equal(response.debugRequests[0].status, "failed");
|
|
assert.equal(response.debugRequests[0].metadata.sessionBootstrapState, "opened-inactive-tab");
|
|
assert.equal(response.debugRequests[1].metadata.sessionBootstrapState, "closed-after-valid-json");
|
|
|
|
// Even six opening failures must leave the second token request available.
|
|
const retryTabs = [];
|
|
const retryRemovedTabs = [];
|
|
const delays = [];
|
|
let tokenRequests = 0;
|
|
let openAttempts = 0;
|
|
const retryListener = loadBackground([
|
|
createResponse("<html>Fallback</html>", "text/html"),
|
|
createResponse(JSON.stringify([
|
|
{ tokenService: "ACCP-TS", uiaasHeader: { value: "account-token" } },
|
|
{ tokenService: "OCICONS-TS", uiaasHeader: { value: "consumption-token" } }
|
|
]), "application/json")
|
|
], retryTabs, retryRemovedTabs, {
|
|
onFetch() { tokenRequests += 1; },
|
|
createTab() {
|
|
assert.equal(tokenRequests, 1, "Token requests must wait for the tab to open");
|
|
openAttempts += 1;
|
|
if (openAttempts <= 6) {
|
|
throw new Error("Temporary tab creation failure");
|
|
}
|
|
return { id: 81 };
|
|
},
|
|
setTimeout(callback, delay) {
|
|
delays.push(delay);
|
|
return setTimeout(callback, 0);
|
|
}
|
|
});
|
|
const retryResponse = await dispatch(retryListener);
|
|
assert.equal(retryResponse.ok, true);
|
|
assert.equal(tokenRequests, 2);
|
|
assert.equal(openAttempts, 7);
|
|
assert.deepEqual(retryRemovedTabs, [81]);
|
|
assert.deepEqual(delays.slice(0, 6), [750, 1500, 3000, 4000, 4000, 4000]);
|
|
assert.ok(retryTabs.every(tab => tab.active === false && tab.windowId === 1));
|
|
assert.equal(retryResponse.debugRequests[0].metadata.sessionTabOpenAttempt, "7");
|
|
assert.equal(retryResponse.debugRequests[0].metadata.sessionTabLastOpenError, "Temporary tab creation failure");
|
|
assert.equal(retryResponse.debugRequests[0].metadata.sessionTabNextRetryDelayMs, undefined);
|
|
|
|
const failedTabs = [];
|
|
const failedRemovedTabs = [];
|
|
const exhausted = await dispatch(loadBackground(
|
|
Array.from({ length: 5 }, () => createResponse("<html>Fallback</html>", "text/html")),
|
|
failedTabs, failedRemovedTabs,
|
|
{ setTimeout: callback => setTimeout(callback, 0) }
|
|
));
|
|
assert.equal(exhausted.ok, false);
|
|
assert.match(exhausted.error, /after 5 attempts/);
|
|
assert.equal(failedTabs.length, 1);
|
|
assert.deepEqual(failedRemovedTabs, [27]);
|
|
|
|
console.log("Consumer token session retry tests passed.");
|
|
}
|
|
|
|
run().catch((error) => {
|
|
console.error(error);
|
|
process.exitCode = 1;
|
|
});
|