feat(s3): enhance S3 deletion logic to handle MD5 errors and improve test coverage

This commit is contained in:
KodekaTeam committed 2026-09-11 21:26:59 +07:00
1 parent 87fdbb493b
commit fb3878edb8
2 files changed
+117 -8

No files matched your search

@@ -1,6 +1,11 @@
import assert from "node:assert/strict";
import test from "node:test";
import { DeleteObjectCommand, DeleteObjectsCommand } from "@aws-sdk/client-s3";
import { getExpiredObjectKeys } from "../../src/server/services/s3-storage-retention.service";
import {
deleteS3ObjectsWithClient,
isMissingContentMd5Error,
} from "../../src/server/services/s3-storage.service";
const now = Date.parse("2026-07-15T00:00:00.000Z");
@@ -70,3 +75,45 @@ test("maximum backup count keeps the newest objects", () => {
assert.deepEqual(keys, ["oldest.tar.gz"]);
});
test("S3 deletion falls back to individual requests when batch MD5 is rejected", async () => {
const commands: unknown[] = [];
const client = {
async send(command: unknown) {
commands.push(command);
if (command instanceof DeleteObjectsCommand) {
throw Object.assign(new Error("Missing required header for this request: Content-MD5"), {
Code: "InvalidRequest",
});
}
return {};
},
};
await deleteS3ObjectsWithClient(
client as never,
"bucket",
["backups/one.tar.gz", "backups/two.tar.gz"],
);
assert.equal(commands.length, 3);
assert.ok(commands[0] instanceof DeleteObjectsCommand);
assert.ok(commands[1] instanceof DeleteObjectCommand);
assert.ok(commands[2] instanceof DeleteObjectCommand);
});
test("S3 deletion does not hide unrelated batch failures", async () => {
const failure = Object.assign(new Error("Access denied"), {
Code: "AccessDenied",
});
const client = {
async send() {
throw failure;
},
};
assert.equal(isMissingContentMd5Error(failure), false);
await assert.rejects(
deleteS3ObjectsWithClient(client as never, "bucket", ["backup.tar.gz"]),
failure,
);
});