ajustes nos teste, adições e remoções

This commit is contained in:
Esdras Renan 2025-10-16 19:29:52 -03:00
parent 68ace0a858
commit 1ce402cdd7
4 changed files with 270 additions and 0 deletions

View file

@ -12,6 +12,12 @@ jobs:
lint-test-build:
name: Lint, Test and Build
runs-on: ubuntu-latest
env:
BETTER_AUTH_SECRET: test-secret
NEXT_PUBLIC_APP_URL: http://localhost:3000
BETTER_AUTH_URL: http://localhost:3000
NEXT_PUBLIC_CONVEX_URL: http://localhost:3210
DATABASE_URL: file:./prisma/db.dev.sqlite
steps:
- name: Checkout
uses: actions/checkout@v4

View file

@ -0,0 +1,58 @@
import { describe, expect, it, beforeEach, vi } from "vitest"
import { api } from "@/convex/_generated/api"
const mutationMock = vi.fn()
vi.mock("@/server/convex-client", () => ({
createConvexClient: () => ({
mutation: mutationMock,
}),
ConvexConfigurationError: class extends Error {},
}))
describe("POST /api/machines/heartbeat", () => {
beforeEach(() => {
mutationMock.mockReset()
})
it("accepts a valid payload and forwards it to Convex", async () => {
const payload = {
machineToken: "token-123",
status: "online",
metrics: { cpu: 42 },
}
mutationMock.mockResolvedValue({ ok: true })
const { POST } = await import("./route")
const response = await POST(
new Request("http://localhost/api/machines/heartbeat", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload),
})
)
expect(response.status).toBe(200)
const body = await response.json()
expect(body).toEqual({ ok: true })
expect(mutationMock).toHaveBeenCalledWith(api.machines.heartbeat, payload)
})
it("rejects an invalid payload", async () => {
const { POST } = await import("./route")
const response = await POST(
new Request("http://localhost/api/machines/heartbeat", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({}),
})
)
expect(response.status).toBe(400)
const body = await response.json()
expect(body).toHaveProperty("error", "Payload inválido")
expect(mutationMock).not.toHaveBeenCalled()
})
})

View file

@ -0,0 +1,99 @@
import { describe, expect, it, beforeEach, vi } from "vitest"
import { api } from "@/convex/_generated/api"
const mutationMock = vi.fn()
vi.mock("@/server/convex-client", () => ({
createConvexClient: () => ({
mutation: mutationMock,
}),
ConvexConfigurationError: class extends Error {},
}))
describe("POST /api/machines/inventory", () => {
beforeEach(() => {
mutationMock.mockReset()
})
it("accepts the token mode payload", async () => {
const payload = {
machineToken: "token-123",
hostname: "machine",
metrics: { cpu: 50 },
}
mutationMock.mockResolvedValue({ ok: true, machineId: "machine-123" })
const { POST } = await import("./route")
const response = await POST(
new Request("http://localhost/api/machines/inventory", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload),
})
)
expect(response.status).toBe(200)
expect(mutationMock).toHaveBeenCalledWith(
api.machines.heartbeat,
expect.objectContaining({
machineToken: "token-123",
hostname: "machine",
metrics: { cpu: 50 },
})
)
const body = await response.json()
expect(body).toEqual({ ok: true, machineId: "machine-123" })
})
it("accepts the provisioning mode payload", async () => {
const payload = {
provisioningCode: "a".repeat(32),
hostname: "machine",
os: { name: "Linux" },
macAddresses: ["00:11:22:33"],
serialNumbers: [],
}
mutationMock.mockResolvedValue({ ok: true, status: "updated", machineId: "machine-987" })
const { POST } = await import("./route")
const response = await POST(
new Request("http://localhost/api/machines/inventory", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload),
})
)
expect(response.status).toBe(200)
expect(mutationMock).toHaveBeenCalledWith(
api.machines.upsertInventory,
expect.objectContaining({
provisioningCode: "a".repeat(32),
hostname: "machine",
os: { name: "Linux" },
macAddresses: ["00:11:22:33"],
serialNumbers: [],
registeredBy: "agent:inventory",
})
)
const body = await response.json()
expect(body).toEqual({ ok: true, machineId: "machine-987", status: "updated" })
})
it("rejects unknown payloads", async () => {
const { POST } = await import("./route")
const response = await POST(
new Request("http://localhost/api/machines/inventory", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ hostname: "machine" }),
})
)
expect(response.status).toBe(400)
const body = await response.json()
expect(body).toEqual({ error: "Formato de payload não suportado" })
expect(mutationMock).not.toHaveBeenCalled()
})
})

