ConusAI vendor v0.1.0-dev.20261013+85463d22
This commit is contained in:
parent
c3c6526952
commit
0da8a2a81b
@@ -0,0 +1,61 @@
|
||||
import { expect, test, type Page } from '@playwright/test'
|
||||
|
||||
// Showcase D23: register() in instrumentation.ts starts the OTLP exporters when the platform
|
||||
// injects OTEL_EXPORTER_OTLP_ENDPOINT, and every server action logs through shared/api/observe's
|
||||
// logger(). This proves the whole chain against a real `next start` production server (not dev,
|
||||
// not a mock of register()): a log a server action emits reaches the fake platform's
|
||||
// /otel/v1/logs route within the exporter's 5 s batch interval.
|
||||
|
||||
const platform = 'http://127.0.0.1:4010'
|
||||
|
||||
interface LogRecordJson {
|
||||
body?: { stringValue?: string }
|
||||
attributes?: Array<{ key: string; value: { stringValue?: string } }>
|
||||
}
|
||||
|
||||
type OtelState = { otel: { logs: Array<{ authorization: string | null; body: { resourceLogs: Array<{ scopeLogs: Array<{ logRecords: LogRecordJson[] }> }> } }> } }
|
||||
|
||||
async function otelLogRecords(): Promise<LogRecordJson[]> {
|
||||
const response = await fetch(`${platform}/__e2e/state`)
|
||||
const state = (await response.json()) as OtelState
|
||||
return state.otel.logs.flatMap((post) => post.body.resourceLogs.flatMap((r) => r.scopeLogs.flatMap((s) => s.logRecords)))
|
||||
}
|
||||
|
||||
function attr(record: LogRecordJson, key: string): string | undefined {
|
||||
return record.attributes?.find((kv) => kv.key === key)?.value.stringValue
|
||||
}
|
||||
|
||||
async function createNote(page: Page, title: string): Promise<void> {
|
||||
await page.goto('/')
|
||||
await page.getByLabel('Title').fill(title)
|
||||
await page.getByLabel('Body').fill('observability e2e')
|
||||
await page.getByRole('button', { name: 'Create note' }).click()
|
||||
await expect(page.getByRole('heading', { name: title })).toBeVisible()
|
||||
}
|
||||
|
||||
test('a note.created server action log reaches the OTLP receiver within the batch interval', async ({ page }) => {
|
||||
const title = `otlp ${Date.now()}-${Math.random().toString(36).slice(2, 7)}`
|
||||
await createNote(page, title)
|
||||
|
||||
await expect
|
||||
.poll(
|
||||
async () => (await otelLogRecords()).some((r) => r.body?.stringValue === 'note.created' && attr(r, 'outcome') === 'ok'),
|
||||
// BatchExporter's default flush interval is 5 s (exporter.ts); this allows one full
|
||||
// interval plus slack for the request round trip and CI scheduling jitter.
|
||||
{ timeout: 9_000 },
|
||||
)
|
||||
.toBe(true)
|
||||
})
|
||||
|
||||
test('the OTLP request carries the deployment token, not the public client', async ({ page }) => {
|
||||
const title = `otlp-auth ${Date.now()}-${Math.random().toString(36).slice(2, 7)}`
|
||||
await createNote(page, title)
|
||||
|
||||
await expect
|
||||
.poll(async () => (await otelLogRecords()).some((r) => r.body?.stringValue === 'note.created'), { timeout: 9_000 })
|
||||
.toBe(true)
|
||||
|
||||
const response = await fetch(`${platform}/__e2e/state`)
|
||||
const state = (await response.json()) as OtelState
|
||||
expect(state.otel.logs.every((post) => post.authorization === 'Bearer e2e-deployment-token')).toBe(true)
|
||||
})
|
||||
Reference in New Issue
Block a user