chore: linting

This commit is contained in:
zhom
2026-04-05 23:04:09 +04:00
parent 80757829c2
commit 05791ace1f
7 changed files with 96 additions and 47 deletions
+2 -2
View File
@@ -85,7 +85,7 @@ jobs:
# Wait for MinIO to be ready
for i in {1..30}; do
if curl -sf http://localhost:8987/minio/health/live; then
if curl -sf http://127.0.0.1:8987/minio/health/live; then
echo "MinIO is ready"
break
fi
@@ -111,7 +111,7 @@ jobs:
working-directory: donut-sync
env:
SYNC_TOKEN: test-sync-token
S3_ENDPOINT: http://localhost:8987
S3_ENDPOINT: http://127.0.0.1:8987
S3_ACCESS_KEY_ID: minioadmin
S3_SECRET_ACCESS_KEY: minioadmin
S3_BUCKET: donut-sync-test
-1
View File
@@ -18,4 +18,3 @@ services:
volumes:
minio_data:
+14 -3
View File
@@ -2,18 +2,29 @@ import { INestApplication } from "@nestjs/common";
import { Test, TestingModule } from "@nestjs/testing";
import request from "supertest";
import { App } from "supertest/types";
import { AppModule } from "./../src/app.module.js";
import { AppController } from "./../src/app.controller.js";
import { AppService } from "./../src/app.service.js";
import { SyncService } from "./../src/sync/sync.service.js";
describe("AppController (e2e)", () => {
let app: INestApplication<App>;
beforeEach(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [AppModule],
controllers: [AppController],
providers: [
AppService,
{
provide: SyncService,
useValue: {
checkS3Connectivity: async () => true,
},
},
],
}).compile();
app = moduleFixture.createNestApplication();
await app.init();
await app.listen(0);
});
afterEach(async () => {
+1
View File
@@ -1,6 +1,7 @@
{
"moduleFileExtensions": ["js", "json", "ts"],
"rootDir": ".",
"maxWorkers": 1,
"testEnvironment": "node",
"testRegex": ".e2e-spec.ts$",
"transform": {
+41 -40
View File
@@ -1,3 +1,5 @@
import type { Server } from "node:http";
import type { AddressInfo } from "node:net";
import { INestApplication } from "@nestjs/common";
import { ConfigModule } from "@nestjs/config";
import { Test, TestingModule } from "@nestjs/testing";
@@ -6,6 +8,11 @@ import { App } from "supertest/types";
import { AppController } from "./../src/app.controller.js";
import { AppService } from "./../src/app.service.js";
import { SyncModule } from "./../src/sync/sync.module.js";
import {
configureTestEnv,
TEST_SYNC_TOKEN,
waitForTestS3,
} from "./test-env.js";
interface PresignResponse {
url: string;
@@ -29,26 +36,12 @@ interface StatResponse {
lastModified?: string;
}
interface SSEError {
code?: string;
timeout?: boolean;
response?: { status: number };
}
const TEST_TOKEN = "test-sync-token";
describe("SyncController (e2e)", () => {
let app: INestApplication<App>;
beforeAll(async () => {
process.env.SYNC_TOKEN = TEST_TOKEN;
process.env.S3_ENDPOINT =
process.env.S3_ENDPOINT || "http://localhost:8987";
process.env.S3_ACCESS_KEY_ID = process.env.S3_ACCESS_KEY_ID || "minioadmin";
process.env.S3_SECRET_ACCESS_KEY =
process.env.S3_SECRET_ACCESS_KEY || "minioadmin";
process.env.S3_BUCKET = "donut-sync-test";
process.env.S3_FORCE_PATH_STYLE = "true";
configureTestEnv();
await waitForTestS3();
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [
@@ -62,7 +55,7 @@ describe("SyncController (e2e)", () => {
}).compile();
app = moduleFixture.createNestApplication();
await app.init();
await app.listen(0);
});
afterAll(async () => {
@@ -88,7 +81,7 @@ describe("SyncController (e2e)", () => {
it("should accept requests with valid token", () => {
return request(app.getHttpServer())
.post("/v1/objects/stat")
.set("Authorization", `Bearer ${TEST_TOKEN}`)
.set("Authorization", `Bearer ${TEST_SYNC_TOKEN}`)
.send({ key: "nonexistent-key" })
.expect(200)
.expect({ exists: false });
@@ -99,7 +92,7 @@ describe("SyncController (e2e)", () => {
it("should return exists: false for non-existent key", () => {
return request(app.getHttpServer())
.post("/v1/objects/stat")
.set("Authorization", `Bearer ${TEST_TOKEN}`)
.set("Authorization", `Bearer ${TEST_SYNC_TOKEN}`)
.send({ key: "does-not-exist" })
.expect(200)
.expect({ exists: false });
@@ -110,7 +103,7 @@ describe("SyncController (e2e)", () => {
it("should return a presigned upload URL", async () => {
const response = await request(app.getHttpServer())
.post("/v1/objects/presign-upload")
.set("Authorization", `Bearer ${TEST_TOKEN}`)
.set("Authorization", `Bearer ${TEST_SYNC_TOKEN}`)
.send({ key: "test/upload-key.txt", contentType: "text/plain" })
.expect(200);
@@ -125,7 +118,7 @@ describe("SyncController (e2e)", () => {
it("should return a presigned download URL", async () => {
const response = await request(app.getHttpServer())
.post("/v1/objects/presign-download")
.set("Authorization", `Bearer ${TEST_TOKEN}`)
.set("Authorization", `Bearer ${TEST_SYNC_TOKEN}`)
.send({ key: "test/download-key.txt" })
.expect(200);
@@ -140,7 +133,7 @@ describe("SyncController (e2e)", () => {
it("should list objects with prefix", async () => {
const response = await request(app.getHttpServer())
.post("/v1/objects/list")
.set("Authorization", `Bearer ${TEST_TOKEN}`)
.set("Authorization", `Bearer ${TEST_SYNC_TOKEN}`)
.send({ prefix: "profiles/" })
.expect(200);
@@ -155,7 +148,7 @@ describe("SyncController (e2e)", () => {
it("should delete object and create tombstone", async () => {
const response = await request(app.getHttpServer())
.post("/v1/objects/delete")
.set("Authorization", `Bearer ${TEST_TOKEN}`)
.set("Authorization", `Bearer ${TEST_SYNC_TOKEN}`)
.send({
key: "test/to-delete.txt",
tombstoneKey: "tombstones/test/to-delete.json",
@@ -176,7 +169,7 @@ describe("SyncController (e2e)", () => {
it("should complete full upload/download cycle with presigned URLs", async () => {
const uploadResponse = await request(app.getHttpServer())
.post("/v1/objects/presign-upload")
.set("Authorization", `Bearer ${TEST_TOKEN}`)
.set("Authorization", `Bearer ${TEST_SYNC_TOKEN}`)
.send({ key: testKey, contentType: "text/plain" })
.expect(200);
@@ -192,7 +185,7 @@ describe("SyncController (e2e)", () => {
const statResponse = await request(app.getHttpServer())
.post("/v1/objects/stat")
.set("Authorization", `Bearer ${TEST_TOKEN}`)
.set("Authorization", `Bearer ${TEST_SYNC_TOKEN}`)
.send({ key: testKey })
.expect(200);
@@ -202,7 +195,7 @@ describe("SyncController (e2e)", () => {
const downloadResponse = await request(app.getHttpServer())
.post("/v1/objects/presign-download")
.set("Authorization", `Bearer ${TEST_TOKEN}`)
.set("Authorization", `Bearer ${TEST_SYNC_TOKEN}`)
.send({ key: testKey })
.expect(200);
@@ -215,13 +208,13 @@ describe("SyncController (e2e)", () => {
await request(app.getHttpServer())
.post("/v1/objects/delete")
.set("Authorization", `Bearer ${TEST_TOKEN}`)
.set("Authorization", `Bearer ${TEST_SYNC_TOKEN}`)
.send({ key: testKey })
.expect(200);
const finalStatResponse = await request(app.getHttpServer())
.post("/v1/objects/stat")
.set("Authorization", `Bearer ${TEST_TOKEN}`)
.set("Authorization", `Bearer ${TEST_SYNC_TOKEN}`)
.send({ key: testKey })
.expect(200);
@@ -238,20 +231,28 @@ describe("SyncController (e2e)", () => {
});
it("should return SSE stream with valid token", async () => {
const response = await request(app.getHttpServer())
.get("/v1/objects/subscribe")
.set("Authorization", `Bearer ${TEST_TOKEN}`)
.set("Accept", "text/event-stream")
.buffer(true)
.timeout(3000)
.catch((err: SSEError) => {
if (err.code === "ECONNABORTED" || err.timeout) {
return err.response ?? { status: 200 };
}
throw err;
});
const address = (
app.getHttpServer() as Server
).address() as AddressInfo | null;
if (!address || typeof address === "string") {
throw new Error("Expected app to be listening on a TCP port");
}
const response = await fetch(
`http://127.0.0.1:${address.port}/v1/objects/subscribe`,
{
headers: {
Accept: "text/event-stream",
Authorization: `Bearer ${TEST_SYNC_TOKEN}`,
},
},
);
expect(response.status).toBe(200);
expect(response.headers.get("content-type")).toContain(
"text/event-stream",
);
await response.body?.cancel();
});
});
});
+37
View File
@@ -0,0 +1,37 @@
import { ListBucketsCommand, S3Client } from "@aws-sdk/client-s3";
export const TEST_SYNC_TOKEN = "test-sync-token";
export const TEST_S3_ENDPOINT = "http://127.0.0.1:8987";
export function configureTestEnv() {
process.env.SYNC_TOKEN ||= TEST_SYNC_TOKEN;
process.env.S3_ENDPOINT ||= TEST_S3_ENDPOINT;
process.env.S3_ACCESS_KEY_ID ||= "minioadmin";
process.env.S3_SECRET_ACCESS_KEY ||= "minioadmin";
process.env.S3_BUCKET ||= "donut-sync-test";
process.env.S3_FORCE_PATH_STYLE ||= "true";
}
export async function waitForTestS3(timeoutMs = 30_000) {
const deadline = Date.now() + timeoutMs;
const s3Client = new S3Client({
endpoint: TEST_S3_ENDPOINT,
region: "us-east-1",
credentials: {
accessKeyId: "minioadmin",
secretAccessKey: "minioadmin",
},
forcePathStyle: true,
});
while (Date.now() < deadline) {
try {
await s3Client.send(new ListBucketsCommand({}));
return;
} catch {}
await new Promise((resolve) => setTimeout(resolve, 500));
}
throw new Error(`Timed out waiting for S3 at ${TEST_S3_ENDPOINT}`);
}
+1 -1
View File
@@ -81,7 +81,7 @@ echo -e "${YELLOW}Waiting for MinIO to be healthy...${NC}"
MAX_RETRIES=30
RETRY_COUNT=0
while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do
if curl -sf http://localhost:8987/minio/health/live > /dev/null 2>&1; then
if curl -sf http://127.0.0.1:8987/minio/health/live > /dev/null 2>&1; then
echo -e "${GREEN}MinIO is ready!${NC}"
break
fi