Files
suaveplan/packages/persistence/storage/storage-s3/tests/integration/set-partial.integration.test.ts
2026-05-27 23:47:53 +01:00

88 lines
3.0 KiB
TypeScript

/**
* Garage-backed integration test for `S3.setPartial`.
*
* Pins STORAGE-01..03 (set-partial semantics) against a real S3 wire so the
* read-modify-write fallback survives AWS-SDK body encoding, content-length,
* and range-read round-trips that an in-memory FakeS3Client cannot exercise.
*
* Skips the suite when the GarageS3Fixture failed to start (no Docker /
* env-bridge incomplete). Set `GARAGE_S3_ENDPOINT`,
* `GARAGE_S3_ADMIN_ENDPOINT`, `GARAGE_S3_ACCESS_KEY_ID`,
* `GARAGE_S3_SECRET_ACCESS_KEY` to bypass container startup and use an
* existing Garage instance.
*/
import {
afterEach,
beforeEach,
describe,
expect,
it,
inject as vitestInject,
} from "@suaveplan/testing/runner";
import { S3 } from "../../src/s3/s3.js";
import { inject } from "./setup.js";
const failed =
(vitestInject as (k: string) => string[] | null | undefined)(
"__integration_failed__"
) ?? [];
const garageUnavailable = failed.includes("garage-s3");
describe.skipIf(garageUnavailable)("S3.setPartial — Garage backed", () => {
let storage: S3;
let key: string;
beforeEach(() => {
const cfg = inject("garage-s3");
storage = new S3({
bucket: cfg.bucket,
region: cfg.region,
endpoint: cfg.endpoint,
accessKeyId: cfg.accessKeyId,
secretAccessKey: cfg.secretAccessKey,
});
key = `set-partial/${Date.now()}-${Math.random().toString(36).slice(2)}`;
});
afterEach(async () => {
await storage.delete(key).catch(() => undefined);
});
it("creates a sparse zero-filled object when key does not exist", {
timeout: 60_000,
}, async () => {
await storage.setPartial(key, 4, new Uint8Array([0xaa, 0xbb]));
const got = await storage.get(key);
expect(got).toEqual(
new Uint8Array([0x00, 0x00, 0x00, 0x00, 0xaa, 0xbb])
);
});
it("extends an existing shorter object with zero gap", {
timeout: 60_000,
}, async () => {
await storage.set(key, new Uint8Array([0x01, 0x02]));
await storage.setPartial(key, 5, new Uint8Array([0xcc]));
const got = await storage.get(key);
expect(got).toEqual(
new Uint8Array([0x01, 0x02, 0x00, 0x00, 0x00, 0xcc])
);
});
it("overwrites overlap and preserves surrounding bytes", {
timeout: 60_000,
}, async () => {
await storage.set(key, new Uint8Array([1, 2, 3, 4, 5, 6]));
await storage.setPartial(key, 2, new Uint8Array([0xff, 0xff]));
const got = await storage.get(key);
expect(got).toEqual(new Uint8Array([1, 2, 0xff, 0xff, 5, 6]));
});
it("zero-length writes are a no-op", { timeout: 60_000 }, async () => {
await storage.set(key, new Uint8Array([0x01, 0x02, 0x03]));
await storage.setPartial(key, 1, new Uint8Array(0));
const got = await storage.get(key);
expect(got).toEqual(new Uint8Array([0x01, 0x02, 0x03]));
});
});