mirror of
https://github.com/tale/headplane.git
synced 2026-07-26 07:48:14 +00:00
add tests for role assignment upsert behavior
This commit is contained in:
@@ -0,0 +1,180 @@
|
||||
import { createClient } from "@libsql/client";
|
||||
import { eq } from "drizzle-orm";
|
||||
import { drizzle } from "drizzle-orm/libsql";
|
||||
import { ulid } from "ulidx";
|
||||
import { beforeEach, describe, expect, test } from "vitest";
|
||||
|
||||
import { users } from "~/server/db/schema";
|
||||
import { Roles } from "~/server/web/roles";
|
||||
|
||||
// Create in-memory database for testing
|
||||
function createTestDb() {
|
||||
const client = createClient({ url: ":memory:" });
|
||||
const db = drizzle(client);
|
||||
return { client, db };
|
||||
}
|
||||
|
||||
// Create the users table schema
|
||||
async function setupSchema(client: ReturnType<typeof createClient>) {
|
||||
await client.execute(`
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id TEXT PRIMARY KEY,
|
||||
sub TEXT NOT NULL UNIQUE,
|
||||
caps INTEGER NOT NULL DEFAULT 0,
|
||||
onboarded INTEGER NOT NULL DEFAULT 0
|
||||
)
|
||||
`);
|
||||
}
|
||||
|
||||
describe("Session role assignment", () => {
|
||||
let db: ReturnType<typeof drizzle>;
|
||||
let client: ReturnType<typeof createClient>;
|
||||
|
||||
beforeEach(async () => {
|
||||
const testDb = createTestDb();
|
||||
db = testDb.db;
|
||||
client = testDb.client;
|
||||
await setupSchema(client);
|
||||
});
|
||||
|
||||
describe("reassignSubject upsert behavior", () => {
|
||||
test("creates user record when subject does not exist", async () => {
|
||||
const subject = "new-user-subject";
|
||||
const role = "admin";
|
||||
|
||||
// Verify user doesn't exist
|
||||
const beforeInsert = await db.select().from(users).where(eq(users.sub, subject));
|
||||
expect(beforeInsert.length).toBe(0);
|
||||
|
||||
// Perform upsert (simulating reassignSubject)
|
||||
await db
|
||||
.insert(users)
|
||||
.values({
|
||||
id: ulid(),
|
||||
sub: subject,
|
||||
caps: Roles[role],
|
||||
onboarded: false,
|
||||
})
|
||||
.onConflictDoUpdate({
|
||||
target: users.sub,
|
||||
set: { caps: Roles[role] },
|
||||
});
|
||||
|
||||
// Verify user was created with correct role
|
||||
const afterInsert = await db.select().from(users).where(eq(users.sub, subject));
|
||||
expect(afterInsert.length).toBe(1);
|
||||
expect(afterInsert[0].caps).toBe(Roles.admin);
|
||||
});
|
||||
|
||||
test("updates existing user role without creating duplicate", async () => {
|
||||
const subject = "existing-user";
|
||||
const initialRole = "member";
|
||||
const newRole = "admin";
|
||||
|
||||
// Create initial user
|
||||
await db.insert(users).values({
|
||||
id: ulid(),
|
||||
sub: subject,
|
||||
caps: Roles[initialRole],
|
||||
onboarded: true,
|
||||
});
|
||||
|
||||
// Verify initial state
|
||||
const beforeUpdate = await db.select().from(users).where(eq(users.sub, subject));
|
||||
expect(beforeUpdate.length).toBe(1);
|
||||
expect(beforeUpdate[0].caps).toBe(Roles.member);
|
||||
expect(beforeUpdate[0].onboarded).toBe(true);
|
||||
|
||||
// Perform upsert (simulating reassignSubject)
|
||||
await db
|
||||
.insert(users)
|
||||
.values({
|
||||
id: ulid(),
|
||||
sub: subject,
|
||||
caps: Roles[newRole],
|
||||
onboarded: false,
|
||||
})
|
||||
.onConflictDoUpdate({
|
||||
target: users.sub,
|
||||
set: { caps: Roles[newRole] },
|
||||
});
|
||||
|
||||
// Verify role was updated, no duplicate created
|
||||
const afterUpdate = await db.select().from(users).where(eq(users.sub, subject));
|
||||
expect(afterUpdate.length).toBe(1);
|
||||
expect(afterUpdate[0].caps).toBe(Roles.admin);
|
||||
// onboarded should remain true (not overwritten)
|
||||
expect(afterUpdate[0].onboarded).toBe(true);
|
||||
});
|
||||
|
||||
test("can assign all role types", async () => {
|
||||
const roles = ["admin", "network_admin", "it_admin", "auditor", "member"] as const;
|
||||
|
||||
for (const role of roles) {
|
||||
const subject = `user-${role}`;
|
||||
|
||||
await db
|
||||
.insert(users)
|
||||
.values({
|
||||
id: ulid(),
|
||||
sub: subject,
|
||||
caps: Roles[role],
|
||||
onboarded: false,
|
||||
})
|
||||
.onConflictDoUpdate({
|
||||
target: users.sub,
|
||||
set: { caps: Roles[role] },
|
||||
});
|
||||
|
||||
const [user] = await db.select().from(users).where(eq(users.sub, subject));
|
||||
expect(user.caps).toBe(Roles[role]);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("member role handling", () => {
|
||||
test("member role has zero capabilities", async () => {
|
||||
const subject = "member-user";
|
||||
|
||||
await db.insert(users).values({
|
||||
id: ulid(),
|
||||
sub: subject,
|
||||
caps: Roles.member,
|
||||
onboarded: false,
|
||||
});
|
||||
|
||||
const [user] = await db.select().from(users).where(eq(users.sub, subject));
|
||||
expect(user.caps).toBe(0);
|
||||
});
|
||||
|
||||
test("upgrading from member to admin grants ui_access", async () => {
|
||||
const subject = "upgrading-user";
|
||||
|
||||
// Start as member
|
||||
await db.insert(users).values({
|
||||
id: ulid(),
|
||||
sub: subject,
|
||||
caps: Roles.member,
|
||||
onboarded: false,
|
||||
});
|
||||
|
||||
// Upgrade to admin
|
||||
await db
|
||||
.insert(users)
|
||||
.values({
|
||||
id: ulid(),
|
||||
sub: subject,
|
||||
caps: Roles.admin,
|
||||
onboarded: false,
|
||||
})
|
||||
.onConflictDoUpdate({
|
||||
target: users.sub,
|
||||
set: { caps: Roles.admin },
|
||||
});
|
||||
|
||||
const [user] = await db.select().from(users).where(eq(users.sub, subject));
|
||||
expect(user.caps).toBe(Roles.admin);
|
||||
expect(user.caps).not.toBe(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user