refactor(api): tighten relay retry policy and config safety bounds
This commit is contained in:
@@ -111,6 +111,118 @@ test("forwardGetData does not retry non-retryable HTTP status", async () => {
|
||||
assert.strictEqual(callCount, 1);
|
||||
});
|
||||
|
||||
test("forwardGetData does not retry unauthorized status", async () => {
|
||||
let callCount = 0;
|
||||
|
||||
const mod = loadRelayForwardingModule({
|
||||
axios: {
|
||||
get: async () => {
|
||||
callCount += 1;
|
||||
const error = new Error("unauthorized");
|
||||
error.response = { status: 401 };
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
getToken: async () => ({ access_token: "token" }),
|
||||
hashAPIPath: () => "&hash=abc",
|
||||
azureHeaders: () => ({ headers: {} }),
|
||||
redactSensitive: (value) => value,
|
||||
consoleLogger: () => {}
|
||||
});
|
||||
|
||||
let thrown = null;
|
||||
try {
|
||||
await mod.forwardGetData({
|
||||
queryUrl: "incidents?$top=1",
|
||||
maxRetries: 3,
|
||||
retryBaseDelayMs: 0,
|
||||
retryMaxDelayMs: 0
|
||||
});
|
||||
} catch (error) {
|
||||
thrown = error;
|
||||
}
|
||||
|
||||
assert.ok(thrown);
|
||||
assert.strictEqual(callCount, 1);
|
||||
});
|
||||
|
||||
test("relayGet avoids duplicate consoleLogger when relay layer already logged", async () => {
|
||||
let consoleLoggerCalls = 0;
|
||||
let respondErrorCalls = 0;
|
||||
|
||||
const mod = loadRelayForwardingModule({
|
||||
axios: {
|
||||
get: async () => {
|
||||
const error = new Error("bad request");
|
||||
error.response = { status: 400 };
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
getToken: async () => ({ access_token: "token" }),
|
||||
hashAPIPath: () => "&hash=abc",
|
||||
azureHeaders: () => ({ headers: {} }),
|
||||
redactSensitive: (value) => value,
|
||||
consoleLogger: () => {
|
||||
consoleLoggerCalls += 1;
|
||||
},
|
||||
respondSuccess: () => {},
|
||||
respondError: () => {
|
||||
respondErrorCalls += 1;
|
||||
}
|
||||
});
|
||||
|
||||
await mod.relayGet({
|
||||
queryUrl: "incidents?$top=1",
|
||||
res: {},
|
||||
errorResponse: { code: "FAILED" }
|
||||
});
|
||||
|
||||
assert.strictEqual(consoleLoggerCalls, 0);
|
||||
assert.strictEqual(respondErrorCalls, 1);
|
||||
});
|
||||
|
||||
test("forwardGetData clamps invalid env config values to safe bounds", async () => {
|
||||
const previousEnv = {
|
||||
RELAY_TIMEOUT_MS: process.env.RELAY_TIMEOUT_MS,
|
||||
RELAY_RETRY_MAX: process.env.RELAY_RETRY_MAX,
|
||||
RELAY_RETRY_BASE_DELAY_MS: process.env.RELAY_RETRY_BASE_DELAY_MS,
|
||||
RELAY_RETRY_MAX_DELAY_MS: process.env.RELAY_RETRY_MAX_DELAY_MS
|
||||
};
|
||||
|
||||
process.env.RELAY_TIMEOUT_MS = "999999";
|
||||
process.env.RELAY_RETRY_MAX = "999";
|
||||
process.env.RELAY_RETRY_BASE_DELAY_MS = "-1";
|
||||
process.env.RELAY_RETRY_MAX_DELAY_MS = "999999";
|
||||
|
||||
let capturedOptions = null;
|
||||
|
||||
const mod = loadRelayForwardingModule({
|
||||
axios: {
|
||||
get: async (url, options) => {
|
||||
capturedOptions = options;
|
||||
return { data: { ok: true } };
|
||||
}
|
||||
},
|
||||
getToken: async () => ({ access_token: "token" }),
|
||||
hashAPIPath: () => "&hash=abc",
|
||||
azureHeaders: () => ({ headers: {} }),
|
||||
redactSensitive: (value) => value,
|
||||
consoleLogger: () => {}
|
||||
});
|
||||
|
||||
await mod.forwardGetData({
|
||||
queryUrl: "incidents?$top=1"
|
||||
});
|
||||
|
||||
assert.strictEqual(capturedOptions.timeout, 30000);
|
||||
|
||||
process.env.RELAY_TIMEOUT_MS = previousEnv.RELAY_TIMEOUT_MS;
|
||||
process.env.RELAY_RETRY_MAX = previousEnv.RELAY_RETRY_MAX;
|
||||
process.env.RELAY_RETRY_BASE_DELAY_MS =
|
||||
previousEnv.RELAY_RETRY_BASE_DELAY_MS;
|
||||
process.env.RELAY_RETRY_MAX_DELAY_MS = previousEnv.RELAY_RETRY_MAX_DELAY_MS;
|
||||
});
|
||||
|
||||
test("forwardGetData applies timeout and appendHash=false behavior", async () => {
|
||||
let capturedUrl = null;
|
||||
let capturedOptions = null;
|
||||
|
||||
Reference in New Issue
Block a user