Files
insforge--insforge/backend/tests/unit/s3-gateway-crud.integration.test.ts
wehub-resource-sync 3a28426bf4
Lint and Format Check / lint-and-format (push) Failing after 0s
Check Migrations / Check for duplicate migration numbers (push) Failing after 1s
CI Pre-merge Check / CI Pre-merge Check (push) Failing after 2m17s
chore: import upstream snapshot with attribution
2026-07-13 12:23:40 +08:00

81 lines
2.6 KiB
TypeScript

/**
* S3 gateway CRUD integration test.
*
* Opt-in: set RUN_S3_GATEWAY_INTEGRATION=1 to run. Requires:
* - backend running at S3_GATEWAY_URL (default http://localhost:3000/storage/v1/s3)
* with a real S3 backend (MinIO via docker-compose.minio.yml is fine)
* - S3_GATEWAY_AK and S3_GATEWAY_SK from a /api/storage/s3/access-keys create response
*/
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
import {
S3Client,
CreateBucketCommand,
PutObjectCommand,
GetObjectCommand,
DeleteObjectCommand,
HeadObjectCommand,
ListObjectsV2Command,
DeleteBucketCommand,
} from '@aws-sdk/client-s3';
const INTEGRATION = process.env.RUN_S3_GATEWAY_INTEGRATION === '1';
const describeIf = INTEGRATION ? describe : describe.skip;
describeIf('S3 gateway CRUD (integration)', () => {
let s3: S3Client;
const bucket = `integ-${Date.now()}`;
beforeAll(() => {
s3 = new S3Client({
endpoint: process.env.S3_GATEWAY_URL || 'http://localhost:3000/storage/v1/s3',
region: 'us-east-2',
forcePathStyle: true,
credentials: {
accessKeyId: process.env.S3_GATEWAY_AK as string,
secretAccessKey: process.env.S3_GATEWAY_SK as string,
},
});
});
afterAll(async () => {
// Best-effort cleanup
await s3.send(new DeleteBucketCommand({ Bucket: bucket })).catch(() => {});
});
it('creates a bucket', async () => {
await s3.send(new CreateBucketCommand({ Bucket: bucket }));
});
it('puts, heads, gets, lists, deletes an object', async () => {
const body = Buffer.from('hello s3 gateway');
await s3.send(
new PutObjectCommand({
Bucket: bucket,
Key: 'k1',
Body: body,
ContentType: 'text/plain',
})
);
const head = await s3.send(new HeadObjectCommand({ Bucket: bucket, Key: 'k1' }));
expect(Number(head.ContentLength)).toBe(body.length);
const got = await s3.send(new GetObjectCommand({ Bucket: bucket, Key: 'k1' }));
const chunks: Buffer[] = [];
for await (const c of got.Body as AsyncIterable<Buffer>) chunks.push(c);
expect(Buffer.concat(chunks).equals(body)).toBe(true);
const listed = await s3.send(new ListObjectsV2Command({ Bucket: bucket }));
expect(listed.Contents?.some((o) => o.Key === 'k1')).toBe(true);
await s3.send(new DeleteObjectCommand({ Bucket: bucket, Key: 'k1' }));
const after = await s3.send(new ListObjectsV2Command({ Bucket: bucket }));
expect(after.Contents?.some((o) => o.Key === 'k1')).toBeFalsy();
});
it('deletes the bucket', async () => {
await s3.send(new DeleteBucketCommand({ Bucket: bucket }));
});
});