Files
supabase/apps/studio/data/workers/worker-logs-query.test.ts
Jordi Enric a46170aa76 feat(workers): add log filters FE-4322 (#49893)
## Problem

Workers log views were limited to the most recent 24 hours and could not
be narrowed by event text or HTTP method.

## Fix

Adds selectable time ranges, event-message search, and an HTTP-method
filter for invocation logs. Filters are applied in the analytics query
and included in the cache key.

## How to test

- Open a worker and select the Invocations tab.
- Change the time range, enter an event message, and select a method.
- Expected result: only matching invocation logs are shown.
- Open Logs or Activity.
- Expected result: message and time filters are available; the method
filter is hidden.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
  * Added worker log filtering by date range and event message.
  * Applied a default 24-hour time range to log searches.
* Improved filter controls and updated empty-state messaging to reflect
the selected range.

* **Bug Fixes**
* Improved filtering accuracy and safer handling of special characters
in event messages.

* **Tests**
  * Added coverage for date-range and message-filter query behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-09-02 15:45:46 +02:00

89 lines
3.2 KiB
TypeScript

import { describe, expect, it } from 'vitest'
import { workersKeys } from './keys'
import { parseWorkerLogRows, workerLogsSql } from './worker-logs-query'
describe('workerLogsSql', () => {
it('reads one worker stream, newest first', () => {
expect(workerLogsSql('embed', 'output')).toBe(
"select id, timestamp, severity_text as severity, event_message as message from logs where log_attributes['worker'] = 'embed' and log_attributes['source'] = 'worker_guest_logs' order by timestamp desc limit 100"
)
})
it('filters by event message before applying the limit', () => {
expect(workerLogsSql('embed', 'requests', { message: 'timeout' })).toBe(
"select id, timestamp, severity_text as severity, event_message as message from logs where log_attributes['worker'] = 'embed' and log_attributes['source'] = 'worker_ingress_logs' and event_message ilike '%timeout%' order by timestamp desc limit 100"
)
})
it('names the right stream for each tab', () => {
expect(workerLogsSql('embed', 'requests')).toContain("'worker_ingress_logs'")
expect(workerLogsSql('embed', 'builds')).toContain("'worker_api_logs'")
})
it('escapes a worker name rather than interpolating it raw', () => {
expect(workerLogsSql("embed' or '1'='1", 'output')).toContain(
"log_attributes['worker'] = 'embed'' or ''1''=''1'"
)
})
it('escapes filter values rather than interpolating them raw', () => {
expect(workerLogsSql('embed', 'requests', { message: "can't connect" })).toContain(
"event_message ilike '%can''t connect%'"
)
})
})
describe('workersKeys.logs', () => {
it('includes the selected time range and filters', () => {
expect(
workersKeys.logs('project-ref', 'embed', 'requests', {
iso_timestamp_start: '2026-09-01T12:00:00.000Z',
iso_timestamp_end: '2026-09-02T12:00:00.000Z',
message: 'timeout',
})
).toEqual([
'projects',
'project-ref',
'worker',
'embed',
'logs',
'requests',
{
iso_timestamp_start: '2026-09-01T12:00:00.000Z',
iso_timestamp_end: '2026-09-02T12:00:00.000Z',
message: 'timeout',
},
])
})
})
describe('parseWorkerLogRows', () => {
it('shapes rows for the logs table with a numeric timestamp', () => {
const [row] = parseWorkerLogRows([
{ id: 'a', timestamp: '2026-08-24T10:00:00.000000', severity: 'ERROR', message: 'boom' },
])
expect(row.id).toBe('a')
expect(row.event_message).toBe('boom')
expect(row.severity_text).toBe('ERROR')
expect(typeof row.timestamp).toBe('number')
expect(Number.isFinite(row.timestamp)).toBe(true)
})
it('falls back to empty strings for null severity and message', () => {
const [row] = parseWorkerLogRows([
{ id: 'a', timestamp: '2026-08-24T10:00:00.000000', severity: null, message: null },
])
expect(row.severity_text).toBe('')
expect(row.event_message).toBe('')
})
it('returns an empty array for a missing result', () => {
expect(parseWorkerLogRows(undefined)).toEqual([])
})
it('rejects a malformed row rather than passing bad data to the table', () => {
expect(() => parseWorkerLogRows([{ timestamp: '2026-08-24T10:00:00.000000' }])).toThrow()
})
})