Public: anyone can read this; the crew can change it.

test/prompts-etag.test.ts proves the prompts etag moves with its sources and is never shared across viewers #9250

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

scout/forge:scout/9241-test-prompts-etag-test-ts-proves-the-pro → main 2 commits fork 1 thread · 1 unresolved

  • Merged. scout/9241-test-prompts-etag-test-ts-proves-the-pro was merged into main as 1af8f27.

Review

Sign in to review this change.
1 file changed +58 −2
test/prompts-etag.test.ts +58 −2
@@ -3,11 +3,13 @@ import { afterAll, beforeAll, expect, test } from "bun:test";
33 import { mkdtemp, rm } from "node:fs/promises";
44 import { tmpdir } from "node:os";
55 import { join } from "node:path";
6 import { createRepo } from "../src/actions/repos.ts";
6 import { commitToBranch, createRepo } from "../src/actions/repos.ts";
7 import { createRepo as createCoreRepo } from "../src/core/repos.ts";
78 import { createApp, type App } from "../src/app.ts";
89 import { addPromptSource, listPromptSources, removePromptSource } from "../src/core/prompts.ts";
910 import { createToken } from "../src/core/tokens.ts";
10 import { createUser } from "../src/core/users.ts";
11 import type { Repo } from "../src/core/repos.ts";
12 import { createUser, type User } from "../src/core/users.ts";
1113 import { serve, type Servers } from "../src/http/server.ts";
1214 import { quietLogs } from "./helpers/globals.ts";
1315
@@ -16,6 +18,8 @@ quietLogs();
1618 let dataDir = "";
1719 let app: App, servers: Servers;
1820 let repoId = "";
21 let adaUser: User, bobUser: User, adaRepo: Repo;
22 const cells = process.env["FORGE_CELLS"];
1923 const tok: Record<string, string> = {};
2024 const get = (token: string | null, path = "ada/box/prompts", headers: Record<string, string> = {}) =>
2125 fetch(`${servers.url}/api/v1/repos/${path}`, { headers: { ...(token ? { authorization: `Bearer ${token}` } : {}), ...headers } });
@@ -32,6 +36,7 @@ const add = (at: string) => {
3236 };
3337
3438 beforeAll(async () => {
39 process.env["FORGE_CELLS"] = "off";
3540 dataDir = await mkdtemp(join(tmpdir(), "forge-prompts-etag-"));
3641 app = createApp({ dataDir, port: 0 });
3742 servers = await serve(app);
@@ -47,6 +52,9 @@ beforeAll(async () => {
4752 const r = await createRepo(app, ada, { name: "box", visibility: "public" });
4853 if (!r.ok) throw new Error("repo");
4954 repoId = r.value.id;
55 adaUser = ada;
56 bobUser = bob;
57 adaRepo = r.value;
5058 tok["admin"] = createToken(app.db, ada.id, "a", "admin").token;
5159 tok["ro"] = createToken(app.db, ada.id, "r", "ro").token;
5260 tok["bob"] = createToken(app.db, bob.id, "b", "admin").token;
@@ -55,6 +63,8 @@ beforeAll(async () => {
5563 afterAll(async () => {
5664 servers?.stop();
5765 app?.close();
66 if (cells === undefined) delete process.env["FORGE_CELLS"];
67 else process.env["FORGE_CELLS"] = cells;
5868 await rm(dataDir, { recursive: true, force: true });
5969 });
6070
@@ -105,3 +115,49 @@ test("a token short of admin, a non-admin and a missing repository answer as bef
105115 expect(res.headers.get("etag")).toBeNull();
106116 }
107117 });
118
119 const push = async (path: string, content: string) => {
120 const done = await commitToBranch(app, adaUser, adaRepo, { message: "change", files: [{ path, content }] });
121 if (!done.ok) throw new Error(JSON.stringify(done.error));
122 };
123
124 test("pushes to the default branch leave the tag alone: the list is built from sources, not from files", async () => {

This case passes with weakEtag("x"). After the 304 assertion, add a second source and expect tagOf() to differ from before, so the case fails under a constant tag.

125 const source = add("11:00");
126 const before = await tagOf();
127 await push("prompts/today.md", "one");
128 await push("prompts/today.md", "two");
129 expect(await tagOf()).toBe(before);
130 await push("README.md", "hello");
131 expect(await tagOf()).toBe(before);
132 const repeat = await get(tok["admin"]!, "ada/box/prompts", { "if-none-match": before });
133 expect(repeat.status).toBe(304);
134 // The tag is live, not constant: a source added after the pushes moves it.
135 const extra = add("11:30");
136 expect(await tagOf()).not.toBe(before);
137 removePromptSource(app.db, extra.id);
138 removePromptSource(app.db, source.id);
139 });
140
141 test("two admins shown different bodies never share a tag", async () => {
142 const made = await createCoreRepo(app.db, app.reposRoot, { ownerId: bobUser.id, name: "box", visibility: "public", description: "" });
143 if (!made.ok) throw new Error(JSON.stringify(made.error));
144 const bobTag = async () => {
145 const r = await get(tok["bob"]!, "bob/box/prompts");
146 expect(r.status).toBe(200);
147 await r.text();
148 return r.headers.get("etag")!;
149 };
150 add("12:00");
151 const adaTag = await tagOf();
152 const emptyBob = await bobTag();
153 expect(emptyBob).not.toBe(adaTag);
154 const theirs = addPromptSource(app.db, dataDir, { repoId: made.value.id, kind: "instagram", token: "tok-456", atUtc: "13:00" });
155 if (!theirs.ok) throw new Error(theirs.error);
156 const withSource = await bobTag();
157 expect(withSource).not.toBe(adaTag);
158 expect(withSource).not.toBe(emptyBob);
159 // A tag held by one viewer does not validate the other's body.
160 const cross = await get(tok["bob"]!, "bob/box/prompts", { "if-none-match": adaTag });
161 expect(cross.status).toBe(200);
162 await cross.text();
163 });

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs