| 1 | import assert from "node:assert/strict"; |
| 2 | import { readFileSync, readdirSync } from "node:fs"; |
| 3 | import { DatabaseSync } from "node:sqlite"; |
| 4 | import { test } from "node:test"; |
| 5 | |
| 6 | // A month-end source's figure reported after its month was charged or |
| 7 | // closed: the production SQL of `late_correction` (src/storage.rs). |
| 8 | const source = name => readFileSync(new URL(`../services/billing/src/${name}.rs`, import.meta.url), "utf8"); |
| 9 | const sqlFile = name => readFileSync(new URL(`../services/billing/src/${name}.sql`, import.meta.url), "utf8"); |
| 10 | const constant = (file, name) => { |
| 11 | const match = source(file).match(new RegExp(`const ${name}: &str = "([\\s\\S]*?)";`)); |
| 12 | assert.ok(match, `${file}::${name}`); |
| 13 | return match[1]; |
| 14 | }; |
| 15 | function database() { |
| 16 | const db = new DatabaseSync(":memory:"); |
| 17 | const dir = new URL("../services/billing/migrations/", import.meta.url); |
| 18 | for (const name of readdirSync(dir).filter(n => n.endsWith(".sql")).sort()) db.exec(readFileSync(new URL(name, dir), "utf8")); |
| 19 | return db; |
| 20 | } |
| 21 | function batch(db, writes) { |
| 22 | db.exec("BEGIN"); |
| 23 | try { |
| 24 | const rows = writes.map(([sql, args]) => db.prepare(sql).all(...args)); |
| 25 | db.exec("COMMIT"); |
| 26 | return rows; |
| 27 | } catch (e) { |
| 28 | db.exec("ROLLBACK"); |
| 29 | throw e; |
| 30 | } |
| 31 | } |
| 32 | const now = "2026-11-03T10:00:00.000Z"; |
| 33 | // One late report, as `late_correction` sends it: the raise, the guarded |
| 34 | // ledger line, the allocation and the balance, in one batch. |
| 35 | function late(db, id, workspace, newCost, charge, oldRaw, { plan = 0 } = {}) { |
| 36 | const raise = constant("storage", "LATE_RAISE"); |
| 37 | const ledger = constant("storage", "LATE_LEDGER"); |
| 38 | const balanceSql = source("storage").split("pub(crate) fn balance_if_posted(")[1].match(/\.prepare\(\s*"([\s\S]*?)"\s*,?\s*\)/)[1]; |
| 39 | const reference = `storage/${workspace}/2026-10/late/${newCost}`; |
| 40 | const rows = batch(db, [ |
| 41 | [raise, [workspace, "storage", "2026-10", newCost, newCost, now, null, oldRaw]], |
| 42 | [ledger, [id, workspace, -charge, "Late", "storage", newCost - oldRaw, reference, "2026-10-31T23:59:59Z", null, "2026-10", newCost]], |
| 43 | [sqlFile("allocate_usage"), [id, workspace, "2026-10", plan, 0, "", 0, 0, 0]], |
| 44 | [constant("allocation", "PLAN"), [id, "2026-10"]], |
| 45 | [constant("allocation", "GIFT"), [id, "2026-10"]], |
| 46 | [balanceSql, [workspace, now, id]], |
| 47 | ]); |
| 48 | return rows[1].length === 1; |
| 49 | } |
| 50 | function charged(db, workspace, cost) { |
| 51 | db.prepare("INSERT INTO pending_usage (workspace, source, month, charge_micros, cost_micros, updated_at, charged_at) VALUES (?, 'storage', '2026-10', ?, ?, ?, ?)") |
| 52 | .run(workspace, cost, cost, now, now); |
| 53 | } |
| 54 | const owed = (db, workspace) => db.prepare("SELECT balance_micros FROM accounts WHERE workspace=?").get(workspace)?.balance_micros ?? 0; |
| 55 | |
| 56 | test("a late higher figure charges only what it adds, once", () => { |
| 57 | const db = database(); |
| 58 | charged(db, "acme", 5_000_000); |
| 59 | assert.equal(late(db, "a", "acme", 7_000_000, 2_400_000, 5_000_000), true); |
| 60 | assert.equal(owed(db, "acme"), -2_400_000); |
| 61 | assert.equal(db.prepare("SELECT cost_micros FROM pending_usage WHERE workspace='acme'").get().cost_micros, 7_000_000); |
| 62 | // The same report again: worked out from the new figure, nothing changes. |
| 63 | assert.equal(late(db, "b", "acme", 7_000_000, 2_400_000, 5_000_000), false); |
| 64 | assert.equal(owed(db, "acme"), -2_400_000); |
| 65 | assert.equal(db.prepare("SELECT COUNT(*) n FROM ledger").get().n, 1); |
| 66 | db.close(); |
| 67 | }); |
| 68 | |
| 69 | test("of two late reports worked out from the same figure, only one is charged", () => { |
| 70 | const db = database(); |
| 71 | charged(db, "acme", 5_000_000); |
| 72 | assert.equal(late(db, "a", "acme", 8_000_000, 3_600_000, 5_000_000), true); |
| 73 | // A stale writer that read 5,000,000 before the first moved it. |
| 74 | assert.equal(late(db, "b", "acme", 6_000_000, 1_200_000, 5_000_000), false); |
| 75 | assert.equal(owed(db, "acme"), -3_600_000); |
| 76 | assert.equal(db.prepare("SELECT cost_micros FROM pending_usage WHERE workspace='acme'").get().cost_micros, 8_000_000); |
| 77 | db.close(); |
| 78 | }); |
| 79 | |
| 80 | test("a closed month with no row yet takes the late figure as a charged row", () => { |
| 81 | const db = database(); |
| 82 | db.prepare("INSERT INTO month_closes (workspace, month, status, amount_micros, closed_at) VALUES ('acme', '2026-10', 'charged', 0, ?)").run(now); |
| 83 | // The ordinary report is refused for a closed month… |
| 84 | db.prepare(constant("storage", "SET_PENDING")).run("acme", "storage", "2026-10", 1, 1, now, null); |
| 85 | assert.equal(db.prepare("SELECT COUNT(*) n FROM pending_usage").get().n, 0); |
| 86 | // …and the late one charges it, and marks the row charged. |
| 87 | assert.equal(late(db, "a", "acme", 4_000_000, 4_800_000, 0), true); |
| 88 | assert.equal(owed(db, "acme"), -4_800_000); |
| 89 | assert.ok(db.prepare("SELECT charged_at FROM pending_usage WHERE workspace='acme'").get().charged_at.startsWith("late: ")); |
| 90 | db.close(); |
| 91 | }); |
| 92 | |
| 93 | test("a late correction draws on that month's allowances first", () => { |
| 94 | const db = database(); |
| 95 | charged(db, "acme", 1_000_000); |
| 96 | db.prepare("INSERT INTO allowance_use (kind, scope, month, used) VALUES ('plan_credit', 'acme', '2026-10', 9000000)").run(); |
| 97 | assert.equal(late(db, "a", "acme", 3_000_000, 2_400_000, 1_000_000, { plan: 10_000_000 }), true); |
| 98 | assert.deepEqual({ ...db.prepare("SELECT amount_micros, credit_micros FROM ledger").get() }, { amount_micros: -1_400_000, credit_micros: 1_000_000 }); |
| 99 | assert.equal(db.prepare("SELECT used FROM allowance_use WHERE kind='plan_credit'").get().used, 10_000_000); |
| 100 | db.close(); |
| 101 | }); |
| 102 | |
| 103 | test("only a raise is charged: a lower late figure changes nothing", () => { |
| 104 | const src = source("storage"); |
| 105 | assert.match(src, /pub\(crate\) fn late_delta\(charged_net: i64, new_net: i64\) -> i64 \{\s*\(new_net - charged_net\)\.max\(0\)/); |
| 106 | assert.match(src, /if new_cost < raw_old \{[\s\S]*?return Ok\(true\);/); |
| 107 | }); |