publish / src /lib /app-data /app-data.test.ts
caustino's picture
Upload 104 files
a038238 verified
Raw History Blame Contribute Delete
15.9 kB
import { afterEach, beforeEach, describe, it, mock } from "node:test";
import assert from "node:assert/strict";
import {
callTool,
failureMemoSize,
isConnectorTokenReady,
} from "./client.server.ts";
import { ConnectorType, GoogleCalendarTools } from "./types.ts";
import type { ToolArgs } from "./types.ts";
import { isLoginRequired, redirectToLoginIfRequired } from "./login.ts";
import { classifyCallToolError } from "./errors.ts";
import type { CallToolResult } from "./types.ts";
type WindowStub = {
location: { assign: (url: string) => void; href: string };
self?: unknown;
top?: unknown;
open?: (url: string, target: string) => unknown;
};
function withWindow<T>(stub: WindowStub, fn: () => T): T {
(globalThis as { window?: unknown }).window = stub;
try {
return fn();
} finally {
delete (globalThis as { window?: unknown }).window;
}
}
function fakeJwt(claims: Record<string, unknown>): string {
const encode = (value: unknown) =>
Buffer.from(JSON.stringify(value)).toString("base64url");
return `${encode({ alg: "HS256", typ: "JWT" })}.${encode(claims)}.sig`;
}
async function withStubbedGate(
status: number,
body: Record<string, unknown>,
run: (calls: () => number) => Promise<void>,
): Promise<void> {
process.env.GROK_CONNECTORS_URL = "https://connectors.invalid.example";
const realFetch = globalThis.fetch;
let calls = 0;
globalThis.fetch = (async () => {
calls += 1;
return new Response(JSON.stringify(body), { status });
}) as typeof fetch;
try {
await run(() => calls);
} finally {
globalThis.fetch = realFetch;
delete process.env.GROK_CONNECTORS_URL;
}
}
describe("callTool failure memo", () => {
it("replays an identical failure within the memo window without refetching", async () => {
await withStubbedGate(500, { ok: false, errorMessage: "boom" }, async (calls) => {
const options = {
connectorType: ConnectorType.GoogleDrive,
token: fakeJwt({ sub: "memo-user-1", iat: 1000, exp: 2000 }),
};
const first = await callTool("google_drive_search", { q: "memo" }, options);
const second = await callTool("google_drive_search", { q: "memo" }, options);
assert.equal(first.ok, false);
assert.equal(first.errorMessage, "boom");
assert.deepEqual(second, first);
assert.equal(calls(), 1);
});
});
it("keys by token identity so a reminted token shares the memo entry", async () => {
await withStubbedGate(500, { ok: false, errorMessage: "boom" }, async (calls) => {
const first = await callTool(
"google_drive_search",
{ q: "remint" },
{
connectorType: ConnectorType.GoogleDrive,
token: fakeJwt({ sub: "memo-user-2", iat: 1000, exp: 2000 }),
},
);
const second = await callTool(
"google_drive_search",
{ q: "remint" },
{
connectorType: ConnectorType.GoogleDrive,
token: fakeJwt({ sub: "memo-user-2", iat: 1001, exp: 2001 }),
},
);
assert.equal(first.ok, false);
assert.deepEqual(second, first);
assert.equal(calls(), 1);
const other = await callTool(
"google_drive_search",
{ q: "remint" },
{
connectorType: ConnectorType.GoogleDrive,
token: fakeJwt({ sub: "memo-user-3", iat: 1000, exp: 2000 }),
},
);
assert.equal(other.ok, false);
assert.equal(calls(), 2);
});
});
it("sweeps expired entries on write so unique keys do not accumulate", async () => {
await withStubbedGate(500, { ok: false, errorMessage: "boom" }, async () => {
mock.timers.enable({ apis: ["Date"], now: 1_000_000 });
try {
const sizeBefore = failureMemoSize();
const options = {
connectorType: ConnectorType.GoogleDrive,
token: fakeJwt({ sub: "memo-user-5", iat: 1000, exp: 2000 }),
};
await callTool("google_drive_search", { q: "sweep-a" }, options);
await callTool("google_drive_search", { q: "sweep-b" }, options);
assert.equal(failureMemoSize(), sizeBefore + 2);
mock.timers.setTime(1_000_000 + 5_001);
await callTool("google_drive_search", { q: "sweep-c" }, options);
assert.equal(
failureMemoSize(),
sizeBefore + 1,
"expired sweep-a/sweep-b entries must be removed on the sweep-c write",
);
} finally {
mock.timers.reset();
}
});
});
it("never memoizes login-required 401s", async () => {
process.env.GROK_PROJECT_ID = "proj-1";
try {
await withStubbedGate(401, { errorMessage: "login required" }, async (calls) => {
const options = {
connectorType: ConnectorType.GoogleDrive,
token: fakeJwt({ sub: "memo-user-4", iat: 1000, exp: 2000 }),
};
const first = await callTool("google_drive_search", { q: "auth" }, options);
const second = await callTool("google_drive_search", { q: "auth" }, options);
assert.equal(first.ok, false);
assert.equal(first.loginRequired, true);
assert.equal(second.loginRequired, true);
assert.equal(calls(), 2);
});
} finally {
delete process.env.GROK_PROJECT_ID;
}
});
});
describe("callTool in the workspace preview vs deployed", () => {
const options = { connectorType: ConnectorType.GoogleDrive };
const savedEnvToken = process.env.GROK_CONNECTOR_ACCESS_TOKEN;
beforeEach(() => {
delete process.env.GROK_CONNECTOR_ACCESS_TOKEN;
delete process.env.GROK_PROJECT_ID;
});
afterEach(() => {
if (savedEnvToken === undefined) {
delete process.env.GROK_CONNECTOR_ACCESS_TOKEN;
} else {
process.env.GROK_CONNECTOR_ACCESS_TOKEN = savedEnvToken;
}
delete process.env.GROK_PROJECT_ID;
});
it("returns pending (no loginRequired) when the preview has no token yet", async () => {
const result = await callTool("google_drive_search", {}, options);
assert.equal(result.ok, false);
assert.equal(result.pending, true);
assert.equal(result.loginRequired, undefined);
assert.match(result.errorMessage ?? "", /^connector_token_pending/);
});
it("returns a plain error (no sign-in CTA) when a deployed app has no token", async () => {
process.env.GROK_PROJECT_ID = "proj-1";
const result = await callTool("google_drive_search", {}, options);
assert.equal(result.ok, false);
assert.equal(result.loginRequired, undefined);
assert.equal(result.loginUrl, undefined);
assert.equal(result.pending, undefined);
assert.match(result.errorMessage ?? "", /^missing_connector_token/);
});
it("treats a gate 401 in the preview as pending and parks the rejected token", async () => {
await withStubbedGate(401, { errorMessage: "login required" }, async (calls) => {
process.env.GROK_CONNECTOR_ACCESS_TOKEN = fakeJwt({ sub: "p", iat: 1, exp: 2 });
assert.equal(isConnectorTokenReady(), true);
const result = await callTool("google_drive_search", {}, options);
assert.equal(result.pending, true);
assert.equal(result.loginRequired, undefined);
assert.match(result.errorMessage ?? "", /^connector_token_pending/);
assert.equal(calls(), 1);
assert.equal(isConnectorTokenReady(), false);
process.env.GROK_CONNECTOR_ACCESS_TOKEN = fakeJwt({ sub: "p", iat: 3, exp: 4 });
assert.equal(isConnectorTokenReady(), true);
});
});
it("keeps loginRequired for a gate 401 on a deployed app", async () => {
process.env.GROK_PROJECT_ID = "proj-1";
await withStubbedGate(401, { errorMessage: "login required" }, async () => {
const result = await callTool("google_drive_search", {}, {
...options,
token: fakeJwt({ sub: "d", iat: 1, exp: 2 }),
});
assert.equal(result.loginRequired, true);
assert.equal(result.pending, undefined);
});
});
});
describe("callTool", () => {
it("resolves ok:false for non-serializable args instead of rejecting", async () => {
process.env.GROK_CONNECTORS_URL = "https://connectors.invalid.example";
try {
const circular: Record<string, unknown> = {};
circular.self = circular;
const result = await callTool(
"google_drive_search",
circular as ToolArgs,
{
connectorType: ConnectorType.GoogleDrive,
token: "opaque-token",
},
);
assert.equal(result.ok, false);
assert.match(result.errorMessage ?? "", /circular/i);
} finally {
delete process.env.GROK_CONNECTORS_URL;
}
});
});
describe("isLoginRequired", () => {
it("is true only for login-required failures", () => {
assert.equal(
isLoginRequired({ ok: false, data: null, loginRequired: true }),
true,
);
assert.equal(isLoginRequired({ ok: false, data: null }), false);
assert.equal(
isLoginRequired({ ok: false, data: null, errorMessage: "access_denied" }),
false,
);
assert.equal(
isLoginRequired({
ok: true,
data: {},
loginRequired: true,
} as CallToolResult),
false,
);
});
});
describe("redirectToLoginIfRequired", () => {
it("no-ops when login is not required", () => {
let target = "";
const did = withWindow(
{
location: {
assign: (u) => {
target = u;
},
href: "https://my-app.grok.me/current",
},
},
() =>
redirectToLoginIfRequired({
ok: false,
data: null,
errorMessage: "tool error",
}),
);
assert.equal(did, false);
assert.equal(target, "");
});
it("navigates to the server-built loginUrl in the browser", () => {
let target = "";
const did = withWindow(
{
location: {
assign: (u) => {
target = u;
},
href: "https://my-app.grok.me/current",
},
},
() =>
redirectToLoginIfRequired({
ok: false,
data: null,
loginRequired: true,
loginUrl: "https://gate.grok.me/__gate/signin?return_to=x",
}),
);
assert.equal(did, true);
assert.equal(target, "https://gate.grok.me/__gate/signin?return_to=x");
});
it("opens a new tab instead of navigating when framed", () => {
let assigned = "";
let opened = "";
const openedTab: { opener?: unknown } = { opener: "parent" };
const did = withWindow(
{
self: "frame",
top: "host",
open: (url) => {
opened = url;
return openedTab;
},
location: {
assign: (u) => {
assigned = u;
},
href: "https://my-app.grok.me/current",
},
},
() =>
redirectToLoginIfRequired({
ok: false,
data: null,
loginRequired: true,
loginUrl: "https://gate.grok.me/__gate/signin?return_to=x",
}),
);
assert.equal(did, true);
assert.equal(opened, "https://gate.grok.me/__gate/signin?return_to=x");
assert.equal(openedTab.opener, null);
assert.equal(assigned, "");
});
it("falls back to navigation when framed and the popup is blocked", () => {
let assigned = "";
const did = withWindow(
{
self: "frame",
top: "host",
open: () => null,
location: {
assign: (u) => {
assigned = u;
},
href: "https://my-app.grok.me/current",
},
},
() =>
redirectToLoginIfRequired({
ok: false,
data: null,
loginRequired: true,
loginUrl: "https://gate.grok.me/__gate/signin?return_to=x",
}),
);
assert.equal(did, true);
assert.equal(assigned, "https://gate.grok.me/__gate/signin?return_to=x");
});
it("returns false when the result has no loginUrl", () => {
let target = "";
const did = withWindow(
{
location: {
assign: (u) => {
target = u;
},
href: "https://my-app.grok.me/current",
},
},
() =>
redirectToLoginIfRequired({ ok: false, data: null, loginRequired: true }),
);
assert.equal(did, false);
assert.equal(target, "");
});
it("returns false on the server (no window)", () => {
const did = redirectToLoginIfRequired({
ok: false,
data: null,
loginRequired: true,
loginUrl: "https://gate.grok.me/__gate/signin?return_to=x",
});
assert.equal(did, false);
});
});
describe("GoogleCalendarTools", () => {
it("does not expose a list_events name", () => {
assert.equal(GoogleCalendarTools.search, "google_calendar_search");
assert.equal(GoogleCalendarTools.listCalendars, "google_calendar_list_calendars");
const toolNames: readonly string[] = Object.values(GoogleCalendarTools);
assert.equal(toolNames.includes("google_calendar_list_events"), false);
});
});
describe("classifyCallToolError", () => {
it("returns null for successful results", () => {
assert.equal(classifyCallToolError({ ok: true, data: {} }), null);
});
it("classifies a pending preview token as pending before any other kind", () => {
const state = classifyCallToolError({
ok: false,
data: null,
pending: true,
errorMessage: "connector_token_pending: the preview has not received the connector token yet",
});
assert.equal(state?.kind, "pending");
assert.match(state?.message ?? "", /Connecting/);
assert.match(state?.detail ?? "", /connector_token_pending/);
});
it("classifies a deployed missing token as error, not a login CTA", () => {
const state = classifyCallToolError({
ok: false,
data: null,
errorMessage: "missing_connector_token: open this app through the edge gate",
});
assert.equal(state?.kind, "error");
assert.match(state?.detail ?? "", /missing_connector_token/);
});
it("classifies gate loginRequired without a missing-token message as login", () => {
const state = classifyCallToolError({
ok: false,
data: null,
loginRequired: true,
errorMessage: "login required",
});
assert.equal(state?.kind, "login");
assert.equal(state?.detail, "login required");
});
it("classifies not_connected and failed_precondition", () => {
assert.equal(
classifyCallToolError({
ok: false,
data: null,
errorMessage: "connector_not_connected: Notion",
})?.kind,
"not_connected",
);
assert.equal(
classifyCallToolError({
ok: false,
data: null,
errorMessage: "FAILED_PRECONDITION: no connector",
})?.kind,
"not_connected",
);
});
it("classifies scope_denied without claiming a missing grant", () => {
const state = classifyCallToolError({
ok: false,
data: null,
errorMessage: "scope_denied: tool notion-list-recent-pages not in grant scopes",
});
assert.equal(state?.kind, "scope_denied");
assert.match(state?.message ?? "", /tool outside its grant/);
assert.match(state?.detail ?? "", /notion-list-recent-pages/);
});
it("classifies access_denied", () => {
assert.equal(
classifyCallToolError({
ok: false,
data: null,
errorMessage: "access_denied",
})?.kind,
"access_denied",
);
});
it("falls back to a generic error with the raw message", () => {
const state = classifyCallToolError({
ok: false,
data: null,
errorMessage: "boom",
});
assert.equal(state?.kind, "error");
assert.equal(state?.message, "boom");
const empty = classifyCallToolError({ ok: false, data: null });
assert.equal(empty?.kind, "error");
assert.equal(empty?.message, "Something went wrong. Try again.");
assert.equal(empty?.detail, undefined);
});
});