Files
outline/server/queues/tasks/CleanupDynamicOAuthClientsTask.test.ts
T
Tom Moor 957648a588 feat: OAuth dynamic client registration (#11462)
* feat: DCR first pass

* Add cleanup task, management endpoints

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* wip

* Combine migrations

* Self review

* fix: Guard OAuth policies

* fix: Application access list not updating on deletion

* feat: Add OAUTH_DISABLE_DCR env var to disable dynamic client registration

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: Validate max length of redirect URIs in DCR schemas

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Self review

* Use withCtx methods for correct event creation

* Remove incorrect scopes_supported

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 17:30:19 -05:00

106 lines
3.1 KiB
TypeScript

import { subDays, subHours } from "date-fns";
import { OAuthClient } from "@server/models";
import { buildOAuthClient, buildUser } from "@server/test/factories";
import CleanupDynamicOAuthClientsTask from "./CleanupDynamicOAuthClientsTask";
const clientExists = async (client: OAuthClient) => {
const found = await OAuthClient.unscoped().findByPk(client.id);
return !!found;
};
describe("CleanupDynamicOAuthClientsTask", () => {
it("should delete never-used dynamic clients older than 48 hours", async () => {
const client = await buildOAuthClient({
createdById: null,
createdAt: subDays(new Date(), 3),
});
const task = new CleanupDynamicOAuthClientsTask();
await task.perform({
limit: 100,
partition: { partitionIndex: 0, partitionCount: 1 },
});
expect(await clientExists(client)).toBe(false);
});
it("should not delete never-used dynamic clients younger than 48 hours", async () => {
const client = await buildOAuthClient({
createdById: null,
createdAt: subHours(new Date(), 12),
});
const task = new CleanupDynamicOAuthClientsTask();
await task.perform({
limit: 100,
partition: { partitionIndex: 0, partitionCount: 1 },
});
expect(await clientExists(client)).toBe(true);
});
it("should delete used dynamic clients inactive for more than 30 days", async () => {
const client = await buildOAuthClient({
createdById: null,
createdAt: subDays(new Date(), 60),
lastActiveAt: subDays(new Date(), 45),
});
const task = new CleanupDynamicOAuthClientsTask();
await task.perform({
limit: 100,
partition: { partitionIndex: 0, partitionCount: 1 },
});
expect(await clientExists(client)).toBe(false);
});
it("should not delete used dynamic clients active within the last 30 days", async () => {
const client = await buildOAuthClient({
createdById: null,
createdAt: subDays(new Date(), 60),
lastActiveAt: subDays(new Date(), 5),
});
const task = new CleanupDynamicOAuthClientsTask();
await task.perform({
limit: 100,
partition: { partitionIndex: 0, partitionCount: 1 },
});
expect(await clientExists(client)).toBe(true);
});
it("should not delete non-dynamic clients regardless of age or activity", async () => {
const user = await buildUser();
const client = await buildOAuthClient({
teamId: user.teamId,
createdAt: subDays(new Date(), 90),
});
const task = new CleanupDynamicOAuthClientsTask();
await task.perform({
limit: 100,
partition: { partitionIndex: 0, partitionCount: 1 },
});
expect(await clientExists(client)).toBe(true);
});
it("should not delete recently active dynamic client even if created long ago", async () => {
const client = await buildOAuthClient({
createdById: null,
createdAt: subDays(new Date(), 90),
lastActiveAt: subDays(new Date(), 2),
});
const task = new CleanupDynamicOAuthClientsTask();
await task.perform({
limit: 100,
partition: { partitionIndex: 0, partitionCount: 1 },
});
expect(await clientExists(client)).toBe(true);
});
});