fix: allow removing orphaned machine agents
This commit is contained in:
parent
30dd503082
commit
515d1718a6
3 changed files with 107 additions and 5 deletions
100
src/app/api/admin/machines/delete/route.test.ts
Normal file
100
src/app/api/admin/machines/delete/route.test.ts
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"
|
||||
|
||||
const mutationMock = vi.fn()
|
||||
const deleteManyMock = vi.fn()
|
||||
const assertAuthenticatedSession = vi.fn()
|
||||
|
||||
vi.mock("convex/browser", () => ({
|
||||
ConvexHttpClient: vi.fn().mockImplementation(() => ({
|
||||
mutation: mutationMock,
|
||||
})),
|
||||
}))
|
||||
|
||||
vi.mock("@/lib/prisma", () => ({
|
||||
prisma: {
|
||||
authUser: {
|
||||
deleteMany: deleteManyMock,
|
||||
},
|
||||
},
|
||||
}))
|
||||
|
||||
vi.mock("@/lib/auth-server", () => ({
|
||||
assertAuthenticatedSession: assertAuthenticatedSession,
|
||||
}))
|
||||
|
||||
describe("POST /api/admin/machines/delete", () => {
|
||||
const originalEnv = process.env.NEXT_PUBLIC_CONVEX_URL
|
||||
|
||||
let restoreConsole: (() => void) | undefined
|
||||
|
||||
beforeEach(() => {
|
||||
process.env.NEXT_PUBLIC_CONVEX_URL = "https://convex.example"
|
||||
mutationMock.mockReset()
|
||||
deleteManyMock.mockReset()
|
||||
assertAuthenticatedSession.mockReset()
|
||||
assertAuthenticatedSession.mockResolvedValue({
|
||||
user: {
|
||||
email: "admin@example.com",
|
||||
name: "Admin",
|
||||
role: "ADMIN",
|
||||
tenantId: "tenant-1",
|
||||
avatarUrl: null,
|
||||
},
|
||||
})
|
||||
mutationMock.mockResolvedValueOnce({ _id: "user_123" })
|
||||
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => {})
|
||||
restoreConsole = () => consoleSpy.mockRestore()
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
process.env.NEXT_PUBLIC_CONVEX_URL = originalEnv
|
||||
restoreConsole?.()
|
||||
})
|
||||
|
||||
it("returns ok when the machine removal succeeds", async () => {
|
||||
mutationMock.mockResolvedValueOnce({ ok: true })
|
||||
const { POST } = await import("./route")
|
||||
const response = await POST(
|
||||
new Request("http://localhost/api/admin/machines/delete", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ machineId: "jn_machine" }),
|
||||
})
|
||||
)
|
||||
|
||||
expect(response.status).toBe(200)
|
||||
await expect(response.json()).resolves.toEqual({ ok: true, machineMissing: false })
|
||||
expect(deleteManyMock).toHaveBeenCalledWith({ where: { email: "machine-jn_machine@machines.local" } })
|
||||
expect(mutationMock).toHaveBeenNthCalledWith(1, expect.anything(), expect.objectContaining({ email: "admin@example.com" }))
|
||||
expect(mutationMock).toHaveBeenNthCalledWith(2, expect.anything(), expect.objectContaining({ machineId: "jn_machine" }))
|
||||
})
|
||||
|
||||
it("still succeeds when the Convex machine is already missing", async () => {
|
||||
mutationMock.mockRejectedValueOnce(new Error("Máquina não encontrada"))
|
||||
const { POST } = await import("./route")
|
||||
const response = await POST(
|
||||
new Request("http://localhost/api/admin/machines/delete", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ machineId: "jn_machine" }),
|
||||
})
|
||||
)
|
||||
|
||||
expect(response.status).toBe(200)
|
||||
await expect(response.json()).resolves.toEqual({ ok: true, machineMissing: true })
|
||||
expect(deleteManyMock).toHaveBeenCalledWith({ where: { email: "machine-jn_machine@machines.local" } })
|
||||
})
|
||||
|
||||
it("returns an error for other Convex failures", async () => {
|
||||
mutationMock.mockRejectedValueOnce(new Error("timeout error"))
|
||||
const { POST } = await import("./route")
|
||||
const response = await POST(
|
||||
new Request("http://localhost/api/admin/machines/delete", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ machineId: "jn_machine" }),
|
||||
})
|
||||
)
|
||||
|
||||
expect(response.status).toBe(500)
|
||||
await expect(response.json()).resolves.toEqual({ error: "Falha ao remover máquina no Convex" })
|
||||
expect(deleteManyMock).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
|
@ -48,6 +48,7 @@ export async function POST(request: Request) {
|
|||
return NextResponse.json({ error: "Falha ao identificar o administrador" }, { status: 500 })
|
||||
}
|
||||
|
||||
let machineMissing = false
|
||||
try {
|
||||
await convex.mutation(api.machines.remove, {
|
||||
machineId: parsed.data.machineId as Id<"machines">,
|
||||
|
|
@ -56,16 +57,17 @@ export async function POST(request: Request) {
|
|||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : ""
|
||||
if (message.includes("Máquina não encontrada")) {
|
||||
return NextResponse.json({ error: "Máquina não encontrada" }, { status: 404 })
|
||||
machineMissing = true
|
||||
} else {
|
||||
console.error("[machines.delete] Convex failure", error)
|
||||
return NextResponse.json({ error: "Falha ao remover máquina no Convex" }, { status: 500 })
|
||||
}
|
||||
console.error("[machines.delete] Convex failure", error)
|
||||
return NextResponse.json({ error: "Falha ao remover máquina no Convex" }, { status: 500 })
|
||||
}
|
||||
|
||||
const machineEmail = `machine-${parsed.data.machineId}@machines.local`
|
||||
await prisma.authUser.deleteMany({ where: { email: machineEmail } })
|
||||
|
||||
return NextResponse.json({ ok: true })
|
||||
return NextResponse.json({ ok: true, machineMissing })
|
||||
} catch (error) {
|
||||
console.error("[machines.delete] Falha ao excluir", error)
|
||||
return NextResponse.json({ error: "Falha ao excluir máquina" }, { status: 500 })
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue