Skip to content

Commit 827cc96

Browse files
committed
test(lib-storage): test to validate all required fields are copied
1 parent 0562a0d commit 827cc96

File tree

1 file changed

+246
-0
lines changed

1 file changed

+246
-0
lines changed
Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
import { PutObjectCommandInput } from "@aws-sdk/client-s3";
2+
import { describe, expect, it, vi } from "vitest";
3+
4+
import { Upload } from "./Upload";
5+
6+
vi.mock("@aws-sdk/client-s3", async () => {
7+
const actual = await vi.importActual("@aws-sdk/client-s3");
8+
return {
9+
...actual,
10+
S3Client: vi.fn().mockImplementation(() => ({
11+
send: vi.fn(),
12+
config: {
13+
requestChecksumCalculation: () => Promise.resolve("WHEN_SUPPORTED"),
14+
},
15+
})),
16+
};
17+
});
18+
19+
describe("Upload Request Field Mapping", () => {
20+
it("should copy all required fields from PutObjectRequest to CreateMultipartUpload", async () => {
21+
const uploadParams: PutObjectCommandInput = {
22+
Bucket: "test-bucket",
23+
Key: "test-key",
24+
ContentType: "text/plain",
25+
Metadata: { custom: "value" },
26+
SSECustomerAlgorithm: "AES256",
27+
SSECustomerKey: "test-key",
28+
SSECustomerKeyMD5: "test-md5",
29+
RequestPayer: "requester",
30+
ExpectedBucketOwner: "123456789012",
31+
CacheControl: "no-cache",
32+
ContentDisposition: "attachment",
33+
ContentEncoding: "gzip",
34+
ContentLanguage: "en-US",
35+
ServerSideEncryption: "AES256",
36+
StorageClass: "STANDARD",
37+
ChecksumAlgorithm: "CRC32",
38+
Body: Buffer.from("test data"),
39+
};
40+
41+
const mockSend = vi.fn().mockResolvedValue({ UploadId: "test-upload-id" });
42+
const mockClient = {
43+
send: mockSend,
44+
config: {
45+
requestChecksumCalculation: () => Promise.resolve("WHEN_SUPPORTED"),
46+
},
47+
};
48+
49+
const upload = new Upload({
50+
client: mockClient as any,
51+
params: uploadParams,
52+
});
53+
54+
await (upload as any).__createMultipartUpload();
55+
56+
const createMultipartCall = mockSend.mock.calls[0][0];
57+
const createCommandParams = createMultipartCall.input;
58+
59+
expect(createCommandParams.Bucket).toBe(uploadParams.Bucket);
60+
expect(createCommandParams.Key).toBe(uploadParams.Key);
61+
expect(createCommandParams.ContentType).toBe(uploadParams.ContentType);
62+
expect(createCommandParams.Metadata).toEqual(uploadParams.Metadata);
63+
expect(createCommandParams.SSECustomerAlgorithm).toBe(uploadParams.SSECustomerAlgorithm);
64+
expect(createCommandParams.SSECustomerKey).toBe(uploadParams.SSECustomerKey);
65+
expect(createCommandParams.SSECustomerKeyMD5).toBe(uploadParams.SSECustomerKeyMD5);
66+
expect(createCommandParams.RequestPayer).toBe(uploadParams.RequestPayer);
67+
expect(createCommandParams.ExpectedBucketOwner).toBe(uploadParams.ExpectedBucketOwner);
68+
expect(createCommandParams.CacheControl).toBe(uploadParams.CacheControl);
69+
expect(createCommandParams.ContentDisposition).toBe(uploadParams.ContentDisposition);
70+
expect(createCommandParams.ContentEncoding).toBe(uploadParams.ContentEncoding);
71+
expect(createCommandParams.ContentLanguage).toBe(uploadParams.ContentLanguage);
72+
expect(createCommandParams.ServerSideEncryption).toBe(uploadParams.ServerSideEncryption);
73+
expect(createCommandParams.StorageClass).toBe(uploadParams.StorageClass);
74+
expect(createCommandParams.ChecksumAlgorithm).toBe("CRC32"); // Set by Upload logic
75+
expect(createCommandParams.Body).toBeUndefined(); // Body should be removed for CreateMultipart
76+
});
77+
78+
it("should copy all required fields from PutObjectRequest to UploadPart", async () => {
79+
const uploadParams: PutObjectCommandInput = {
80+
Bucket: "test-bucket",
81+
Key: "test-key",
82+
SSECustomerAlgorithm: "AES256",
83+
SSECustomerKey: "test-key",
84+
SSECustomerKeyMD5: "test-md5",
85+
RequestPayer: "requester",
86+
ExpectedBucketOwner: "123456789012",
87+
ChecksumAlgorithm: "CRC32",
88+
Body: Buffer.from("#".repeat(1024 * 1024 * 6)),
89+
};
90+
91+
const mockSend = vi.fn().mockImplementation((command) => {
92+
if (command.constructor.name === "CreateMultipartUploadCommand") {
93+
return Promise.resolve({ UploadId: "test-upload-id" });
94+
}
95+
if (command.constructor.name === "UploadPartCommand") {
96+
return Promise.resolve({ ETag: "test-etag" });
97+
}
98+
return Promise.resolve({});
99+
});
100+
101+
const mockClient = {
102+
send: mockSend,
103+
config: {
104+
requestHandler: {},
105+
requestChecksumCalculation: () => Promise.resolve("WHEN_SUPPORTED"),
106+
},
107+
};
108+
109+
const upload = new Upload({
110+
client: mockClient as any,
111+
params: uploadParams,
112+
});
113+
114+
await upload.done();
115+
116+
const uploadPartCall = mockSend.mock.calls.find((call) => call[0].constructor.name === "UploadPartCommand");
117+
expect(uploadPartCall).toBeDefined();
118+
const uploadPartParams = uploadPartCall![0].input;
119+
120+
expect(uploadPartParams.Bucket).toBe(uploadParams.Bucket);
121+
expect(uploadPartParams.Key).toBe(uploadParams.Key);
122+
expect(uploadPartParams.SSECustomerAlgorithm).toBe(uploadParams.SSECustomerAlgorithm);
123+
expect(uploadPartParams.SSECustomerKey).toBe(uploadParams.SSECustomerKey);
124+
expect(uploadPartParams.SSECustomerKeyMD5).toBe(uploadParams.SSECustomerKeyMD5);
125+
expect(uploadPartParams.RequestPayer).toBe(uploadParams.RequestPayer);
126+
expect(uploadPartParams.ExpectedBucketOwner).toBe(uploadParams.ExpectedBucketOwner);
127+
expect(uploadPartParams.UploadId).toBe("test-upload-id");
128+
expect(uploadPartParams.PartNumber).toBe(1);
129+
expect(uploadPartParams.ContentLength).toBeUndefined();
130+
});
131+
132+
it("should copy all required fields from PutObjectRequest to CompleteMultipartUpload", async () => {
133+
const uploadParams: PutObjectCommandInput = {
134+
Bucket: "test-bucket",
135+
Key: "test-key",
136+
SSECustomerAlgorithm: "AES256",
137+
SSECustomerKey: "test-key",
138+
SSECustomerKeyMD5: "test-md5",
139+
RequestPayer: "requester",
140+
ExpectedBucketOwner: "123456789012",
141+
ChecksumCRC32: "test-checksum",
142+
IfMatch: "test-etag",
143+
IfNoneMatch: "test-none-match",
144+
Body: Buffer.from("#".repeat(1024 * 1024 * 6)),
145+
};
146+
147+
const mockSend = vi.fn().mockImplementation((command) => {
148+
if (command.constructor.name === "CreateMultipartUploadCommand") {
149+
return Promise.resolve({ UploadId: "test-upload-id" });
150+
}
151+
if (command.constructor.name === "UploadPartCommand") {
152+
return Promise.resolve({ ETag: "test-etag" });
153+
}
154+
if (command.constructor.name === "CompleteMultipartUploadCommand") {
155+
return Promise.resolve({ Location: "test-location" });
156+
}
157+
return Promise.resolve({});
158+
});
159+
160+
const mockClient = {
161+
send: mockSend,
162+
config: {
163+
requestHandler: {},
164+
requestChecksumCalculation: () => Promise.resolve("WHEN_SUPPORTED"),
165+
},
166+
};
167+
168+
const upload = new Upload({
169+
client: mockClient as any,
170+
params: uploadParams,
171+
});
172+
173+
await upload.done();
174+
175+
const completeCall = mockSend.mock.calls.find(
176+
(call) => call[0].constructor.name === "CompleteMultipartUploadCommand"
177+
);
178+
expect(completeCall).toBeDefined();
179+
const completeParams = completeCall![0].input;
180+
181+
expect(completeParams.Bucket).toBe(uploadParams.Bucket);
182+
expect(completeParams.Key).toBe(uploadParams.Key);
183+
expect(completeParams.SSECustomerAlgorithm).toBe(uploadParams.SSECustomerAlgorithm);
184+
expect(completeParams.SSECustomerKey).toBe(uploadParams.SSECustomerKey);
185+
expect(completeParams.SSECustomerKeyMD5).toBe(uploadParams.SSECustomerKeyMD5);
186+
expect(completeParams.RequestPayer).toBe(uploadParams.RequestPayer);
187+
expect(completeParams.ExpectedBucketOwner).toBe(uploadParams.ExpectedBucketOwner);
188+
expect(completeParams.ChecksumCRC32).toBe(uploadParams.ChecksumCRC32);
189+
expect(completeParams.IfMatch).toBe(uploadParams.IfMatch);
190+
expect(completeParams.IfNoneMatch).toBe(uploadParams.IfNoneMatch);
191+
expect(completeParams.UploadId).toBe("test-upload-id");
192+
expect(completeParams.Body).toBeUndefined();
193+
expect(completeParams.MultipartUpload.Parts).toBeDefined();
194+
});
195+
196+
it("should map response fields from PutObject to Upload response", () => {
197+
const putObjectResponse = {
198+
ETag: "test-etag",
199+
VersionId: "test-version",
200+
ServerSideEncryption: "AES256",
201+
SSEKMSKeyId: "test-kms-key",
202+
BucketKeyEnabled: true,
203+
ChecksumCRC32: "test-checksum",
204+
RequestCharged: "requester",
205+
};
206+
207+
const uploadResponse = {
208+
...putObjectResponse,
209+
Bucket: "test-bucket",
210+
Key: "test-key",
211+
Location: "https://test-bucket.s3.amazonaws.com/test-key",
212+
};
213+
214+
expect(uploadResponse.ETag).toBe("test-etag");
215+
expect(uploadResponse.VersionId).toBe("test-version");
216+
expect(uploadResponse.ServerSideEncryption).toBe("AES256");
217+
expect(uploadResponse.SSEKMSKeyId).toBe("test-kms-key");
218+
expect(uploadResponse.BucketKeyEnabled).toBe(true);
219+
expect(uploadResponse.ChecksumCRC32).toBe("test-checksum");
220+
expect(uploadResponse.RequestCharged).toBe("requester");
221+
});
222+
223+
it("should map response fields from CompleteMultipartUpload to Upload response", () => {
224+
const completeMultipartResponse = {
225+
ETag: "test-etag",
226+
VersionId: "test-version",
227+
ServerSideEncryption: "AES256",
228+
SSEKMSKeyId: "test-kms-key",
229+
BucketKeyEnabled: true,
230+
ChecksumCRC32: "test-checksum",
231+
Location: "https://test-bucket.s3.amazonaws.com/test-key",
232+
};
233+
234+
const uploadResponse = {
235+
...completeMultipartResponse,
236+
};
237+
238+
expect(uploadResponse.ETag).toBe("test-etag");
239+
expect(uploadResponse.VersionId).toBe("test-version");
240+
expect(uploadResponse.ServerSideEncryption).toBe("AES256");
241+
expect(uploadResponse.SSEKMSKeyId).toBe("test-kms-key");
242+
expect(uploadResponse.BucketKeyEnabled).toBe(true);
243+
expect(uploadResponse.ChecksumCRC32).toBe("test-checksum");
244+
expect(uploadResponse.Location).toBe("https://test-bucket.s3.amazonaws.com/test-key");
245+
});
246+
});

0 commit comments

Comments
 (0)