test/donor-tenancy.test.js
Rama main · réplica de lectura del repositorio original.
import { test } from "node:test";
import assert from "node:assert/strict";
import { mkdtemp, mkdir, writeFile, rm } from "node:fs/promises";
import { tmpdir } from "node:os";
import path from "node:path";
/**
* Whose letterhead a report is drawn on.
*
* The donor decides the headers, margins, footer and watermark a report is
* graded against — it is institutional in exactly the way identity and brand
* marks are, and it was the last of the three still install-wide. A box
* serving two colleges put one college's template on the other's submission,
* and nothing failed: the .docx renders, it is simply the wrong document.
*/
const scratch = await mkdtemp(path.join(tmpdir(), "forge-donor-tenancy-"));
process.env.FORGE_REFERENCE_DIR = path.join(scratch, "reference");
process.env.FORGE_DECKS_DIR = path.join(scratch, "decks");
await mkdir(process.env.FORGE_REFERENCE_DIR, { recursive: true });
await mkdir(process.env.FORGE_DECKS_DIR, { recursive: true });
const REFERENCE = process.env.FORGE_REFERENCE_DIR;
const DECKS = process.env.FORGE_DECKS_DIR;
const { donorDirFor, donorDirForDeck, donorStatus, resolveDonor } = await import("../src/report.js");
const { userReferenceDir } = await import("../src/tenant.js");
/** A .docx only has to be findable here; nothing in this file opens one. */
async function putDonor(dir, name) {
await mkdir(dir, { recursive: true });
await writeFile(path.join(dir, name), "PK");
}
async function deck(slug, meta) {
const dir = path.join(DECKS, slug);
await mkdir(dir, { recursive: true });
await writeFile(path.join(dir, "meta.yaml"), meta);
return dir;
}
test("an account with no template of its own uses the operator's", async () => {
await putDonor(REFERENCE, "institute-template.docx");
assert.equal(await donorDirFor("nobody@example.com"), REFERENCE);
assert.equal(await donorDirFor(null), REFERENCE);
});
test("an account's own template overrides the operator's", async () => {
const mine = userReferenceDir("a@example.com");
await putDonor(mine, "my-college.docx");
assert.equal(await donorDirFor("a@example.com"), mine);
assert.equal((await donorStatus(await donorDirFor("a@example.com"))).detail, "my-college.docx");
// And the account beside it is untouched — the failure this exists to stop.
assert.equal(await donorDirFor("b@example.com"), REFERENCE);
assert.equal((await donorStatus(await donorDirFor("b@example.com"))).detail, "institute-template.docx");
});
test("an empty account directory is not a template", async () => {
// Uploading and then removing leaves the directory behind. Falling into it
// would turn "I removed mine" into "reports stopped working".
const dir = userReferenceDir("c@example.com");
await mkdir(dir, { recursive: true });
assert.equal(await donorDirFor("c@example.com"), REFERENCE);
});
test("a deck resolves the donor from its own owner, not the caller", async () => {
// An admin rendering someone else's report must still draw it on THEIR
// template. The deck records the owner, which is why renderReport needs no
// user threaded through it.
const owned = await deck("owned", "slug: owned\nowner: a@example.com\n");
assert.equal(await donorDirForDeck(owned), userReferenceDir("a@example.com"));
const cli = await deck("cli-run", "slug: cli-run\n");
assert.equal(await donorDirForDeck(cli), REFERENCE);
// A folder from before meta.yaml existed is the operator's, like every other
// ownerless deck.
const legacy = path.join(DECKS, "legacy");
await mkdir(legacy, { recursive: true });
assert.equal(await donorDirForDeck(legacy), REFERENCE);
});
test("the not-found error names the directory actually searched", async () => {
// Pointing a user at the install-wide reference/ when their own account
// directory is the empty one sends them to fix the wrong thing.
const dir = path.join(scratch, "empty-somewhere");
await mkdir(dir, { recursive: true });
await assert.rejects(resolveDonor(null, dir), (err) => err.message.includes(dir));
});
test("the operator's own status still ignores the per-account subtree", async () => {
// reference/users/ sits inside REFERENCE. donorStatus filters to .docx, so a
// directory of accounts must not read as a second template and trip the
// "multiple donors" refusal for everybody.
const status = await donorStatus(REFERENCE);
assert.equal(status.ok, true);
assert.deepEqual(status.donors, ["institute-template.docx"]);
});
test.after(() => rm(scratch, { recursive: true, force: true }));