Ctrl K
ComunidadGuías…

test/donor-tenancy.test.js

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
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 }));