Ctrl K
ComunidadGuías…

scripts/__tests__/log-percentiles.test.ts

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
import { describe, it, expect } from 'vitest'
import {
  extractRecord,
  parseArgs,
  percentile,
  renderMarkdown,
  summarize,
} from '../perf/log-percentiles'

const opLine = (operation: string, durationMs: number, authMs = 2) =>
  JSON.stringify({
    level: 'info',
    module: `api/${operation}`,
    msg: 'op completed',
    operation,
    durationMs,
    authMs,
  })

describe('extractRecord', () => {
  it('parses a bare logger line', () => {
    expect(extractRecord(opLine('period.list', 77))).toMatchObject({
      operation: 'period.list',
      durationMs: 77,
    })
  })

  it('unwraps the JSON embedded in a vercel logs --json envelope', () => {
    const envelope = JSON.stringify({
      timestamp: 1,
      source: 'serverless',
      requestPath: '/api/bookkeeping/fiscal-periods',
      message: `    ${opLine('period.list', 77)}`,
    })
    expect(extractRecord(envelope)).toMatchObject({
      source: 'serverless',
      operation: 'period.list',
      durationMs: 77,
    })
  })

  it('keeps a non-JSON message as the envelope only', () => {
    expect(extractRecord(JSON.stringify({ message: 'plain text' }))).toEqual({
      message: 'plain text',
    })
  })

  it('ignores blank and unparseable lines', () => {
    expect(extractRecord('')).toBeNull()
    expect(extractRecord('not json')).toBeNull()
    expect(extractRecord('{broken')).toBeNull()
  })
})

describe('percentile', () => {
  it('uses nearest rank', () => {
    const sorted = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    expect(percentile(sorted, 50)).toBe(5)
    expect(percentile(sorted, 90)).toBe(9)
    expect(percentile(sorted, 99)).toBe(10)
    expect(percentile([42], 50)).toBe(42)
    expect(Number.isNaN(percentile([], 50))).toBe(true)
  })
})

describe('summarize', () => {
  const records = [
    { operation: 'a', durationMs: 10, authMs: 1 },
    { operation: 'a', durationMs: 30, authMs: 1 },
    { operation: 'b', durationMs: 100, authMs: 50 },
    { operation: 'b', durationMs: 'oops', authMs: 5 },
  ]

  it('groups by the requested keys and ranks slowest first', () => {
    const rows = summarize(records, { fields: ['durationMs', 'authMs'], groupBy: ['operation'] })
    expect(rows.map((r) => r.group)).toEqual(['b', 'a'])
    expect(rows[1].count).toBe(2)
    expect(rows[1].fields.durationMs).toEqual({ p50: 10, p90: 30, p99: 30, max: 30 })
    // The non-numeric durationMs is skipped for that field but the row still counts the sample.
    expect(rows[0].count).toBe(2)
    expect(rows[0].fields.durationMs.max).toBe(100)
  })

  it('applies exact-match filters and min-count', () => {
    const rows = summarize(records, {
      fields: ['durationMs'],
      groupBy: ['operation'],
      filters: [{ key: 'operation', value: 'a' }],
    })
    expect(rows).toHaveLength(1)
    expect(rows[0].group).toBe('a')
    expect(summarize(records, { fields: ['durationMs'], groupBy: ['operation'], minCount: 3 })).toEqual([])
  })

  it('produces a single "all" row without grouping', () => {
    const rows = summarize(records, { fields: ['durationMs'] })
    expect(rows).toHaveLength(1)
    expect(rows[0].group).toBe('all')
    expect(rows[0].count).toBe(4)
  })
})

describe('renderMarkdown + parseArgs', () => {
  it('renders a markdown table with one column set per field', () => {
    const rows = summarize([{ k: 'x', v: 5 }], { fields: ['v'], groupBy: ['k'] })
    const md = renderMarkdown(rows, ['v'])
    expect(md.split('\n')[0]).toBe('| group | n | v p50 | v p90 | v p99 | v max |')
    expect(md).toContain('| x | 1 | 5 | 5 | 5 | 5 |')
  })

  it('parses the documented CLI flags', () => {
    expect(
      parseArgs(['--field', 'a,b', '--group', 'kind,route', '--filter', 'msg=op completed', '--min-count', '5']),
    ).toEqual({
      fields: ['a', 'b'],
      groupBy: ['kind', 'route'],
      filters: [{ key: 'msg', value: 'op completed' }],
      minCount: 5,
    })
    expect(() => parseArgs([])).toThrow('--field is required')
    expect(() => parseArgs(['--bogus'])).toThrow('unknown option')
  })
})