| 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 | // Execute production SQL against the complete migrated schema. These verify |
| 7 | // transaction/retry contracts; Stripe HTTP and Worker execution need staging. |
| 8 | const source = (name) => readFileSync(new URL(`../services/billing/src/${name}.rs`, import.meta.url), "utf8"); |
| 9 | const constant = (file, name) => { |
| 10 | const match = source(file).match(new RegExp(`const ${name}: &str = "([\\s\\S]*?)";`)); |
| 11 | assert.ok(match, `${file}::${name}`); |
| 12 | return match[1]; |
| 13 | }; |
| 14 | const prepares = (file, from, to) => { |
| 15 | const text = source(file).split(from)[1].split(to)[0]; |
| 16 | return [...text.matchAll(/\.prepare\(\s*"([\s\S]*?)"\s*,?\s*\)/g)].map((m) => m[1]); |
| 17 | }; |
| 18 | function database() { |
| 19 | const db = new DatabaseSync(":memory:"); |
| 20 | const dir = new URL("../services/billing/migrations/", import.meta.url); |
| 21 | for (const name of readdirSync(dir) |
| 22 | .filter((n) => n.endsWith(".sql")) |
| 23 | .sort()) |
| 24 | db.exec(readFileSync(new URL(name, dir), "utf8")); |
| 25 | return db; |
| 26 | } |
| 27 | const at = "2026-10-14T12:00:00Z"; |
| 28 | test("late enterprise overdue writes cannot reopen terminal invoices or pause paid workspaces", () => { |
| 29 | const db = database(); |
| 30 | db.prepare("INSERT INTO accounts(workspace,balance_micros,created_at) VALUES ('fixture',0,?)").run(at); |
| 31 | db.prepare( |
| 32 | "INSERT INTO enterprise_invoices(invoice_id,account_id,period,amount_micros,status,created_by,created_at) VALUES ('in_fixture','ent_fixture','now',10000000,'open','staff',?)", |
| 33 | ).run(at); |
| 34 | const update = db.prepare(constant("webhooks", "ENTERPRISE_STATUS")); |
| 35 | const stop = db.prepare(constant("webhooks", "ENTERPRISE_OVERDUE_STOP")); |
| 36 | update.get("overdue", "in_fixture"); |
| 37 | stop.run("fixture", at, "overdue", "in_fixture"); |
| 38 | assert.equal(db.prepare("SELECT autopay_error FROM limits WHERE workspace='fixture'").get().autopay_error, "overdue"); |
| 39 | batch(db, [ |
| 40 | ["UPDATE enterprise_invoices SET status='paid' WHERE invoice_id='in_fixture'", []], |
| 41 | [constant("lib", "CLEAR_STOP"), ["fixture"]], |
| 42 | ]); |
| 43 | assert.equal(update.get("overdue", "in_fixture"), undefined); |
| 44 | stop.run("fixture", at, "late overdue", "in_fixture"); |
| 45 | assert.equal(db.prepare("SELECT autopay_error FROM limits WHERE workspace='fixture'").get().autopay_error, null); |
| 46 | db.exec("UPDATE enterprise_invoices SET status='void'"); |
| 47 | assert.equal(update.get("overdue", "in_fixture"), undefined); |
| 48 | stop.run("fixture", at, "late overdue", "in_fixture"); |
| 49 | assert.equal(db.prepare("SELECT autopay_error FROM limits WHERE workspace='fixture'").get().autopay_error, null); |
| 50 | }); |
| 51 | test("enterprise invoice acquisition freezes one payload and rejects stale balances after completion", () => { |
| 52 | const db = database(); |
| 53 | db.prepare("INSERT INTO accounts(workspace,balance_micros,created_at) VALUES ('fixture',-10000000,?)").run(at); |
| 54 | db.prepare("INSERT INTO account_members(workspace,account_id,added_by,added_at) VALUES ('fixture','ent_fixture','staff',?)").run(at); |
| 55 | const snapshots = JSON.stringify([{ workspace: "fixture", balance: -10000000, invoiced: 0 }]); |
| 56 | const acquire = db.prepare(constant("enterprise_attempt", "INSERT")); |
| 57 | const payload = JSON.stringify({ lines: [{ workspace: "fixture", amountMicros: 10000000 }] }); |
| 58 | acquire.run("ent_fixture", "first", payload, 1, snapshots); |
| 59 | acquire.run("ent_fixture", "second", '{"amount":20000000}', 2, snapshots); |
| 60 | assert.deepEqual({ ...db.prepare("SELECT id,payload FROM enterprise_invoice_attempts").get() }, { id: "first", payload }); |
| 61 | assert.throws(() => db.exec("UPDATE account_members SET account_id='ent_other' WHERE workspace='fixture'"), /pending enterprise invoice/); |
| 62 | assert.throws(() => db.exec("DELETE FROM account_members WHERE workspace='fixture'"), /pending enterprise invoice/); |
| 63 | db.prepare( |
| 64 | "INSERT INTO enterprise_invoices(invoice_id,account_id,period,amount_micros,status,created_by,created_at) VALUES ('in_first','ent_fixture','now',10000000,'open','staff',?)", |
| 65 | ).run(at); |
| 66 | db.exec("INSERT INTO enterprise_invoice_lines VALUES ('in_first','fixture',10000000); UPDATE enterprise_invoice_attempts SET completed=1"); |
| 67 | db.prepare(constant("enterprise_attempt", "RETIRE")).run("ent_fixture"); |
| 68 | acquire.run("ent_fixture", "stale", "{}", 3, snapshots); |
| 69 | assert.equal(db.prepare("SELECT COUNT(*) n FROM enterprise_invoice_attempts").get().n, 0); |
| 70 | db.exec("UPDATE accounts SET balance_micros=-15000000 WHERE workspace='fixture'"); |
| 71 | const fresh = JSON.stringify([{ workspace: "fixture", balance: -15000000, invoiced: 10000000 }]); |
| 72 | acquire.run("ent_fixture", "additional", '{"amount":5000000}', 4, fresh); |
| 73 | assert.equal(db.prepare("SELECT id FROM enterprise_invoice_attempts").get().id, "additional"); |
| 74 | }); |
| 75 | test("a late enterprise invoice writer cannot recreate old lines after completion and rename", () => { |
| 76 | const db = database(); |
| 77 | const writes = prepares("webhooks", "async fn finish_enterprise_attempt(", "/// An enterprise invoice paid:").filter((sql) => |
| 78 | sql.startsWith("INSERT INTO enterprise_invoice"), |
| 79 | ); |
| 80 | assert.equal(writes.length, 2); |
| 81 | db.prepare("INSERT INTO enterprise_invoice_attempts(account_id,id,payload,created_ms) VALUES ('ent_fixture','attempt','{}',1)").run(); |
| 82 | const invoice = ["in_fixture", "ent_fixture", "now", 10000000, null, "staff", at, "attempt"]; |
| 83 | const line = ["in_fixture", "old", 10000000, "attempt"]; |
| 84 | batch(db, [ |
| 85 | [writes[0], invoice], |
| 86 | [writes[1], line], |
| 87 | ]); |
| 88 | db.exec("UPDATE enterprise_invoice_attempts SET completed=1; UPDATE enterprise_invoice_lines SET workspace='renamed'"); |
| 89 | batch(db, [ |
| 90 | [writes[0], invoice], |
| 91 | [writes[1], line], |
| 92 | ]); |
| 93 | assert.deepEqual( |
| 94 | db |
| 95 | .prepare("SELECT workspace FROM enterprise_invoice_lines") |
| 96 | .all() |
| 97 | .map((r) => r.workspace), |
| 98 | ["renamed"], |
| 99 | ); |
| 100 | db.prepare(constant("enterprise_attempt", "RETIRE")).run("ent_fixture"); |
| 101 | batch(db, [ |
| 102 | [writes[0], invoice], |
| 103 | [writes[1], line], |
| 104 | ]); |
| 105 | assert.equal(db.prepare("SELECT SUM(amount_micros) n FROM enterprise_invoice_lines").get().n, 10000000); |
| 106 | }); |
| 107 | test("fee waivers refuse subscriptions that may still charge, including delinquent plans", () => { |
| 108 | const db = database(); |
| 109 | const insert = db.prepare( |
| 110 | "INSERT INTO subscriptions (workspace, feature, subscription_id, status, started_by, started_at, updated_at) VALUES (?, 'plan', ?, ?, 'staff', ?, ?)", |
| 111 | ); |
| 112 | for (const status of ["active", "past_due", "incomplete", "unpaid", "canceled"]) { |
| 113 | insert.run(status, `sub_${status}`, status, at, at); |
| 114 | const found = db.prepare(constant("accounts", "FEE_WAIVER_SUBSCRIPTIONS")).get(status); |
| 115 | assert.equal(Boolean(found), status !== "canceled", status); |
| 116 | } |
| 117 | assert.equal(db.prepare(constant("accounts", "FEE_WAIVER_SUBSCRIPTIONS")).get("new-workspace"), undefined); |
| 118 | }); |
| 119 | test("demo detach finds all sources through bounded compound selects", () => { |
| 120 | const db = database(); |
| 121 | db.prepare("INSERT INTO accounts (workspace,balance_micros,created_at) VALUES ('demo',8000000,?)").run(at); |
| 122 | db.prepare("INSERT INTO allowance_use (kind,scope,month,used) VALUES ('plan_credit','allowance-only','2026-10',500)").run(); |
| 123 | const sql = constant("detach", "FOUND").replace("{internal}", constant("sales", "INTERNAL_SQL")); |
| 124 | const rows = db.prepare(sql).all(null, "2026-10"); |
| 125 | assert.deepEqual( |
| 126 | rows.map((r) => r.workspace), |
| 127 | ["allowance-only", "demo"], |
| 128 | ); |
| 129 | assert.equal(rows[0].plan_credit, 500); |
| 130 | assert.equal(rows[1].balance, 8000000); |
| 131 | assert.deepEqual( |
| 132 | db |
| 133 | .prepare(sql) |
| 134 | .all("demo", "2026-10") |
| 135 | .map((r) => r.workspace), |
| 136 | ["demo"], |
| 137 | ); |
| 138 | // D1 rejects the former long UNION. Each candidate CTE stays small. |
| 139 | for (const cte of sql.split("AS MATERIALIZED (").slice(1)) { |
| 140 | assert.ok((cte.split(")")[0].match(/UNION/g) ?? []).length <= 3); |
| 141 | } |
| 142 | }); |
| 143 | function batch(db, writes) { |
| 144 | db.exec("BEGIN"); |
| 145 | try { |
| 146 | for (const [sql, args] of writes) db.prepare(sql).run(...args); |
| 147 | db.exec("COMMIT"); |
| 148 | } catch (e) { |
| 149 | db.exec("ROLLBACK"); |
| 150 | throw e; |
| 151 | } |
| 152 | } |
| 153 | const entries = prepares("lib", "pub(crate) fn entry_statements(", "/// What follows an entry"); |
| 154 | const stops = prepares("lib", "fn after_entry_statements(", "async fn account("); |
| 155 | const extras = prepares("tax", "pub(crate) fn extras_statements(", "/// A payment's tax and fee"); |
| 156 | function payment(reference, amount = 25_000_000) { |
| 157 | assert.equal(entries.length, 2); |
| 158 | assert.equal(stops.length, 1); |
| 159 | assert.equal(extras.length, 1); |
| 160 | return [ |
| 161 | [entries[0], [reference, "fixture", "top_up", amount, "Paid in advance", null, reference, null, at]], |
| 162 | [entries[1], ["fixture", amount, "cus_fixture", at]], |
| 163 | [stops[0], ["fixture", amount]], |
| 164 | [constant("lib", "CLEAR_STOP"), ["fixture"]], |
| 165 | [extras[0], [`${reference}/tax`, "fixture", "tax", 2_000_000, reference, "pi_fixture", null, at]], |
| 166 | ]; |
| 167 | } |
| 168 | test("payment, balance, dispute repayment and tax commit once together", () => { |
| 169 | const db = database(); |
| 170 | db.prepare("INSERT INTO limits (workspace, updated_at, dispute_owed_micros, autopay_failed_at) VALUES (?, ?, ?, ?)").run("fixture", at, 30_000_000, at); |
| 171 | batch(db, payment("cs_fixture")); |
| 172 | assert.equal(db.prepare("SELECT balance_micros FROM accounts WHERE workspace='fixture'").get().balance_micros, 25_000_000); |
| 173 | assert.equal(db.prepare("SELECT dispute_owed_micros FROM limits WHERE workspace='fixture'").get().dispute_owed_micros, 5_000_000); |
| 174 | assert.throws(() => batch(db, payment("cs_fixture")), /UNIQUE/); |
| 175 | assert.equal(db.prepare("SELECT dispute_owed_micros FROM limits WHERE workspace='fixture'").get().dispute_owed_micros, 5_000_000); |
| 176 | assert.equal(db.prepare("SELECT COUNT(*) n FROM tax_and_fees").get().n, 1); |
| 177 | batch(db, payment("cs_second", 5_000_000)); |
| 178 | assert.equal(db.prepare("SELECT autopay_failed_at FROM limits WHERE workspace='fixture'").get().autopay_failed_at, null); |
| 179 | db.close(); |
| 180 | }); |
| 181 | test("a failure writing tax rolls back the credit and payment-stop updates", () => { |
| 182 | const db = database(); |
| 183 | db.prepare("INSERT INTO limits (workspace, updated_at, dispute_owed_micros, autopay_failed_at) VALUES (?, ?, ?, ?)").run("fixture", at, 25_000_000, at); |
| 184 | db.exec("CREATE TRIGGER fail_tax BEFORE INSERT ON tax_and_fees BEGIN SELECT RAISE(ABORT, 'injected failure'); END"); |
| 185 | assert.throws(() => batch(db, payment("cs_fixture")), /injected failure/); |
| 186 | assert.equal(db.prepare("SELECT COUNT(*) n FROM ledger").get().n, 0); |
| 187 | assert.equal(db.prepare("SELECT COUNT(*) n FROM accounts WHERE workspace='fixture'").get().n, 0); |
| 188 | assert.equal(db.prepare("SELECT dispute_owed_micros FROM limits WHERE workspace='fixture'").get().dispute_owed_micros, 25_000_000); |
| 189 | db.exec("DROP TRIGGER fail_tax"); |
| 190 | batch(db, payment("cs_fixture")); |
| 191 | assert.equal(db.prepare("SELECT COUNT(*) n FROM tax_and_fees").get().n, 1); |
| 192 | db.close(); |
| 193 | }); |
| 194 | test("payment never clears an open dispute", () => { |
| 195 | const db = database(); |
| 196 | db.prepare("INSERT INTO limits (workspace, updated_at, autopay_failed_at) VALUES (?, ?, ?)").run("fixture", at, at); |
| 197 | db.prepare("INSERT INTO disputes (dispute_id, workspace, charge_id, status, updated_at) VALUES ('dp_fixture', 'fixture', 'ch_fixture', 'open', ?)").run(at); |
| 198 | batch(db, payment("cs_fixture")); |
| 199 | assert.equal(db.prepare("SELECT autopay_failed_at FROM limits WHERE workspace='fixture'").get().autopay_failed_at, at); |
| 200 | db.close(); |
| 201 | }); |
| 202 | test("concurrent invoice requests freeze one payload even as usage changes", () => { |
| 203 | const db = database(); |
| 204 | db.prepare("INSERT INTO accounts (workspace, balance_micros, created_at) VALUES ('fixture', -10000000, ?)").run(at); |
| 205 | const insert = db.prepare(constant("invoice_attempt", "INSERT")); |
| 206 | insert.run("attempt_a", "fixture", '{"amount":1000}', 1000, -10_000_000); |
| 207 | db.exec("UPDATE accounts SET balance_micros=-20000000 WHERE workspace='fixture'"); |
| 208 | insert.run("attempt_b", "fixture", '{"amount":2000}', 2000, -20_000_000); |
| 209 | assert.deepEqual({ ...db.prepare("SELECT id, payload FROM invoice_attempts").get() }, { id: "attempt_a", payload: '{"amount":1000}' }); |
| 210 | assert.equal(db.prepare(constant("invoice_attempt", "RETIRE")).run("fixture").changes, 0); |
| 211 | assert.equal(db.prepare(constant("closing", "UNPAID_INVOICES_SQL")).get("fixture").n, 1); |
| 212 | db.close(); |
| 213 | }); |
| 214 | test("a stale invoice calculation cannot create an attempt after payment changes the balance", () => { |
| 215 | const db = database(); |
| 216 | db.prepare("INSERT INTO accounts (workspace, balance_micros, created_at) VALUES ('fixture', 0, ?)").run(at); |
| 217 | const result = db.prepare(constant("invoice_attempt", "INSERT")).run("attempt_a", "fixture", "{}", 1000, -10_000_000); |
| 218 | assert.equal(result.changes, 0); |
| 219 | db.close(); |
| 220 | }); |
| 221 | test("the migration registry covers every billing migration", () => { |
| 222 | const dir = new URL("../services/billing/migrations/", import.meta.url); |
| 223 | const lib = source("lib"); |
| 224 | for (const name of readdirSync(dir).filter((n) => n.endsWith(".sql"))) assert.ok(lib.includes(`include_str!("../migrations/${name}")`), name); |
| 225 | }); |
| 226 | |
| 227 | const sqlFile = (name) => readFileSync(new URL(`../services/billing/src/${name}.sql`, import.meta.url), "utf8"); |
| 228 | function refund(db, cents, tax, plan = false) { |
| 229 | const reference = `refund/ch_fixture/${cents + tax}`; |
| 230 | const writes = [[sqlFile(plan ? "refund_plan" : "refund_ledger"), [reference, "fixture", cents * 10_000, reference, at, "refund/ch_fixture/%"]]]; |
| 231 | if (!plan) writes.push([constant("webhooks", "REFUND_BALANCE"), [reference, "fixture"]]); |
| 232 | writes.push([sqlFile("refund_extras"), [`${reference}/tax`, "fixture", "tax", tax * 10_000, reference, "pi_fixture", at, "refund/ch_fixture/%"]]); |
| 233 | batch(db, writes); |
| 234 | } |
| 235 | test("partial refunds, duplicate deliveries and reversed ordering debit only the cumulative total", () => { |
| 236 | for (const order of [ |
| 237 | [1000, 2500, 2500], |
| 238 | [2500, 1000, 2500], |
| 239 | ]) { |
| 240 | const db = database(); |
| 241 | batch(db, payment("cs_fixture")); |
| 242 | for (const cents of order) refund(db, cents, cents * 0.08); |
| 243 | assert.equal(db.prepare("SELECT balance_micros FROM accounts WHERE workspace='fixture'").get().balance_micros, 0); |
| 244 | assert.equal(db.prepare("SELECT SUM(amount_micros) n FROM tax_and_fees WHERE workspace='fixture'").get().n, 0); |
| 245 | db.close(); |
| 246 | } |
| 247 | }); |
| 248 | test("refund tax failure rolls back the reversal and retries without a second debit", () => { |
| 249 | const db = database(); |
| 250 | batch(db, payment("cs_fixture")); |
| 251 | db.exec("CREATE TRIGGER fail_refund_tax BEFORE INSERT ON tax_and_fees WHEN NEW.amount_micros < 0 BEGIN SELECT RAISE(ABORT, 'injected failure'); END"); |
| 252 | assert.throws(() => refund(db, 2500, 200), /injected failure/); |
| 253 | assert.equal(db.prepare("SELECT balance_micros FROM accounts WHERE workspace='fixture'").get().balance_micros, 25_000_000); |
| 254 | db.exec("DROP TRIGGER fail_refund_tax"); |
| 255 | refund(db, 2500, 200); |
| 256 | refund(db, 2500, 200); |
| 257 | assert.equal(db.prepare("SELECT balance_micros FROM accounts WHERE workspace='fixture'").get().balance_micros, 0); |
| 258 | db.close(); |
| 259 | }); |
| 260 | test("plan refunds reduce revenue without debiting prepaid usage credit", () => { |
| 261 | const db = database(); |
| 262 | batch(db, payment("cs_fixture")); |
| 263 | refund(db, 1000, 80, true); |
| 264 | refund(db, 2500, 200, true); |
| 265 | refund(db, 1000, 80, true); |
| 266 | assert.equal(db.prepare("SELECT SUM(amount_micros) n FROM plan_payments WHERE workspace='fixture'").get().n, -25_000_000); |
| 267 | assert.equal(db.prepare("SELECT balance_micros FROM accounts WHERE workspace='fixture'").get().balance_micros, 25_000_000); |
| 268 | db.close(); |
| 269 | }); |
| 270 | |
| 271 | test("one card cannot fund concurrent trials or another trial after being replaced", () => { |
| 272 | const db = database(); |
| 273 | const grantSql = prepares("credits", "pub(crate) async fn ensure_grant(", "/// Takes up to")[0]; |
| 274 | const card = db.prepare( |
| 275 | "INSERT INTO card_checks (workspace, setup_intent, payment_method, fingerprint, funding, checked_by, checked_at) VALUES (?, ?, ?, ?, 'credit', 'fixture', ?)", |
| 276 | ); |
| 277 | card.run("trial_a", "seti_a", "pm_a", "same_card", at); |
| 278 | card.run("trial_b", "seti_b", "pm_b", "same_card", at); |
| 279 | const grant = db.prepare(grantSql); |
| 280 | grant.run("trial_a", "2026-10", 5_000_000, at, 100_000_000); |
| 281 | grant.run("trial_b", "2026-10", 5_000_000, at, 100_000_000); |
| 282 | assert.equal(db.prepare("SELECT COUNT(*) n FROM trial_grants WHERE workspace IN ('trial_a','trial_b')").get().n, 1); |
| 283 | db.exec("UPDATE card_checks SET fingerprint='replacement_card' WHERE workspace='trial_a'"); |
| 284 | grant.run("trial_b", "2026-10", 5_000_000, at, 100_000_000); |
| 285 | assert.equal(db.prepare("SELECT COUNT(*) n FROM trial_grants WHERE workspace='trial_b'").get().n, 0); |
| 286 | db.close(); |
| 287 | }); |
| 288 | |
| 289 | function usage(id, reference, workspace, gross, { plan = 10_000_000, trial = 1, pool = 1_000_000, repo = 1_000_000, given = 0, when = at } = {}) { |
| 290 | const insert = prepares("storage", "pub(crate) async fn post_usage_with(", "/// Takes `charged`")[0]; |
| 291 | const balance = prepares("storage", "pub(crate) fn balance_if_posted(", "/// Writes down")[0]; |
| 292 | const month = when.slice(0, 7); |
| 293 | return [ |
| 294 | [insert, [id, workspace, -gross, "Usage", `${workspace}/repo`, "sandbox", gross, reference, when, 0, 0, 0, 0, null]], |
| 295 | [sqlFile("allocate_usage"), [id, workspace, month, plan, trial, `${workspace}/repo`, pool, repo, given]], |
| 296 | [constant("allocation", "PLAN"), [id, month]], |
| 297 | [constant("allocation", "GIFT"), [id, month]], |
| 298 | [constant("allocation", "TRIAL"), [id]], |
| 299 | [constant("allocation", "OSS_POOL"), [id, month]], |
| 300 | [constant("allocation", "OSS_REPO"), [id, month, `${workspace}/repo`]], |
| 301 | [balance, [workspace, at, id]], |
| 302 | ]; |
| 303 | } |
| 304 | test("usage allocation, source debits and ledger posting conserve credit across retries", () => { |
| 305 | const db = database(); |
| 306 | db.prepare("INSERT INTO trial_grants (workspace, month, granted_micros, used_micros, created_at) VALUES ('fixture', '2026-10', 1000000, 0, ?)").run(at); |
| 307 | batch(db, usage("usage_a", "run/a", "fixture", 12_000_000)); |
| 308 | const read = () => ({ ...db.prepare("SELECT amount_micros, credit_micros, trial_micros, oss_micros FROM ledger WHERE id='usage_a'").get() }); |
| 309 | assert.deepEqual(read(), { amount_micros: 0, credit_micros: 10_000_000, trial_micros: 1_000_000, oss_micros: 1_000_000 }); |
| 310 | batch(db, usage("duplicate", "run/a", "fixture", 12_000_000)); |
| 311 | assert.equal(db.prepare("SELECT SUM(used) n FROM allowance_use WHERE kind='plan_credit'").get().n, 10_000_000); |
| 312 | batch(db, usage("usage_b", "run/b", "fixture", 2_000_000)); |
| 313 | assert.equal(db.prepare("SELECT balance_micros FROM accounts WHERE workspace='fixture'").get().balance_micros, -2_000_000); |
| 314 | db.close(); |
| 315 | }); |
| 316 | test("an interrupted usage transaction consumes no allowance and a retry posts once", () => { |
| 317 | const db = database(); |
| 318 | db.exec("CREATE TRIGGER fail_usage_balance BEFORE INSERT ON accounts WHEN NEW.workspace='fixture' BEGIN SELECT RAISE(ABORT, 'injected failure'); END"); |
| 319 | assert.throws(() => batch(db, usage("usage_a", "run/a", "fixture", 5_000_000)), /injected failure/); |
| 320 | assert.equal(db.prepare("SELECT COUNT(*) n FROM ledger WHERE id='usage_a'").get().n, 0); |
| 321 | assert.equal(db.prepare("SELECT COUNT(*) n FROM allowance_use WHERE scope='fixture'").get().n, 0); |
| 322 | db.exec("DROP TRIGGER fail_usage_balance"); |
| 323 | batch(db, usage("usage_b", "run/a", "fixture", 5_000_000)); |
| 324 | assert.equal(db.prepare("SELECT used FROM allowance_use WHERE scope='fixture' AND kind='plan_credit'").get().used, 5_000_000); |
| 325 | db.close(); |
| 326 | }); |
| 327 | test("different workspaces share one bounded OSS pool and free overruns remain explicit", () => { |
| 328 | const db = database(); |
| 329 | batch(db, usage("a", "run/a", "a", 800_000, { plan: 0, trial: 0 })); |
| 330 | batch(db, usage("b", "run/b", "b", 800_000, { plan: 0, trial: 0, given: 1 })); |
| 331 | assert.equal(db.prepare("SELECT used FROM allowance_use WHERE kind='oss_pool'").get().used, 1_000_000); |
| 332 | assert.deepEqual( |
| 333 | { ...db.prepare("SELECT amount_micros, oss_micros, given_micros FROM ledger WHERE id='b'").get() }, |
| 334 | { amount_micros: 0, oss_micros: 200_000, given_micros: 600_000 }, |
| 335 | ); |
| 336 | db.close(); |
| 337 | }); |