Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 | /** * Smoke test results endpoint * * POST /api/smoke-test-results * * Receives test results from the smoke test CronJob and stores them in the database. * Protected by internal cluster networking (no auth required - only accessible from within the cluster). * * Request body: * { * id: string, // Unique run ID * startedAt: string, // ISO timestamp * completedAt?: string,// ISO timestamp (optional if still running) * status: 'running' | 'passed' | 'failed' | 'error', * totalTests?: number, * passedTests?: number, * failedTests?: number, * durationMs?: number, * resultsJson?: string, // JSON-stringified detailed results * errorMessage?: string, * } */ import { type NextRequest, NextResponse } from 'next/server' import { desc, inArray } from 'drizzle-orm' import { db } from '@/db' import { smokeTestRuns } from '@/db/schema' import { metrics, updateSmokeTestMetrics } from '@/lib/metrics' import { withAuth } from '@/lib/auth/withAuth' export const dynamic = 'force-dynamic' interface SmokeTestResultsRequest { id: string startedAt: string completedAt?: string status: 'running' | 'passed' | 'failed' | 'error' totalTests?: number passedTests?: number failedTests?: number durationMs?: number resultsJson?: string errorMessage?: string } interface SmokeTestResultsResponse { success: boolean id: string message?: string } export const POST = withAuth(async (request): Promise<NextResponse<SmokeTestResultsResponse>> => { try { const body = (await request.json()) as SmokeTestResultsRequest // Validate required fields if (!body.id || !body.startedAt || !body.status) { return NextResponse.json( { success: false, id: '', message: 'Missing required fields: id, startedAt, status', }, { status: 400 } ) } // Validate status if (!['running', 'passed', 'failed', 'error'].includes(body.status)) { return NextResponse.json( { success: false, id: '', message: 'Invalid status value' }, { status: 400 } ) } // Insert or update the test run await db .insert(smokeTestRuns) .values({ id: body.id, startedAt: new Date(body.startedAt), completedAt: body.completedAt ? new Date(body.completedAt) : null, status: body.status, totalTests: body.totalTests ?? null, passedTests: body.passedTests ?? null, failedTests: body.failedTests ?? null, durationMs: body.durationMs ?? null, resultsJson: body.resultsJson ?? null, errorMessage: body.errorMessage ?? null, }) .onConflictDoUpdate({ target: smokeTestRuns.id, set: { completedAt: body.completedAt ? new Date(body.completedAt) : null, status: body.status, totalTests: body.totalTests ?? null, passedTests: body.passedTests ?? null, failedTests: body.failedTests ?? null, durationMs: body.durationMs ?? null, resultsJson: body.resultsJson ?? null, errorMessage: body.errorMessage ?? null, }, }) // Update Prometheus metrics for completed runs if (body.status !== 'running') { updateSmokeTestMetrics({ status: body.status, startedAt: new Date(body.startedAt), completedAt: body.completedAt ? new Date(body.completedAt) : null, totalTests: body.totalTests ?? null, passedTests: body.passedTests ?? null, failedTests: body.failedTests ?? null, durationMs: body.durationMs ?? null, }) metrics.smokeTest.runsTotal.inc({ status: body.status }) } // Clean up old test runs (keep last 100) // Get IDs to keep (newest 100) const runsToKeep = await db .select({ id: smokeTestRuns.id }) .from(smokeTestRuns) .orderBy(desc(smokeTestRuns.startedAt)) .limit(100) if (runsToKeep.length >= 100) { // Get all run IDs const allRuns = await db.select({ id: smokeTestRuns.id }).from(smokeTestRuns) const keepIds = new Set(runsToKeep.map((r) => r.id)) const idsToDelete = allRuns.filter((r) => !keepIds.has(r.id)).map((r) => r.id) if (idsToDelete.length > 0) { await db.delete(smokeTestRuns).where(inArray(smokeTestRuns.id, idsToDelete)) } } return NextResponse.json({ success: true, id: body.id, message: 'Test results recorded', }) } catch (error) { console.error('Error storing smoke test results:', error) return NextResponse.json( { success: false, id: '', message: error instanceof Error ? error.message : 'Unknown error', }, { status: 500 } ) } }) |