恢复付款入口与常开基线(08-01-reimbursement-notification-progress-clarity)
这个提交包含在:
@@ -0,0 +1,148 @@
|
||||
const { execFile } = require("node:child_process");
|
||||
const { mkdtemp, readFile, rm } = require("node:fs/promises");
|
||||
const http = require("node:http");
|
||||
const os = require("node:os");
|
||||
const path = require("node:path");
|
||||
const { promisify } = require("node:util");
|
||||
|
||||
const execFileAsync = promisify(execFile);
|
||||
const ROOT_DIR = path.resolve(__dirname, "../../../..");
|
||||
const SNAPSHOT_SCRIPT = path.join(ROOT_DIR, "scripts/qa/payment-batch-flag-snapshot.mjs");
|
||||
|
||||
async function readJsonBody(request) {
|
||||
const chunks = [];
|
||||
for await (const chunk of request) chunks.push(chunk);
|
||||
return JSON.parse(Buffer.concat(chunks).toString("utf8") || "{}");
|
||||
}
|
||||
|
||||
async function withFlagApi(initialFlag, callback) {
|
||||
let flag = { ...initialFlag, departmentIds: [...initialFlag.departmentIds] };
|
||||
const server = http.createServer(async (request, response) => {
|
||||
response.setHeader("content-type", "application/json");
|
||||
if (request.method === "POST" && request.url === "/api/auth/login") {
|
||||
response.end(JSON.stringify({ data: { accessToken: "synthetic-access-token" } }));
|
||||
return;
|
||||
}
|
||||
if (request.method === "GET" && request.url === "/api/system/feature-flags") {
|
||||
response.end(JSON.stringify({ data: { items: [flag] } }));
|
||||
return;
|
||||
}
|
||||
if (request.method === "PUT" && request.url === "/api/system/feature-flags/payment_batch_v1") {
|
||||
const body = await readJsonBody(request);
|
||||
if (body.expectedVersion !== flag.version) {
|
||||
response.statusCode = 409;
|
||||
response.end(JSON.stringify({ error: { code: "CONFLICT" } }));
|
||||
return;
|
||||
}
|
||||
flag = {
|
||||
...flag,
|
||||
overrideMode: body.overrideMode,
|
||||
rolloutType: body.rolloutType,
|
||||
departmentIds: [...body.departmentIds],
|
||||
note: body.note,
|
||||
version: flag.version + 1,
|
||||
effectiveEnabled: body.overrideMode === "force_on",
|
||||
effectiveReason: `mock_${body.overrideMode}`,
|
||||
};
|
||||
response.end(JSON.stringify({ data: { item: flag } }));
|
||||
return;
|
||||
}
|
||||
response.statusCode = 404;
|
||||
response.end(JSON.stringify({ error: { code: "NOT_FOUND" } }));
|
||||
});
|
||||
|
||||
await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
|
||||
const address = server.address();
|
||||
const baseUrl = `http://127.0.0.1:${address.port}`;
|
||||
try {
|
||||
await callback({
|
||||
baseUrl,
|
||||
getFlag: () => flag,
|
||||
setFlag: (next) => {
|
||||
flag = { ...next, departmentIds: [...next.departmentIds] };
|
||||
},
|
||||
});
|
||||
} finally {
|
||||
await new Promise((resolve, reject) => server.close((error) => error ? reject(error) : resolve()));
|
||||
}
|
||||
}
|
||||
|
||||
function runSnapshotScript(action, baseUrl, snapshotFile) {
|
||||
return execFileAsync(process.execPath, [SNAPSHOT_SCRIPT, action, "--snapshot-file", snapshotFile], {
|
||||
env: {
|
||||
...process.env,
|
||||
P2_FIN_LIVE_APPROVED: "1",
|
||||
LIVE_SMOKE_BASE_URL: baseUrl,
|
||||
LIVE_SMOKE_ADMIN_IDENTIFIER: "synthetic-admin",
|
||||
LIVE_SMOKE_ADMIN_PASSWORD: "synthetic-password",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
describe.each([
|
||||
{
|
||||
label: "force_off allowlist",
|
||||
initial: {
|
||||
flagKey: "payment_batch_v1",
|
||||
overrideMode: "force_off",
|
||||
rolloutType: "department_allowlist",
|
||||
departmentIds: ["00000000-0000-4000-8000-000000000001"],
|
||||
note: "original off note",
|
||||
version: 3,
|
||||
effectiveEnabled: false,
|
||||
effectiveReason: "flag_force_off",
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "force_on global",
|
||||
initial: {
|
||||
flagKey: "payment_batch_v1",
|
||||
overrideMode: "force_on",
|
||||
rolloutType: "global",
|
||||
departmentIds: [],
|
||||
note: "original on note",
|
||||
version: 8,
|
||||
effectiveEnabled: true,
|
||||
effectiveReason: "flag_force_on_global",
|
||||
},
|
||||
},
|
||||
])("payment batch flag snapshot: $label", ({ initial }) => {
|
||||
it("restores the caller configuration instead of forcing a fixed mode", async () => {
|
||||
const tempDir = await mkdtemp(path.join(os.tmpdir(), "hyb-oa-payment-flag-"));
|
||||
const snapshotFile = path.join(tempDir, "snapshot.json");
|
||||
try {
|
||||
await withFlagApi(initial, async ({ baseUrl, getFlag, setFlag }) => {
|
||||
await runSnapshotScript("capture", baseUrl, snapshotFile);
|
||||
const saved = JSON.parse(await readFile(snapshotFile, "utf8"));
|
||||
expect(saved).toMatchObject({
|
||||
overrideMode: initial.overrideMode,
|
||||
rolloutType: initial.rolloutType,
|
||||
departmentIds: initial.departmentIds,
|
||||
note: initial.note,
|
||||
effectiveEnabled: initial.effectiveEnabled,
|
||||
});
|
||||
|
||||
setFlag({
|
||||
...getFlag(),
|
||||
overrideMode: initial.overrideMode === "force_on" ? "force_off" : "force_on",
|
||||
rolloutType: "global",
|
||||
departmentIds: [],
|
||||
note: "temporary window state",
|
||||
version: getFlag().version + 1,
|
||||
effectiveEnabled: initial.overrideMode !== "force_on",
|
||||
effectiveReason: "temporary",
|
||||
});
|
||||
|
||||
await runSnapshotScript("restore", baseUrl, snapshotFile);
|
||||
expect(getFlag()).toMatchObject({
|
||||
overrideMode: initial.overrideMode,
|
||||
rolloutType: initial.rolloutType,
|
||||
departmentIds: initial.departmentIds,
|
||||
note: initial.note,
|
||||
});
|
||||
});
|
||||
} finally {
|
||||
await rm(tempDir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
});
|
||||
在新工单中引用
屏蔽一个用户