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
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:
commit
fa9c73363d
1367 files changed
+355735
No files matched your search
@@ -0,0 +1,122 @@
|
||||
// ptt-upload tests focus on the fingerprint (fast-upload) path: the
|
||||
// regular load path goes through ffmpeg's silk encoder + the OS temp
|
||||
// directory, which we don't want to exercise in a unit test. The
|
||||
// fingerprint path covers most of what makes ptt-upload distinct
|
||||
// (group/c2c requestId difference, command id mapping, the group-only
|
||||
// bytesGeneralFlags blob, voiceFormat honouring).
|
||||
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
|
||||
vi.mock('@snowluma/protocol/highway/pipeline', () => ({
|
||||
runNtv2Upload: vi.fn(async () => ({ msgInfo: { msgInfoBody: [], extBizInfo: {} } })),
|
||||
finalizeMediaMsgInfo: vi.fn(() => new Uint8Array([0xaa, 0xbb])),
|
||||
hexToBytes: vi.fn((hex: string) => new Uint8Array(hex.length / 2)),
|
||||
}));
|
||||
|
||||
import * as pipeline from '@snowluma/protocol/highway/pipeline';
|
||||
import {
|
||||
uploadPttMsgInfo,
|
||||
GROUP_PTT_CMD_ID,
|
||||
PRIVATE_PTT_CMD_ID,
|
||||
} from '@snowluma/protocol/highway/ptt-upload';
|
||||
|
||||
const FINGERPRINT = {
|
||||
noByteFallback: true,
|
||||
md5Hex: 'aa',
|
||||
sha1Hex: 'bb',
|
||||
fileSize: 1234,
|
||||
duration: 5,
|
||||
} as any;
|
||||
|
||||
describe('ptt-upload', () => {
|
||||
beforeEach(() => {
|
||||
vi.mocked(pipeline.runNtv2Upload).mockClear();
|
||||
vi.mocked(pipeline.finalizeMediaMsgInfo).mockClear();
|
||||
});
|
||||
|
||||
it('retains successful upload metadata for self-sent history', async () => {
|
||||
const node = { fileUuid: 'uploaded-resource', storeId: 1, info: { fileSize: 1234 } };
|
||||
vi.mocked(pipeline.runNtv2Upload).mockResolvedValueOnce({
|
||||
msgInfo: { msgInfoBody: [{ index: node }] },
|
||||
} as any);
|
||||
const element = { ...FINGERPRINT };
|
||||
await uploadPttMsgInfo({} as any, true, 12345, element);
|
||||
expect(element).toMatchObject({
|
||||
fileId: 'uploaded-resource',
|
||||
mediaNode: node,
|
||||
md5Hex: 'aa',
|
||||
sha1Hex: 'bb',
|
||||
});
|
||||
expect(element.fileName).toBeTruthy();
|
||||
});
|
||||
|
||||
it('group: 0x126E_100 + GROUP_PTT_CMD_ID + group-flavored bytesGeneralFlags', async () => {
|
||||
await uploadPttMsgInfo({} as any, true, 12345, FINGERPRINT);
|
||||
const args = vi.mocked(pipeline.runNtv2Upload).mock.calls[0]![0];
|
||||
expect(args.oidbCmd).toBe(0x126e);
|
||||
expect(args.serviceCmd).toBe('OidbSvcTrpcTcp.0x126e_100');
|
||||
expect(args.requestId).toBe(1); // group
|
||||
expect(args.businessType).toBe(3);
|
||||
expect(args.uploads[0]!.cmdId).toBe(GROUP_PTT_CMD_ID);
|
||||
|
||||
const groupFlags = (args.extBizInfo as any).ptt.bytesGeneralFlags;
|
||||
expect(groupFlags).toEqual(
|
||||
new Uint8Array([0x9a, 0x01, 0x07, 0xaa, 0x03, 0x04, 0x08, 0x08, 0x12, 0x00]),
|
||||
);
|
||||
});
|
||||
|
||||
it('c2c: 0x126D_100 + PRIVATE_PTT_CMD_ID + requestId=4 + no generalFlags', async () => {
|
||||
await uploadPttMsgInfo({} as any, false, 'recipient-uid', FINGERPRINT);
|
||||
const args = vi.mocked(pipeline.runNtv2Upload).mock.calls[0]![0];
|
||||
expect(args.oidbCmd).toBe(0x126d);
|
||||
expect(args.serviceCmd).toBe('OidbSvcTrpcTcp.0x126d_100');
|
||||
expect(args.requestId).toBe(4);
|
||||
expect(args.uploads[0]!.cmdId).toBe(PRIVATE_PTT_CMD_ID);
|
||||
|
||||
// Private voice must not carry a generalFlags blob: with the NapCat c2c
|
||||
// one present the receiver drops the progress bar even though the waveform
|
||||
// is in the payload. Group keeps its 10-byte blob (covered above).
|
||||
expect((args.extBizInfo as any).ptt.bytesGeneralFlags).toBeUndefined();
|
||||
expect((args.extBizInfo as any).ptt.waveform).toBeUndefined();
|
||||
|
||||
// Reserve stays the bare legacy 4 bytes, same as group voice.
|
||||
expect([...(args.extBizInfo as any).ptt.bytesReserve]).toEqual([0x08, 0x00, 0x38, 0x00]);
|
||||
});
|
||||
|
||||
it('fingerprint path does not invent a waveform', async () => {
|
||||
await uploadPttMsgInfo({} as any, true, 12345, FINGERPRINT);
|
||||
const args = vi.mocked(pipeline.runNtv2Upload).mock.calls[0]![0];
|
||||
expect((args.extBizInfo as any).ptt.waveform).toBeUndefined();
|
||||
expect(pipeline.finalizeMediaMsgInfo).toHaveBeenCalledOnce();
|
||||
});
|
||||
|
||||
it('fingerprint payload: zero bytes, fastOnlyError ready, voiceFormat defaults to 1', async () => {
|
||||
await uploadPttMsgInfo({} as any, true, 12345, FINGERPRINT);
|
||||
const args = vi.mocked(pipeline.runNtv2Upload).mock.calls[0]![0];
|
||||
expect(args.uploads[0]!.bytes.length).toBe(0);
|
||||
expect(args.uploads[0]!.fastOnlyError).toMatch(/record fast-upload not available/);
|
||||
const fileInfo: any = (args.uploadInfo[0] as any).fileInfo;
|
||||
expect(fileInfo.type.voiceFormat).toBe(1);
|
||||
expect(fileInfo.time).toBe(5);
|
||||
});
|
||||
|
||||
it('honours an explicit voiceFormat from the fingerprint', async () => {
|
||||
await uploadPttMsgInfo({} as any, true, 12345, { ...FINGERPRINT, voiceFormat: 2 });
|
||||
const fileInfo: any = (
|
||||
vi.mocked(pipeline.runNtv2Upload).mock.calls[0]![0].uploadInfo[0] as any
|
||||
).fileInfo;
|
||||
expect(fileInfo.type.voiceFormat).toBe(2);
|
||||
});
|
||||
|
||||
it('fingerprint mode rejects when md5Hex or sha1Hex is missing', async () => {
|
||||
await expect(
|
||||
uploadPttMsgInfo({} as any, true, 12345, { noByteFallback: true } as any),
|
||||
).rejects.toThrow(/requires md5Hex/);
|
||||
});
|
||||
|
||||
it('finalize is called without a defaultPic (ptt copies pic from server only)', async () => {
|
||||
await uploadPttMsgInfo({} as any, true, 12345, FINGERPRINT);
|
||||
const args = vi.mocked(pipeline.finalizeMediaMsgInfo).mock.calls[0]!;
|
||||
expect(args[1]).toBeUndefined();
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user