From 7bf26a3138a5aee4202fe1c778013bc03eb78768 Mon Sep 17 00:00:00 2001 From: chahinebrini Date: Thu, 18 Jun 2026 03:47:24 +0200 Subject: [PATCH] test(backend): add unit tests for MDM health-check DB helpers --- backend/tests/devices/mdm-health.test.ts | 303 +++++++++++++++++++++++ 1 file changed, 303 insertions(+) create mode 100644 backend/tests/devices/mdm-health.test.ts diff --git a/backend/tests/devices/mdm-health.test.ts b/backend/tests/devices/mdm-health.test.ts new file mode 100644 index 0000000..39989f6 --- /dev/null +++ b/backend/tests/devices/mdm-health.test.ts @@ -0,0 +1,303 @@ +/** + * Unit tests for the MDM health-check DB helpers in server/db/mdm.ts. + * + * Coverage: + * - getLinkedUserDevices + * - getMdmEnrollmentStatusesByUdids + * - updateUserDeviceMdmHealth + * + * All DB calls are mocked via vi.mock("../../server/utils/prisma") and + * vi.mock("pg"). + */ +import { describe, expect, it, vi, beforeEach } from "vitest"; +import { + getLinkedUserDevices, + getMdmEnrollmentStatusesByUdids, + updateUserDeviceMdmHealth, + type MdmEnrollmentStatus, +} from "../../server/db/mdm"; + +// ─── Prisma mock ───────────────────────────────────────────────────────────── + +const mockPrisma = { + userDevice: { + findMany: vi.fn(), + update: vi.fn(), + }, +}; + +vi.mock("../../server/utils/prisma", () => ({ + usePrisma: () => mockPrisma, +})); + +// ─── pg / NanoMDM pool mock ────────────────────────────────────────────────── + +const { mockPool } = vi.hoisted(() => { + const mockPool = { + query: vi.fn(), + }; + return { mockPool }; +}); + +vi.mock("pg", () => ({ + __esModule: true, + default: { + Pool: vi.fn(() => mockPool), + }, +})); + +// ─── Runtime config override ───────────────────────────────────────────────── +// setup.ts stubs useRuntimeConfig, but it does not include mdmDatabaseUrl which +// useMdmPool() requires to build the NanoMDM pg.Pool. + +beforeEach(() => { + const useRuntimeConfig = (globalThis as Record) + .useRuntimeConfig as ReturnType; + useRuntimeConfig.mockReturnValue({ + public: { supabase: { url: "", key: "" } }, + supabase: { url: "", key: "" }, + mdmDatabaseUrl: "postgres://localhost:5432/nanomdm", + }); +}); + +// ─── getLinkedUserDevices ──────────────────────────────────────────────────── + +describe("getLinkedUserDevices", () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + it("returns an empty array when no linked iOS devices exist", async () => { + mockPrisma.userDevice.findMany.mockResolvedValue([]); + + const result = await getLinkedUserDevices(); + + expect(result).toEqual([]); + expect(mockPrisma.userDevice.findMany).toHaveBeenCalledTimes(1); + expect(mockPrisma.userDevice.findMany).toHaveBeenCalledWith({ + where: { platform: "ios", mdmId: { not: null } }, + select: { + id: true, + userId: true, + deviceId: true, + platform: true, + mdmId: true, + mdmEnrolled: true, + mdmSupervised: true, + mdmLastSeenAt: true, + }, + }); + }); + + it("returns only iOS devices with mdmId != null and passes the correct where clause", async () => { + const now = new Date("2026-06-18T00:00:00.000Z"); + const devices = [ + { + id: "user-device-1", + userId: "user-1", + deviceId: "capacitor-id-1", + platform: "ios", + mdmId: "udid-1", + mdmEnrolled: true, + mdmSupervised: true, + mdmLastSeenAt: now, + }, + ]; + mockPrisma.userDevice.findMany.mockResolvedValue(devices); + + const result = await getLinkedUserDevices(); + + expect(result).toEqual(devices); + expect(mockPrisma.userDevice.findMany).toHaveBeenCalledTimes(1); + expect(mockPrisma.userDevice.findMany).toHaveBeenCalledWith({ + where: { platform: "ios", mdmId: { not: null } }, + select: { + id: true, + userId: true, + deviceId: true, + platform: true, + mdmId: true, + mdmEnrolled: true, + mdmSupervised: true, + mdmLastSeenAt: true, + }, + }); + }); + + it("returns multiple linked iOS devices when present", async () => { + const t1 = new Date("2026-06-17T10:00:00.000Z"); + const t2 = new Date("2026-06-17T11:00:00.000Z"); + const devices = [ + { + id: "user-device-1", + userId: "user-1", + deviceId: "capacitor-id-1", + platform: "ios", + mdmId: "udid-1", + mdmEnrolled: true, + mdmSupervised: true, + mdmLastSeenAt: t1, + }, + { + id: "user-device-2", + userId: "user-2", + deviceId: "capacitor-id-2", + platform: "ios", + mdmId: "udid-2", + mdmEnrolled: false, + mdmSupervised: false, + mdmLastSeenAt: t2, + }, + ]; + mockPrisma.userDevice.findMany.mockResolvedValue(devices); + + const result = await getLinkedUserDevices(); + + expect(result).toEqual(devices); + expect(result).toHaveLength(2); + expect(mockPrisma.userDevice.findMany).toHaveBeenCalledTimes(1); + }); +}); + +// ─── getMdmEnrollmentStatusesByUdids ───────────────────────────────────────── + +describe("getMdmEnrollmentStatusesByUdids", () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + it("returns an empty map without querying the pool when given an empty array", async () => { + const result = await getMdmEnrollmentStatusesByUdids([]); + + expect(result).toEqual(new Map()); + expect(mockPool.query).not.toHaveBeenCalled(); + }); + + it("maps NanoMDM rows to Map correctly", async () => { + const lastSeenAt = new Date("2026-06-17T12:34:56.000Z"); + mockPool.query.mockResolvedValue({ + rows: [ + { + udid: "udid-enrolled", + enrolled: true, + supervised: true, + last_seen_at: lastSeenAt, + }, + { + udid: "udid-not-enrolled", + enrolled: false, + supervised: false, + last_seen_at: null, + }, + ], + }); + + const result = await getMdmEnrollmentStatusesByUdids([ + "udid-enrolled", + "udid-not-enrolled", + ]); + + expect(result).toEqual( + new Map([ + [ + "udid-enrolled", + { enrolled: true, supervised: true, lastSeenAt: lastSeenAt }, + ], + [ + "udid-not-enrolled", + { enrolled: false, supervised: false, lastSeenAt: null }, + ], + ]), + ); + expect(mockPool.query).toHaveBeenCalledTimes(1); + const [actualQuery, actualParams] = mockPool.query.mock.calls[0]; + expect(actualQuery).toContain( + "LEFT JOIN enrollments e ON e.device_id = d.id", + ); + expect(actualQuery).toContain( + "COALESCE(e.enabled = TRUE, FALSE) AS enrolled", + ); + expect(actualQuery).toContain("(d.unlock_token IS NOT NULL) AS supervised"); + expect(actualQuery).toContain("WHERE d.id = ANY($1::text[])"); + expect(actualParams).toEqual([["udid-enrolled", "udid-not-enrolled"]]); + }); + + it("omits UDIDs that are missing from NanoMDM", async () => { + mockPool.query.mockResolvedValue({ + rows: [ + { + udid: "udid-present", + enrolled: true, + supervised: true, + last_seen_at: null, + }, + ], + }); + + const result = await getMdmEnrollmentStatusesByUdids([ + "udid-present", + "udid-missing", + ]); + + expect(result).toEqual( + new Map([ + [ + "udid-present", + { enrolled: true, supervised: true, lastSeenAt: null }, + ], + ]), + ); + expect(result.has("udid-missing")).toBe(false); + expect(mockPool.query).toHaveBeenCalledTimes(1); + }); +}); + +// ─── updateUserDeviceMdmHealth ─────────────────────────────────────────────── + +describe("updateUserDeviceMdmHealth", () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + it("calls prisma.userDevice.update with the correct where and data", async () => { + mockPrisma.userDevice.update.mockResolvedValue({ id: "user-device-1" }); + + const status: MdmEnrollmentStatus = { + enrolled: true, + supervised: false, + lastSeenAt: null, + }; + + await updateUserDeviceMdmHealth("user-device-1", status); + + expect(mockPrisma.userDevice.update).toHaveBeenCalledTimes(1); + expect(mockPrisma.userDevice.update).toHaveBeenCalledWith({ + where: { id: "user-device-1" }, + data: { + mdmEnrolled: true, + mdmSupervised: false, + mdmLastSeenAt: null, + }, + }); + }); + + it("persists a truthy lastSeenAt and supervised flag", async () => { + mockPrisma.userDevice.update.mockResolvedValue({ id: "user-device-2" }); + const lastSeenAt = new Date("2026-06-17T12:34:56.000Z"); + + await updateUserDeviceMdmHealth("user-device-2", { + enrolled: true, + supervised: true, + lastSeenAt, + }); + + expect(mockPrisma.userDevice.update).toHaveBeenCalledWith({ + where: { id: "user-device-2" }, + data: { + mdmEnrolled: true, + mdmSupervised: true, + mdmLastSeenAt: lastSeenAt, + }, + }); + }); +});