300 lines
8.6 KiB
TypeScript
300 lines
8.6 KiB
TypeScript
type MockFunction = {
|
|
(...args: unknown[]): unknown;
|
|
mockResolvedValue(value: unknown): MockFunction;
|
|
};
|
|
|
|
declare const expect: {
|
|
(actual: unknown): {
|
|
toBe(expected: unknown): void;
|
|
toBeTruthy(): void;
|
|
toHaveBeenCalledWith(...expected: unknown[]): void;
|
|
};
|
|
any(constructor: unknown): unknown;
|
|
objectContaining(value: Record<string, unknown>): unknown;
|
|
};
|
|
|
|
declare const vi: {
|
|
fn(implementation?: (...args: unknown[]) => unknown): MockFunction;
|
|
clearAllMocks(): void;
|
|
resetModules(): void;
|
|
};
|
|
|
|
export const isolationTenantA = {
|
|
id: "tenant_session_iso_a",
|
|
name: "Tenant Session Isolation A",
|
|
slug: "tenant-session-isolation-a",
|
|
};
|
|
|
|
export const isolationTenantB = {
|
|
id: "tenant_session_iso_b",
|
|
name: "Tenant Session Isolation B",
|
|
slug: "tenant-session-isolation-b",
|
|
};
|
|
|
|
export const isolationUserA = {
|
|
id: "user_session_iso_a",
|
|
email: "user-a@example.test",
|
|
tenantId: isolationTenantA.id,
|
|
};
|
|
|
|
export const isolationUserB = {
|
|
id: "user_session_iso_b",
|
|
email: "user-b@example.test",
|
|
tenantId: isolationTenantB.id,
|
|
};
|
|
|
|
export const isolationAdminUser = {
|
|
id: "user_session_iso_admin",
|
|
email: "admin@example.test",
|
|
tenantId: null,
|
|
admin: true,
|
|
};
|
|
|
|
export const isolationAdminSession = {
|
|
userId: isolationAdminUser.id,
|
|
tenantId: null,
|
|
isSuperAdmin: true,
|
|
canAccessTenants: [isolationTenantA.id, isolationTenantB.id],
|
|
};
|
|
|
|
export const isolationApiKeyLogA = {
|
|
id: "api_key_log_session_iso_a",
|
|
apiKeyId: "api_key_session_iso_a",
|
|
};
|
|
|
|
export const isolationApiKeyLogB = {
|
|
id: "api_key_log_session_iso_b",
|
|
apiKeyId: "api_key_session_iso_b",
|
|
};
|
|
|
|
export const isolationInactiveApiKeyLog = {
|
|
id: "api_key_log_session_iso_inactive",
|
|
apiKeyId: "api_key_session_iso_inactive",
|
|
};
|
|
|
|
export const isolationInactiveApiKey = {
|
|
id: isolationInactiveApiKeyLog.apiKeyId,
|
|
key: "sk_test_session_iso_inactive",
|
|
tenantId: isolationTenantA.id,
|
|
active: false,
|
|
};
|
|
|
|
export const isolationRevokedBearerSession = {
|
|
id: "session_session_iso_revoked",
|
|
userId: isolationUserA.id,
|
|
tenantId: isolationTenantA.id,
|
|
token: "bearer_session_iso_revoked",
|
|
revokedAt: "2024-01-01T00:00:00.000Z",
|
|
};
|
|
|
|
export const isolationInvalidBearerToken = "bearer_session_iso_invalid";
|
|
|
|
export const isolationTiming = {
|
|
startTime: 1_700_000_000_000,
|
|
serverTiming: "unit;dur=1",
|
|
};
|
|
|
|
export const isolationParentEntity = {
|
|
id: "entity_session_iso_parent",
|
|
name: "Parent",
|
|
slug: "parents",
|
|
title: "Parent",
|
|
titlePlural: "Parents",
|
|
properties: [],
|
|
};
|
|
|
|
export const isolationChildEntity = {
|
|
id: "entity_session_iso_child",
|
|
name: "Child",
|
|
slug: "children",
|
|
title: "Child",
|
|
titlePlural: "Children",
|
|
properties: [],
|
|
};
|
|
|
|
export const isolationTenantARow = {
|
|
id: "row_session_iso_a",
|
|
entityId: isolationParentEntity.id,
|
|
tenantId: isolationTenantA.id,
|
|
createdByUserId: isolationUserA.id,
|
|
values: [{ name: "name", textValue: "Tenant A row" }],
|
|
};
|
|
|
|
export const isolationTenantBRow = {
|
|
id: "row_session_iso_b",
|
|
entityId: isolationParentEntity.id,
|
|
tenantId: isolationTenantB.id,
|
|
createdByUserId: isolationUserB.id,
|
|
values: [{ name: "name", textValue: "Tenant B row" }],
|
|
};
|
|
|
|
export const isolationTenantAChildRow = {
|
|
id: "row_session_iso_a_child",
|
|
entityId: isolationChildEntity.id,
|
|
tenantId: isolationTenantA.id,
|
|
createdByUserId: isolationUserA.id,
|
|
values: [{ name: "name", textValue: "Tenant A child row" }],
|
|
};
|
|
|
|
export const isolationTenantBChildRow = {
|
|
id: "row_session_iso_b_child",
|
|
entityId: isolationChildEntity.id,
|
|
tenantId: isolationTenantB.id,
|
|
createdByUserId: isolationUserB.id,
|
|
values: [{ name: "name", textValue: "Tenant B child row" }],
|
|
};
|
|
|
|
export const isolationTenantARelationship = {
|
|
id: "relationship_session_iso_a",
|
|
parentId: isolationTenantARow.id,
|
|
childId: isolationTenantAChildRow.id,
|
|
tenantId: isolationTenantA.id,
|
|
parent: { entity: isolationParentEntity, item: isolationTenantARow },
|
|
child: { entity: isolationChildEntity, item: isolationTenantAChildRow },
|
|
};
|
|
|
|
export const isolationTenantBRelationship = {
|
|
id: "relationship_session_iso_b",
|
|
parentId: isolationTenantBRow.id,
|
|
childId: isolationTenantBChildRow.id,
|
|
tenantId: isolationTenantB.id,
|
|
parent: { entity: isolationParentEntity, item: isolationTenantBRow },
|
|
child: { entity: isolationChildEntity, item: isolationTenantBChildRow },
|
|
};
|
|
|
|
export const isolationUsage = {
|
|
title: "api.usage",
|
|
value: 50,
|
|
remaining: 10,
|
|
};
|
|
|
|
export const isolationAccessTenantASession = {
|
|
tenant: isolationTenantA,
|
|
userId: isolationUserA.id,
|
|
entity: isolationParentEntity,
|
|
apiKeyLog: isolationApiKeyLogA,
|
|
usage: isolationUsage,
|
|
};
|
|
|
|
export const isolationAccessTenantBSession = {
|
|
tenant: isolationTenantB,
|
|
userId: isolationUserB.id,
|
|
entity: isolationParentEntity,
|
|
apiKeyLog: isolationApiKeyLogB,
|
|
usage: isolationUsage,
|
|
};
|
|
|
|
export const isolationRelationshipAccessTenantASession = {
|
|
tenant: isolationTenantA,
|
|
userId: isolationUserA.id,
|
|
apiKeyLog: isolationApiKeyLogA,
|
|
parentRow: isolationTenantARow,
|
|
childRow: isolationTenantAChildRow,
|
|
};
|
|
|
|
export const isolationRelationshipAccessTenantBSession = {
|
|
tenant: isolationTenantB,
|
|
userId: isolationUserB.id,
|
|
apiKeyLog: isolationApiKeyLogB,
|
|
parentRow: isolationTenantBRow,
|
|
childRow: isolationTenantBChildRow,
|
|
};
|
|
|
|
export type IsolationMocks = {
|
|
createMetrics: ReturnType<typeof vi.fn>;
|
|
getTranslations: ReturnType<typeof vi.fn>;
|
|
setApiKeyLogStatus: ReturnType<typeof vi.fn>;
|
|
reportUsage: ReturnType<typeof vi.fn>;
|
|
};
|
|
|
|
export function makeJsonRequest(method: string, url: string, body?: unknown): Request {
|
|
return new Request(url, {
|
|
method,
|
|
body: body === undefined ? undefined : JSON.stringify(body),
|
|
headers: body === undefined ? undefined : { "Content-Type": "application/json" },
|
|
});
|
|
}
|
|
|
|
export function makeTenantASessionJsonRequest(method: string, path: string, body?: unknown): Request {
|
|
return makeJsonRequest(method, `https://example.test${path}`, body);
|
|
}
|
|
|
|
export function makeTenantBSessionJsonRequest(method: string, path: string, body?: unknown): Request {
|
|
return makeJsonRequest(method, `https://example.test${path}`, body);
|
|
}
|
|
|
|
export function makeGetRequest(path: string): Request {
|
|
return new Request(`https://example.test${path}`, { method: "GET" });
|
|
}
|
|
|
|
export function makeAdminHostGetRequest(path: string): Request {
|
|
return new Request(`https://admin.example.test${path}`, { method: "GET" });
|
|
}
|
|
|
|
export function makeApiKeyGetRequest(path: string, apiKey: string): Request {
|
|
return new Request(`https://example.test${path}`, {
|
|
method: "GET",
|
|
headers: { Authorization: `Bearer ${apiKey}` },
|
|
});
|
|
}
|
|
|
|
export function makeInactiveApiKeyGetRequest(path: string): Request {
|
|
return makeApiKeyGetRequest(path, isolationInactiveApiKey.key);
|
|
}
|
|
|
|
export function makeBearerSessionGetRequest(path: string, token: string): Request {
|
|
return new Request(`https://example.test${path}`, {
|
|
method: "GET",
|
|
headers: { Cookie: `session=${token}` },
|
|
});
|
|
}
|
|
|
|
export function makeRevokedBearerSessionGetRequest(path: string): Request {
|
|
return makeBearerSessionGetRequest(path, isolationRevokedBearerSession.token);
|
|
}
|
|
|
|
export function makeInvalidBearerSessionGetRequest(path: string): Request {
|
|
return makeBearerSessionGetRequest(path, isolationInvalidBearerToken);
|
|
}
|
|
|
|
export function makeTenantASessionGetRequest(path: string): Request {
|
|
return makeGetRequest(path);
|
|
}
|
|
|
|
export function makeTenantBSessionGetRequest(path: string): Request {
|
|
return makeGetRequest(path);
|
|
}
|
|
|
|
export async function expectJsonResponse<TBody = unknown>(response: Response, status: number): Promise<TBody> {
|
|
expect(response.status).toBe(status);
|
|
expect(response.headers.get("Server-Timing")).toBeTruthy();
|
|
return (await response.json()) as TBody;
|
|
}
|
|
|
|
export function expectStatusLog(setApiKeyLogStatus: ReturnType<typeof vi.fn>, logId: string, status: number, error?: string): void {
|
|
expect(setApiKeyLogStatus).toHaveBeenCalledWith(
|
|
logId,
|
|
expect.objectContaining({
|
|
status,
|
|
startTime: expect.any(Number),
|
|
...(error === undefined ? {} : { error }),
|
|
}),
|
|
);
|
|
}
|
|
|
|
export function createDeniedIsolationError(message: string, status = 403, apiKeyLog = isolationApiKeyLogA): Error & { status: number; apiKeyLog: typeof isolationApiKeyLogA } {
|
|
return Object.assign(new Error(message), { status, apiKeyLog });
|
|
}
|
|
|
|
export function resetIsolationMocks(mocks: IsolationMocks): void {
|
|
vi.clearAllMocks();
|
|
vi.resetModules();
|
|
mocks.createMetrics.mockResolvedValue({
|
|
time: vi.fn((value) => value),
|
|
getServerTimingHeader: () => ({ "Server-Timing": isolationTiming.serverTiming }),
|
|
});
|
|
mocks.getTranslations.mockResolvedValue({ t: (value: string) => value });
|
|
mocks.setApiKeyLogStatus.mockResolvedValue(undefined);
|
|
mocks.reportUsage.mockResolvedValue(undefined);
|
|
}
|