test: increase test coverage
This commit is contained in:
parent
1c2bd02512
commit
932f148463
4 changed files with 310 additions and 4 deletions
|
|
@ -1,9 +1,11 @@
|
||||||
import { beforeEach, describe, expect, test } from "bun:test";
|
import { beforeEach, describe, expect, test } from "bun:test";
|
||||||
import { eq } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
import { db } from "~/server/db/db";
|
import { db, sqlite } from "~/server/db/db";
|
||||||
import { account, invitation, member, organization, usersTable } from "~/server/db/schema";
|
import { account, invitation, member, organization, usersTable } from "~/server/db/schema";
|
||||||
import { ensureDefaultOrg } from "../create-default-org";
|
import { ensureDefaultOrg } from "../create-default-org";
|
||||||
|
|
||||||
|
const CREATE_DEFAULT_ORG_ROLLBACK_TRIGGER = "create_default_org_member_abort";
|
||||||
|
|
||||||
function randomId() {
|
function randomId() {
|
||||||
return Bun.randomUUIDv7();
|
return Bun.randomUUIDv7();
|
||||||
}
|
}
|
||||||
|
|
@ -12,6 +14,14 @@ function randomSlug(prefix: string) {
|
||||||
return `${prefix}-${Math.random().toString(36).slice(2, 8)}`;
|
return `${prefix}-${Math.random().toString(36).slice(2, 8)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function escapeSqlLiteral(value: string) {
|
||||||
|
return value.replaceAll("'", "''");
|
||||||
|
}
|
||||||
|
|
||||||
|
function dropTrigger(name: string) {
|
||||||
|
sqlite.exec(`DROP TRIGGER IF EXISTS ${name};`);
|
||||||
|
}
|
||||||
|
|
||||||
async function createUser(email: string, username: string) {
|
async function createUser(email: string, username: string) {
|
||||||
const userId = randomId();
|
const userId = randomId();
|
||||||
await db.insert(usersTable).values({
|
await db.insert(usersTable).values({
|
||||||
|
|
@ -25,6 +35,7 @@ async function createUser(email: string, username: string) {
|
||||||
|
|
||||||
describe("ensureDefaultOrg", () => {
|
describe("ensureDefaultOrg", () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
|
dropTrigger(CREATE_DEFAULT_ORG_ROLLBACK_TRIGGER);
|
||||||
await db.delete(member);
|
await db.delete(member);
|
||||||
await db.delete(account);
|
await db.delete(account);
|
||||||
await db.delete(invitation);
|
await db.delete(invitation);
|
||||||
|
|
@ -71,4 +82,29 @@ describe("ensureDefaultOrg", () => {
|
||||||
expect(membership.role).toBe("owner");
|
expect(membership.role).toBe("owner");
|
||||||
expect(membership.organization.name).toContain("Workspace");
|
expect(membership.organization.name).toContain("Workspace");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("rolls back organization creation when membership insertion fails", async () => {
|
||||||
|
const userId = await createUser("rollback-user@example.com", randomSlug("rollback-user"));
|
||||||
|
|
||||||
|
sqlite.exec(`
|
||||||
|
CREATE TRIGGER ${CREATE_DEFAULT_ORG_ROLLBACK_TRIGGER}
|
||||||
|
BEFORE INSERT ON member
|
||||||
|
WHEN NEW.user_id = '${escapeSqlLiteral(userId)}'
|
||||||
|
BEGIN
|
||||||
|
SELECT RAISE(ABORT, 'forced createDefaultOrg rollback');
|
||||||
|
END;
|
||||||
|
`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await expect(ensureDefaultOrg(userId)).rejects.toThrow("forced createDefaultOrg rollback");
|
||||||
|
} finally {
|
||||||
|
dropTrigger(CREATE_DEFAULT_ORG_ROLLBACK_TRIGGER);
|
||||||
|
}
|
||||||
|
|
||||||
|
const memberships = await db.select().from(member).where(eq(member.userId, userId));
|
||||||
|
const organizations = await db.select().from(organization);
|
||||||
|
|
||||||
|
expect(memberships).toHaveLength(0);
|
||||||
|
expect(organizations).toHaveLength(0);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,11 @@
|
||||||
import { beforeEach, describe, expect, test } from "bun:test";
|
import { beforeEach, describe, expect, test } from "bun:test";
|
||||||
import { db } from "~/server/db/db";
|
import { db, sqlite } from "~/server/db/db";
|
||||||
import { account, member, organization, sessionsTable, usersTable } from "~/server/db/schema";
|
import { account, member, organization, sessionsTable, usersTable } from "~/server/db/schema";
|
||||||
import { authService } from "../auth.service";
|
import { authService } from "../auth.service";
|
||||||
|
|
||||||
|
const DELETE_USER_ACCOUNT_ROLLBACK_TRIGGER = "delete_user_account_abort";
|
||||||
|
const REMOVE_ORG_MEMBER_ROLLBACK_TRIGGER = "remove_org_member_reassign_abort";
|
||||||
|
|
||||||
function randomId() {
|
function randomId() {
|
||||||
return Bun.randomUUIDv7();
|
return Bun.randomUUIDv7();
|
||||||
}
|
}
|
||||||
|
|
@ -11,6 +14,14 @@ function randomSlug(prefix: string) {
|
||||||
return `${prefix}-${Math.random().toString(36).slice(2, 8)}`;
|
return `${prefix}-${Math.random().toString(36).slice(2, 8)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function escapeSqlLiteral(value: string) {
|
||||||
|
return value.replaceAll("'", "''");
|
||||||
|
}
|
||||||
|
|
||||||
|
function dropTrigger(name: string) {
|
||||||
|
sqlite.exec(`DROP TRIGGER IF EXISTS ${name};`);
|
||||||
|
}
|
||||||
|
|
||||||
async function createUser(email: string) {
|
async function createUser(email: string) {
|
||||||
const id = randomId();
|
const id = randomId();
|
||||||
|
|
||||||
|
|
@ -83,6 +94,8 @@ async function createAccount({ userId, providerId }: { userId: string; providerI
|
||||||
|
|
||||||
describe("authService account and membership management", () => {
|
describe("authService account and membership management", () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
|
dropTrigger(DELETE_USER_ACCOUNT_ROLLBACK_TRIGGER);
|
||||||
|
dropTrigger(REMOVE_ORG_MEMBER_ROLLBACK_TRIGGER);
|
||||||
await db.delete(account);
|
await db.delete(account);
|
||||||
await db.delete(member);
|
await db.delete(member);
|
||||||
await db.delete(sessionsTable);
|
await db.delete(sessionsTable);
|
||||||
|
|
@ -145,6 +158,46 @@ describe("authService account and membership management", () => {
|
||||||
expect(existingAccount).toEqual({ id: onlyAccountId });
|
expect(existingAccount).toEqual({ id: onlyAccountId });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("deleteUserAccount leaves accounts untouched when deletion fails", async () => {
|
||||||
|
const userId = await createUser(`${randomSlug("user")}@example.com`);
|
||||||
|
const credentialAccountId = await createAccount({
|
||||||
|
userId,
|
||||||
|
providerId: "credential",
|
||||||
|
});
|
||||||
|
const oidcAccountId = await createAccount({ userId, providerId: "oidc-acme" });
|
||||||
|
await createSession({ userId, activeOrganizationId: null });
|
||||||
|
|
||||||
|
sqlite.exec(`
|
||||||
|
CREATE TRIGGER ${DELETE_USER_ACCOUNT_ROLLBACK_TRIGGER}
|
||||||
|
BEFORE DELETE ON account
|
||||||
|
WHEN OLD.id = '${escapeSqlLiteral(credentialAccountId)}'
|
||||||
|
BEGIN
|
||||||
|
SELECT RAISE(ABORT, 'forced deleteUserAccount rollback');
|
||||||
|
END;
|
||||||
|
`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await expect(authService.deleteUserAccount(userId, credentialAccountId)).rejects.toThrow(
|
||||||
|
"forced deleteUserAccount rollback",
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
dropTrigger(DELETE_USER_ACCOUNT_ROLLBACK_TRIGGER);
|
||||||
|
}
|
||||||
|
|
||||||
|
const remainingAccounts = await db.query.account.findMany({
|
||||||
|
where: { userId },
|
||||||
|
columns: { id: true },
|
||||||
|
});
|
||||||
|
const remainingSessions = await db.query.sessionsTable.findMany({
|
||||||
|
where: { userId },
|
||||||
|
columns: { id: true },
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(remainingAccounts).toHaveLength(2);
|
||||||
|
expect(remainingAccounts).toEqual(expect.arrayContaining([{ id: credentialAccountId }, { id: oidcAccountId }]));
|
||||||
|
expect(remainingSessions).toHaveLength(1);
|
||||||
|
});
|
||||||
|
|
||||||
test("removeOrgMember rehomes active sessions to another organization membership", async () => {
|
test("removeOrgMember rehomes active sessions to another organization membership", async () => {
|
||||||
const userId = await createUser(`${randomSlug("user")}@example.com`);
|
const userId = await createUser(`${randomSlug("user")}@example.com`);
|
||||||
const removedOrgId = await createOrganization("Removed Org");
|
const removedOrgId = await createOrganization("Removed Org");
|
||||||
|
|
@ -205,6 +258,53 @@ describe("authService account and membership management", () => {
|
||||||
expect(removedMembership).toBeUndefined();
|
expect(removedMembership).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("removeOrgMember rolls back membership removal when session reassignment fails", async () => {
|
||||||
|
const userId = await createUser(`${randomSlug("user")}@example.com`);
|
||||||
|
const removedOrgId = await createOrganization("Removed Org");
|
||||||
|
const fallbackOrgId = await createOrganization("Fallback Org");
|
||||||
|
const membershipId = await createMembership({
|
||||||
|
userId,
|
||||||
|
organizationId: removedOrgId,
|
||||||
|
role: "member",
|
||||||
|
});
|
||||||
|
await createMembership({
|
||||||
|
userId,
|
||||||
|
organizationId: fallbackOrgId,
|
||||||
|
role: "member",
|
||||||
|
});
|
||||||
|
await createSession({ userId, activeOrganizationId: removedOrgId });
|
||||||
|
|
||||||
|
sqlite.exec(`
|
||||||
|
CREATE TRIGGER ${REMOVE_ORG_MEMBER_ROLLBACK_TRIGGER}
|
||||||
|
BEFORE UPDATE OF active_organization_id ON sessions_table
|
||||||
|
WHEN OLD.user_id = '${escapeSqlLiteral(userId)}'
|
||||||
|
AND NEW.active_organization_id = '${escapeSqlLiteral(fallbackOrgId)}'
|
||||||
|
BEGIN
|
||||||
|
SELECT RAISE(ABORT, 'forced removeOrgMember rollback');
|
||||||
|
END;
|
||||||
|
`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await expect(authService.removeOrgMember(membershipId, removedOrgId)).rejects.toThrow(
|
||||||
|
"forced removeOrgMember rollback",
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
dropTrigger(REMOVE_ORG_MEMBER_ROLLBACK_TRIGGER);
|
||||||
|
}
|
||||||
|
|
||||||
|
const session = await db.query.sessionsTable.findFirst({
|
||||||
|
where: { userId },
|
||||||
|
columns: { activeOrganizationId: true },
|
||||||
|
});
|
||||||
|
const removedMembership = await db.query.member.findFirst({
|
||||||
|
where: { id: membershipId },
|
||||||
|
columns: { id: true },
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(session?.activeOrganizationId).toBe(removedOrgId);
|
||||||
|
expect(removedMembership).toEqual({ id: membershipId });
|
||||||
|
});
|
||||||
|
|
||||||
test("removeOrgMember returns isOwner=true and does not remove owner membership", async () => {
|
test("removeOrgMember returns isOwner=true and does not remove owner membership", async () => {
|
||||||
const userId = await createUser(`${randomSlug("user")}@example.com`);
|
const userId = await createUser(`${randomSlug("user")}@example.com`);
|
||||||
const orgId = await createOrganization("Owner Org");
|
const orgId = await createOrganization("Owner Org");
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
import { beforeEach, describe, expect, test } from "bun:test";
|
import { beforeEach, describe, expect, test } from "bun:test";
|
||||||
import { db } from "~/server/db/db";
|
import { db, sqlite } from "~/server/db/db";
|
||||||
import { member, organization, sessionsTable, usersTable } from "~/server/db/schema";
|
import { member, organization, sessionsTable, usersTable } from "~/server/db/schema";
|
||||||
import { authService } from "../auth.service";
|
import { authService } from "../auth.service";
|
||||||
|
|
||||||
|
const CLEANUP_USER_ORGS_ROLLBACK_TRIGGER = "cleanup_user_orgs_final_session_abort";
|
||||||
|
|
||||||
function randomId() {
|
function randomId() {
|
||||||
return Bun.randomUUIDv7();
|
return Bun.randomUUIDv7();
|
||||||
}
|
}
|
||||||
|
|
@ -11,6 +13,14 @@ function randomSlug(prefix: string) {
|
||||||
return `${prefix}-${Math.random().toString(36).slice(2, 8)}`;
|
return `${prefix}-${Math.random().toString(36).slice(2, 8)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function escapeSqlLiteral(value: string) {
|
||||||
|
return value.replaceAll("'", "''");
|
||||||
|
}
|
||||||
|
|
||||||
|
function dropTrigger(name: string) {
|
||||||
|
sqlite.exec(`DROP TRIGGER IF EXISTS ${name};`);
|
||||||
|
}
|
||||||
|
|
||||||
async function createUser(email: string) {
|
async function createUser(email: string) {
|
||||||
const id = randomId();
|
const id = randomId();
|
||||||
|
|
||||||
|
|
@ -77,6 +87,7 @@ async function createSession({
|
||||||
|
|
||||||
describe("authService.cleanupUserOrganizations", () => {
|
describe("authService.cleanupUserOrganizations", () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
|
dropTrigger(CLEANUP_USER_ORGS_ROLLBACK_TRIGGER);
|
||||||
await db.delete(member);
|
await db.delete(member);
|
||||||
await db.delete(sessionsTable);
|
await db.delete(sessionsTable);
|
||||||
await db.delete(organization);
|
await db.delete(organization);
|
||||||
|
|
@ -158,4 +169,95 @@ describe("authService.cleanupUserOrganizations", () => {
|
||||||
|
|
||||||
expect(membership).toBeUndefined();
|
expect(membership).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("sets active organization to null for affected members without a fallback organization", async () => {
|
||||||
|
const deletedUserId = await createUser(`${randomSlug("deleted")}@example.com`);
|
||||||
|
const affectedUserId = await createUser(`${randomSlug("affected")}@example.com`);
|
||||||
|
const deletedWorkspaceId = await createOrganization("Deleted Workspace");
|
||||||
|
|
||||||
|
await createMembership({ userId: deletedUserId, organizationId: deletedWorkspaceId, role: "owner" });
|
||||||
|
await createMembership({ userId: affectedUserId, organizationId: deletedWorkspaceId, role: "member" });
|
||||||
|
|
||||||
|
const affectedSessionId = await createSession({
|
||||||
|
userId: affectedUserId,
|
||||||
|
activeOrganizationId: deletedWorkspaceId,
|
||||||
|
});
|
||||||
|
|
||||||
|
await authService.cleanupUserOrganizations(deletedUserId);
|
||||||
|
|
||||||
|
const updatedSession = await db.query.sessionsTable.findFirst({
|
||||||
|
where: { id: affectedSessionId },
|
||||||
|
columns: { activeOrganizationId: true },
|
||||||
|
});
|
||||||
|
const deletedWorkspace = await db.query.organization.findFirst({
|
||||||
|
where: { id: deletedWorkspaceId },
|
||||||
|
columns: { id: true },
|
||||||
|
});
|
||||||
|
const removedMembership = await db.query.member.findFirst({
|
||||||
|
where: { AND: [{ organizationId: deletedWorkspaceId }, { userId: affectedUserId }] },
|
||||||
|
columns: { id: true },
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(deletedWorkspace).toBeUndefined();
|
||||||
|
expect(updatedSession?.activeOrganizationId).toBeNull();
|
||||||
|
expect(removedMembership).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("rolls back organization cleanup when session nulling fails", async () => {
|
||||||
|
const affectedUserId = await createUser(`${randomSlug("admin")}@example.com`);
|
||||||
|
const deletedUserId = await createUser(`${randomSlug("deleted")}@example.com`);
|
||||||
|
|
||||||
|
const fallbackWorkspaceId = await createOrganization("Fallback Workspace");
|
||||||
|
const deletedWorkspaceId = await createOrganization("Deleted Workspace");
|
||||||
|
|
||||||
|
await createMembership({ userId: affectedUserId, organizationId: fallbackWorkspaceId, role: "owner" });
|
||||||
|
await createMembership({ userId: deletedUserId, organizationId: deletedWorkspaceId, role: "owner" });
|
||||||
|
await createMembership({ userId: affectedUserId, organizationId: deletedWorkspaceId, role: "member" });
|
||||||
|
|
||||||
|
const affectedSessionId = await createSession({
|
||||||
|
userId: affectedUserId,
|
||||||
|
activeOrganizationId: deletedWorkspaceId,
|
||||||
|
});
|
||||||
|
const deletedUserSessionId = await createSession({
|
||||||
|
userId: deletedUserId,
|
||||||
|
activeOrganizationId: deletedWorkspaceId,
|
||||||
|
});
|
||||||
|
|
||||||
|
sqlite.exec(`
|
||||||
|
CREATE TRIGGER ${CLEANUP_USER_ORGS_ROLLBACK_TRIGGER}
|
||||||
|
BEFORE UPDATE OF active_organization_id ON sessions_table
|
||||||
|
WHEN OLD.user_id = '${escapeSqlLiteral(deletedUserId)}' AND NEW.active_organization_id IS NULL
|
||||||
|
BEGIN
|
||||||
|
SELECT RAISE(ABORT, 'forced cleanup rollback');
|
||||||
|
END;
|
||||||
|
`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await expect(authService.cleanupUserOrganizations(deletedUserId)).rejects.toThrow("forced cleanup rollback");
|
||||||
|
} finally {
|
||||||
|
dropTrigger(CLEANUP_USER_ORGS_ROLLBACK_TRIGGER);
|
||||||
|
}
|
||||||
|
|
||||||
|
const deletedWorkspace = await db.query.organization.findFirst({
|
||||||
|
where: { id: deletedWorkspaceId },
|
||||||
|
columns: { id: true },
|
||||||
|
});
|
||||||
|
const affectedSession = await db.query.sessionsTable.findFirst({
|
||||||
|
where: { id: affectedSessionId },
|
||||||
|
columns: { activeOrganizationId: true },
|
||||||
|
});
|
||||||
|
const deletedUserSession = await db.query.sessionsTable.findFirst({
|
||||||
|
where: { id: deletedUserSessionId },
|
||||||
|
columns: { activeOrganizationId: true },
|
||||||
|
});
|
||||||
|
const affectedMembership = await db.query.member.findFirst({
|
||||||
|
where: { AND: [{ organizationId: deletedWorkspaceId }, { userId: affectedUserId }] },
|
||||||
|
columns: { id: true },
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(deletedWorkspace).toEqual({ id: deletedWorkspaceId });
|
||||||
|
expect(affectedSession?.activeOrganizationId).toBe(deletedWorkspaceId);
|
||||||
|
expect(deletedUserSession?.activeOrganizationId).toBe(deletedWorkspaceId);
|
||||||
|
expect(affectedMembership).not.toBeUndefined();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
import { beforeEach, describe, expect, test } from "bun:test";
|
import { beforeEach, describe, expect, test } from "bun:test";
|
||||||
import { db } from "~/server/db/db";
|
import { db, sqlite } from "~/server/db/db";
|
||||||
import { account, invitation, member, organization, sessionsTable, ssoProvider, usersTable } from "~/server/db/schema";
|
import { account, invitation, member, organization, sessionsTable, ssoProvider, usersTable } from "~/server/db/schema";
|
||||||
import { ssoService } from "../sso.service";
|
import { ssoService } from "../sso.service";
|
||||||
|
|
||||||
|
const DELETE_SSO_PROVIDER_ROLLBACK_TRIGGER = "delete_sso_provider_sessions_abort";
|
||||||
|
|
||||||
function randomId() {
|
function randomId() {
|
||||||
return Bun.randomUUIDv7();
|
return Bun.randomUUIDv7();
|
||||||
}
|
}
|
||||||
|
|
@ -11,6 +13,14 @@ function randomSlug(prefix: string) {
|
||||||
return `${prefix}-${Math.random().toString(36).slice(2, 8)}`;
|
return `${prefix}-${Math.random().toString(36).slice(2, 8)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function escapeSqlLiteral(value: string) {
|
||||||
|
return value.replaceAll("'", "''");
|
||||||
|
}
|
||||||
|
|
||||||
|
function dropTrigger(name: string) {
|
||||||
|
sqlite.exec(`DROP TRIGGER IF EXISTS ${name};`);
|
||||||
|
}
|
||||||
|
|
||||||
async function createUser(email: string) {
|
async function createUser(email: string) {
|
||||||
const id = randomId();
|
const id = randomId();
|
||||||
|
|
||||||
|
|
@ -48,6 +58,7 @@ async function createSession(userId: string) {
|
||||||
|
|
||||||
describe("ssoService.deleteSsoProvider", () => {
|
describe("ssoService.deleteSsoProvider", () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
|
dropTrigger(DELETE_SSO_PROVIDER_ROLLBACK_TRIGGER);
|
||||||
await db.delete(member);
|
await db.delete(member);
|
||||||
await db.delete(account);
|
await db.delete(account);
|
||||||
await db.delete(sessionsTable);
|
await db.delete(sessionsTable);
|
||||||
|
|
@ -191,4 +202,61 @@ describe("ssoService.deleteSsoProvider", () => {
|
||||||
expect(remainingProvider).toBeUndefined();
|
expect(remainingProvider).toBeUndefined();
|
||||||
expect(remainingAccounts).toHaveLength(1);
|
expect(remainingAccounts).toHaveLength(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("deleteSsoProvider rolls back account and provider deletion when session revocation fails", async () => {
|
||||||
|
const org = await createOrganization("Org A");
|
||||||
|
const providerOwner = await createUser(`${randomSlug("owner")}@example.com`);
|
||||||
|
const accountUser = await createUser(`${randomSlug("member")}@example.com`);
|
||||||
|
|
||||||
|
const providerId = `oidc-${randomSlug("provider")}`;
|
||||||
|
|
||||||
|
await db.insert(ssoProvider).values({
|
||||||
|
id: randomId(),
|
||||||
|
providerId,
|
||||||
|
organizationId: org,
|
||||||
|
userId: providerOwner,
|
||||||
|
issuer: "https://issuer.example.com",
|
||||||
|
domain: "example.com",
|
||||||
|
});
|
||||||
|
|
||||||
|
await db.insert(account).values({
|
||||||
|
id: randomId(),
|
||||||
|
accountId: randomSlug("acct"),
|
||||||
|
providerId,
|
||||||
|
userId: accountUser,
|
||||||
|
});
|
||||||
|
await createSession(accountUser);
|
||||||
|
|
||||||
|
sqlite.exec(`
|
||||||
|
CREATE TRIGGER ${DELETE_SSO_PROVIDER_ROLLBACK_TRIGGER}
|
||||||
|
BEFORE DELETE ON sessions_table
|
||||||
|
WHEN OLD.user_id = '${escapeSqlLiteral(accountUser)}'
|
||||||
|
BEGIN
|
||||||
|
SELECT RAISE(ABORT, 'forced deleteSsoProvider rollback');
|
||||||
|
END;
|
||||||
|
`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await expect(ssoService.deleteSsoProvider(providerId, org)).rejects.toThrow("forced deleteSsoProvider rollback");
|
||||||
|
} finally {
|
||||||
|
dropTrigger(DELETE_SSO_PROVIDER_ROLLBACK_TRIGGER);
|
||||||
|
}
|
||||||
|
|
||||||
|
const remainingProvider = await db.query.ssoProvider.findFirst({
|
||||||
|
where: { providerId },
|
||||||
|
columns: { id: true },
|
||||||
|
});
|
||||||
|
const remainingAccounts = await db.query.account.findMany({
|
||||||
|
where: { providerId },
|
||||||
|
columns: { id: true },
|
||||||
|
});
|
||||||
|
const remainingSessions = await db.query.sessionsTable.findMany({
|
||||||
|
where: { userId: accountUser },
|
||||||
|
columns: { id: true },
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(remainingProvider).not.toBeUndefined();
|
||||||
|
expect(remainingAccounts).toHaveLength(1);
|
||||||
|
expect(remainingSessions).toHaveLength(1);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue