refactor: 프론트 템플릿 리펙토링
This commit is contained in:
@@ -0,0 +1,549 @@
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
|
||||
import type { BrowserDataObservation } from "../../src/application/ports/browser-file-storage/shared.ts";
|
||||
import { sha256Hex } from "../../src/adapters/browser-transfer/presigned/incremental-sha256.ts";
|
||||
import {
|
||||
CHECKSUM_HEADER,
|
||||
CONTROL_ENDPOINT,
|
||||
DATA_ORIGIN,
|
||||
DIGEST_HEADER,
|
||||
DOWNLOAD_HREF,
|
||||
DOWNLOAD_PATH,
|
||||
NOW,
|
||||
POLICY_HEADER,
|
||||
REQUEST_BINDING_SHA256,
|
||||
UPLOAD_SESSION_ID,
|
||||
collect,
|
||||
createHarness,
|
||||
downloadCapabilityPayload,
|
||||
downloadResponse,
|
||||
jsonResponse,
|
||||
responseWithUrl,
|
||||
uploadCapabilityPayload,
|
||||
} from "./presigned-transfer-fixture.ts";
|
||||
|
||||
describe("presigned upload part execution", () => {
|
||||
it("snapshots, verifies and uploads a PUT part with a separate response receipt", async () => {
|
||||
const original = new Uint8Array([9, 8, 7]);
|
||||
const checksum = sha256Hex(original);
|
||||
const payload = uploadCapabilityPayload({
|
||||
bytes: original,
|
||||
checksum,
|
||||
});
|
||||
let releaseDigest: (() => void) | undefined;
|
||||
const digestGate = new Promise<void>((resolve) => {
|
||||
releaseDigest = resolve;
|
||||
});
|
||||
const sentBodies: number[][] = [];
|
||||
const dataCalls: RequestInit[] = [];
|
||||
const fetcher = vi.fn(async (input: RequestInfo | URL, init?: RequestInit) => {
|
||||
if (String(input) === CONTROL_ENDPOINT) return jsonResponse(payload);
|
||||
dataCalls.push(init ?? {});
|
||||
sentBodies.push([
|
||||
...new Uint8Array(init?.body as ArrayBuffer),
|
||||
]);
|
||||
return responseWithUrl(
|
||||
new Response(null, {
|
||||
status: 200,
|
||||
headers: {
|
||||
[POLICY_HEADER]: "v1",
|
||||
"Content-Length": "0",
|
||||
ETag: "\"part-etag-1\"",
|
||||
},
|
||||
}),
|
||||
String(payload.href),
|
||||
);
|
||||
}) as unknown as typeof fetch;
|
||||
const { provider, executor } = createHarness({
|
||||
fetcher,
|
||||
digestBytes: async (bytes) => {
|
||||
await digestGate;
|
||||
return sha256Hex(bytes);
|
||||
},
|
||||
});
|
||||
const issued = await provider.issueUploadPart({
|
||||
sessionId: UPLOAD_SESSION_ID,
|
||||
requestBindingSha256: REQUEST_BINDING_SHA256,
|
||||
uploadBindingSha256: "b".repeat(64),
|
||||
partNumber: 1,
|
||||
offset: 0,
|
||||
byteLength: original.byteLength,
|
||||
checksumSha256: checksum,
|
||||
mediaType: "application/octet-stream",
|
||||
idempotencyKey: "part-attempt-1",
|
||||
signal: new AbortController().signal,
|
||||
});
|
||||
expect(issued.ok).toBe(true);
|
||||
if (!issued.ok) return;
|
||||
const request = {
|
||||
capability: issued.value,
|
||||
sessionId: UPLOAD_SESSION_ID,
|
||||
requestBindingSha256: REQUEST_BINDING_SHA256,
|
||||
uploadBindingSha256: "b".repeat(64),
|
||||
partNumber: 1,
|
||||
offset: 0,
|
||||
byteLength: original.byteLength,
|
||||
checksumSha256: checksum,
|
||||
idempotencyKey: "part-attempt-1",
|
||||
bytes: original,
|
||||
signal: new AbortController().signal,
|
||||
};
|
||||
const pending = executor.uploadParts.put(request);
|
||||
original.fill(0);
|
||||
request.sessionId = "mutated-session";
|
||||
request.requestBindingSha256 = "d".repeat(64);
|
||||
request.checksumSha256 = "f".repeat(64);
|
||||
releaseDigest?.();
|
||||
|
||||
expect(await pending).toEqual({
|
||||
ok: true,
|
||||
value: {
|
||||
bytesWritten: 3,
|
||||
checksumSha256: checksum,
|
||||
receiptToken: "part-etag-1",
|
||||
},
|
||||
});
|
||||
expect(sentBodies).toEqual([[9, 8, 7]]);
|
||||
expect(dataCalls[0]).toMatchObject({
|
||||
method: "PUT",
|
||||
credentials: "omit",
|
||||
redirect: "error",
|
||||
referrerPolicy: "no-referrer",
|
||||
});
|
||||
expect(
|
||||
(dataCalls[0]?.headers as Headers).get(CHECKSUM_HEADER),
|
||||
).toBe(checksum);
|
||||
});
|
||||
|
||||
it.each(["sessionId", "requestBindingSha256"] as const)(
|
||||
"rejects an actual PUT whose %s differs from the capability",
|
||||
async (field) => {
|
||||
const bytes = new Uint8Array([3, 2, 1]);
|
||||
const checksum = sha256Hex(bytes);
|
||||
const payload = uploadCapabilityPayload({ bytes, checksum });
|
||||
const fetcher = vi.fn(async () =>
|
||||
jsonResponse(payload),
|
||||
) as unknown as typeof fetch;
|
||||
const { provider, executor } = createHarness({ fetcher });
|
||||
const issued = await provider.issueUploadPart({
|
||||
sessionId: UPLOAD_SESSION_ID,
|
||||
requestBindingSha256: REQUEST_BINDING_SHA256,
|
||||
uploadBindingSha256: "b".repeat(64),
|
||||
partNumber: 1,
|
||||
offset: 0,
|
||||
byteLength: bytes.byteLength,
|
||||
checksumSha256: checksum,
|
||||
mediaType: "application/octet-stream",
|
||||
idempotencyKey: "part-attempt-1",
|
||||
signal: new AbortController().signal,
|
||||
});
|
||||
expect(issued.ok).toBe(true);
|
||||
if (!issued.ok) return;
|
||||
expect(
|
||||
await executor.uploadParts.put({
|
||||
capability: issued.value,
|
||||
sessionId:
|
||||
field === "sessionId"
|
||||
? "different-session"
|
||||
: UPLOAD_SESSION_ID,
|
||||
requestBindingSha256:
|
||||
field === "requestBindingSha256"
|
||||
? "d".repeat(64)
|
||||
: REQUEST_BINDING_SHA256,
|
||||
uploadBindingSha256: "b".repeat(64),
|
||||
partNumber: 1,
|
||||
offset: 0,
|
||||
byteLength: bytes.byteLength,
|
||||
checksumSha256: checksum,
|
||||
idempotencyKey: "part-attempt-1",
|
||||
bytes,
|
||||
signal: new AbortController().signal,
|
||||
}),
|
||||
).toMatchObject({
|
||||
ok: false,
|
||||
error: { code: "POLICY_REJECTED" },
|
||||
});
|
||||
expect(fetcher).toHaveBeenCalledTimes(1);
|
||||
},
|
||||
);
|
||||
|
||||
it("rejects URL-shaped upload receipts", async () => {
|
||||
const bytes = new Uint8Array([4, 5, 6]);
|
||||
const checksum = sha256Hex(bytes);
|
||||
const payload = uploadCapabilityPayload({ bytes, checksum });
|
||||
const fetcher = vi.fn(async (input: RequestInfo | URL) => {
|
||||
if (String(input) === CONTROL_ENDPOINT) {
|
||||
return jsonResponse(payload);
|
||||
}
|
||||
return responseWithUrl(
|
||||
new Response(null, {
|
||||
status: 200,
|
||||
headers: {
|
||||
[POLICY_HEADER]: "v1",
|
||||
"Content-Length": "0",
|
||||
ETag: "\"https://objects.example/authorizing-token\"",
|
||||
},
|
||||
}),
|
||||
String(payload.href),
|
||||
);
|
||||
}) as unknown as typeof fetch;
|
||||
const { provider, executor } = createHarness({ fetcher });
|
||||
const issued = await provider.issueUploadPart({
|
||||
sessionId: UPLOAD_SESSION_ID,
|
||||
requestBindingSha256: REQUEST_BINDING_SHA256,
|
||||
uploadBindingSha256: "b".repeat(64),
|
||||
partNumber: 1,
|
||||
offset: 0,
|
||||
byteLength: bytes.byteLength,
|
||||
checksumSha256: checksum,
|
||||
mediaType: "application/octet-stream",
|
||||
idempotencyKey: "part-attempt-1",
|
||||
signal: new AbortController().signal,
|
||||
});
|
||||
expect(issued.ok).toBe(true);
|
||||
if (!issued.ok) return;
|
||||
expect(
|
||||
await executor.uploadParts.put({
|
||||
capability: issued.value,
|
||||
sessionId: UPLOAD_SESSION_ID,
|
||||
requestBindingSha256: REQUEST_BINDING_SHA256,
|
||||
uploadBindingSha256: "b".repeat(64),
|
||||
partNumber: 1,
|
||||
offset: 0,
|
||||
byteLength: bytes.byteLength,
|
||||
checksumSha256: checksum,
|
||||
idempotencyKey: "part-attempt-1",
|
||||
bytes,
|
||||
signal: new AbortController().signal,
|
||||
}),
|
||||
).toMatchObject({
|
||||
ok: false,
|
||||
error: { code: "INTEGRITY_FAILED" },
|
||||
});
|
||||
});
|
||||
|
||||
it("drains a bounded successful PUT acknowledgement without cancelling it", async () => {
|
||||
const bytes = new Uint8Array([4, 5, 6]);
|
||||
const checksum = sha256Hex(bytes);
|
||||
const payload = uploadCapabilityPayload(
|
||||
{ bytes, checksum },
|
||||
{ expectedResponseByteLength: 2 },
|
||||
);
|
||||
let cancelled = false;
|
||||
const fetcher = vi.fn(async (input: RequestInfo | URL) => {
|
||||
if (String(input) === CONTROL_ENDPOINT) {
|
||||
return jsonResponse(payload);
|
||||
}
|
||||
const body = new ReadableStream<Uint8Array>({
|
||||
start(controller) {
|
||||
controller.enqueue(new Uint8Array([8, 9]));
|
||||
controller.close();
|
||||
},
|
||||
cancel() {
|
||||
cancelled = true;
|
||||
},
|
||||
});
|
||||
return responseWithUrl(
|
||||
new Response(body, {
|
||||
status: 200,
|
||||
headers: {
|
||||
[POLICY_HEADER]: "v1",
|
||||
"Content-Length": "2",
|
||||
ETag: "\"part-etag-1\"",
|
||||
},
|
||||
}),
|
||||
String(payload.href),
|
||||
);
|
||||
}) as unknown as typeof fetch;
|
||||
const { provider, executor } = createHarness({ fetcher });
|
||||
const issued = await provider.issueUploadPart({
|
||||
sessionId: UPLOAD_SESSION_ID,
|
||||
requestBindingSha256: REQUEST_BINDING_SHA256,
|
||||
uploadBindingSha256: "b".repeat(64),
|
||||
partNumber: 1,
|
||||
offset: 0,
|
||||
byteLength: bytes.byteLength,
|
||||
checksumSha256: checksum,
|
||||
mediaType: "application/octet-stream",
|
||||
idempotencyKey: "part-attempt-1",
|
||||
signal: new AbortController().signal,
|
||||
});
|
||||
expect(issued.ok).toBe(true);
|
||||
if (!issued.ok) return;
|
||||
expect(
|
||||
await executor.uploadParts.put({
|
||||
capability: issued.value,
|
||||
sessionId: UPLOAD_SESSION_ID,
|
||||
requestBindingSha256: REQUEST_BINDING_SHA256,
|
||||
uploadBindingSha256: "b".repeat(64),
|
||||
partNumber: 1,
|
||||
offset: 0,
|
||||
byteLength: bytes.byteLength,
|
||||
checksumSha256: checksum,
|
||||
idempotencyKey: "part-attempt-1",
|
||||
bytes,
|
||||
signal: new AbortController().signal,
|
||||
}),
|
||||
).toMatchObject({
|
||||
ok: true,
|
||||
value: { receiptToken: "part-etag-1" },
|
||||
});
|
||||
expect(cancelled).toBe(false);
|
||||
});
|
||||
|
||||
it("accepts an empty 204 PUT acknowledgement", async () => {
|
||||
const bytes = new Uint8Array([4, 5, 6]);
|
||||
const checksum = sha256Hex(bytes);
|
||||
const payload = uploadCapabilityPayload(
|
||||
{ bytes, checksum },
|
||||
{
|
||||
expectedStatus: 204,
|
||||
expectedResponseByteLength: 0,
|
||||
},
|
||||
);
|
||||
const fetcher = vi.fn(async (input: RequestInfo | URL) =>
|
||||
String(input) === CONTROL_ENDPOINT
|
||||
? jsonResponse(payload)
|
||||
: responseWithUrl(
|
||||
new Response(null, {
|
||||
status: 204,
|
||||
headers: {
|
||||
[POLICY_HEADER]: "v1",
|
||||
ETag: "\"part-etag-204\"",
|
||||
},
|
||||
}),
|
||||
String(payload.href),
|
||||
),
|
||||
) as unknown as typeof fetch;
|
||||
const { provider, executor } = createHarness({ fetcher });
|
||||
const issued = await provider.issueUploadPart({
|
||||
sessionId: UPLOAD_SESSION_ID,
|
||||
requestBindingSha256: REQUEST_BINDING_SHA256,
|
||||
uploadBindingSha256: "b".repeat(64),
|
||||
partNumber: 1,
|
||||
offset: 0,
|
||||
byteLength: bytes.byteLength,
|
||||
checksumSha256: checksum,
|
||||
mediaType: "application/octet-stream",
|
||||
idempotencyKey: "part-attempt-1",
|
||||
signal: new AbortController().signal,
|
||||
});
|
||||
expect(issued.ok).toBe(true);
|
||||
if (!issued.ok) return;
|
||||
expect(
|
||||
await executor.uploadParts.put({
|
||||
capability: issued.value,
|
||||
sessionId: UPLOAD_SESSION_ID,
|
||||
requestBindingSha256: REQUEST_BINDING_SHA256,
|
||||
uploadBindingSha256: "b".repeat(64),
|
||||
partNumber: 1,
|
||||
offset: 0,
|
||||
byteLength: bytes.byteLength,
|
||||
checksumSha256: checksum,
|
||||
idempotencyKey: "part-attempt-1",
|
||||
bytes,
|
||||
signal: new AbortController().signal,
|
||||
}),
|
||||
).toMatchObject({
|
||||
ok: true,
|
||||
value: { receiptToken: "part-etag-204" },
|
||||
});
|
||||
});
|
||||
|
||||
it("cancels a PUT acknowledgement whose declared length violates its binding", async () => {
|
||||
const bytes = new Uint8Array([4, 5, 6]);
|
||||
const checksum = sha256Hex(bytes);
|
||||
const payload = uploadCapabilityPayload({ bytes, checksum });
|
||||
let cancelled = false;
|
||||
const fetcher = vi.fn(async (input: RequestInfo | URL) => {
|
||||
if (String(input) === CONTROL_ENDPOINT) {
|
||||
return jsonResponse(payload);
|
||||
}
|
||||
const body = new ReadableStream<Uint8Array>({
|
||||
pull() {},
|
||||
cancel() {
|
||||
cancelled = true;
|
||||
},
|
||||
});
|
||||
return responseWithUrl(
|
||||
new Response(body, {
|
||||
status: 200,
|
||||
headers: {
|
||||
[POLICY_HEADER]: "v1",
|
||||
"Content-Length": "1",
|
||||
ETag: "\"part-etag-1\"",
|
||||
},
|
||||
}),
|
||||
String(payload.href),
|
||||
);
|
||||
}) as unknown as typeof fetch;
|
||||
const { provider, executor } = createHarness({ fetcher });
|
||||
const issued = await provider.issueUploadPart({
|
||||
sessionId: UPLOAD_SESSION_ID,
|
||||
requestBindingSha256: REQUEST_BINDING_SHA256,
|
||||
uploadBindingSha256: "b".repeat(64),
|
||||
partNumber: 1,
|
||||
offset: 0,
|
||||
byteLength: bytes.byteLength,
|
||||
checksumSha256: checksum,
|
||||
mediaType: "application/octet-stream",
|
||||
idempotencyKey: "part-attempt-1",
|
||||
signal: new AbortController().signal,
|
||||
});
|
||||
expect(issued.ok).toBe(true);
|
||||
if (!issued.ok) return;
|
||||
expect(
|
||||
await executor.uploadParts.put({
|
||||
capability: issued.value,
|
||||
sessionId: UPLOAD_SESSION_ID,
|
||||
requestBindingSha256: REQUEST_BINDING_SHA256,
|
||||
uploadBindingSha256: "b".repeat(64),
|
||||
partNumber: 1,
|
||||
offset: 0,
|
||||
byteLength: bytes.byteLength,
|
||||
checksumSha256: checksum,
|
||||
idempotencyKey: "part-attempt-1",
|
||||
bytes,
|
||||
signal: new AbortController().signal,
|
||||
}),
|
||||
).toMatchObject({
|
||||
ok: false,
|
||||
error: { code: "POLICY_REJECTED" },
|
||||
});
|
||||
expect(cancelled).toBe(true);
|
||||
});
|
||||
|
||||
it("observes only safe operation, outcome, failure and byte buckets", async () => {
|
||||
const bytes = new Uint8Array([7, 8, 9]);
|
||||
const downloadPayload = downloadCapabilityPayload(bytes);
|
||||
const checksum = sha256Hex(bytes);
|
||||
const uploadPayload = uploadCapabilityPayload({ bytes, checksum });
|
||||
const observations: BrowserDataObservation[] = [];
|
||||
const fetcher = vi.fn(
|
||||
async (input: RequestInfo | URL, init?: RequestInit) => {
|
||||
if (String(input) === CONTROL_ENDPOINT) {
|
||||
const request = JSON.parse(String(init?.body)) as {
|
||||
method: string;
|
||||
};
|
||||
return jsonResponse(
|
||||
request.method === "GET"
|
||||
? downloadPayload
|
||||
: uploadPayload,
|
||||
);
|
||||
}
|
||||
if (String(input) === DOWNLOAD_HREF) {
|
||||
return downloadResponse(
|
||||
bytes.slice().buffer,
|
||||
downloadPayload,
|
||||
);
|
||||
}
|
||||
return responseWithUrl(
|
||||
new Response(null, {
|
||||
status: 200,
|
||||
headers: {
|
||||
[POLICY_HEADER]: "v1",
|
||||
"Content-Length": "0",
|
||||
ETag: "\"part-etag-secret\"",
|
||||
},
|
||||
}),
|
||||
String(uploadPayload.href),
|
||||
);
|
||||
},
|
||||
) as unknown as typeof fetch;
|
||||
const { provider, executor } = createHarness({
|
||||
fetcher,
|
||||
observer: {
|
||||
record(observation) {
|
||||
observations.push(observation);
|
||||
},
|
||||
},
|
||||
});
|
||||
const issuedDownload = await provider.issueDownload({
|
||||
resourceId: "resource-1",
|
||||
signal: new AbortController().signal,
|
||||
});
|
||||
expect(issuedDownload.ok).toBe(true);
|
||||
if (!issuedDownload.ok) return;
|
||||
const opened = await executor.downloadSources.open({
|
||||
resourceId: "resource-1",
|
||||
capability: issuedDownload.value,
|
||||
signal: new AbortController().signal,
|
||||
});
|
||||
expect(opened.ok).toBe(true);
|
||||
if (!opened.ok) return;
|
||||
expect((await collect(opened.value)).every((result) => result.ok)).toBe(
|
||||
true,
|
||||
);
|
||||
|
||||
const issuedUpload = await provider.issueUploadPart({
|
||||
sessionId: UPLOAD_SESSION_ID,
|
||||
requestBindingSha256: REQUEST_BINDING_SHA256,
|
||||
uploadBindingSha256: "b".repeat(64),
|
||||
partNumber: 1,
|
||||
offset: 0,
|
||||
byteLength: bytes.byteLength,
|
||||
checksumSha256: checksum,
|
||||
mediaType: "application/octet-stream",
|
||||
idempotencyKey: "part-attempt-1",
|
||||
signal: new AbortController().signal,
|
||||
});
|
||||
expect(issuedUpload.ok).toBe(true);
|
||||
if (!issuedUpload.ok) return;
|
||||
expect(
|
||||
await executor.uploadParts.put({
|
||||
capability: issuedUpload.value,
|
||||
sessionId: UPLOAD_SESSION_ID,
|
||||
requestBindingSha256: REQUEST_BINDING_SHA256,
|
||||
uploadBindingSha256: "b".repeat(64),
|
||||
partNumber: 1,
|
||||
offset: 0,
|
||||
byteLength: bytes.byteLength,
|
||||
checksumSha256: checksum,
|
||||
idempotencyKey: "part-attempt-1",
|
||||
bytes,
|
||||
signal: new AbortController().signal,
|
||||
}),
|
||||
).toMatchObject({ ok: true });
|
||||
|
||||
expect(observations).toEqual([
|
||||
{
|
||||
operation: "PRESIGNED_TRANSFER",
|
||||
outcome: "SUCCEEDED",
|
||||
byteBucket: "LT1MIB",
|
||||
},
|
||||
{
|
||||
operation: "PRESIGNED_TRANSFER",
|
||||
outcome: "SUCCEEDED",
|
||||
byteBucket: "LT1MIB",
|
||||
},
|
||||
{
|
||||
operation: "DOWNLOAD",
|
||||
outcome: "SUCCEEDED",
|
||||
byteBucket: "LT1MIB",
|
||||
},
|
||||
{
|
||||
operation: "PRESIGNED_TRANSFER",
|
||||
outcome: "SUCCEEDED",
|
||||
byteBucket: "LT1MIB",
|
||||
},
|
||||
{
|
||||
operation: "UPLOAD_PART",
|
||||
outcome: "SUCCEEDED",
|
||||
byteBucket: "LT1MIB",
|
||||
},
|
||||
]);
|
||||
const serialized = JSON.stringify(observations);
|
||||
for (const secret of [
|
||||
DOWNLOAD_HREF,
|
||||
"do-not-log-this",
|
||||
checksum,
|
||||
"capability-download-1",
|
||||
"capability-upload-1",
|
||||
"part-etag-secret",
|
||||
"resource-1",
|
||||
]) {
|
||||
expect(serialized).not.toContain(secret);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
Reference in New Issue
Block a user