Add filters and context to host operation history
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { currentOperationSource, withOperationSource } from '../../src/lib/server/hosts/operation-context.js';
|
||||
import { trackActivity, workerActivity } from '../../src/lib/server/pipeline/activity.js';
|
||||
|
||||
describe('host operation source context', () => {
|
||||
it('isolates overlapping asynchronous sources and restores the caller', async () => {
|
||||
let release!: () => void;
|
||||
const barrier = new Promise<void>(resolve => { release = resolve; });
|
||||
const first = withOperationSource('GET /servers/[name]', async () => {
|
||||
await barrier;
|
||||
return currentOperationSource();
|
||||
});
|
||||
const second = withOperationSource('Status monitor', async () => {
|
||||
release();
|
||||
await Promise.resolve();
|
||||
return currentOperationSource();
|
||||
});
|
||||
expect(currentOperationSource()).toBeNull();
|
||||
expect(await Promise.all([first, second])).toEqual(['GET /servers/[name]', 'Status monitor']);
|
||||
expect(currentOperationSource()).toBeNull();
|
||||
});
|
||||
|
||||
it('lets explicit background work override incidental request context without leaking it', async () => {
|
||||
await withOperationSource('POST /api/servers/[name]/refresh', async () => {
|
||||
await withOperationSource('Status monitor', async () => {
|
||||
await Promise.resolve();
|
||||
expect(currentOperationSource()).toBe('Status monitor');
|
||||
});
|
||||
expect(currentOperationSource()).toBe('POST /api/servers/[name]/refresh');
|
||||
expect(() => withOperationSource('Failing task', () => { throw new Error('failed'); })).toThrow('failed');
|
||||
expect(currentOperationSource()).toBe('POST /api/servers/[name]/refresh');
|
||||
});
|
||||
expect(currentOperationSource()).toBeNull();
|
||||
});
|
||||
|
||||
it('gives background activity a source while preserving its initiating source through nested activity', async () => {
|
||||
await trackActivity('context-test', 'Reconciling campaigns', async () => {
|
||||
await Promise.resolve();
|
||||
expect(currentOperationSource()).toBe('Reconciling campaigns');
|
||||
await trackActivity('context-test-child', 'Waiting for files.read', async () => {
|
||||
expect(currentOperationSource()).toBe('Reconciling campaigns');
|
||||
});
|
||||
});
|
||||
await withOperationSource('POST /api/servers/[name]/restart', () =>
|
||||
trackActivity('context-test-request', 'Processing provisioning requests', async () => {
|
||||
expect(currentOperationSource()).toBe('POST /api/servers/[name]/restart');
|
||||
}));
|
||||
expect(currentOperationSource()).toBeNull();
|
||||
expect(workerActivity()).toEqual([]);
|
||||
});
|
||||
|
||||
it('restores context and clears activity when asynchronous work rejects', async () => {
|
||||
await withOperationSource('Manual maintenance check', async () => {
|
||||
await expect(trackActivity('context-test-error', 'Waiting for files.read', async () => {
|
||||
await Promise.resolve();
|
||||
expect(currentOperationSource()).toBe('Manual maintenance check');
|
||||
throw new Error('unavailable');
|
||||
})).rejects.toThrow('unavailable');
|
||||
expect(currentOperationSource()).toBe('Manual maintenance check');
|
||||
});
|
||||
expect(currentOperationSource()).toBeNull();
|
||||
expect(workerActivity()).toEqual([]);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user