parse-multipart.test.mjs
85 lines 3.4 KB
Raw
sha256:65ccb454656ea5acdea0a10e559b78bcde1eb6ff753ecc2911bc99d1c3d7cadd feat(calendar): enforce agent context tiers in retrieval AP… Human minor ⚠ breaking 1 day ago
1 /**
2 * Tests for hub/gateway/parse-multipart.mjs — minimal multipart/form-data file parser.
3 * Used by the gateway to extract image uploads without forwarding binary bodies to another Lambda.
4 */
5 import { describe, it } from 'node:test';
6 import assert from 'node:assert';
7 import { parseMultipartFile } from '../hub/gateway/parse-multipart.mjs';
8
9 /**
10 * Build a minimal multipart/form-data body containing one file field.
11 */
12 function buildMultipart(boundary, filename, contentType, data) {
13 const parts = [
14 `--${boundary}\r\n`,
15 `Content-Disposition: form-data; name="image"; filename="${filename}"\r\n`,
16 `Content-Type: ${contentType}\r\n`,
17 `\r\n`,
18 ];
19 const header = Buffer.from(parts.join(''), 'binary');
20 const footer = Buffer.from(`\r\n--${boundary}--\r\n`, 'binary');
21 return Buffer.concat([header, data, footer]);
22 }
23
24 describe('parseMultipartFile', () => {
25 it('extracts file buffer from a well-formed multipart body', () => {
26 const boundary = 'TestBoundary1234';
27 const payload = Buffer.from([0xFF, 0xD8, 0xFF, 0xE0, 0x01, 0x02]);
28 const body = buildMultipart(boundary, 'photo.jpg', 'image/jpeg', payload);
29 const result = parseMultipartFile(body, boundary);
30 assert.ok(result, 'should return a result');
31 assert.strictEqual(result.filename, 'photo.jpg');
32 assert.strictEqual(result.contentType, 'image/jpeg');
33 assert.deepStrictEqual(result.data, payload);
34 });
35
36 it('returns null for a body with no file parts', () => {
37 const boundary = 'NoBoundary';
38 // A text field (no filename) — should be ignored
39 const body = Buffer.from(
40 `--${boundary}\r\nContent-Disposition: form-data; name="text"\r\n\r\nhello\r\n--${boundary}--\r\n`,
41 'binary',
42 );
43 const result = parseMultipartFile(body, boundary);
44 assert.strictEqual(result, null);
45 });
46
47 it('returns null for empty body', () => {
48 assert.strictEqual(parseMultipartFile(Buffer.alloc(0), 'boundary'), null);
49 });
50
51 it('handles PNG payload correctly', () => {
52 const boundary = 'PngBoundary';
53 const pngHeader = Buffer.from([0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]);
54 const body = buildMultipart(boundary, 'image.png', 'image/png', pngHeader);
55 const result = parseMultipartFile(body, boundary);
56 assert.ok(result);
57 assert.strictEqual(result.filename, 'image.png');
58 assert.deepStrictEqual(result.data, pngHeader);
59 });
60
61 it('handles filename with spaces and special chars', () => {
62 const boundary = 'SpaceBoundary';
63 const data = Buffer.from([0xFF, 0xD8, 0xFF]);
64 const body = buildMultipart(boundary, 'my photo (1).jpg', 'image/jpeg', data);
65 const result = parseMultipartFile(body, boundary);
66 assert.ok(result);
67 assert.strictEqual(result.filename, 'my photo (1).jpg');
68 });
69
70 it('defaults content-type to application/octet-stream when missing', () => {
71 const boundary = 'NoCtBoundary';
72 const data = Buffer.from([0xFF, 0xD8, 0xFF]);
73 const parts = [
74 `--${boundary}\r\n`,
75 `Content-Disposition: form-data; name="image"; filename="photo.jpg"\r\n`,
76 `\r\n`,
77 ];
78 const header = Buffer.from(parts.join(''), 'binary');
79 const footer = Buffer.from(`\r\n--${boundary}--\r\n`, 'binary');
80 const body = Buffer.concat([header, data, footer]);
81 const result = parseMultipartFile(body, boundary);
82 assert.ok(result);
83 assert.strictEqual(result.contentType, 'application/octet-stream');
84 });
85 });
File History 2 commits
sha256:65ccb454656ea5acdea0a10e559b78bcde1eb6ff753ecc2911bc99d1c3d7cadd feat(calendar): enforce agent context tiers in retrieval AP… Human minor 1 day ago
sha256:9103f98c89257ed2b01c237cea895dabb3e85ea337dccb1161c175e4422355b6 docs: accept Calendar Events v0 spec with Phase 0 security … Human 1 day ago