Quality / test (push) Canceled after 0s
Schedule configurable completed pricing-job cleanup in the worker, broaden repository cleanup across sellers, add unit and integration coverage, and update pricing operational documentation.
142 lines
3.9 KiB
JavaScript
142 lines
3.9 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import test from "node:test";
|
|
|
|
import {
|
|
createPricingProvider,
|
|
createPricingProviderRegistry,
|
|
} from "../../api/src/modules/pricing/providers/pricing-provider.js";
|
|
import {
|
|
getPricingJobRetentionCutoff,
|
|
processNextPersistentPricingRefreshJob,
|
|
purgeCompletedPricingRefreshJobs,
|
|
runPricingRefreshJob,
|
|
} from "../src/pricing-refresh-worker.js";
|
|
|
|
test("calculates a UTC retention cutoff and purges completed jobs before it", async () => {
|
|
const now = new Date("2026-09-09T12:00:00.000Z");
|
|
const cutoff = getPricingJobRetentionCutoff({ now, retentionDays: 30 });
|
|
assert.equal(cutoff.toISOString(), "2026-08-10T12:00:00.000Z");
|
|
|
|
let receivedCutoff;
|
|
const deleted = await purgeCompletedPricingRefreshJobs({
|
|
jobRepository: {
|
|
async purgeCompletedBefore(value) {
|
|
receivedCutoff = value;
|
|
return 3;
|
|
},
|
|
},
|
|
now,
|
|
retentionDays: 30,
|
|
});
|
|
|
|
assert.equal(deleted, 3);
|
|
assert.equal(receivedCutoff.toISOString(), cutoff.toISOString());
|
|
});
|
|
|
|
test("rejects invalid pricing job retention days", () => {
|
|
assert.throws(
|
|
() => getPricingJobRetentionCutoff({ retentionDays: 0 }),
|
|
/positive integer/,
|
|
);
|
|
});
|
|
|
|
test("completes a pricing refresh through the provider and pricing service boundaries", async () => {
|
|
const providerRegistry = createPricingProviderRegistry([
|
|
createPricingProvider({
|
|
id: "fixture-provider",
|
|
async observe() {
|
|
return [{ priceMinor: 2500, sourceIdentifier: "fixture-1" }];
|
|
},
|
|
}),
|
|
]);
|
|
const saved = [];
|
|
const result = await runPricingRefreshJob({
|
|
job: {
|
|
id: "job-1",
|
|
type: "PRICING_REFRESH",
|
|
providerId: "fixture-provider",
|
|
sellerId: "seller-1",
|
|
productId: "product-1",
|
|
inventoryItemId: "inventory-1",
|
|
conditionId: "condition-1",
|
|
},
|
|
providerRegistry,
|
|
pricingService: {
|
|
async addObservation(input) {
|
|
saved.push(input);
|
|
return input;
|
|
},
|
|
async calculate() {
|
|
return { valuation: { valueMinor: 2500 } };
|
|
},
|
|
},
|
|
});
|
|
|
|
assert.equal(result.status, "COMPLETED");
|
|
assert.equal(result.valuation.valuation.valueMinor, 2500);
|
|
assert.equal(saved[0].providerId, "fixture-provider");
|
|
});
|
|
|
|
test("fails a refresh clearly when a provider is unavailable", async () => {
|
|
const result = await runPricingRefreshJob({
|
|
job: { id: "job-2", type: "PRICING_REFRESH", providerId: "missing" },
|
|
providerRegistry: createPricingProviderRegistry(),
|
|
pricingService: {},
|
|
});
|
|
|
|
assert.equal(result.status, "FAILED");
|
|
assert.match(result.error, /not configured/);
|
|
});
|
|
|
|
test("persists completed and failed outcomes through the job repository", async () => {
|
|
const calls = [];
|
|
const jobRepository = {
|
|
async claimNext() {
|
|
return { id: "job-3", type: "PRICING_REFRESH", providerId: "fixture" };
|
|
},
|
|
async complete(id, observations, valuation) {
|
|
calls.push(["complete", id, observations, valuation]);
|
|
},
|
|
async fail(id, error) {
|
|
calls.push(["fail", id, error]);
|
|
},
|
|
};
|
|
|
|
await processNextPersistentPricingRefreshJob({
|
|
jobRepository,
|
|
async pricingRefreshJob() {
|
|
return {
|
|
status: "COMPLETED",
|
|
observations: [{ id: "observation-1" }],
|
|
valuation: { valueMinor: 2500 },
|
|
};
|
|
},
|
|
});
|
|
|
|
assert.deepEqual(calls, [
|
|
["complete", "job-3", [{ id: "observation-1" }], { valueMinor: 2500 }],
|
|
]);
|
|
});
|
|
|
|
test("persists failed pricing refresh outcomes through the repository", async () => {
|
|
const calls = [];
|
|
await processNextPersistentPricingRefreshJob({
|
|
jobRepository: {
|
|
async claimNext() {
|
|
return { id: "job-4" };
|
|
},
|
|
async complete() {
|
|
throw new Error("not expected");
|
|
},
|
|
async fail(id, error) {
|
|
calls.push([id, error]);
|
|
},
|
|
},
|
|
async pricingRefreshJob() {
|
|
return { status: "FAILED", error: "Provider unavailable." };
|
|
},
|
|
});
|
|
|
|
assert.deepEqual(calls, [["job-4", "Provider unavailable."]]);
|
|
});
|