Files
SnowLuma/packages/bridge/tests/process-enumerator.test.ts
2026-10-12 15:43:34 +08:00

58 lines
2.4 KiB
TypeScript

import { describe, it, expect, vi } from 'vitest';
import { createNativeProcessEnumerator } from '../src/process-enumerator';
import type { HookProcessBaseInfo } from '../src/injector';
const QQ = (pid: number): HookProcessBaseInfo => ({ pid, name: 'qq', path: '' });
describe('createNativeProcessEnumerator', () => {
describe('no addon (macOS / missing) → synchronous fallback, never a worker', () => {
it('returns the sync lister result', async () => {
const en = createNativeProcessEnumerator({
addonPath: null,
fallbackSync: () => [QQ(10), QQ(20)],
processName: 'qq',
});
expect(await en.enumerate()).toEqual([QQ(10), QQ(20)]);
en.dispose();
});
it('maps a throwing sync lister to UNKNOWN (null), not an empty list', async () => {
const en = createNativeProcessEnumerator({
addonPath: null,
fallbackSync: () => {
throw new Error('boom');
},
processName: 'qq',
});
expect(await en.enumerate()).toBeNull();
en.dispose();
});
});
describe('worker isolation that cannot load the addon → permanent fallback', () => {
it('falls back to the sync lister after the worker reports a fatal load error', async () => {
const fallback = vi.fn(() => [QQ(7)]);
const en = createNativeProcessEnumerator({
// A path that exists nowhere → process.dlopen throws in the worker →
// the worker posts 'fatal' → isolation is abandoned for good.
addonPath: '/nonexistent/snowluma-test.node',
fallbackSync: fallback,
processName: 'qq',
timeoutMs: 200,
});
// First call spawns the worker; the fatal message drains it to UNKNOWN.
const first = await en.enumerate();
expect(first).toBeNull();
// Give the 'fatal' message a moment to flip isolationBroken if it hadn't
// already, then subsequent calls take the synchronous fallback.
await new Promise((r) => setTimeout(r, 50));
const second = await en.enumerate();
expect(second).toEqual([QQ(7)]);
expect(fallback).toHaveBeenCalled();
en.dispose();
});
});
});