/** * 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])); }); });