SnowLuma v2.4.2 source snapshot
Dev Build / cleanup (push) Waiting to run
Dev Build / typecheck (push) Waiting to run
Publish MCP to npm / Build, test, and publish MCP (push) Waiting to run
Publish SDK to npm / Build, test, and publish SDK (push) Waiting to run
Sync action catalog to docs / sync (push) Waiting to run
Publish UI to npm / Build and publish UI (push) Waiting to run
Build and Release / preflight (push) Waiting to run

This commit is contained in:
TanTan committed 2026-11-13 09:02:00 +08:00
commit fa9c73363d
1367 files changed
+355735

No files matched your search

@@ -0,0 +1,138 @@
import { afterEach, describe, expect, it, vi } from 'vitest';
import {
getLogLevel,
runWithRequestId,
setLogLevel,
subscribeLogs,
type LogEntry,
} from '@snowluma/common/logger';
import { createHmac } from 'crypto';
import { buildDispatchPayload } from '../src/event-filter';
import { HttpPostAdapter } from '../src/network/http-post-adapter';
import type { NetworkAdapterContext } from '../src/network/adapter';
import type { HttpClientNetwork, JsonObject } from '../src/types';
const CTX: NetworkAdapterContext = {
uin: '10001',
api: {} as never,
buildLifecycleEvent: () => ({}),
buildHeartbeatEvent: () => ({}),
};
afterEach(() => {
vi.unstubAllGlobals();
});
describe('HttpPostAdapter event ownership', () => {
it('keeps onEvent pending until the webhook request completes', async () => {
let finishFetch!: () => void;
const fetchGate = new Promise<void>((resolve) => {
finishFetch = resolve;
});
vi.stubGlobal(
'fetch',
vi.fn(async () => {
await fetchGate;
return new Response(null, { status: 204 });
}),
);
const config: HttpClientNetwork = {
name: 'post',
url: 'http://127.0.0.1:5700/events',
messageFormat: 'array',
reportSelfMessage: false,
};
const adapter = new HttpPostAdapter('post', config, CTX);
adapter.open();
const event: JsonObject = { post_type: 'notice', notice_type: 'test' };
let completed = false;
const posting = adapter.onEvent(event, buildDispatchPayload(event)).then(() => {
completed = true;
});
await Promise.resolve();
expect(completed).toBe(false);
finishFetch();
await posting;
expect(completed).toBe(true);
});
it.each([
['accepted', () => Promise.resolve(new Response(null, { status: 204 })), 204],
['rejected', () => Promise.resolve(new Response(null, { status: 503 })), 503],
['transport_failed', () => Promise.reject(new Error('network down')), undefined],
] as const)('traces a truthful %s terminal', async (outcome, fetchImpl, status) => {
const previousLevel = getLogLevel();
const entries: LogEntry[] = [];
const unsubscribe = subscribeLogs((entry) => entries.push(entry));
setLogLevel('trace');
vi.stubGlobal('fetch', vi.fn(fetchImpl));
try {
const config: HttpClientNetwork = {
name: 'post',
url: 'http://127.0.0.1:5700/events',
messageFormat: 'array',
reportSelfMessage: false,
};
const adapter = new HttpPostAdapter('post', config, CTX);
adapter.open();
const event: JsonObject = { post_type: 'notice', notice_type: 'trace' };
await runWithRequestId(7100, () => adapter.onEvent(event, buildDispatchPayload(event)));
const terminals = entries.filter(
(entry) =>
entry.scope === 'OneBot.POST' &&
entry.level === 'trace' &&
entry.req === 7100 &&
entry.message.startsWith('http_report_terminal'),
);
expect(terminals).toHaveLength(1);
expect(terminals[0]?.message).toContain(`target=post outcome=${outcome}`);
if (status !== undefined) {
expect(terminals[0]?.message).toContain(`status=${status}`);
}
} finally {
unsubscribe();
setLogLevel(previousLevel);
}
});
it('uses one coherent config epoch when reload races HMAC computation', async () => {
const fetchMock = vi.fn(async () => new Response(null, { status: 204 }));
vi.stubGlobal('fetch', fetchMock);
const oldConfig: HttpClientNetwork = {
name: 'post',
url: 'http://127.0.0.1:5700/old',
accessToken: 'old-token',
timeoutMs: 1111,
messageFormat: 'array',
reportSelfMessage: false,
};
const newConfig: HttpClientNetwork = {
...oldConfig,
url: 'http://127.0.0.1:5700/new',
accessToken: 'new-token',
timeoutMs: 2222,
};
const adapter = new HttpPostAdapter('post', oldConfig, CTX);
adapter.open();
const event: JsonObject = { post_type: 'notice', notice_type: 'epoch' };
const payload = buildDispatchPayload(event);
const posting = adapter.onEvent(event, payload);
await adapter.reload(newConfig);
await posting;
expect(fetchMock).toHaveBeenCalledOnce();
const [url, init] = fetchMock.mock.calls[0]!;
expect(url).toBe(oldConfig.url);
const body = String(init?.body ?? '');
expect((init?.headers as Record<string, string>)['X-Signature']).toBe(
`sha1=${createHmac('sha1', oldConfig.accessToken!).update(body).digest('hex')}`,
);
});
});