View file

@ -0,0 +1,107 @@
import { describe, expect, it, beforeEach, vi } from "vitest"
import { NextRequest } from "next/server"
import { MACHINE_CTX_COOKIE, serializeMachineCookie } from "@/server/machines/context"
const mockAssertSession = vi.fn()
vi.mock("@/lib/auth-server", () => ({
assertAuthenticatedSession: mockAssertSession,
}))
const mockCreateConvexClient = vi.fn()
vi.mock("@/server/convex-client", () => {
class ConvexConfigurationError extends Error {}
return {
createConvexClient: mockCreateConvexClient,
ConvexConfigurationError,
}
})
const mockCookieStore = {
get: vi.fn<() => unknown, []>(),
}
vi.mock("next/headers", () => ({
cookies: vi.fn(async () => mockCookieStore),
}))
describe("GET /api/machines/session", () => {
beforeEach(() => {
vi.clearAllMocks()
mockCookieStore.get.mockReturnValue(undefined)
mockCreateConvexClient.mockReturnValue({
query: vi.fn(),
mutation: vi.fn(),
})
})
it("returns 403 when the current session is not a machine", async () => {
mockAssertSession.mockResolvedValue({ user: { role: "admin" } })
const { GET } = await import("./route")
const response = await GET(new NextRequest("https://example.com/api/machines/session"))
expect(response.status).toBe(403)
const payload = await response.json()
expect(payload).toEqual({ error: "Sessão de máquina não encontrada." })
expect(mockCreateConvexClient).not.toHaveBeenCalled()
})
it("returns machine context and sets cookie when lookup succeeds", async () => {
mockAssertSession.mockResolvedValue({
user: { role: "machine", email: "device@example.com" },
})
mockCookieStore.get.mockReturnValueOnce(undefined)
const sampleContext = {
id: "machine-123",
tenantId: "tenant-1",
companyId: "company-1",
companySlug: "acme",
persona: "manager",
assignedUserId: "user-789",
assignedUserEmail: "manager@acme.com",
assignedUserName: "Manager Doe",
assignedUserRole: "MANAGER",
metadata: null,
authEmail: "device@example.com",
}
let call = 0
const queryMock = vi.fn(async (_route: unknown, args: unknown) => {
call += 1
if (call === 1) {
expect(args).toEqual({ authEmail: "device@example.com" })
return { id: "machine-123" }
}
if (call === 2) {
expect(args).toEqual({ machineId: "machine-123" })
return sampleContext
}
return null
})
mockCreateConvexClient.mockReturnValue({
query: queryMock,
mutation: vi.fn(),
})
const { GET } = await import("./route")
const response = await GET(new NextRequest("https://example.com/api/machines/session"))
expect(response.status).toBe(200)
const payload = await response.json()
expect(payload.machine.id).toBe(sampleContext.id)
expect(payload.machine.assignedUserEmail).toBe(sampleContext.assignedUserEmail)
const cookie = response.cookies.get(MACHINE_CTX_COOKIE)
expect(cookie?.value).toBe(serializeMachineCookie({
machineId: sampleContext.id,
persona: sampleContext.persona,
assignedUserId: sampleContext.assignedUserId,
assignedUserEmail: sampleContext.assignedUserEmail,
assignedUserName: sampleContext.assignedUserName,
assignedUserRole: sampleContext.assignedUserRole,
}))
})
})