Files
doktainer-upstream/tests/backend/container-redeploy-routes.test.ts
KodekaTeam 87fdbb493b feat(sessions): implement user session management with session tracking and revocation
- Introduced new database schema for user sessions and session events.
- Implemented session management page with filtering, sorting, and revocation capabilities.
- Added backend services for creating, revoking, and expiring user sessions.
- Implemented session cookie handling and security measures.
- Created tests for session management functionalities and security features.
2026-09-11 13:34:01 +07:00

70 lines
3.2 KiB
TypeScript

import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import test from "node:test";
const routes = readFileSync("src/server/routes/containers.ts", "utf8");
const api = readFileSync("src/lib/api.ts", "utf8");
const redeployService = readFileSync(
"src/server/services/deployment-rollback.service.ts",
"utf8",
);
const detailPage = readFileSync(
"src/app/projects/[projectId]/environments/[environmentId]/containers/[containerId]/page.tsx",
"utf8",
);
const actionConstants = readFileSync(
"src/app/projects/[projectId]/environments/[environmentId]/containers/[containerId]/data/app-detail-constants.ts",
"utf8",
);
test("redeploy endpoints require container write authorization", () => {
for (const path of ['"/:id/redeploy-job"', '"/:id/redeploy"']) {
const start = routes.indexOf(path);
assert.ok(start >= 0, `${path} route should exist`);
assert.match(routes.slice(start, start + 180), /containerWriteAccess/);
}
const previewStart = routes.indexOf('"/:id/redeploy-plan"');
assert.ok(previewStart >= 0, "redeploy preview route should exist");
assert.match(routes.slice(previewStart, previewStart + 180), /containerReadAccess/);
});
test("internal deployment jobs retain browser session authentication", () => {
const helperStart = routes.indexOf("function buildInternalJobHeaders");
assert.ok(helperStart >= 0, "internal job header builder should exist");
const helper = routes.slice(helperStart, helperStart + 900);
assert.match(helper, /"x-doktainer-request": "1"/);
assert.match(helper, /const cookie = headers\.cookie/);
assert.match(helper, /nextHeaders\.cookie = cookie/);
});
test("redeploy restores the stored current revision without invoking source rebuild", () => {
assert.match(redeployService, /redeployContainerCurrentRevision/);
assert.match(redeployService, /getRollbackSnapshot\(input\)/);
assert.match(redeployService, /trigger: input\.operation/);
assert.match(redeployService, /operation: "REDEPLOY"/);
assert.match(redeployService, /containerId_idempotencyKey/);
assert.match(redeployService, /replaceRuntimeWithProxyCandidate/);
assert.match(redeployService, /status: "VALIDATING"/);
assert.match(redeployService, /status: "SWITCHING"/);
const redeployStart = routes.indexOf('"/:id/redeploy"');
const redeployRoute = routes.slice(redeployStart, redeployStart + 1800);
assert.match(redeployRoute, /redeployContainerCurrentRevision/);
assert.match(redeployRoute, /ContainerRedeploySchema\.safeParse/);
assert.doesNotMatch(redeployRoute, /rebuildAppInstall|repoUrl|gitClone/);
});
test("client presents redeploy and rebuild as separate operations", () => {
assert.match(api, /createRedeployJob/);
assert.match(api, /redeployPlan/);
assert.match(api, /createRebuildJob/);
assert.match(actionConstants, /label: "Redeploy current revision"/);
assert.match(actionConstants, /label: "Rebuild from source"/);
assert.match(detailPage, /runDeploymentOperation\("redeploy"\)/);
assert.match(detailPage, /runDeploymentOperation\("rebuild"\)/);
assert.match(detailPage, /No source code will be fetched and no image will be built/);
assert.match(detailPage, /proxyTrafficContinuous/);
assert.match(detailPage, /overlappingRuntime/);
});