Implemented the feature to identify and update estimates based on the ACR value, consumption start date, and ramp-up

This commit is contained in:
2026-10-20 15:55:58 -03:00
parent 71d550dfb1
commit 60daabfe91
31 changed files with 2800 additions and 43 deletions

View File

@@ -0,0 +1,102 @@
const test = require("node:test");
const assert = require("node:assert/strict");
const { loadBackground, response, plain } = require("./support/characterization.cjs");
const { loadApplication } = require("./support/application.cjs");
const type = "opportunitiesExtension.requestWorkloadForecastUpdate";
const payload = [{ year: 2026, month: 11, amount: 303.03, updatedBy: "test@example.invalid" }];
const message = { type, workloadId: "1234", authorization: { value: "synthetic-wwb" }, payload };
for (const family of ["chrome", "firefox"]) {
test(`${family}: forecast PATCH uses dynamic workload, JSON, WWB authorization and invalidates cache on 204`, async () => {
const calls = [];
const storage = { "opportunitiesExtension.workloadsCache.v1": { old: { items: [{ id: 1234 }] } } };
const h = loadBackground({ family, storage, fetch: async (url, options) => {
calls.push({ url, options });
return new Response(null, { status: 204 });
} });
const result = await h.dispatch(message);
assert.equal(result.ok, true);
assert.equal(calls.length, 1);
assert.ok(calls[0].url.endsWith("/workloads/1234/forecast"));
assert.equal(calls[0].options.method, "PATCH");
assert.equal(calls[0].options.credentials, "include");
assert.equal(calls[0].options.headers["wwb-provider-authorization"], "synthetic-wwb");
assert.equal(calls[0].options.headers["Content-Type"], "application/json");
assert.deepEqual(JSON.parse(calls[0].options.body), payload);
assert.deepEqual(storage["opportunitiesExtension.workloadsCache.v1"], {});
assert.equal(result.debugRequests[0].name, "requestWorkloadForecastUpdate");
assert.equal(result.debugRequests[0].httpStatus, 204);
});
test(`${family}: denied PATCH preserves cache, returns debug and is not automatically retried`, async () => {
let calls = 0;
const storage = { "opportunitiesExtension.workloadsCache.v1": { old: { items: [{ id: 1234 }] } } };
const before = JSON.stringify(storage);
const h = loadBackground({ family, storage, fetch: async () => { calls++; return response({ error: "Denied" }, 403); } });
const result = await h.dispatch(message);
assert.equal(result.ok, false);
assert.equal(result.httpStatus, 403);
assert.equal(calls, 1);
assert.equal(JSON.stringify(storage), before);
assert.equal(result.debugRequests[0].httpStatus, 403);
});
}
test("forecast update rejects invalid identity, invalid amounts and duplicate months before fetch", async () => {
let calls = 0;
const h = loadBackground({ fetch: async () => { calls++; return response({}); } });
for (const change of [{ workloadId: "../other" }, { authorization: {} }, { payload: [] },
{ payload: [{ ...payload[0], amount: -1 }] }, { payload: [{ ...payload[0], month: 13 }] },
{ payload: [{ ...payload[0], updatedBy: "" }] }, { payload: [payload[0], payload[0]] }]) {
assert.equal((await h.dispatch({ ...message, ...change })).ok, false);
}
assert.equal(calls, 0);
});
function setup() {
const app = loadApplication("content");
const item = { RevnId: 1234, RampMonths_c: 2, workload: { id: 1234, adjustedACR: 50000,
consumptionStartDate: "2026-11-25", forecast: [
{ year: 2026, month: 10, adjustedConsumptionAmount: 0 },
{ year: 2026, month: 11, adjustedConsumptionAmount: 100 },
{ year: 2026, month: 12, adjustedConsumptionAmount: 100 }
] } };
app.currentUser.ensure = async () => {};
app.currentUser.getUserId = () => "test@example.invalid";
app.authContentSession.requestConsumerTokenServiceOnce = async () => ({ workloadActions: message.authorization });
app.debugContentLog.appendBackgroundRequestLog = () => {};
app.productsContentJobs.queueProductsTableRender = () => {};
app.productsContentState.opptyProductsByNumber.set("ONE", { items: [item] });
app.productsContentState.opptyProductsByNumber.set("TWO", { items: [{ ...item }] });
app.productsContentState.workloadsByCustomer.set("99", { status: "ready", workloads: [item.workload], byId: new Map([["1234", item.workload]]) });
return { app, item };
}
test("content constructs calculated months and updates both joins only after successful PATCH", async () => {
const { app, item } = setup();
let release, sent;
app.platformContentMessages.sendRuntimeMessage = value => { sent = value; return new Promise(resolve => { release = resolve; }); };
const saving = app.workloadForecastUpdate.save(item);
await new Promise(resolve => setImmediate(resolve));
assert.equal(item.workload.forecast[1].adjustedConsumptionAmount, 100);
assert.equal(sent.type, type);
assert.equal(sent.workloadId, "1234");
assert.deepEqual(plain(sent.payload), [payload[0], { year: 2026, month: 12, amount: 3030.30, updatedBy: "test@example.invalid" }]);
await assert.rejects(app.workloadForecastUpdate.save(item), /already being updated/);
release({ ok: true });
await saving;
assert.equal(app.rampProjection.compare(item).status, "matched");
assert.equal(app.productsContentState.workloadsByCustomer.get("99").byId.get("1234").forecast[1].adjustedConsumptionAmount, 303.03);
for (const record of app.productsContentState.opptyProductsByNumber.values()) assert.equal(app.rampProjection.compare(record.items[0]).status, "matched");
});
test("failed forecast update leaves values unchanged and allows a deliberate retry", async () => {
const { app, item } = setup();
const before = JSON.stringify(item);
app.platformContentMessages.sendRuntimeMessage = async () => ({ ok: false, error: "Forbidden" });
await assert.rejects(app.workloadForecastUpdate.save(item), /Forbidden/);
assert.equal(JSON.stringify(item), before);
app.platformContentMessages.sendRuntimeMessage = async () => ({ ok: true });
await app.workloadForecastUpdate.save(item);
assert.equal(app.rampProjection.compare(item).status, "matched");
});