mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
Feat/monorepo (#292)
* feat(create-turbo): apply official-starter transform * refactor: move folder * wip: monorepo * feat: add builf * refactor: add pr * update * add .env * refactor: update build * refactor: update build docker * refactor: add progress plain * refactor: remove node pty * refactor: remove * remove * refactor: update * refacotr: uopdate * refactor: add remix app * add env * refactor: add pnpm start * refactor: remove * refactor: remove folders * refactor: remove .dockerfile * chore: update biome * test * choe: add husky * remove .docker folder * feat: add docs website * refactor: add husky * chore(version): bump version * refactor: add new changes * refactor: update circle path * refactor: update * refactor: update * refactor: update dockerfile * refactor: update dockerfile * refactor: update command * refactor: update * refactor: update dockerfile * refactor: add tsx * refactor: update dockerfile * refactor: add deps * refactor: up[date * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: yuodate * refactor: remove * refactor: uncomment * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: updare * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: imprt * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: remove * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: change path * refactor: update * refactor: update * refactor: upoadte * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: add * refactor: update * refactor: update * refactor: add * refactor: update * refactor: remove * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: removed * refactor: update * refactor: update * refactor: update * refactor: add config * refactor: update * refactor: add * refactor: update * refactor: update * refactor: remove * refactor: update * refactor: remove * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: add docs * refactor: update * refactor: add website * refactor: update * refactor: update * refactor: update * refactor: update * refactor: add ignore builds * refactor: update * refactor: update * refactor: add * refactor: update * refactor: update * refactor: remove needs * refactor: update * refactor: update * refactor: add config * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: remove * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: add * refactor: update * refactor: update * refactor: update * refactor: update * refactor: upodate * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update * refactor: update package json * refactor: add biome * refactor: add sponsors * refactor: update * refactor: update * refactor: remove * refactor: update * refactor: update * refactor: update * refactor: update scripts * refactor: remove * refactor: update * refactor: remove --------- Co-authored-by: Turbobot <turbobot@vercel.com>
This commit is contained in:
476
apps/dokploy/__test__/compose/compose.test.ts
Normal file
476
apps/dokploy/__test__/compose/compose.test.ts
Normal file
@@ -0,0 +1,476 @@
|
||||
import { addPrefixToAllProperties } from "@/server/utils/docker/compose";
|
||||
import type { ComposeSpecification } from "@/server/utils/docker/types";
|
||||
import { load } from "js-yaml";
|
||||
import { expect, test } from "vitest";
|
||||
|
||||
const composeFile1 = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
web:
|
||||
image: nginx:latest
|
||||
container_name: web_container
|
||||
depends_on:
|
||||
- app
|
||||
networks:
|
||||
- frontend
|
||||
volumes_from:
|
||||
- data
|
||||
links:
|
||||
- db
|
||||
extends:
|
||||
service: base_service
|
||||
configs:
|
||||
- source: web_config
|
||||
|
||||
app:
|
||||
image: node:14
|
||||
networks:
|
||||
- backend
|
||||
- frontend
|
||||
|
||||
db:
|
||||
image: postgres:13
|
||||
networks:
|
||||
- backend
|
||||
|
||||
data:
|
||||
image: busybox
|
||||
volumes:
|
||||
- /data
|
||||
|
||||
base_service:
|
||||
image: base:latest
|
||||
|
||||
networks:
|
||||
frontend:
|
||||
driver: bridge
|
||||
backend:
|
||||
driver: bridge
|
||||
|
||||
volumes:
|
||||
web_data:
|
||||
driver: local
|
||||
|
||||
configs:
|
||||
web_config:
|
||||
file: ./web_config.yml
|
||||
|
||||
secrets:
|
||||
db_password:
|
||||
file: ./db_password.txt
|
||||
`;
|
||||
|
||||
const expectedComposeFile1 = load(`
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
web-testhash:
|
||||
image: nginx:latest
|
||||
container_name: web_container-testhash
|
||||
depends_on:
|
||||
- app-testhash
|
||||
networks:
|
||||
- frontend-testhash
|
||||
volumes_from:
|
||||
- data-testhash
|
||||
links:
|
||||
- db-testhash
|
||||
extends:
|
||||
service: base_service-testhash
|
||||
configs:
|
||||
- source: web_config-testhash
|
||||
|
||||
app-testhash:
|
||||
image: node:14
|
||||
networks:
|
||||
- backend-testhash
|
||||
- frontend-testhash
|
||||
|
||||
db-testhash:
|
||||
image: postgres:13
|
||||
networks:
|
||||
- backend-testhash
|
||||
|
||||
data-testhash:
|
||||
image: busybox
|
||||
volumes:
|
||||
- /data
|
||||
|
||||
base_service-testhash:
|
||||
image: base:latest
|
||||
|
||||
networks:
|
||||
frontend-testhash:
|
||||
driver: bridge
|
||||
backend-testhash:
|
||||
driver: bridge
|
||||
|
||||
volumes:
|
||||
web_data-testhash:
|
||||
driver: local
|
||||
|
||||
configs:
|
||||
web_config-testhash:
|
||||
file: ./web_config.yml
|
||||
|
||||
secrets:
|
||||
db_password-testhash:
|
||||
file: ./db_password.txt
|
||||
`) as ComposeSpecification;
|
||||
|
||||
test("Add prefix to all properties in compose file 1", () => {
|
||||
const composeData = load(composeFile1) as ComposeSpecification;
|
||||
const prefix = "testhash";
|
||||
|
||||
const updatedComposeData = addPrefixToAllProperties(composeData, prefix);
|
||||
|
||||
expect(updatedComposeData).toEqual(expectedComposeFile1);
|
||||
});
|
||||
|
||||
const composeFile2 = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
frontend:
|
||||
image: nginx:latest
|
||||
depends_on:
|
||||
- backend
|
||||
networks:
|
||||
- public
|
||||
volumes_from:
|
||||
- logs
|
||||
links:
|
||||
- cache
|
||||
extends:
|
||||
service: shared_service
|
||||
secrets:
|
||||
- db_password
|
||||
|
||||
backend:
|
||||
image: node:14
|
||||
networks:
|
||||
- private
|
||||
- public
|
||||
|
||||
cache:
|
||||
image: redis:latest
|
||||
networks:
|
||||
- private
|
||||
|
||||
logs:
|
||||
image: busybox
|
||||
volumes:
|
||||
- /logs
|
||||
|
||||
shared_service:
|
||||
image: shared:latest
|
||||
|
||||
networks:
|
||||
public:
|
||||
driver: bridge
|
||||
private:
|
||||
driver: bridge
|
||||
|
||||
volumes:
|
||||
logs:
|
||||
driver: local
|
||||
|
||||
configs:
|
||||
app_config:
|
||||
file: ./app_config.yml
|
||||
|
||||
secrets:
|
||||
db_password:
|
||||
file: ./db_password.txt
|
||||
`;
|
||||
|
||||
const expectedComposeFile2 = load(`
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
frontend-testhash:
|
||||
image: nginx:latest
|
||||
depends_on:
|
||||
- backend-testhash
|
||||
networks:
|
||||
- public-testhash
|
||||
volumes_from:
|
||||
- logs-testhash
|
||||
links:
|
||||
- cache-testhash
|
||||
extends:
|
||||
service: shared_service-testhash
|
||||
secrets:
|
||||
- db_password-testhash
|
||||
|
||||
backend-testhash:
|
||||
image: node:14
|
||||
networks:
|
||||
- private-testhash
|
||||
- public-testhash
|
||||
|
||||
cache-testhash:
|
||||
image: redis:latest
|
||||
networks:
|
||||
- private-testhash
|
||||
|
||||
logs-testhash:
|
||||
image: busybox
|
||||
volumes:
|
||||
- /logs
|
||||
|
||||
shared_service-testhash:
|
||||
image: shared:latest
|
||||
|
||||
networks:
|
||||
public-testhash:
|
||||
driver: bridge
|
||||
private-testhash:
|
||||
driver: bridge
|
||||
|
||||
volumes:
|
||||
logs-testhash:
|
||||
driver: local
|
||||
|
||||
configs:
|
||||
app_config-testhash:
|
||||
file: ./app_config.yml
|
||||
|
||||
secrets:
|
||||
db_password-testhash:
|
||||
file: ./db_password.txt
|
||||
`) as ComposeSpecification;
|
||||
|
||||
test("Add prefix to all properties in compose file 2", () => {
|
||||
const composeData = load(composeFile2) as ComposeSpecification;
|
||||
const prefix = "testhash";
|
||||
|
||||
const updatedComposeData = addPrefixToAllProperties(composeData, prefix);
|
||||
|
||||
expect(updatedComposeData).toEqual(expectedComposeFile2);
|
||||
});
|
||||
|
||||
const composeFile3 = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
service_a:
|
||||
image: service_a:latest
|
||||
depends_on:
|
||||
- service_b
|
||||
networks:
|
||||
- net_a
|
||||
volumes_from:
|
||||
- data_volume
|
||||
links:
|
||||
- service_c
|
||||
extends:
|
||||
service: common_service
|
||||
configs:
|
||||
- source: service_a_config
|
||||
|
||||
service_b:
|
||||
image: service_b:latest
|
||||
networks:
|
||||
- net_b
|
||||
- net_a
|
||||
|
||||
service_c:
|
||||
image: service_c:latest
|
||||
networks:
|
||||
- net_b
|
||||
|
||||
data_volume:
|
||||
image: busybox
|
||||
volumes:
|
||||
- /data
|
||||
|
||||
common_service:
|
||||
image: common:latest
|
||||
|
||||
networks:
|
||||
net_a:
|
||||
driver: bridge
|
||||
net_b:
|
||||
driver: bridge
|
||||
|
||||
volumes:
|
||||
data_volume:
|
||||
driver: local
|
||||
|
||||
configs:
|
||||
service_a_config:
|
||||
file: ./service_a_config.yml
|
||||
|
||||
secrets:
|
||||
service_secret:
|
||||
file: ./service_secret.txt
|
||||
`;
|
||||
|
||||
const expectedComposeFile3 = load(`
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
service_a-testhash:
|
||||
image: service_a:latest
|
||||
depends_on:
|
||||
- service_b-testhash
|
||||
networks:
|
||||
- net_a-testhash
|
||||
volumes_from:
|
||||
- data_volume-testhash
|
||||
links:
|
||||
- service_c-testhash
|
||||
extends:
|
||||
service: common_service-testhash
|
||||
configs:
|
||||
- source: service_a_config-testhash
|
||||
|
||||
service_b-testhash:
|
||||
image: service_b:latest
|
||||
networks:
|
||||
- net_b-testhash
|
||||
- net_a-testhash
|
||||
|
||||
service_c-testhash:
|
||||
image: service_c:latest
|
||||
networks:
|
||||
- net_b-testhash
|
||||
|
||||
data_volume-testhash:
|
||||
image: busybox
|
||||
volumes:
|
||||
- /data
|
||||
|
||||
common_service-testhash:
|
||||
image: common:latest
|
||||
|
||||
networks:
|
||||
net_a-testhash:
|
||||
driver: bridge
|
||||
net_b-testhash:
|
||||
driver: bridge
|
||||
|
||||
volumes:
|
||||
data_volume-testhash:
|
||||
driver: local
|
||||
|
||||
configs:
|
||||
service_a_config-testhash:
|
||||
file: ./service_a_config.yml
|
||||
|
||||
secrets:
|
||||
service_secret-testhash:
|
||||
file: ./service_secret.txt
|
||||
`) as ComposeSpecification;
|
||||
|
||||
test("Add prefix to all properties in compose file 3", () => {
|
||||
const composeData = load(composeFile3) as ComposeSpecification;
|
||||
const prefix = "testhash";
|
||||
|
||||
const updatedComposeData = addPrefixToAllProperties(composeData, prefix);
|
||||
|
||||
expect(updatedComposeData).toEqual(expectedComposeFile3);
|
||||
});
|
||||
|
||||
const composeFile = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
plausible_db:
|
||||
image: postgres:16-alpine
|
||||
restart: always
|
||||
volumes:
|
||||
- db-data:/var/lib/postgresql/data
|
||||
environment:
|
||||
- POSTGRES_PASSWORD=postgres
|
||||
|
||||
plausible_events_db:
|
||||
image: clickhouse/clickhouse-server:24.3.3.102-alpine
|
||||
restart: always
|
||||
volumes:
|
||||
- event-data:/var/lib/clickhouse
|
||||
- event-logs:/var/log/clickhouse-server
|
||||
- ./clickhouse/clickhouse-config.xml:/etc/clickhouse-server/config.d/logging.xml:ro
|
||||
- ./clickhouse/clickhouse-user-config.xml:/etc/clickhouse-server/users.d/logging.xml:ro
|
||||
ulimits:
|
||||
nofile:
|
||||
soft: 262144
|
||||
hard: 262144
|
||||
|
||||
plausible:
|
||||
image: ghcr.io/plausible/community-edition:v2.1.0
|
||||
restart: always
|
||||
command: sh -c "sleep 10 && /entrypoint.sh db createdb && /entrypoint.sh db migrate && /entrypoint.sh run"
|
||||
depends_on:
|
||||
- plausible_db
|
||||
- plausible_events_db
|
||||
ports:
|
||||
- 127.0.0.1:8000:8000
|
||||
env_file:
|
||||
- plausible-conf.env
|
||||
|
||||
volumes:
|
||||
db-data:
|
||||
driver: local
|
||||
event-data:
|
||||
driver: local
|
||||
event-logs:
|
||||
driver: local
|
||||
`;
|
||||
|
||||
const expectedComposeFile = load(`
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
plausible_db-testhash:
|
||||
image: postgres:16-alpine
|
||||
restart: always
|
||||
volumes:
|
||||
- db-data-testhash:/var/lib/postgresql/data
|
||||
environment:
|
||||
- POSTGRES_PASSWORD=postgres
|
||||
|
||||
plausible_events_db-testhash:
|
||||
image: clickhouse/clickhouse-server:24.3.3.102-alpine
|
||||
restart: always
|
||||
volumes:
|
||||
- event-data-testhash:/var/lib/clickhouse
|
||||
- event-logs-testhash:/var/log/clickhouse-server
|
||||
- ./clickhouse/clickhouse-config.xml:/etc/clickhouse-server/config.d/logging.xml:ro
|
||||
- ./clickhouse/clickhouse-user-config.xml:/etc/clickhouse-server/users.d/logging.xml:ro
|
||||
ulimits:
|
||||
nofile:
|
||||
soft: 262144
|
||||
hard: 262144
|
||||
|
||||
plausible-testhash:
|
||||
image: ghcr.io/plausible/community-edition:v2.1.0
|
||||
restart: always
|
||||
command: sh -c "sleep 10 && /entrypoint.sh db createdb && /entrypoint.sh db migrate && /entrypoint.sh run"
|
||||
depends_on:
|
||||
- plausible_db-testhash
|
||||
- plausible_events_db-testhash
|
||||
ports:
|
||||
- 127.0.0.1:8000:8000
|
||||
env_file:
|
||||
- plausible-conf.env
|
||||
|
||||
volumes:
|
||||
db-data-testhash:
|
||||
driver: local
|
||||
event-data-testhash:
|
||||
driver: local
|
||||
event-logs-testhash:
|
||||
driver: local
|
||||
`) as ComposeSpecification;
|
||||
|
||||
test("Add prefix to all properties in Plausible compose file", () => {
|
||||
const composeData = load(composeFile) as ComposeSpecification;
|
||||
const prefix = "testhash";
|
||||
|
||||
const updatedComposeData = addPrefixToAllProperties(composeData, prefix);
|
||||
|
||||
expect(updatedComposeData).toEqual(expectedComposeFile);
|
||||
});
|
||||
178
apps/dokploy/__test__/compose/config/config-root.test.ts
Normal file
178
apps/dokploy/__test__/compose/config/config-root.test.ts
Normal file
@@ -0,0 +1,178 @@
|
||||
import { generateRandomHash } from "@/server/utils/docker/compose";
|
||||
import { addPrefixToConfigsRoot } from "@/server/utils/docker/compose/configs";
|
||||
import type { ComposeSpecification } from "@/server/utils/docker/types";
|
||||
import { load } from "js-yaml";
|
||||
import { expect, test } from "vitest";
|
||||
|
||||
test("Generate random hash with 8 characters", () => {
|
||||
const hash = generateRandomHash();
|
||||
|
||||
expect(hash).toBeDefined();
|
||||
expect(hash.length).toBe(8);
|
||||
});
|
||||
|
||||
const composeFile = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
web:
|
||||
image: nginx:latest
|
||||
|
||||
configs:
|
||||
web-config:
|
||||
file: ./web-config.yml
|
||||
`;
|
||||
|
||||
test("Add prefix to configs in root property", () => {
|
||||
const composeData = load(composeFile) as ComposeSpecification;
|
||||
|
||||
const prefix = generateRandomHash();
|
||||
|
||||
if (!composeData?.configs) {
|
||||
return;
|
||||
}
|
||||
const configs = addPrefixToConfigsRoot(composeData.configs, prefix);
|
||||
|
||||
expect(configs).toBeDefined();
|
||||
for (const configKey of Object.keys(configs)) {
|
||||
expect(configKey).toContain(`-${prefix}`);
|
||||
expect(configs[configKey]).toBeDefined();
|
||||
}
|
||||
});
|
||||
|
||||
const composeFileMultipleConfigs = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
web:
|
||||
image: nginx:latest
|
||||
configs:
|
||||
- source: web-config
|
||||
target: /etc/nginx/nginx.conf
|
||||
- source: another-config
|
||||
target: /etc/nginx/another.conf
|
||||
|
||||
configs:
|
||||
web-config:
|
||||
file: ./web-config.yml
|
||||
another-config:
|
||||
file: ./another-config.yml
|
||||
`;
|
||||
|
||||
test("Add prefix to multiple configs in root property", () => {
|
||||
const composeData = load(composeFileMultipleConfigs) as ComposeSpecification;
|
||||
|
||||
const prefix = generateRandomHash();
|
||||
|
||||
if (!composeData?.configs) {
|
||||
return;
|
||||
}
|
||||
const configs = addPrefixToConfigsRoot(composeData.configs, prefix);
|
||||
|
||||
expect(configs).toBeDefined();
|
||||
for (const configKey of Object.keys(configs)) {
|
||||
expect(configKey).toContain(`-${prefix}`);
|
||||
expect(configs[configKey]).toBeDefined();
|
||||
}
|
||||
expect(configs).toHaveProperty(`web-config-${prefix}`);
|
||||
expect(configs).toHaveProperty(`another-config-${prefix}`);
|
||||
});
|
||||
|
||||
const composeFileDifferentProperties = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
web:
|
||||
image: nginx:latest
|
||||
|
||||
configs:
|
||||
web-config:
|
||||
file: ./web-config.yml
|
||||
special-config:
|
||||
external: true
|
||||
`;
|
||||
|
||||
test("Add prefix to configs with different properties in root property", () => {
|
||||
const composeData = load(
|
||||
composeFileDifferentProperties,
|
||||
) as ComposeSpecification;
|
||||
|
||||
const prefix = generateRandomHash();
|
||||
|
||||
if (!composeData?.configs) {
|
||||
return;
|
||||
}
|
||||
const configs = addPrefixToConfigsRoot(composeData.configs, prefix);
|
||||
|
||||
expect(configs).toBeDefined();
|
||||
for (const configKey of Object.keys(configs)) {
|
||||
expect(configKey).toContain(`-${prefix}`);
|
||||
expect(configs[configKey]).toBeDefined();
|
||||
}
|
||||
expect(configs).toHaveProperty(`web-config-${prefix}`);
|
||||
expect(configs).toHaveProperty(`special-config-${prefix}`);
|
||||
});
|
||||
|
||||
const composeFileConfigRoot = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
web:
|
||||
image: nginx:latest
|
||||
|
||||
app:
|
||||
image: node:latest
|
||||
|
||||
db:
|
||||
image: postgres:latest
|
||||
|
||||
configs:
|
||||
web_config:
|
||||
file: ./web-config.yml
|
||||
|
||||
app_config:
|
||||
file: ./app-config.json
|
||||
|
||||
db_config:
|
||||
file: ./db-config.yml
|
||||
`;
|
||||
|
||||
// Expected compose file con el prefijo `testhash`
|
||||
const expectedComposeFileConfigRoot = load(`
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
web:
|
||||
image: nginx:latest
|
||||
|
||||
app:
|
||||
image: node:latest
|
||||
|
||||
db:
|
||||
image: postgres:latest
|
||||
|
||||
configs:
|
||||
web_config-testhash:
|
||||
file: ./web-config.yml
|
||||
|
||||
app_config-testhash:
|
||||
file: ./app-config.json
|
||||
|
||||
db_config-testhash:
|
||||
file: ./db-config.yml
|
||||
`) as ComposeSpecification;
|
||||
|
||||
test("Add prefix to configs in root property", () => {
|
||||
const composeData = load(composeFileConfigRoot) as ComposeSpecification;
|
||||
|
||||
const prefix = "testhash";
|
||||
|
||||
if (!composeData?.configs) {
|
||||
return;
|
||||
}
|
||||
const configs = addPrefixToConfigsRoot(composeData.configs, prefix);
|
||||
const updatedComposeData = { ...composeData, configs };
|
||||
|
||||
// Verificar que el resultado coincide con el archivo esperado
|
||||
expect(updatedComposeData).toEqual(expectedComposeFileConfigRoot);
|
||||
});
|
||||
197
apps/dokploy/__test__/compose/config/config-service.test.ts
Normal file
197
apps/dokploy/__test__/compose/config/config-service.test.ts
Normal file
@@ -0,0 +1,197 @@
|
||||
import { generateRandomHash } from "@/server/utils/docker/compose";
|
||||
import { addPrefixToConfigsInServices } from "@/server/utils/docker/compose/configs";
|
||||
import type { ComposeSpecification } from "@/server/utils/docker/types";
|
||||
import { load } from "js-yaml";
|
||||
import { expect, test } from "vitest";
|
||||
|
||||
const composeFile = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
web:
|
||||
image: nginx:latest
|
||||
configs:
|
||||
- source: web-config
|
||||
target: /etc/nginx/nginx.conf
|
||||
|
||||
configs:
|
||||
web-config:
|
||||
file: ./web-config.yml
|
||||
`;
|
||||
|
||||
test("Add prefix to configs in services", () => {
|
||||
const composeData = load(composeFile) as ComposeSpecification;
|
||||
|
||||
const prefix = generateRandomHash();
|
||||
|
||||
if (!composeData?.services) {
|
||||
return;
|
||||
}
|
||||
const services = addPrefixToConfigsInServices(composeData.services, prefix);
|
||||
const actualComposeData = { ...composeData, services };
|
||||
|
||||
expect(actualComposeData.services?.web?.configs).toContainEqual({
|
||||
source: `web-config-${prefix}`,
|
||||
target: "/etc/nginx/nginx.conf",
|
||||
});
|
||||
});
|
||||
|
||||
const composeFileSingleServiceConfig = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
web:
|
||||
image: nginx:latest
|
||||
configs:
|
||||
- source: web-config
|
||||
target: /etc/nginx/nginx.conf
|
||||
|
||||
configs:
|
||||
web-config:
|
||||
file: ./web-config.yml
|
||||
`;
|
||||
|
||||
test("Add prefix to configs in services with single config", () => {
|
||||
const composeData = load(
|
||||
composeFileSingleServiceConfig,
|
||||
) as ComposeSpecification;
|
||||
|
||||
const prefix = generateRandomHash();
|
||||
|
||||
if (!composeData?.services) {
|
||||
return;
|
||||
}
|
||||
const services = addPrefixToConfigsInServices(composeData.services, prefix);
|
||||
|
||||
expect(services).toBeDefined();
|
||||
for (const serviceKey of Object.keys(services)) {
|
||||
const serviceConfigs = services?.[serviceKey]?.configs;
|
||||
if (serviceConfigs) {
|
||||
for (const config of serviceConfigs) {
|
||||
if (typeof config === "object") {
|
||||
expect(config.source).toContain(`-${prefix}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const composeFileMultipleServicesConfigs = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
web:
|
||||
image: nginx:latest
|
||||
configs:
|
||||
- source: web-config
|
||||
target: /etc/nginx/nginx.conf
|
||||
- source: common-config
|
||||
target: /etc/nginx/common.conf
|
||||
|
||||
app:
|
||||
image: node:14
|
||||
configs:
|
||||
- source: app-config
|
||||
target: /usr/src/app/config.json
|
||||
- source: common-config
|
||||
target: /usr/src/app/common.json
|
||||
|
||||
configs:
|
||||
web-config:
|
||||
file: ./web-config.yml
|
||||
app-config:
|
||||
file: ./app-config.json
|
||||
common-config:
|
||||
file: ./common-config.yml
|
||||
`;
|
||||
|
||||
test("Add prefix to configs in services with multiple configs", () => {
|
||||
const composeData = load(
|
||||
composeFileMultipleServicesConfigs,
|
||||
) as ComposeSpecification;
|
||||
|
||||
const prefix = generateRandomHash();
|
||||
|
||||
if (!composeData?.services) {
|
||||
return;
|
||||
}
|
||||
const services = addPrefixToConfigsInServices(composeData.services, prefix);
|
||||
|
||||
expect(services).toBeDefined();
|
||||
for (const serviceKey of Object.keys(services)) {
|
||||
const serviceConfigs = services?.[serviceKey]?.configs;
|
||||
if (serviceConfigs) {
|
||||
for (const config of serviceConfigs) {
|
||||
if (typeof config === "object") {
|
||||
expect(config.source).toContain(`-${prefix}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const composeFileConfigServices = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
web:
|
||||
image: nginx:latest
|
||||
configs:
|
||||
- source: web_config
|
||||
target: /etc/nginx/nginx.conf
|
||||
|
||||
app:
|
||||
image: node:latest
|
||||
configs:
|
||||
- source: app_config
|
||||
target: /usr/src/app/config.json
|
||||
|
||||
db:
|
||||
image: postgres:latest
|
||||
configs:
|
||||
- source: db_config
|
||||
target: /etc/postgresql/postgresql.conf
|
||||
|
||||
`;
|
||||
|
||||
// Expected compose file con el prefijo `testhash`
|
||||
const expectedComposeFileConfigServices = load(`
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
web:
|
||||
image: nginx:latest
|
||||
configs:
|
||||
- source: web_config-testhash
|
||||
target: /etc/nginx/nginx.conf
|
||||
|
||||
app:
|
||||
image: node:latest
|
||||
configs:
|
||||
- source: app_config-testhash
|
||||
target: /usr/src/app/config.json
|
||||
|
||||
db:
|
||||
image: postgres:latest
|
||||
configs:
|
||||
- source: db_config-testhash
|
||||
target: /etc/postgresql/postgresql.conf
|
||||
|
||||
`) as ComposeSpecification;
|
||||
|
||||
test("Add prefix to configs in services", () => {
|
||||
const composeData = load(composeFileConfigServices) as ComposeSpecification;
|
||||
|
||||
const prefix = "testhash";
|
||||
|
||||
if (!composeData?.services) {
|
||||
return;
|
||||
}
|
||||
const updatedComposeData = addPrefixToConfigsInServices(
|
||||
composeData.services,
|
||||
prefix,
|
||||
);
|
||||
const actualComposeData = { ...composeData, services: updatedComposeData };
|
||||
|
||||
expect(actualComposeData).toEqual(expectedComposeFileConfigServices);
|
||||
});
|
||||
249
apps/dokploy/__test__/compose/config/config.test.ts
Normal file
249
apps/dokploy/__test__/compose/config/config.test.ts
Normal file
@@ -0,0 +1,249 @@
|
||||
import { generateRandomHash } from "@/server/utils/docker/compose";
|
||||
import {
|
||||
addPrefixToAllConfigs,
|
||||
addPrefixToConfigsRoot,
|
||||
} from "@/server/utils/docker/compose/configs";
|
||||
import type { ComposeSpecification } from "@/server/utils/docker/types";
|
||||
import { load } from "js-yaml";
|
||||
import { expect, test } from "vitest";
|
||||
|
||||
test("Generate random hash with 8 characters", () => {
|
||||
const hash = generateRandomHash();
|
||||
|
||||
expect(hash).toBeDefined();
|
||||
expect(hash.length).toBe(8);
|
||||
});
|
||||
|
||||
const composeFileCombinedConfigs = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
web:
|
||||
image: nginx:latest
|
||||
configs:
|
||||
- source: web_config
|
||||
target: /etc/nginx/nginx.conf
|
||||
|
||||
app:
|
||||
image: node:14
|
||||
configs:
|
||||
- source: app_config
|
||||
target: /usr/src/app/config.json
|
||||
|
||||
db:
|
||||
image: postgres:13
|
||||
configs:
|
||||
- source: db_config
|
||||
target: /etc/postgresql/postgresql.conf
|
||||
|
||||
configs:
|
||||
web_config:
|
||||
file: ./web-config.yml
|
||||
|
||||
app_config:
|
||||
file: ./app-config.json
|
||||
|
||||
db_config:
|
||||
file: ./db-config.yml
|
||||
`;
|
||||
|
||||
const expectedComposeFileCombinedConfigs = load(`
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
web:
|
||||
image: nginx:latest
|
||||
configs:
|
||||
- source: web_config-testhash
|
||||
target: /etc/nginx/nginx.conf
|
||||
|
||||
app:
|
||||
image: node:14
|
||||
configs:
|
||||
- source: app_config-testhash
|
||||
target: /usr/src/app/config.json
|
||||
|
||||
db:
|
||||
image: postgres:13
|
||||
configs:
|
||||
- source: db_config-testhash
|
||||
target: /etc/postgresql/postgresql.conf
|
||||
|
||||
configs:
|
||||
web_config-testhash:
|
||||
file: ./web-config.yml
|
||||
|
||||
app_config-testhash:
|
||||
file: ./app-config.json
|
||||
|
||||
db_config-testhash:
|
||||
file: ./db-config.yml
|
||||
`) as ComposeSpecification;
|
||||
|
||||
test("Add prefix to all configs in root and services", () => {
|
||||
const composeData = load(composeFileCombinedConfigs) as ComposeSpecification;
|
||||
|
||||
const prefix = "testhash";
|
||||
|
||||
const updatedComposeData = addPrefixToAllConfigs(composeData, prefix);
|
||||
|
||||
expect(updatedComposeData).toEqual(expectedComposeFileCombinedConfigs);
|
||||
});
|
||||
|
||||
const composeFileWithEnvAndExternal = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
web:
|
||||
image: nginx:latest
|
||||
configs:
|
||||
- source: web_config
|
||||
target: /etc/nginx/nginx.conf
|
||||
environment:
|
||||
- NGINX_CONFIG=/etc/nginx/nginx.conf
|
||||
|
||||
app:
|
||||
image: node:14
|
||||
configs:
|
||||
- source: app_config
|
||||
target: /usr/src/app/config.json
|
||||
|
||||
db:
|
||||
image: postgres:13
|
||||
configs:
|
||||
- source: db_config
|
||||
target: /etc/postgresql/postgresql.conf
|
||||
|
||||
configs:
|
||||
web_config:
|
||||
external: true
|
||||
|
||||
app_config:
|
||||
file: ./app-config.json
|
||||
|
||||
db_config:
|
||||
environment: dev
|
||||
file: ./db-config.yml
|
||||
`;
|
||||
|
||||
const expectedComposeFileWithEnvAndExternal = load(`
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
web:
|
||||
image: nginx:latest
|
||||
configs:
|
||||
- source: web_config-testhash
|
||||
target: /etc/nginx/nginx.conf
|
||||
environment:
|
||||
- NGINX_CONFIG=/etc/nginx/nginx.conf
|
||||
|
||||
app:
|
||||
image: node:14
|
||||
configs:
|
||||
- source: app_config-testhash
|
||||
target: /usr/src/app/config.json
|
||||
|
||||
db:
|
||||
image: postgres:13
|
||||
configs:
|
||||
- source: db_config-testhash
|
||||
target: /etc/postgresql/postgresql.conf
|
||||
|
||||
configs:
|
||||
web_config-testhash:
|
||||
external: true
|
||||
|
||||
app_config-testhash:
|
||||
file: ./app-config.json
|
||||
|
||||
db_config-testhash:
|
||||
environment: dev
|
||||
file: ./db-config.yml
|
||||
`) as ComposeSpecification;
|
||||
|
||||
test("Add prefix to configs with environment and external", () => {
|
||||
const composeData = load(
|
||||
composeFileWithEnvAndExternal,
|
||||
) as ComposeSpecification;
|
||||
|
||||
const prefix = "testhash";
|
||||
|
||||
const updatedComposeData = addPrefixToAllConfigs(composeData, prefix);
|
||||
|
||||
expect(updatedComposeData).toEqual(expectedComposeFileWithEnvAndExternal);
|
||||
});
|
||||
|
||||
const composeFileWithTemplateDriverAndLabels = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
web:
|
||||
image: nginx:latest
|
||||
configs:
|
||||
- source: web_config
|
||||
target: /etc/nginx/nginx.conf
|
||||
|
||||
app:
|
||||
image: node:14
|
||||
configs:
|
||||
- source: app_config
|
||||
target: /usr/src/app/config.json
|
||||
|
||||
configs:
|
||||
web_config:
|
||||
file: ./web-config.yml
|
||||
template_driver: golang
|
||||
|
||||
app_config:
|
||||
file: ./app-config.json
|
||||
labels:
|
||||
- app=frontend
|
||||
|
||||
db_config:
|
||||
file: ./db-config.yml
|
||||
`;
|
||||
|
||||
const expectedComposeFileWithTemplateDriverAndLabels = load(`
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
web:
|
||||
image: nginx:latest
|
||||
configs:
|
||||
- source: web_config-testhash
|
||||
target: /etc/nginx/nginx.conf
|
||||
|
||||
app:
|
||||
image: node:14
|
||||
configs:
|
||||
- source: app_config-testhash
|
||||
target: /usr/src/app/config.json
|
||||
|
||||
configs:
|
||||
web_config-testhash:
|
||||
file: ./web-config.yml
|
||||
template_driver: golang
|
||||
|
||||
app_config-testhash:
|
||||
file: ./app-config.json
|
||||
labels:
|
||||
- app=frontend
|
||||
|
||||
db_config-testhash:
|
||||
file: ./db-config.yml
|
||||
`) as ComposeSpecification;
|
||||
|
||||
test("Add prefix to configs with template driver and labels", () => {
|
||||
const composeData = load(
|
||||
composeFileWithTemplateDriverAndLabels,
|
||||
) as ComposeSpecification;
|
||||
|
||||
const prefix = "testhash";
|
||||
|
||||
const updatedComposeData = addPrefixToAllConfigs(composeData, prefix);
|
||||
|
||||
expect(updatedComposeData).toEqual(
|
||||
expectedComposeFileWithTemplateDriverAndLabels,
|
||||
);
|
||||
});
|
||||
281
apps/dokploy/__test__/compose/network/network-root.test.ts
Normal file
281
apps/dokploy/__test__/compose/network/network-root.test.ts
Normal file
@@ -0,0 +1,281 @@
|
||||
import { generateRandomHash } from "@/server/utils/docker/compose";
|
||||
import { addPrefixToNetworksRoot } from "@/server/utils/docker/compose/network";
|
||||
import type { ComposeSpecification } from "@/server/utils/docker/types";
|
||||
import { load } from "js-yaml";
|
||||
import { expect, test } from "vitest";
|
||||
|
||||
const composeFile = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
web:
|
||||
image: nginx:latest
|
||||
networks:
|
||||
- frontend
|
||||
|
||||
networks:
|
||||
frontend:
|
||||
driver: bridge
|
||||
driver_opts:
|
||||
com.docker.network.driver.mtu: 1200
|
||||
|
||||
backend:
|
||||
driver: bridge
|
||||
attachable: true
|
||||
|
||||
external_network:
|
||||
external: true
|
||||
|
||||
`;
|
||||
|
||||
test("Generate random hash with 8 characters", () => {
|
||||
const hash = generateRandomHash();
|
||||
|
||||
expect(hash).toBeDefined();
|
||||
expect(hash.length).toBe(8);
|
||||
});
|
||||
|
||||
test("Add prefix to networks root property", () => {
|
||||
const composeData = load(composeFile) as ComposeSpecification;
|
||||
|
||||
const prefix = generateRandomHash();
|
||||
|
||||
if (!composeData?.networks) {
|
||||
return;
|
||||
}
|
||||
const networks = addPrefixToNetworksRoot(composeData.networks, prefix);
|
||||
|
||||
expect(networks).toBeDefined();
|
||||
for (const volumeKey of Object.keys(networks)) {
|
||||
expect(volumeKey).toContain(`-${prefix}`);
|
||||
}
|
||||
});
|
||||
|
||||
const composeFile2 = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
app:
|
||||
image: myapp:latest
|
||||
networks:
|
||||
- app_net
|
||||
|
||||
networks:
|
||||
app_net:
|
||||
driver: bridge
|
||||
driver_opts:
|
||||
com.docker.network.driver.mtu: 1500
|
||||
ipam:
|
||||
driver: default
|
||||
config:
|
||||
- subnet: 172.20.0.0/16
|
||||
|
||||
database_net:
|
||||
driver: overlay
|
||||
attachable: true
|
||||
|
||||
monitoring_net:
|
||||
driver: bridge
|
||||
internal: true
|
||||
`;
|
||||
|
||||
test("Add prefix to advanced networks root property (2 TRY)", () => {
|
||||
const composeData = load(composeFile2) as ComposeSpecification;
|
||||
|
||||
const prefix = generateRandomHash();
|
||||
|
||||
if (!composeData?.networks) {
|
||||
return;
|
||||
}
|
||||
const networks = addPrefixToNetworksRoot(composeData.networks, prefix);
|
||||
|
||||
expect(networks).toBeDefined();
|
||||
for (const networkKey of Object.keys(networks)) {
|
||||
expect(networkKey).toContain(`-${prefix}`);
|
||||
}
|
||||
});
|
||||
|
||||
const composeFile3 = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
web:
|
||||
image: nginx:latest
|
||||
networks:
|
||||
- frontend
|
||||
- backend
|
||||
|
||||
networks:
|
||||
frontend:
|
||||
external:
|
||||
name: my_external_network
|
||||
|
||||
backend:
|
||||
driver: bridge
|
||||
labels:
|
||||
- "com.example.description=Backend network"
|
||||
- "com.example.environment=production"
|
||||
|
||||
external_network:
|
||||
external: true
|
||||
`;
|
||||
|
||||
test("Add prefix to networks with external properties", () => {
|
||||
const composeData = load(composeFile3) as ComposeSpecification;
|
||||
|
||||
const prefix = generateRandomHash();
|
||||
|
||||
if (!composeData?.networks) {
|
||||
return;
|
||||
}
|
||||
const networks = addPrefixToNetworksRoot(composeData.networks, prefix);
|
||||
|
||||
expect(networks).toBeDefined();
|
||||
for (const networkKey of Object.keys(networks)) {
|
||||
expect(networkKey).toContain(`-${prefix}`);
|
||||
}
|
||||
});
|
||||
|
||||
const composeFile4 = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
db:
|
||||
image: postgres:13
|
||||
networks:
|
||||
- db_net
|
||||
|
||||
networks:
|
||||
db_net:
|
||||
driver: bridge
|
||||
ipam:
|
||||
config:
|
||||
- subnet: 192.168.1.0/24
|
||||
- gateway: 192.168.1.1
|
||||
- aux_addresses:
|
||||
host1: 192.168.1.2
|
||||
host2: 192.168.1.3
|
||||
|
||||
external_network:
|
||||
external: true
|
||||
`;
|
||||
|
||||
test("Add prefix to networks with IPAM configurations", () => {
|
||||
const composeData = load(composeFile4) as ComposeSpecification;
|
||||
|
||||
const prefix = generateRandomHash();
|
||||
|
||||
if (!composeData?.networks) {
|
||||
return;
|
||||
}
|
||||
const networks = addPrefixToNetworksRoot(composeData.networks, prefix);
|
||||
|
||||
expect(networks).toBeDefined();
|
||||
for (const networkKey of Object.keys(networks)) {
|
||||
expect(networkKey).toContain(`-${prefix}`);
|
||||
}
|
||||
});
|
||||
|
||||
const composeFile5 = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
api:
|
||||
image: myapi:latest
|
||||
networks:
|
||||
- api_net
|
||||
|
||||
networks:
|
||||
api_net:
|
||||
driver: bridge
|
||||
options:
|
||||
com.docker.network.bridge.name: br0
|
||||
enable_ipv6: true
|
||||
ipam:
|
||||
driver: default
|
||||
config:
|
||||
- subnet: "2001:db8:1::/64"
|
||||
- gateway: "2001:db8:1::1"
|
||||
|
||||
external_network:
|
||||
external: true
|
||||
`;
|
||||
|
||||
test("Add prefix to networks with custom options", () => {
|
||||
const composeData = load(composeFile5) as ComposeSpecification;
|
||||
|
||||
const prefix = generateRandomHash();
|
||||
|
||||
if (!composeData?.networks) {
|
||||
return;
|
||||
}
|
||||
const networks = addPrefixToNetworksRoot(composeData.networks, prefix);
|
||||
|
||||
expect(networks).toBeDefined();
|
||||
for (const networkKey of Object.keys(networks)) {
|
||||
expect(networkKey).toContain(`-${prefix}`);
|
||||
}
|
||||
});
|
||||
|
||||
const composeFile6 = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
web:
|
||||
image: nginx:latest
|
||||
networks:
|
||||
- frontend
|
||||
|
||||
networks:
|
||||
frontend:
|
||||
driver: bridge
|
||||
driver_opts:
|
||||
com.docker.network.driver.mtu: 1200
|
||||
|
||||
backend:
|
||||
driver: bridge
|
||||
attachable: true
|
||||
|
||||
external_network:
|
||||
external: true
|
||||
`;
|
||||
|
||||
// Expected compose file with static prefix `testhash`
|
||||
const expectedComposeFile6 = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
web:
|
||||
image: nginx:latest
|
||||
networks:
|
||||
- frontend-testhash
|
||||
|
||||
networks:
|
||||
frontend-testhash:
|
||||
driver: bridge
|
||||
driver_opts:
|
||||
com.docker.network.driver.mtu: 1200
|
||||
|
||||
backend-testhash:
|
||||
driver: bridge
|
||||
attachable: true
|
||||
|
||||
external_network-testhash:
|
||||
external: true
|
||||
`;
|
||||
|
||||
test("Add prefix to networks with static prefix", () => {
|
||||
const composeData = load(composeFile6) as ComposeSpecification;
|
||||
|
||||
const prefix = "testhash";
|
||||
|
||||
if (!composeData?.networks) {
|
||||
return;
|
||||
}
|
||||
const networks = addPrefixToNetworksRoot(composeData.networks, prefix);
|
||||
|
||||
const expectedComposeData = load(
|
||||
expectedComposeFile6,
|
||||
) as ComposeSpecification;
|
||||
expect(networks).toStrictEqual(expectedComposeData.networks);
|
||||
});
|
||||
184
apps/dokploy/__test__/compose/network/network-service.test.ts
Normal file
184
apps/dokploy/__test__/compose/network/network-service.test.ts
Normal file
@@ -0,0 +1,184 @@
|
||||
import { generateRandomHash } from "@/server/utils/docker/compose";
|
||||
import { addPrefixToServiceNetworks } from "@/server/utils/docker/compose/network";
|
||||
import type { ComposeSpecification } from "@/server/utils/docker/types";
|
||||
import { load } from "js-yaml";
|
||||
import { expect, test } from "vitest";
|
||||
|
||||
const composeFile = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
web:
|
||||
image: nginx:latest
|
||||
networks:
|
||||
- frontend
|
||||
- backend
|
||||
|
||||
api:
|
||||
image: myapi:latest
|
||||
networks:
|
||||
- backend
|
||||
`;
|
||||
|
||||
test("Add prefix to networks in services", () => {
|
||||
const composeData = load(composeFile) as ComposeSpecification;
|
||||
|
||||
const prefix = generateRandomHash();
|
||||
|
||||
if (!composeData?.services) {
|
||||
return;
|
||||
}
|
||||
const services = addPrefixToServiceNetworks(composeData.services, prefix);
|
||||
const actualComposeData = { ...composeData, services };
|
||||
|
||||
expect(actualComposeData?.services?.web?.networks).toContain(
|
||||
`frontend-${prefix}`,
|
||||
);
|
||||
|
||||
expect(actualComposeData?.services?.api?.networks).toContain(
|
||||
`backend-${prefix}`,
|
||||
);
|
||||
|
||||
const apiNetworks = actualComposeData?.services?.api?.networks;
|
||||
|
||||
expect(apiNetworks).toBeDefined();
|
||||
expect(actualComposeData?.services?.api?.networks).toContain(
|
||||
`backend-${prefix}`,
|
||||
);
|
||||
});
|
||||
|
||||
// Caso 2: Objeto con aliases
|
||||
const composeFile2 = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
api:
|
||||
image: myapi:latest
|
||||
networks:
|
||||
frontend:
|
||||
aliases:
|
||||
- api
|
||||
|
||||
networks:
|
||||
frontend:
|
||||
driver: bridge
|
||||
`;
|
||||
|
||||
test("Add prefix to networks in services with aliases", () => {
|
||||
const composeData = load(composeFile2) as ComposeSpecification;
|
||||
|
||||
const prefix = generateRandomHash();
|
||||
|
||||
if (!composeData?.services) {
|
||||
return;
|
||||
}
|
||||
const services = addPrefixToServiceNetworks(composeData.services, prefix);
|
||||
const actualComposeData = { ...composeData, services };
|
||||
|
||||
expect(actualComposeData.services?.api?.networks).toHaveProperty(
|
||||
`frontend-${prefix}`,
|
||||
);
|
||||
|
||||
const networkConfig = actualComposeData?.services?.api?.networks as {
|
||||
[key: string]: { aliases?: string[] };
|
||||
};
|
||||
expect(networkConfig[`frontend-${prefix}`]).toBeDefined();
|
||||
expect(networkConfig[`frontend-${prefix}`]?.aliases).toContain("api");
|
||||
|
||||
expect(actualComposeData.services?.api?.networks).not.toHaveProperty(
|
||||
"frontend-ash",
|
||||
);
|
||||
});
|
||||
|
||||
const composeFile3 = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
redis:
|
||||
image: redis:alpine
|
||||
networks:
|
||||
backend:
|
||||
|
||||
networks:
|
||||
backend:
|
||||
driver: bridge
|
||||
`;
|
||||
|
||||
test("Add prefix to networks in services (Object with simple networks)", () => {
|
||||
const composeData = load(composeFile3) as ComposeSpecification;
|
||||
|
||||
const prefix = generateRandomHash();
|
||||
|
||||
if (!composeData?.services) {
|
||||
return;
|
||||
}
|
||||
const services = addPrefixToServiceNetworks(composeData.services, prefix);
|
||||
const actualComposeData = { ...composeData, services };
|
||||
|
||||
expect(actualComposeData.services?.redis?.networks).toHaveProperty(
|
||||
`backend-${prefix}`,
|
||||
);
|
||||
});
|
||||
|
||||
const composeFileCombined = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
web:
|
||||
image: nginx:latest
|
||||
networks:
|
||||
- frontend
|
||||
- backend
|
||||
|
||||
api:
|
||||
image: myapi:latest
|
||||
networks:
|
||||
frontend:
|
||||
aliases:
|
||||
- api
|
||||
|
||||
redis:
|
||||
image: redis:alpine
|
||||
networks:
|
||||
backend:
|
||||
|
||||
networks:
|
||||
frontend:
|
||||
driver: bridge
|
||||
|
||||
backend:
|
||||
driver: bridge
|
||||
`;
|
||||
|
||||
test("Add prefix to networks in services (combined case)", () => {
|
||||
const composeData = load(composeFileCombined) as ComposeSpecification;
|
||||
|
||||
const prefix = generateRandomHash();
|
||||
|
||||
if (!composeData?.services) {
|
||||
return;
|
||||
}
|
||||
const services = addPrefixToServiceNetworks(composeData.services, prefix);
|
||||
const actualComposeData = { ...composeData, services };
|
||||
|
||||
// Caso 1: ListOfStrings
|
||||
expect(actualComposeData.services?.web?.networks).toContain(
|
||||
`frontend-${prefix}`,
|
||||
);
|
||||
expect(actualComposeData.services?.web?.networks).toContain(
|
||||
`backend-${prefix}`,
|
||||
);
|
||||
|
||||
// Caso 2: Objeto con aliases
|
||||
const apiNetworks = actualComposeData.services?.api?.networks as {
|
||||
[key: string]: unknown;
|
||||
};
|
||||
expect(apiNetworks).toHaveProperty(`frontend-${prefix}`);
|
||||
expect(apiNetworks[`frontend-${prefix}`]).toBeDefined();
|
||||
expect(apiNetworks).not.toHaveProperty("frontend");
|
||||
|
||||
// Caso 3: Objeto con redes simples
|
||||
const redisNetworks = actualComposeData.services?.redis?.networks;
|
||||
expect(redisNetworks).toHaveProperty(`backend-${prefix}`);
|
||||
expect(redisNetworks).not.toHaveProperty("backend");
|
||||
});
|
||||
256
apps/dokploy/__test__/compose/network/network.test.ts
Normal file
256
apps/dokploy/__test__/compose/network/network.test.ts
Normal file
@@ -0,0 +1,256 @@
|
||||
import { generateRandomHash } from "@/server/utils/docker/compose";
|
||||
import {
|
||||
addPrefixToAllNetworks,
|
||||
addPrefixToServiceNetworks,
|
||||
} from "@/server/utils/docker/compose/network";
|
||||
import { addPrefixToNetworksRoot } from "@/server/utils/docker/compose/network";
|
||||
import type { ComposeSpecification } from "@/server/utils/docker/types";
|
||||
import { load } from "js-yaml";
|
||||
import { expect, test } from "vitest";
|
||||
|
||||
const composeFileCombined = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
web:
|
||||
image: nginx:latest
|
||||
networks:
|
||||
- frontend
|
||||
- backend
|
||||
|
||||
api:
|
||||
image: myapi:latest
|
||||
networks:
|
||||
frontend:
|
||||
aliases:
|
||||
- api
|
||||
|
||||
redis:
|
||||
image: redis:alpine
|
||||
networks:
|
||||
backend:
|
||||
|
||||
networks:
|
||||
frontend:
|
||||
driver: bridge
|
||||
|
||||
backend:
|
||||
driver: bridge
|
||||
`;
|
||||
|
||||
test("Add prefix to networks in services and root (combined case)", () => {
|
||||
const composeData = load(composeFileCombined) as ComposeSpecification;
|
||||
|
||||
const prefix = generateRandomHash();
|
||||
|
||||
// Prefijo para redes definidas en el root
|
||||
if (composeData.networks) {
|
||||
composeData.networks = addPrefixToNetworksRoot(
|
||||
composeData.networks,
|
||||
prefix,
|
||||
);
|
||||
}
|
||||
|
||||
// Prefijo para redes definidas en los servicios
|
||||
if (composeData.services) {
|
||||
composeData.services = addPrefixToServiceNetworks(
|
||||
composeData.services,
|
||||
prefix,
|
||||
);
|
||||
}
|
||||
|
||||
const actualComposeData = { ...composeData };
|
||||
|
||||
// Verificar redes en root
|
||||
expect(actualComposeData.networks).toHaveProperty(`frontend-${prefix}`);
|
||||
expect(actualComposeData.networks).toHaveProperty(`backend-${prefix}`);
|
||||
expect(actualComposeData.networks).not.toHaveProperty("frontend");
|
||||
expect(actualComposeData.networks).not.toHaveProperty("backend");
|
||||
|
||||
// Caso 1: ListOfStrings
|
||||
expect(actualComposeData.services?.web?.networks).toContain(
|
||||
`frontend-${prefix}`,
|
||||
);
|
||||
expect(actualComposeData.services?.web?.networks).toContain(
|
||||
`backend-${prefix}`,
|
||||
);
|
||||
|
||||
// Caso 2: Objeto con aliases
|
||||
const apiNetworks = actualComposeData.services?.api?.networks as {
|
||||
[key: string]: { aliases?: string[] };
|
||||
};
|
||||
expect(apiNetworks).toHaveProperty(`frontend-${prefix}`);
|
||||
expect(apiNetworks?.[`frontend-${prefix}`]?.aliases).toContain("api");
|
||||
expect(apiNetworks).not.toHaveProperty("frontend");
|
||||
|
||||
// Caso 3: Objeto con redes simples
|
||||
const redisNetworks = actualComposeData.services?.redis?.networks;
|
||||
expect(redisNetworks).toHaveProperty(`backend-${prefix}`);
|
||||
expect(redisNetworks).not.toHaveProperty("backend");
|
||||
});
|
||||
|
||||
const expectedComposeFile = load(`
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
web:
|
||||
image: nginx:latest
|
||||
networks:
|
||||
- frontend-testhash
|
||||
- backend-testhash
|
||||
|
||||
api:
|
||||
image: myapi:latest
|
||||
networks:
|
||||
frontend-testhash:
|
||||
aliases:
|
||||
- api
|
||||
|
||||
redis:
|
||||
image: redis:alpine
|
||||
networks:
|
||||
backend-testhash:
|
||||
|
||||
networks:
|
||||
frontend-testhash:
|
||||
driver: bridge
|
||||
|
||||
backend-testhash:
|
||||
driver: bridge
|
||||
`);
|
||||
|
||||
test("Add prefix to networks in compose file", () => {
|
||||
const composeData = load(composeFileCombined) as ComposeSpecification;
|
||||
|
||||
const prefix = "testhash";
|
||||
if (!composeData?.networks) {
|
||||
return;
|
||||
}
|
||||
const updatedComposeData = addPrefixToAllNetworks(composeData, prefix);
|
||||
|
||||
expect(updatedComposeData).toEqual(expectedComposeFile);
|
||||
});
|
||||
|
||||
const composeFile2 = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
web:
|
||||
image: nginx:latest
|
||||
networks:
|
||||
- frontend
|
||||
- backend
|
||||
|
||||
db:
|
||||
image: postgres:latest
|
||||
networks:
|
||||
backend:
|
||||
aliases:
|
||||
- db
|
||||
|
||||
networks:
|
||||
frontend:
|
||||
external: true
|
||||
|
||||
backend:
|
||||
driver: bridge
|
||||
`;
|
||||
|
||||
const expectedComposeFile2 = load(`
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
web:
|
||||
image: nginx:latest
|
||||
networks:
|
||||
- frontend-testhash
|
||||
- backend-testhash
|
||||
|
||||
db:
|
||||
image: postgres:latest
|
||||
networks:
|
||||
backend-testhash:
|
||||
aliases:
|
||||
- db
|
||||
|
||||
networks:
|
||||
frontend-testhash:
|
||||
external: true
|
||||
|
||||
backend-testhash:
|
||||
driver: bridge
|
||||
`);
|
||||
|
||||
test("Add prefix to networks in compose file with external and internal networks", () => {
|
||||
const composeData = load(composeFile2) as ComposeSpecification;
|
||||
|
||||
const prefix = "testhash";
|
||||
const updatedComposeData = addPrefixToAllNetworks(composeData, prefix);
|
||||
|
||||
expect(updatedComposeData).toEqual(expectedComposeFile2);
|
||||
});
|
||||
|
||||
const composeFile3 = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
app:
|
||||
image: myapp:latest
|
||||
networks:
|
||||
frontend:
|
||||
aliases:
|
||||
- app
|
||||
backend:
|
||||
|
||||
worker:
|
||||
image: worker:latest
|
||||
networks:
|
||||
- backend
|
||||
|
||||
networks:
|
||||
frontend:
|
||||
driver: bridge
|
||||
attachable: true
|
||||
|
||||
backend:
|
||||
driver: bridge
|
||||
driver_opts:
|
||||
com.docker.network.bridge.enable_icc: "true"
|
||||
`;
|
||||
|
||||
const expectedComposeFile3 = load(`
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
app:
|
||||
image: myapp:latest
|
||||
networks:
|
||||
frontend-testhash:
|
||||
aliases:
|
||||
- app
|
||||
backend-testhash:
|
||||
|
||||
worker:
|
||||
image: worker:latest
|
||||
networks:
|
||||
- backend-testhash
|
||||
|
||||
networks:
|
||||
frontend-testhash:
|
||||
driver: bridge
|
||||
attachable: true
|
||||
|
||||
backend-testhash:
|
||||
driver: bridge
|
||||
driver_opts:
|
||||
com.docker.network.bridge.enable_icc: "true"
|
||||
`);
|
||||
|
||||
test("Add prefix to networks in compose file with multiple services and complex network configurations", () => {
|
||||
const composeData = load(composeFile3) as ComposeSpecification;
|
||||
|
||||
const prefix = "testhash";
|
||||
const updatedComposeData = addPrefixToAllNetworks(composeData, prefix);
|
||||
|
||||
expect(updatedComposeData).toEqual(expectedComposeFile3);
|
||||
});
|
||||
103
apps/dokploy/__test__/compose/secrets/secret-root.test.ts
Normal file
103
apps/dokploy/__test__/compose/secrets/secret-root.test.ts
Normal file
@@ -0,0 +1,103 @@
|
||||
import { generateRandomHash } from "@/server/utils/docker/compose";
|
||||
import { addPrefixToSecretsRoot } from "@/server/utils/docker/compose/secrets";
|
||||
import type { ComposeSpecification } from "@/server/utils/docker/types";
|
||||
import { dump, load } from "js-yaml";
|
||||
import { expect, test } from "vitest";
|
||||
|
||||
test("Generate random hash with 8 characters", () => {
|
||||
const hash = generateRandomHash();
|
||||
|
||||
expect(hash).toBeDefined();
|
||||
expect(hash.length).toBe(8);
|
||||
});
|
||||
|
||||
const composeFileSecretsRoot = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
web:
|
||||
image: nginx:latest
|
||||
|
||||
secrets:
|
||||
db_password:
|
||||
file: ./db_password.txt
|
||||
`;
|
||||
|
||||
test("Add prefix to secrets in root property", () => {
|
||||
const composeData = load(composeFileSecretsRoot) as ComposeSpecification;
|
||||
const prefix = generateRandomHash();
|
||||
|
||||
if (!composeData?.secrets) {
|
||||
return;
|
||||
}
|
||||
const secrets = addPrefixToSecretsRoot(composeData.secrets, prefix);
|
||||
expect(secrets).toBeDefined();
|
||||
if (secrets) {
|
||||
for (const secretKey of Object.keys(secrets)) {
|
||||
expect(secretKey).toContain(`-${prefix}`);
|
||||
expect(secrets[secretKey]).toBeDefined();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const composeFileSecretsRoot1 = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
api:
|
||||
image: myapi:latest
|
||||
|
||||
secrets:
|
||||
api_key:
|
||||
file: ./api_key.txt
|
||||
`;
|
||||
|
||||
test("Add prefix to secrets in root property (Test 1)", () => {
|
||||
const composeData = load(composeFileSecretsRoot1) as ComposeSpecification;
|
||||
const prefix = generateRandomHash();
|
||||
|
||||
if (!composeData?.secrets) {
|
||||
return;
|
||||
}
|
||||
const secrets = addPrefixToSecretsRoot(composeData.secrets, prefix);
|
||||
expect(secrets).toBeDefined();
|
||||
|
||||
if (secrets) {
|
||||
for (const secretKey of Object.keys(secrets)) {
|
||||
expect(secretKey).toContain(`-${prefix}`);
|
||||
expect(secrets[secretKey]).toBeDefined();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const composeFileSecretsRoot2 = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
frontend:
|
||||
image: nginx:latest
|
||||
|
||||
secrets:
|
||||
frontend_secret:
|
||||
file: ./frontend_secret.txt
|
||||
db_password:
|
||||
external: true
|
||||
`;
|
||||
|
||||
test("Add prefix to secrets in root property (Test 2)", () => {
|
||||
const composeData = load(composeFileSecretsRoot2) as ComposeSpecification;
|
||||
const prefix = generateRandomHash();
|
||||
|
||||
if (!composeData?.secrets) {
|
||||
return;
|
||||
}
|
||||
const secrets = addPrefixToSecretsRoot(composeData.secrets, prefix);
|
||||
expect(secrets).toBeDefined();
|
||||
|
||||
if (secrets) {
|
||||
for (const secretKey of Object.keys(secrets)) {
|
||||
expect(secretKey).toContain(`-${prefix}`);
|
||||
expect(secrets[secretKey]).toBeDefined();
|
||||
}
|
||||
}
|
||||
});
|
||||
113
apps/dokploy/__test__/compose/secrets/secret-services.test.ts
Normal file
113
apps/dokploy/__test__/compose/secrets/secret-services.test.ts
Normal file
@@ -0,0 +1,113 @@
|
||||
import { generateRandomHash } from "@/server/utils/docker/compose";
|
||||
import { addPrefixToSecretsInServices } from "@/server/utils/docker/compose/secrets";
|
||||
import type { ComposeSpecification } from "@/server/utils/docker/types";
|
||||
import { load } from "js-yaml";
|
||||
import { expect, test } from "vitest";
|
||||
|
||||
const composeFileSecretsServices = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
db:
|
||||
image: postgres:latest
|
||||
secrets:
|
||||
- db_password
|
||||
|
||||
secrets:
|
||||
db_password:
|
||||
file: ./db_password.txt
|
||||
`;
|
||||
|
||||
test("Add prefix to secrets in services", () => {
|
||||
const composeData = load(composeFileSecretsServices) as ComposeSpecification;
|
||||
const prefix = generateRandomHash();
|
||||
|
||||
if (!composeData.services) {
|
||||
return;
|
||||
}
|
||||
|
||||
const updatedComposeData = addPrefixToSecretsInServices(
|
||||
composeData.services,
|
||||
prefix,
|
||||
);
|
||||
const actualComposeData = { ...composeData, services: updatedComposeData };
|
||||
|
||||
expect(actualComposeData.services?.db?.secrets).toContain(
|
||||
`db_password-${prefix}`,
|
||||
);
|
||||
});
|
||||
|
||||
const composeFileSecretsServices1 = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
app:
|
||||
image: node:14
|
||||
secrets:
|
||||
- app_secret
|
||||
|
||||
secrets:
|
||||
app_secret:
|
||||
file: ./app_secret.txt
|
||||
`;
|
||||
|
||||
test("Add prefix to secrets in services (Test 1)", () => {
|
||||
const composeData = load(composeFileSecretsServices1) as ComposeSpecification;
|
||||
const prefix = generateRandomHash();
|
||||
|
||||
if (!composeData.services) {
|
||||
return;
|
||||
}
|
||||
|
||||
const updatedComposeData = addPrefixToSecretsInServices(
|
||||
composeData.services,
|
||||
prefix,
|
||||
);
|
||||
const actualComposeData = { ...composeData, services: updatedComposeData };
|
||||
|
||||
expect(actualComposeData.services?.app?.secrets).toContain(
|
||||
`app_secret-${prefix}`,
|
||||
);
|
||||
});
|
||||
|
||||
const composeFileSecretsServices2 = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
backend:
|
||||
image: backend:latest
|
||||
secrets:
|
||||
- backend_secret
|
||||
frontend:
|
||||
image: frontend:latest
|
||||
secrets:
|
||||
- frontend_secret
|
||||
|
||||
secrets:
|
||||
backend_secret:
|
||||
file: ./backend_secret.txt
|
||||
frontend_secret:
|
||||
file: ./frontend_secret.txt
|
||||
`;
|
||||
|
||||
test("Add prefix to secrets in services (Test 2)", () => {
|
||||
const composeData = load(composeFileSecretsServices2) as ComposeSpecification;
|
||||
const prefix = generateRandomHash();
|
||||
|
||||
if (!composeData.services) {
|
||||
return;
|
||||
}
|
||||
|
||||
const updatedComposeData = addPrefixToSecretsInServices(
|
||||
composeData.services,
|
||||
prefix,
|
||||
);
|
||||
const actualComposeData = { ...composeData, services: updatedComposeData };
|
||||
|
||||
expect(actualComposeData.services?.backend?.secrets).toContain(
|
||||
`backend_secret-${prefix}`,
|
||||
);
|
||||
expect(actualComposeData.services?.frontend?.secrets).toContain(
|
||||
`frontend_secret-${prefix}`,
|
||||
);
|
||||
});
|
||||
159
apps/dokploy/__test__/compose/secrets/secret.test.ts
Normal file
159
apps/dokploy/__test__/compose/secrets/secret.test.ts
Normal file
@@ -0,0 +1,159 @@
|
||||
import { addPrefixToAllSecrets } from "@/server/utils/docker/compose/secrets";
|
||||
import type { ComposeSpecification } from "@/server/utils/docker/types";
|
||||
import { load } from "js-yaml";
|
||||
import { expect, test } from "vitest";
|
||||
|
||||
const composeFileCombinedSecrets = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
web:
|
||||
image: nginx:latest
|
||||
secrets:
|
||||
- web_secret
|
||||
|
||||
app:
|
||||
image: node:14
|
||||
secrets:
|
||||
- app_secret
|
||||
|
||||
secrets:
|
||||
web_secret:
|
||||
file: ./web_secret.txt
|
||||
|
||||
app_secret:
|
||||
file: ./app_secret.txt
|
||||
`;
|
||||
|
||||
const expectedComposeFileCombinedSecrets = load(`
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
web:
|
||||
image: nginx:latest
|
||||
secrets:
|
||||
- web_secret-testhash
|
||||
|
||||
app:
|
||||
image: node:14
|
||||
secrets:
|
||||
- app_secret-testhash
|
||||
|
||||
secrets:
|
||||
web_secret-testhash:
|
||||
file: ./web_secret.txt
|
||||
|
||||
app_secret-testhash:
|
||||
file: ./app_secret.txt
|
||||
`) as ComposeSpecification;
|
||||
|
||||
test("Add prefix to all secrets", () => {
|
||||
const composeData = load(composeFileCombinedSecrets) as ComposeSpecification;
|
||||
const prefix = "testhash";
|
||||
|
||||
const updatedComposeData = addPrefixToAllSecrets(composeData, prefix);
|
||||
|
||||
expect(updatedComposeData).toEqual(expectedComposeFileCombinedSecrets);
|
||||
});
|
||||
|
||||
const composeFileCombinedSecrets3 = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
api:
|
||||
image: myapi:latest
|
||||
secrets:
|
||||
- api_key
|
||||
|
||||
cache:
|
||||
image: redis:latest
|
||||
secrets:
|
||||
- cache_secret
|
||||
|
||||
secrets:
|
||||
api_key:
|
||||
file: ./api_key.txt
|
||||
cache_secret:
|
||||
file: ./cache_secret.txt
|
||||
`;
|
||||
|
||||
const expectedComposeFileCombinedSecrets3 = load(`
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
api:
|
||||
image: myapi:latest
|
||||
secrets:
|
||||
- api_key-testhash
|
||||
|
||||
cache:
|
||||
image: redis:latest
|
||||
secrets:
|
||||
- cache_secret-testhash
|
||||
|
||||
secrets:
|
||||
api_key-testhash:
|
||||
file: ./api_key.txt
|
||||
cache_secret-testhash:
|
||||
file: ./cache_secret.txt
|
||||
`) as ComposeSpecification;
|
||||
|
||||
test("Add prefix to all secrets (3rd Case)", () => {
|
||||
const composeData = load(composeFileCombinedSecrets3) as ComposeSpecification;
|
||||
const prefix = "testhash";
|
||||
|
||||
const updatedComposeData = addPrefixToAllSecrets(composeData, prefix);
|
||||
|
||||
expect(updatedComposeData).toEqual(expectedComposeFileCombinedSecrets3);
|
||||
});
|
||||
|
||||
const composeFileCombinedSecrets4 = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
web:
|
||||
image: nginx:latest
|
||||
secrets:
|
||||
- web_secret
|
||||
|
||||
db:
|
||||
image: postgres:latest
|
||||
secrets:
|
||||
- db_password
|
||||
|
||||
secrets:
|
||||
web_secret:
|
||||
file: ./web_secret.txt
|
||||
db_password:
|
||||
file: ./db_password.txt
|
||||
`;
|
||||
|
||||
const expectedComposeFileCombinedSecrets4 = load(`
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
web:
|
||||
image: nginx:latest
|
||||
secrets:
|
||||
- web_secret-testhash
|
||||
|
||||
db:
|
||||
image: postgres:latest
|
||||
secrets:
|
||||
- db_password-testhash
|
||||
|
||||
secrets:
|
||||
web_secret-testhash:
|
||||
file: ./web_secret.txt
|
||||
db_password-testhash:
|
||||
file: ./db_password.txt
|
||||
`) as ComposeSpecification;
|
||||
|
||||
test("Add prefix to all secrets (4th Case)", () => {
|
||||
const composeData = load(composeFileCombinedSecrets4) as ComposeSpecification;
|
||||
const prefix = "testhash";
|
||||
|
||||
const updatedComposeData = addPrefixToAllSecrets(composeData, prefix);
|
||||
|
||||
expect(updatedComposeData).toEqual(expectedComposeFileCombinedSecrets4);
|
||||
});
|
||||
@@ -0,0 +1,59 @@
|
||||
import { generateRandomHash } from "@/server/utils/docker/compose";
|
||||
import { addPrefixToServiceNames } from "@/server/utils/docker/compose/service";
|
||||
import type { ComposeSpecification } from "@/server/utils/docker/types";
|
||||
import { load } from "js-yaml";
|
||||
import { expect, test } from "vitest";
|
||||
|
||||
const composeFile = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
web:
|
||||
image: nginx:latest
|
||||
container_name: web_container
|
||||
|
||||
api:
|
||||
image: myapi:latest
|
||||
|
||||
networks:
|
||||
default:
|
||||
driver: bridge
|
||||
`;
|
||||
|
||||
test("Generate random hash with 8 characters", () => {
|
||||
const hash = generateRandomHash();
|
||||
|
||||
expect(hash).toBeDefined();
|
||||
expect(hash.length).toBe(8);
|
||||
});
|
||||
|
||||
test("Add prefix to service names with container_name in compose file", () => {
|
||||
const composeData = load(composeFile) as ComposeSpecification;
|
||||
|
||||
const prefix = generateRandomHash();
|
||||
|
||||
if (!composeData.services) {
|
||||
return;
|
||||
}
|
||||
const updatedComposeData = addPrefixToServiceNames(
|
||||
composeData.services,
|
||||
prefix,
|
||||
);
|
||||
const actualComposeData = { ...composeData, services: updatedComposeData };
|
||||
|
||||
// Verificar que el nombre del contenedor ha cambiado correctamente
|
||||
expect(actualComposeData.services?.[`web-${prefix}`]?.container_name).toBe(
|
||||
`web_container-${prefix}`,
|
||||
);
|
||||
// Verificar que la nueva clave del servicio tiene el prefijo y la vieja clave no existe
|
||||
expect(actualComposeData.services).toHaveProperty(`web-${prefix}`);
|
||||
expect(actualComposeData.services).not.toHaveProperty("web");
|
||||
|
||||
// Verificar que la configuración de la imagen sigue igual
|
||||
expect(actualComposeData.services?.[`web-${prefix}`]?.image).toBe(
|
||||
"nginx:latest",
|
||||
);
|
||||
expect(actualComposeData.services?.[`api-${prefix}`]?.image).toBe(
|
||||
"myapi:latest",
|
||||
);
|
||||
});
|
||||
150
apps/dokploy/__test__/compose/service/service-depends-on.test.ts
Normal file
150
apps/dokploy/__test__/compose/service/service-depends-on.test.ts
Normal file
@@ -0,0 +1,150 @@
|
||||
import { generateRandomHash } from "@/server/utils/docker/compose";
|
||||
import { addPrefixToServiceNames } from "@/server/utils/docker/compose/service";
|
||||
import type { ComposeSpecification } from "@/server/utils/docker/types";
|
||||
import { load } from "js-yaml";
|
||||
import { expect, test } from "vitest";
|
||||
|
||||
test("Generate random hash with 8 characters", () => {
|
||||
const hash = generateRandomHash();
|
||||
|
||||
expect(hash).toBeDefined();
|
||||
expect(hash.length).toBe(8);
|
||||
});
|
||||
|
||||
const composeFile4 = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
web:
|
||||
image: nginx:latest
|
||||
depends_on:
|
||||
- db
|
||||
- api
|
||||
|
||||
api:
|
||||
image: myapi:latest
|
||||
|
||||
db:
|
||||
image: postgres:latest
|
||||
|
||||
networks:
|
||||
default:
|
||||
driver: bridge
|
||||
`;
|
||||
|
||||
test("Add prefix to service names with depends_on (array) in compose file", () => {
|
||||
const composeData = load(composeFile4) as ComposeSpecification;
|
||||
|
||||
const prefix = generateRandomHash();
|
||||
|
||||
if (!composeData.services) {
|
||||
return;
|
||||
}
|
||||
const updatedComposeData = addPrefixToServiceNames(
|
||||
composeData.services,
|
||||
prefix,
|
||||
);
|
||||
const actualComposeData = { ...composeData, services: updatedComposeData };
|
||||
|
||||
// Verificar que la nueva clave del servicio tiene el prefijo y la vieja clave no existe
|
||||
expect(actualComposeData.services).toHaveProperty(`web-${prefix}`);
|
||||
expect(actualComposeData.services).not.toHaveProperty("web");
|
||||
|
||||
// Verificar que la configuración de la imagen sigue igual
|
||||
expect(actualComposeData.services?.[`web-${prefix}`]?.image).toBe(
|
||||
"nginx:latest",
|
||||
);
|
||||
expect(actualComposeData.services?.[`api-${prefix}`]?.image).toBe(
|
||||
"myapi:latest",
|
||||
);
|
||||
|
||||
// Verificar que los nombres en depends_on tienen el prefijo
|
||||
expect(actualComposeData.services?.[`web-${prefix}`]?.depends_on).toContain(
|
||||
`db-${prefix}`,
|
||||
);
|
||||
expect(actualComposeData.services?.[`web-${prefix}`]?.depends_on).toContain(
|
||||
`api-${prefix}`,
|
||||
);
|
||||
|
||||
// Verificar que los servicios `db` y `api` también tienen el prefijo
|
||||
expect(actualComposeData.services).toHaveProperty(`db-${prefix}`);
|
||||
expect(actualComposeData.services).not.toHaveProperty("db");
|
||||
expect(actualComposeData.services?.[`db-${prefix}`]?.image).toBe(
|
||||
"postgres:latest",
|
||||
);
|
||||
expect(actualComposeData.services).toHaveProperty(`api-${prefix}`);
|
||||
expect(actualComposeData.services).not.toHaveProperty("api");
|
||||
expect(actualComposeData.services?.[`api-${prefix}`]?.image).toBe(
|
||||
"myapi:latest",
|
||||
);
|
||||
});
|
||||
|
||||
const composeFile5 = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
web:
|
||||
image: nginx:latest
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
api:
|
||||
condition: service_started
|
||||
|
||||
api:
|
||||
image: myapi:latest
|
||||
|
||||
db:
|
||||
image: postgres:latest
|
||||
|
||||
networks:
|
||||
default:
|
||||
driver: bridge
|
||||
`;
|
||||
|
||||
test("Add prefix to service names with depends_on (object) in compose file", () => {
|
||||
const composeData = load(composeFile5) as ComposeSpecification;
|
||||
|
||||
const prefix = generateRandomHash();
|
||||
|
||||
if (!composeData.services) {
|
||||
return;
|
||||
}
|
||||
const updatedComposeData = addPrefixToServiceNames(
|
||||
composeData.services,
|
||||
prefix,
|
||||
);
|
||||
const actualComposeData = { ...composeData, services: updatedComposeData };
|
||||
|
||||
// Verificar que la nueva clave del servicio tiene el prefijo y la vieja clave no existe
|
||||
expect(actualComposeData.services).toHaveProperty(`web-${prefix}`);
|
||||
expect(actualComposeData.services).not.toHaveProperty("web");
|
||||
|
||||
// Verificar que la configuración de la imagen sigue igual
|
||||
expect(actualComposeData.services?.[`web-${prefix}`]?.image).toBe(
|
||||
"nginx:latest",
|
||||
);
|
||||
expect(actualComposeData.services?.[`api-${prefix}`]?.image).toBe(
|
||||
"myapi:latest",
|
||||
);
|
||||
|
||||
// Verificar que los nombres en depends_on tienen el prefijo
|
||||
const webDependsOn = actualComposeData.services?.[`web-${prefix}`]
|
||||
?.depends_on as Record<string, any>;
|
||||
expect(webDependsOn).toHaveProperty(`db-${prefix}`);
|
||||
expect(webDependsOn).toHaveProperty(`api-${prefix}`);
|
||||
expect(webDependsOn[`db-${prefix}`].condition).toBe("service_healthy");
|
||||
expect(webDependsOn[`api-${prefix}`].condition).toBe("service_started");
|
||||
|
||||
// Verificar que los servicios `db` y `api` también tienen el prefijo
|
||||
expect(actualComposeData.services).toHaveProperty(`db-${prefix}`);
|
||||
expect(actualComposeData.services).not.toHaveProperty("db");
|
||||
expect(actualComposeData.services?.[`db-${prefix}`]?.image).toBe(
|
||||
"postgres:latest",
|
||||
);
|
||||
expect(actualComposeData.services).toHaveProperty(`api-${prefix}`);
|
||||
expect(actualComposeData.services).not.toHaveProperty("api");
|
||||
expect(actualComposeData.services?.[`api-${prefix}`]?.image).toBe(
|
||||
"myapi:latest",
|
||||
);
|
||||
});
|
||||
131
apps/dokploy/__test__/compose/service/service-extends.test.ts
Normal file
131
apps/dokploy/__test__/compose/service/service-extends.test.ts
Normal file
@@ -0,0 +1,131 @@
|
||||
import { generateRandomHash } from "@/server/utils/docker/compose";
|
||||
import { addPrefixToServiceNames } from "@/server/utils/docker/compose/service";
|
||||
import type { ComposeSpecification } from "@/server/utils/docker/types";
|
||||
import { load } from "js-yaml";
|
||||
import { expect, test } from "vitest";
|
||||
|
||||
test("Generate random hash with 8 characters", () => {
|
||||
const hash = generateRandomHash();
|
||||
|
||||
expect(hash).toBeDefined();
|
||||
expect(hash.length).toBe(8);
|
||||
});
|
||||
|
||||
const composeFile6 = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
web:
|
||||
image: nginx:latest
|
||||
extends: base_service
|
||||
|
||||
api:
|
||||
image: myapi:latest
|
||||
|
||||
base_service:
|
||||
image: base:latest
|
||||
|
||||
networks:
|
||||
default:
|
||||
driver: bridge
|
||||
`;
|
||||
|
||||
test("Add prefix to service names with extends (string) in compose file", () => {
|
||||
const composeData = load(composeFile6) as ComposeSpecification;
|
||||
|
||||
const prefix = generateRandomHash();
|
||||
|
||||
if (!composeData.services) {
|
||||
return;
|
||||
}
|
||||
const updatedComposeData = addPrefixToServiceNames(
|
||||
composeData.services,
|
||||
prefix,
|
||||
);
|
||||
const actualComposeData = { ...composeData, services: updatedComposeData };
|
||||
|
||||
// Verificar que la nueva clave del servicio tiene el prefijo y la vieja clave no existe
|
||||
expect(actualComposeData.services).toHaveProperty(`web-${prefix}`);
|
||||
expect(actualComposeData.services).not.toHaveProperty("web");
|
||||
|
||||
// Verificar que la configuración de la imagen sigue igual
|
||||
expect(actualComposeData.services?.[`web-${prefix}`]?.image).toBe(
|
||||
"nginx:latest",
|
||||
);
|
||||
expect(actualComposeData.services?.[`api-${prefix}`]?.image).toBe(
|
||||
"myapi:latest",
|
||||
);
|
||||
|
||||
// Verificar que el nombre en extends tiene el prefijo
|
||||
expect(actualComposeData.services?.[`web-${prefix}`]?.extends).toBe(
|
||||
`base_service-${prefix}`,
|
||||
);
|
||||
|
||||
// Verificar que el servicio `base_service` también tiene el prefijo
|
||||
expect(actualComposeData.services).toHaveProperty(`base_service-${prefix}`);
|
||||
expect(actualComposeData.services).not.toHaveProperty("base_service");
|
||||
expect(actualComposeData.services?.[`base_service-${prefix}`]?.image).toBe(
|
||||
"base:latest",
|
||||
);
|
||||
});
|
||||
|
||||
const composeFile7 = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
web:
|
||||
image: nginx:latest
|
||||
extends:
|
||||
service: base_service
|
||||
file: docker-compose.base.yml
|
||||
|
||||
api:
|
||||
image: myapi:latest
|
||||
|
||||
base_service:
|
||||
image: base:latest
|
||||
|
||||
networks:
|
||||
default:
|
||||
driver: bridge
|
||||
`;
|
||||
|
||||
test("Add prefix to service names with extends (object) in compose file", () => {
|
||||
const composeData = load(composeFile7) as ComposeSpecification;
|
||||
|
||||
const prefix = generateRandomHash();
|
||||
|
||||
if (!composeData.services) {
|
||||
return;
|
||||
}
|
||||
const updatedComposeData = addPrefixToServiceNames(
|
||||
composeData.services,
|
||||
prefix,
|
||||
);
|
||||
const actualComposeData = { ...composeData, services: updatedComposeData };
|
||||
|
||||
// Verificar que la nueva clave del servicio tiene el prefijo y la vieja clave no existe
|
||||
expect(actualComposeData.services).toHaveProperty(`web-${prefix}`);
|
||||
expect(actualComposeData.services).not.toHaveProperty("web");
|
||||
|
||||
// Verificar que la configuración de la imagen sigue igual
|
||||
expect(actualComposeData.services?.[`web-${prefix}`]?.image).toBe(
|
||||
"nginx:latest",
|
||||
);
|
||||
expect(actualComposeData.services?.[`api-${prefix}`]?.image).toBe(
|
||||
"myapi:latest",
|
||||
);
|
||||
|
||||
// Verificar que el nombre en extends.service tiene el prefijo
|
||||
const webExtends = actualComposeData.services?.[`web-${prefix}`]?.extends;
|
||||
if (typeof webExtends !== "string") {
|
||||
expect(webExtends?.service).toBe(`base_service-${prefix}`);
|
||||
}
|
||||
|
||||
// Verificar que el servicio `base_service` también tiene el prefijo
|
||||
expect(actualComposeData.services).toHaveProperty(`base_service-${prefix}`);
|
||||
expect(actualComposeData.services).not.toHaveProperty("base_service");
|
||||
expect(actualComposeData.services?.[`base_service-${prefix}`]?.image).toBe(
|
||||
"base:latest",
|
||||
);
|
||||
});
|
||||
76
apps/dokploy/__test__/compose/service/service-links.test.ts
Normal file
76
apps/dokploy/__test__/compose/service/service-links.test.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
import { generateRandomHash } from "@/server/utils/docker/compose";
|
||||
import { addPrefixToServiceNames } from "@/server/utils/docker/compose/service";
|
||||
import type { ComposeSpecification } from "@/server/utils/docker/types";
|
||||
import { load } from "js-yaml";
|
||||
import { expect, test } from "vitest";
|
||||
|
||||
test("Generate random hash with 8 characters", () => {
|
||||
const hash = generateRandomHash();
|
||||
|
||||
expect(hash).toBeDefined();
|
||||
expect(hash.length).toBe(8);
|
||||
});
|
||||
|
||||
const composeFile2 = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
web:
|
||||
image: nginx:latest
|
||||
links:
|
||||
- db
|
||||
|
||||
api:
|
||||
image: myapi:latest
|
||||
|
||||
db:
|
||||
image: postgres:latest
|
||||
|
||||
networks:
|
||||
default:
|
||||
driver: bridge
|
||||
`;
|
||||
|
||||
test("Add prefix to service names with links in compose file", () => {
|
||||
const composeData = load(composeFile2) as ComposeSpecification;
|
||||
|
||||
const prefix = generateRandomHash();
|
||||
|
||||
if (!composeData.services) {
|
||||
return;
|
||||
}
|
||||
const updatedComposeData = addPrefixToServiceNames(
|
||||
composeData.services,
|
||||
prefix,
|
||||
);
|
||||
const actualComposeData = { ...composeData, services: updatedComposeData };
|
||||
|
||||
// Verificar que la nueva clave del servicio tiene el prefijo y la vieja clave no existe
|
||||
expect(actualComposeData.services).toHaveProperty(`web-${prefix}`);
|
||||
expect(actualComposeData.services).not.toHaveProperty("web");
|
||||
|
||||
// Verificar que la configuración de la imagen sigue igual
|
||||
expect(actualComposeData.services?.[`web-${prefix}`]?.image).toBe(
|
||||
"nginx:latest",
|
||||
);
|
||||
expect(actualComposeData.services?.[`api-${prefix}`]?.image).toBe(
|
||||
"myapi:latest",
|
||||
);
|
||||
|
||||
// Verificar que los nombres en links tienen el prefijo
|
||||
expect(actualComposeData.services?.[`web-${prefix}`]?.links).toContain(
|
||||
`db-${prefix}`,
|
||||
);
|
||||
|
||||
// Verificar que los servicios `db` y `api` también tienen el prefijo
|
||||
expect(actualComposeData.services).toHaveProperty(`db-${prefix}`);
|
||||
expect(actualComposeData.services).not.toHaveProperty("db");
|
||||
expect(actualComposeData.services?.[`db-${prefix}`]?.image).toBe(
|
||||
"postgres:latest",
|
||||
);
|
||||
expect(actualComposeData.services).toHaveProperty(`api-${prefix}`);
|
||||
expect(actualComposeData.services).not.toHaveProperty("api");
|
||||
expect(actualComposeData.services?.[`api-${prefix}`]?.image).toBe(
|
||||
"myapi:latest",
|
||||
);
|
||||
});
|
||||
49
apps/dokploy/__test__/compose/service/service-names.test.ts
Normal file
49
apps/dokploy/__test__/compose/service/service-names.test.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import { generateRandomHash } from "@/server/utils/docker/compose";
|
||||
import { addPrefixToServiceNames } from "@/server/utils/docker/compose/service";
|
||||
import type { ComposeSpecification } from "@/server/utils/docker/types";
|
||||
import { load } from "js-yaml";
|
||||
import { expect, test } from "vitest";
|
||||
|
||||
test("Generate random hash with 8 characters", () => {
|
||||
const hash = generateRandomHash();
|
||||
|
||||
expect(hash).toBeDefined();
|
||||
expect(hash.length).toBe(8);
|
||||
});
|
||||
|
||||
const composeFile = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
web:
|
||||
image: nginx:latest
|
||||
|
||||
api:
|
||||
image: myapi:latest
|
||||
|
||||
networks:
|
||||
default:
|
||||
driver: bridge
|
||||
`;
|
||||
|
||||
test("Add prefix to service names in compose file", () => {
|
||||
const composeData = load(composeFile) as ComposeSpecification;
|
||||
|
||||
const prefix = generateRandomHash();
|
||||
|
||||
if (!composeData.services) {
|
||||
return;
|
||||
}
|
||||
const updatedComposeData = addPrefixToServiceNames(
|
||||
composeData.services,
|
||||
prefix,
|
||||
);
|
||||
const actualComposeData = { ...composeData, services: updatedComposeData };
|
||||
|
||||
// Verificar que los nombres de los servicios han cambiado correctamente
|
||||
expect(actualComposeData.services).toHaveProperty(`web-${prefix}`);
|
||||
expect(actualComposeData.services).toHaveProperty(`api-${prefix}`);
|
||||
// Verificar que las claves originales no existen
|
||||
expect(actualComposeData.services).not.toHaveProperty("web");
|
||||
expect(actualComposeData.services).not.toHaveProperty("api");
|
||||
});
|
||||
375
apps/dokploy/__test__/compose/service/service.test.ts
Normal file
375
apps/dokploy/__test__/compose/service/service.test.ts
Normal file
@@ -0,0 +1,375 @@
|
||||
import {
|
||||
addPrefixToAllServiceNames,
|
||||
addPrefixToServiceNames,
|
||||
} from "@/server/utils/docker/compose/service";
|
||||
import type { ComposeSpecification } from "@/server/utils/docker/types";
|
||||
import { load } from "js-yaml";
|
||||
import { expect, test } from "vitest";
|
||||
|
||||
const composeFileCombinedAllCases = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
web:
|
||||
image: nginx:latest
|
||||
container_name: web_container
|
||||
links:
|
||||
- api
|
||||
depends_on:
|
||||
- api
|
||||
extends: base_service
|
||||
|
||||
api:
|
||||
image: myapi:latest
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
volumes_from:
|
||||
- db
|
||||
|
||||
db:
|
||||
image: postgres:latest
|
||||
|
||||
base_service:
|
||||
image: base:latest
|
||||
|
||||
networks:
|
||||
default:
|
||||
driver: bridge
|
||||
`;
|
||||
|
||||
const expectedComposeFile = load(`
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
web-testhash:
|
||||
image: nginx:latest
|
||||
container_name: web_container-testhash
|
||||
links:
|
||||
- api-testhash
|
||||
depends_on:
|
||||
- api-testhash
|
||||
extends: base_service-testhash
|
||||
|
||||
api-testhash:
|
||||
image: myapi:latest
|
||||
depends_on:
|
||||
db-testhash:
|
||||
condition: service_healthy
|
||||
volumes_from:
|
||||
- db-testhash
|
||||
|
||||
db-testhash:
|
||||
image: postgres:latest
|
||||
|
||||
base_service-testhash:
|
||||
image: base:latest
|
||||
|
||||
networks:
|
||||
default:
|
||||
driver: bridge
|
||||
`);
|
||||
|
||||
test("Add prefix to all service names in compose file", () => {
|
||||
const composeData = load(composeFileCombinedAllCases) as ComposeSpecification;
|
||||
|
||||
const prefix = "testhash";
|
||||
|
||||
if (!composeData.services) {
|
||||
return;
|
||||
}
|
||||
const updatedComposeData = addPrefixToServiceNames(
|
||||
composeData.services,
|
||||
prefix,
|
||||
);
|
||||
const actualComposeData = { ...composeData, services: updatedComposeData };
|
||||
|
||||
expect(actualComposeData).toEqual(expectedComposeFile);
|
||||
});
|
||||
|
||||
const composeFile1 = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
web:
|
||||
image: nginx:latest
|
||||
container_name: web_container
|
||||
depends_on:
|
||||
- app
|
||||
networks:
|
||||
- frontend
|
||||
volumes_from:
|
||||
- data
|
||||
links:
|
||||
- db
|
||||
extends:
|
||||
service: base_service
|
||||
|
||||
app:
|
||||
image: node:14
|
||||
networks:
|
||||
- backend
|
||||
- frontend
|
||||
|
||||
db:
|
||||
image: postgres:13
|
||||
networks:
|
||||
- backend
|
||||
|
||||
data:
|
||||
image: busybox
|
||||
volumes:
|
||||
- /data
|
||||
|
||||
base_service:
|
||||
image: base:latest
|
||||
|
||||
networks:
|
||||
frontend:
|
||||
driver: bridge
|
||||
backend:
|
||||
driver: bridge
|
||||
`;
|
||||
|
||||
const expectedComposeFile1 = load(`
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
web-testhash:
|
||||
image: nginx:latest
|
||||
container_name: web_container-testhash
|
||||
depends_on:
|
||||
- app-testhash
|
||||
networks:
|
||||
- frontend
|
||||
volumes_from:
|
||||
- data-testhash
|
||||
links:
|
||||
- db-testhash
|
||||
extends:
|
||||
service: base_service-testhash
|
||||
|
||||
app-testhash:
|
||||
image: node:14
|
||||
networks:
|
||||
- backend
|
||||
- frontend
|
||||
|
||||
db-testhash:
|
||||
image: postgres:13
|
||||
networks:
|
||||
- backend
|
||||
|
||||
data-testhash:
|
||||
image: busybox
|
||||
volumes:
|
||||
- /data
|
||||
|
||||
base_service-testhash:
|
||||
image: base:latest
|
||||
|
||||
networks:
|
||||
frontend:
|
||||
driver: bridge
|
||||
backend:
|
||||
driver: bridge
|
||||
`) as ComposeSpecification;
|
||||
|
||||
test("Add prefix to all service names in compose file 1", () => {
|
||||
const composeData = load(composeFile1) as ComposeSpecification;
|
||||
const prefix = "testhash";
|
||||
|
||||
const updatedComposeData = addPrefixToAllServiceNames(composeData, prefix);
|
||||
|
||||
expect(updatedComposeData).toEqual(expectedComposeFile1);
|
||||
});
|
||||
|
||||
const composeFile2 = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
frontend:
|
||||
image: nginx:latest
|
||||
depends_on:
|
||||
- backend
|
||||
networks:
|
||||
- public
|
||||
volumes_from:
|
||||
- logs
|
||||
links:
|
||||
- cache
|
||||
extends:
|
||||
service: shared_service
|
||||
|
||||
backend:
|
||||
image: node:14
|
||||
networks:
|
||||
- private
|
||||
- public
|
||||
|
||||
cache:
|
||||
image: redis:latest
|
||||
networks:
|
||||
- private
|
||||
|
||||
logs:
|
||||
image: busybox
|
||||
volumes:
|
||||
- /logs
|
||||
|
||||
shared_service:
|
||||
image: shared:latest
|
||||
|
||||
networks:
|
||||
public:
|
||||
driver: bridge
|
||||
private:
|
||||
driver: bridge
|
||||
`;
|
||||
|
||||
const expectedComposeFile2 = load(`
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
frontend-testhash:
|
||||
image: nginx:latest
|
||||
depends_on:
|
||||
- backend-testhash
|
||||
networks:
|
||||
- public
|
||||
volumes_from:
|
||||
- logs-testhash
|
||||
links:
|
||||
- cache-testhash
|
||||
extends:
|
||||
service: shared_service-testhash
|
||||
|
||||
backend-testhash:
|
||||
image: node:14
|
||||
networks:
|
||||
- private
|
||||
- public
|
||||
|
||||
cache-testhash:
|
||||
image: redis:latest
|
||||
networks:
|
||||
- private
|
||||
|
||||
logs-testhash:
|
||||
image: busybox
|
||||
volumes:
|
||||
- /logs
|
||||
|
||||
shared_service-testhash:
|
||||
image: shared:latest
|
||||
|
||||
networks:
|
||||
public:
|
||||
driver: bridge
|
||||
private:
|
||||
driver: bridge
|
||||
`) as ComposeSpecification;
|
||||
|
||||
test("Add prefix to all service names in compose file 2", () => {
|
||||
const composeData = load(composeFile2) as ComposeSpecification;
|
||||
const prefix = "testhash";
|
||||
|
||||
const updatedComposeData = addPrefixToAllServiceNames(composeData, prefix);
|
||||
|
||||
expect(updatedComposeData).toEqual(expectedComposeFile2);
|
||||
});
|
||||
|
||||
const composeFile3 = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
service_a:
|
||||
image: service_a:latest
|
||||
depends_on:
|
||||
- service_b
|
||||
networks:
|
||||
- net_a
|
||||
volumes_from:
|
||||
- data_volume
|
||||
links:
|
||||
- service_c
|
||||
extends:
|
||||
service: common_service
|
||||
|
||||
service_b:
|
||||
image: service_b:latest
|
||||
networks:
|
||||
- net_b
|
||||
- net_a
|
||||
|
||||
service_c:
|
||||
image: service_c:latest
|
||||
networks:
|
||||
- net_b
|
||||
|
||||
data_volume:
|
||||
image: busybox
|
||||
volumes:
|
||||
- /data
|
||||
|
||||
common_service:
|
||||
image: common:latest
|
||||
|
||||
networks:
|
||||
net_a:
|
||||
driver: bridge
|
||||
net_b:
|
||||
driver: bridge
|
||||
`;
|
||||
|
||||
const expectedComposeFile3 = load(`
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
service_a-testhash:
|
||||
image: service_a:latest
|
||||
depends_on:
|
||||
- service_b-testhash
|
||||
networks:
|
||||
- net_a
|
||||
volumes_from:
|
||||
- data_volume-testhash
|
||||
links:
|
||||
- service_c-testhash
|
||||
extends:
|
||||
service: common_service-testhash
|
||||
|
||||
service_b-testhash:
|
||||
image: service_b:latest
|
||||
networks:
|
||||
- net_b
|
||||
- net_a
|
||||
|
||||
service_c-testhash:
|
||||
image: service_c:latest
|
||||
networks:
|
||||
- net_b
|
||||
|
||||
data_volume-testhash:
|
||||
image: busybox
|
||||
volumes:
|
||||
- /data
|
||||
|
||||
common_service-testhash:
|
||||
image: common:latest
|
||||
|
||||
networks:
|
||||
net_a:
|
||||
driver: bridge
|
||||
net_b:
|
||||
driver: bridge
|
||||
`) as ComposeSpecification;
|
||||
|
||||
test("Add prefix to all service names in compose file 3", () => {
|
||||
const composeData = load(composeFile3) as ComposeSpecification;
|
||||
const prefix = "testhash";
|
||||
|
||||
const updatedComposeData = addPrefixToAllServiceNames(composeData, prefix);
|
||||
|
||||
expect(updatedComposeData).toEqual(expectedComposeFile3);
|
||||
});
|
||||
@@ -0,0 +1,78 @@
|
||||
import { generateRandomHash } from "@/server/utils/docker/compose";
|
||||
import { addPrefixToServiceNames } from "@/server/utils/docker/compose/service";
|
||||
import type { ComposeSpecification } from "@/server/utils/docker/types";
|
||||
import { load } from "js-yaml";
|
||||
import { expect, test } from "vitest";
|
||||
|
||||
test("Generate random hash with 8 characters", () => {
|
||||
const hash = generateRandomHash();
|
||||
|
||||
expect(hash).toBeDefined();
|
||||
expect(hash.length).toBe(8);
|
||||
});
|
||||
|
||||
const composeFile3 = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
web:
|
||||
image: nginx:latest
|
||||
volumes_from:
|
||||
- shared
|
||||
|
||||
api:
|
||||
image: myapi:latest
|
||||
volumes_from:
|
||||
- shared
|
||||
|
||||
shared:
|
||||
image: busybox
|
||||
volumes:
|
||||
- /data
|
||||
|
||||
networks:
|
||||
default:
|
||||
driver: bridge
|
||||
`;
|
||||
|
||||
test("Add prefix to service names with volumes_from in compose file", () => {
|
||||
const composeData = load(composeFile3) as ComposeSpecification;
|
||||
|
||||
const prefix = generateRandomHash();
|
||||
|
||||
if (!composeData.services) {
|
||||
return;
|
||||
}
|
||||
const updatedComposeData = addPrefixToServiceNames(
|
||||
composeData.services,
|
||||
prefix,
|
||||
);
|
||||
const actualComposeData = { ...composeData, services: updatedComposeData };
|
||||
|
||||
// Verificar que la nueva clave del servicio tiene el prefijo y la vieja clave no existe
|
||||
expect(actualComposeData.services).toHaveProperty(`web-${prefix}`);
|
||||
expect(actualComposeData.services).not.toHaveProperty("web");
|
||||
|
||||
// Verificar que la configuración de la imagen sigue igual
|
||||
expect(actualComposeData.services?.[`web-${prefix}`]?.image).toBe(
|
||||
"nginx:latest",
|
||||
);
|
||||
expect(actualComposeData.services?.[`api-${prefix}`]?.image).toBe(
|
||||
"myapi:latest",
|
||||
);
|
||||
|
||||
// Verificar que los nombres en volumes_from tienen el prefijo
|
||||
expect(actualComposeData.services?.[`web-${prefix}`]?.volumes_from).toContain(
|
||||
`shared-${prefix}`,
|
||||
);
|
||||
expect(actualComposeData.services?.[`api-${prefix}`]?.volumes_from).toContain(
|
||||
`shared-${prefix}`,
|
||||
);
|
||||
|
||||
// Verificar que el servicio shared también tiene el prefijo
|
||||
expect(actualComposeData.services).toHaveProperty(`shared-${prefix}`);
|
||||
expect(actualComposeData.services).not.toHaveProperty("shared");
|
||||
expect(actualComposeData.services?.[`shared-${prefix}`]?.image).toBe(
|
||||
"busybox",
|
||||
);
|
||||
});
|
||||
1120
apps/dokploy/__test__/compose/volume/volume-2.test.ts
Normal file
1120
apps/dokploy/__test__/compose/volume/volume-2.test.ts
Normal file
File diff suppressed because it is too large
Load Diff
195
apps/dokploy/__test__/compose/volume/volume-root.test.ts
Normal file
195
apps/dokploy/__test__/compose/volume/volume-root.test.ts
Normal file
@@ -0,0 +1,195 @@
|
||||
import { generateRandomHash } from "@/server/utils/docker/compose";
|
||||
import { addPrefixToVolumesRoot } from "@/server/utils/docker/compose/volume";
|
||||
import type { ComposeSpecification } from "@/server/utils/docker/types";
|
||||
import { load } from "js-yaml";
|
||||
import { expect, test } from "vitest";
|
||||
|
||||
const composeFile = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
web:
|
||||
image: nginx:latest
|
||||
volumes:
|
||||
- web_data:/var/lib/nginx/data
|
||||
|
||||
volumes:
|
||||
web_data:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
default:
|
||||
driver: bridge
|
||||
`;
|
||||
|
||||
test("Generate random hash with 8 characters", () => {
|
||||
const hash = generateRandomHash();
|
||||
|
||||
expect(hash).toBeDefined();
|
||||
expect(hash.length).toBe(8);
|
||||
});
|
||||
|
||||
test("Add prefix to volumes in root property", () => {
|
||||
const composeData = load(composeFile) as ComposeSpecification;
|
||||
|
||||
const prefix = generateRandomHash();
|
||||
|
||||
if (!composeData?.volumes) {
|
||||
return;
|
||||
}
|
||||
const volumes = addPrefixToVolumesRoot(composeData.volumes, prefix);
|
||||
expect(volumes).toBeDefined();
|
||||
for (const volumeKey of Object.keys(volumes)) {
|
||||
expect(volumeKey).toContain(`-${prefix}`);
|
||||
expect(volumes[volumeKey]).toBeDefined();
|
||||
}
|
||||
});
|
||||
|
||||
const composeFile2 = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
app:
|
||||
image: node:latest
|
||||
volumes:
|
||||
- app_data:/var/lib/app/data
|
||||
|
||||
volumes:
|
||||
app_data:
|
||||
driver: local
|
||||
driver_opts:
|
||||
type: nfs
|
||||
o: addr=10.0.0.1,rw
|
||||
device: ":/exported/path"
|
||||
|
||||
networks:
|
||||
default:
|
||||
driver: bridge
|
||||
`;
|
||||
|
||||
test("Add prefix to volumes in root property (Case 2)", () => {
|
||||
const composeData = load(composeFile2) as ComposeSpecification;
|
||||
|
||||
const prefix = generateRandomHash();
|
||||
|
||||
if (!composeData?.volumes) {
|
||||
return;
|
||||
}
|
||||
const volumes = addPrefixToVolumesRoot(composeData.volumes, prefix);
|
||||
expect(volumes).toBeDefined();
|
||||
for (const volumeKey of Object.keys(volumes)) {
|
||||
expect(volumeKey).toContain(`-${prefix}`);
|
||||
expect(volumes[volumeKey]).toBeDefined();
|
||||
}
|
||||
});
|
||||
|
||||
const composeFile3 = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
db:
|
||||
image: postgres:latest
|
||||
volumes:
|
||||
- db_data:/var/lib/postgresql/data
|
||||
|
||||
volumes:
|
||||
db_data:
|
||||
external: true
|
||||
|
||||
networks:
|
||||
default:
|
||||
driver: bridge
|
||||
`;
|
||||
|
||||
test("Add prefix to volumes in root property (Case 3)", () => {
|
||||
const composeData = load(composeFile3) as ComposeSpecification;
|
||||
|
||||
const prefix = generateRandomHash();
|
||||
|
||||
if (!composeData?.volumes) {
|
||||
return;
|
||||
}
|
||||
const volumes = addPrefixToVolumesRoot(composeData.volumes, prefix);
|
||||
|
||||
expect(volumes).toBeDefined();
|
||||
for (const volumeKey of Object.keys(volumes)) {
|
||||
expect(volumeKey).toContain(`-${prefix}`);
|
||||
expect(volumes[volumeKey]).toBeDefined();
|
||||
}
|
||||
});
|
||||
|
||||
const composeFile4 = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
web:
|
||||
image: nginx:latest
|
||||
|
||||
app:
|
||||
image: node:latest
|
||||
|
||||
db:
|
||||
image: postgres:latest
|
||||
|
||||
volumes:
|
||||
web_data:
|
||||
driver: local
|
||||
|
||||
app_data:
|
||||
driver: local
|
||||
driver_opts:
|
||||
type: nfs
|
||||
o: addr=10.0.0.1,rw
|
||||
device: ":/exported/path"
|
||||
|
||||
db_data:
|
||||
external: true
|
||||
|
||||
|
||||
`;
|
||||
|
||||
// Expected compose file con el prefijo `testhash`
|
||||
const expectedComposeFile4 = load(`
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
web:
|
||||
image: nginx:latest
|
||||
|
||||
app:
|
||||
image: node:latest
|
||||
|
||||
db:
|
||||
image: postgres:latest
|
||||
|
||||
volumes:
|
||||
web_data-testhash:
|
||||
driver: local
|
||||
|
||||
app_data-testhash:
|
||||
driver: local
|
||||
driver_opts:
|
||||
type: nfs
|
||||
o: addr=10.0.0.1,rw
|
||||
device: ":/exported/path"
|
||||
|
||||
db_data-testhash:
|
||||
external: true
|
||||
|
||||
|
||||
`) as ComposeSpecification;
|
||||
|
||||
test("Add prefix to volumes in root property", () => {
|
||||
const composeData = load(composeFile4) as ComposeSpecification;
|
||||
|
||||
const prefix = "testhash";
|
||||
|
||||
if (!composeData?.volumes) {
|
||||
return;
|
||||
}
|
||||
const volumes = addPrefixToVolumesRoot(composeData.volumes, prefix);
|
||||
const updatedComposeData = { ...composeData, volumes };
|
||||
|
||||
// Verificar que el resultado coincide con el archivo esperado
|
||||
expect(updatedComposeData).toEqual(expectedComposeFile4);
|
||||
});
|
||||
81
apps/dokploy/__test__/compose/volume/volume-services.test.ts
Normal file
81
apps/dokploy/__test__/compose/volume/volume-services.test.ts
Normal file
@@ -0,0 +1,81 @@
|
||||
import { generateRandomHash } from "@/server/utils/docker/compose";
|
||||
import { addPrefixToVolumesInServices } from "@/server/utils/docker/compose/volume";
|
||||
import type { ComposeSpecification } from "@/server/utils/docker/types";
|
||||
import { load } from "js-yaml";
|
||||
import { expect, test } from "vitest";
|
||||
|
||||
test("Generate random hash with 8 characters", () => {
|
||||
const hash = generateRandomHash();
|
||||
|
||||
expect(hash).toBeDefined();
|
||||
expect(hash.length).toBe(8);
|
||||
});
|
||||
|
||||
const composeFile1 = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
db:
|
||||
image: postgres:latest
|
||||
volumes:
|
||||
- db_data:/var/lib/postgresql/data
|
||||
`;
|
||||
|
||||
test("Add prefix to volumes declared directly in services", () => {
|
||||
const composeData = load(composeFile1) as ComposeSpecification;
|
||||
|
||||
const prefix = generateRandomHash();
|
||||
|
||||
if (!composeData.services) {
|
||||
return;
|
||||
}
|
||||
|
||||
const updatedComposeData = addPrefixToVolumesInServices(
|
||||
composeData.services,
|
||||
prefix,
|
||||
);
|
||||
const actualComposeData = { ...composeData, services: updatedComposeData };
|
||||
expect(actualComposeData.services?.db?.volumes).toContain(
|
||||
`db_data-${prefix}:/var/lib/postgresql/data`,
|
||||
);
|
||||
});
|
||||
|
||||
const composeFileTypeVolume = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
db:
|
||||
image: postgres:latest
|
||||
volumes:
|
||||
- type: volume
|
||||
source: db-test
|
||||
target: /var/lib/postgresql/data
|
||||
|
||||
volumes:
|
||||
db-test:
|
||||
driver: local
|
||||
`;
|
||||
|
||||
test("Add prefix to volumes declared directly in services (Case 2)", () => {
|
||||
const composeData = load(composeFileTypeVolume) as ComposeSpecification;
|
||||
|
||||
const prefix = generateRandomHash();
|
||||
|
||||
if (!composeData.services) {
|
||||
return;
|
||||
}
|
||||
|
||||
const updatedComposeData = addPrefixToVolumesInServices(
|
||||
composeData.services,
|
||||
prefix,
|
||||
);
|
||||
const actualComposeData = { ...composeData, services: updatedComposeData };
|
||||
|
||||
expect(actualComposeData.services?.db?.volumes).toEqual([
|
||||
{
|
||||
type: "volume",
|
||||
source: `db-test-${prefix}`,
|
||||
target: "/var/lib/postgresql/data",
|
||||
},
|
||||
]);
|
||||
});
|
||||
288
apps/dokploy/__test__/compose/volume/volume.test.ts
Normal file
288
apps/dokploy/__test__/compose/volume/volume.test.ts
Normal file
@@ -0,0 +1,288 @@
|
||||
import { generateRandomHash } from "@/server/utils/docker/compose";
|
||||
import {
|
||||
addPrefixToAllVolumes,
|
||||
addPrefixToVolumesInServices,
|
||||
} from "@/server/utils/docker/compose/volume";
|
||||
import type { ComposeSpecification } from "@/server/utils/docker/types";
|
||||
import { load } from "js-yaml";
|
||||
import { expect, test } from "vitest";
|
||||
|
||||
const composeFileTypeVolume = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
db1:
|
||||
image: postgres:latest
|
||||
volumes:
|
||||
- "db-test:/var/lib/postgresql/data"
|
||||
db2:
|
||||
image: postgres:latest
|
||||
volumes:
|
||||
- type: volume
|
||||
source: db-test
|
||||
target: /var/lib/postgresql/data
|
||||
|
||||
volumes:
|
||||
db-test:
|
||||
driver: local
|
||||
`;
|
||||
|
||||
const expectedComposeFileTypeVolume = load(`
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
db1:
|
||||
image: postgres:latest
|
||||
volumes:
|
||||
- "db-test-testhash:/var/lib/postgresql/data"
|
||||
db2:
|
||||
image: postgres:latest
|
||||
volumes:
|
||||
- type: volume
|
||||
source: db-test-testhash
|
||||
target: /var/lib/postgresql/data
|
||||
|
||||
volumes:
|
||||
db-test-testhash:
|
||||
driver: local
|
||||
`) as ComposeSpecification;
|
||||
|
||||
test("Add prefix to volumes with type: volume in services", () => {
|
||||
const composeData = load(composeFileTypeVolume) as ComposeSpecification;
|
||||
|
||||
const prefix = "testhash";
|
||||
|
||||
const updatedComposeData = addPrefixToAllVolumes(composeData, prefix);
|
||||
const actualComposeData = { ...composeData, ...updatedComposeData };
|
||||
|
||||
expect(actualComposeData).toEqual(expectedComposeFileTypeVolume);
|
||||
});
|
||||
|
||||
const composeFileTypeVolume1 = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
web:
|
||||
image: nginx:latest
|
||||
volumes:
|
||||
- "web-data:/var/www/html"
|
||||
- type: volume
|
||||
source: web-logs
|
||||
target: /var/log/nginx
|
||||
|
||||
volumes:
|
||||
web-data:
|
||||
driver: local
|
||||
web-logs:
|
||||
driver: local
|
||||
`;
|
||||
|
||||
const expectedComposeFileTypeVolume1 = load(`
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
web:
|
||||
image: nginx:latest
|
||||
volumes:
|
||||
- "web-data-testhash:/var/www/html"
|
||||
- type: volume
|
||||
source: web-logs-testhash
|
||||
target: /var/log/nginx
|
||||
|
||||
volumes:
|
||||
web-data-testhash:
|
||||
driver: local
|
||||
web-logs-testhash:
|
||||
driver: local
|
||||
`) as ComposeSpecification;
|
||||
|
||||
test("Add prefix to mixed volumes in services", () => {
|
||||
const composeData = load(composeFileTypeVolume1) as ComposeSpecification;
|
||||
|
||||
const prefix = "testhash";
|
||||
|
||||
const updatedComposeData = addPrefixToAllVolumes(composeData, prefix);
|
||||
const actualComposeData = { ...composeData, ...updatedComposeData };
|
||||
|
||||
expect(actualComposeData).toEqual(expectedComposeFileTypeVolume1);
|
||||
});
|
||||
|
||||
const composeFileTypeVolume2 = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
app:
|
||||
image: node:latest
|
||||
volumes:
|
||||
- "app-data:/usr/src/app"
|
||||
- type: volume
|
||||
source: app-logs
|
||||
target: /var/log/app
|
||||
volume:
|
||||
nocopy: true
|
||||
|
||||
volumes:
|
||||
app-data:
|
||||
driver: local
|
||||
app-logs:
|
||||
driver: local
|
||||
driver_opts:
|
||||
o: bind
|
||||
type: none
|
||||
device: /path/to/app/logs
|
||||
`;
|
||||
|
||||
const expectedComposeFileTypeVolume2 = load(`
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
app:
|
||||
image: node:latest
|
||||
volumes:
|
||||
- "app-data-testhash:/usr/src/app"
|
||||
- type: volume
|
||||
source: app-logs-testhash
|
||||
target: /var/log/app
|
||||
volume:
|
||||
nocopy: true
|
||||
|
||||
volumes:
|
||||
app-data-testhash:
|
||||
driver: local
|
||||
app-logs-testhash:
|
||||
driver: local
|
||||
driver_opts:
|
||||
o: bind
|
||||
type: none
|
||||
device: /path/to/app/logs
|
||||
`) as ComposeSpecification;
|
||||
|
||||
test("Add prefix to complex volume configurations in services", () => {
|
||||
const composeData = load(composeFileTypeVolume2) as ComposeSpecification;
|
||||
|
||||
const prefix = "testhash";
|
||||
|
||||
const updatedComposeData = addPrefixToAllVolumes(composeData, prefix);
|
||||
const actualComposeData = { ...composeData, ...updatedComposeData };
|
||||
|
||||
expect(actualComposeData).toEqual(expectedComposeFileTypeVolume2);
|
||||
});
|
||||
|
||||
const composeFileTypeVolume3 = `
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
web:
|
||||
image: nginx:latest
|
||||
volumes:
|
||||
- "web-data:/usr/share/nginx/html"
|
||||
- type: volume
|
||||
source: web-logs
|
||||
target: /var/log/nginx
|
||||
volume:
|
||||
nocopy: true
|
||||
|
||||
api:
|
||||
image: node:latest
|
||||
volumes:
|
||||
- "api-data:/usr/src/app"
|
||||
- type: volume
|
||||
source: api-logs
|
||||
target: /var/log/app
|
||||
volume:
|
||||
nocopy: true
|
||||
- type: volume
|
||||
source: shared-logs
|
||||
target: /shared/logs
|
||||
|
||||
volumes:
|
||||
web-data:
|
||||
driver: local
|
||||
web-logs:
|
||||
driver: local
|
||||
driver_opts:
|
||||
o: bind
|
||||
type: none
|
||||
device: /path/to/web/logs
|
||||
|
||||
api-data:
|
||||
driver: local
|
||||
api-logs:
|
||||
driver: local
|
||||
driver_opts:
|
||||
o: bind
|
||||
type: none
|
||||
device: /path/to/api/logs
|
||||
|
||||
shared-logs:
|
||||
driver: local
|
||||
driver_opts:
|
||||
o: bind
|
||||
type: none
|
||||
device: /path/to/shared/logs
|
||||
`;
|
||||
|
||||
const expectedComposeFileTypeVolume3 = load(`
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
web:
|
||||
image: nginx:latest
|
||||
volumes:
|
||||
- "web-data-testhash:/usr/share/nginx/html"
|
||||
- type: volume
|
||||
source: web-logs-testhash
|
||||
target: /var/log/nginx
|
||||
volume:
|
||||
nocopy: true
|
||||
|
||||
api:
|
||||
image: node:latest
|
||||
volumes:
|
||||
- "api-data-testhash:/usr/src/app"
|
||||
- type: volume
|
||||
source: api-logs-testhash
|
||||
target: /var/log/app
|
||||
volume:
|
||||
nocopy: true
|
||||
- type: volume
|
||||
source: shared-logs-testhash
|
||||
target: /shared/logs
|
||||
|
||||
volumes:
|
||||
web-data-testhash:
|
||||
driver: local
|
||||
web-logs-testhash:
|
||||
driver: local
|
||||
driver_opts:
|
||||
o: bind
|
||||
type: none
|
||||
device: /path/to/web/logs
|
||||
|
||||
api-data-testhash:
|
||||
driver: local
|
||||
api-logs-testhash:
|
||||
driver: local
|
||||
driver_opts:
|
||||
o: bind
|
||||
type: none
|
||||
device: /path/to/api/logs
|
||||
|
||||
shared-logs-testhash:
|
||||
driver: local
|
||||
driver_opts:
|
||||
o: bind
|
||||
type: none
|
||||
device: /path/to/shared/logs
|
||||
`) as ComposeSpecification;
|
||||
|
||||
test("Add prefix to complex nested volumes configuration in services", () => {
|
||||
const composeData = load(composeFileTypeVolume3) as ComposeSpecification;
|
||||
|
||||
const prefix = "testhash";
|
||||
|
||||
const updatedComposeData = addPrefixToAllVolumes(composeData, prefix);
|
||||
const actualComposeData = { ...composeData, ...updatedComposeData };
|
||||
|
||||
expect(actualComposeData).toEqual(expectedComposeFileTypeVolume3);
|
||||
});
|
||||
98
apps/dokploy/__test__/drop/drop.test.test.ts
Normal file
98
apps/dokploy/__test__/drop/drop.test.test.ts
Normal file
@@ -0,0 +1,98 @@
|
||||
import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import { APPLICATIONS_PATH } from "@/server/constants";
|
||||
import { unzipDrop } from "@/server/utils/builders/drop";
|
||||
import AdmZip from "adm-zip";
|
||||
import { afterAll, beforeAll, describe, expect, it, vi } from "vitest";
|
||||
|
||||
if (typeof window === "undefined") {
|
||||
const undici = require("undici");
|
||||
globalThis.File = undici.File as any;
|
||||
globalThis.FileList = undici.FileList as any;
|
||||
}
|
||||
|
||||
vi.mock("@/server/constants", () => ({
|
||||
APPLICATIONS_PATH: "./__test__/drop/zips/output",
|
||||
}));
|
||||
|
||||
describe("unzipDrop using real zip files", () => {
|
||||
beforeAll(async () => {
|
||||
await fs.rm(APPLICATIONS_PATH, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await fs.rm(APPLICATIONS_PATH, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
it("should correctly extract a zip with a single root folder", async () => {
|
||||
const appName = "single-file";
|
||||
const outputPath = path.join(APPLICATIONS_PATH, appName, "code");
|
||||
const zip = new AdmZip("./__test__/drop/zips/single-file.zip");
|
||||
|
||||
const zipBuffer = zip.toBuffer();
|
||||
const file = new File([zipBuffer], "single.zip");
|
||||
await unzipDrop(file, appName);
|
||||
|
||||
const files = await fs.readdir(outputPath, { withFileTypes: true });
|
||||
expect(files.some((f) => f.name === "test.txt")).toBe(true);
|
||||
});
|
||||
|
||||
it("should correctly extract a zip with a single root folder and a subfolder", async () => {
|
||||
const appName = "folderwithfile";
|
||||
const outputPath = path.join(APPLICATIONS_PATH, appName, "code");
|
||||
const zip = new AdmZip("./__test__/drop/zips/folder-with-file.zip");
|
||||
|
||||
const zipBuffer = zip.toBuffer();
|
||||
const file = new File([zipBuffer], "single.zip");
|
||||
await unzipDrop(file, appName);
|
||||
|
||||
const files = await fs.readdir(outputPath, { withFileTypes: true });
|
||||
expect(files.some((f) => f.name === "folder1.txt")).toBe(true);
|
||||
});
|
||||
|
||||
it("should correctly extract a zip with multiple root folders", async () => {
|
||||
const appName = "two-folders";
|
||||
const outputPath = path.join(APPLICATIONS_PATH, appName, "code");
|
||||
const zip = new AdmZip("./__test__/drop/zips/two-folders.zip");
|
||||
|
||||
const zipBuffer = zip.toBuffer();
|
||||
const file = new File([zipBuffer], "single.zip");
|
||||
await unzipDrop(file, appName);
|
||||
|
||||
const files = await fs.readdir(outputPath, { withFileTypes: true });
|
||||
|
||||
expect(files.some((f) => f.name === "folder1")).toBe(true);
|
||||
expect(files.some((f) => f.name === "folder2")).toBe(true);
|
||||
});
|
||||
|
||||
it("should correctly extract a zip with a single root with a file", async () => {
|
||||
const appName = "nested";
|
||||
const outputPath = path.join(APPLICATIONS_PATH, appName, "code");
|
||||
const zip = new AdmZip("./__test__/drop/zips/nested.zip");
|
||||
|
||||
const zipBuffer = zip.toBuffer();
|
||||
const file = new File([zipBuffer], "single.zip");
|
||||
await unzipDrop(file, appName);
|
||||
|
||||
const files = await fs.readdir(outputPath, { withFileTypes: true });
|
||||
|
||||
expect(files.some((f) => f.name === "folder1")).toBe(true);
|
||||
expect(files.some((f) => f.name === "folder2")).toBe(true);
|
||||
expect(files.some((f) => f.name === "folder3")).toBe(true);
|
||||
});
|
||||
|
||||
it("should correctly extract a zip with a single root with a folder", async () => {
|
||||
const appName = "folder-with-sibling-file";
|
||||
const outputPath = path.join(APPLICATIONS_PATH, appName, "code");
|
||||
const zip = new AdmZip("./__test__/drop/zips/folder-with-sibling-file.zip");
|
||||
|
||||
const zipBuffer = zip.toBuffer();
|
||||
const file = new File([zipBuffer], "single.zip");
|
||||
await unzipDrop(file, appName);
|
||||
|
||||
const files = await fs.readdir(outputPath, { withFileTypes: true });
|
||||
|
||||
expect(files.some((f) => f.name === "folder1")).toBe(true);
|
||||
expect(files.some((f) => f.name === "test.txt")).toBe(true);
|
||||
});
|
||||
});
|
||||
BIN
apps/dokploy/__test__/drop/zips/folder-with-file.zip
Normal file
BIN
apps/dokploy/__test__/drop/zips/folder-with-file.zip
Normal file
Binary file not shown.
BIN
apps/dokploy/__test__/drop/zips/folder-with-sibling-file.zip
Normal file
BIN
apps/dokploy/__test__/drop/zips/folder-with-sibling-file.zip
Normal file
Binary file not shown.
1
apps/dokploy/__test__/drop/zips/folder1/folder1.txt
Normal file
1
apps/dokploy/__test__/drop/zips/folder1/folder1.txt
Normal file
@@ -0,0 +1 @@
|
||||
Gogogogogogo
|
||||
1
apps/dokploy/__test__/drop/zips/folder2/folder2.txt
Normal file
1
apps/dokploy/__test__/drop/zips/folder2/folder2.txt
Normal file
@@ -0,0 +1 @@
|
||||
gogogogogog
|
||||
1
apps/dokploy/__test__/drop/zips/folder3/file3.txt
Normal file
1
apps/dokploy/__test__/drop/zips/folder3/file3.txt
Normal file
@@ -0,0 +1 @@
|
||||
gogogogogogogogogo
|
||||
BIN
apps/dokploy/__test__/drop/zips/nested.zip
Normal file
BIN
apps/dokploy/__test__/drop/zips/nested.zip
Normal file
Binary file not shown.
BIN
apps/dokploy/__test__/drop/zips/single-file.zip
Normal file
BIN
apps/dokploy/__test__/drop/zips/single-file.zip
Normal file
Binary file not shown.
1
apps/dokploy/__test__/drop/zips/test.txt
Normal file
1
apps/dokploy/__test__/drop/zips/test.txt
Normal file
@@ -0,0 +1 @@
|
||||
dsafasdfasdf
|
||||
BIN
apps/dokploy/__test__/drop/zips/two-folders.zip
Normal file
BIN
apps/dokploy/__test__/drop/zips/two-folders.zip
Normal file
Binary file not shown.
187
apps/dokploy/__test__/traefik/traefik.test.ts
Normal file
187
apps/dokploy/__test__/traefik/traefik.test.ts
Normal file
@@ -0,0 +1,187 @@
|
||||
import type { Domain } from "@/server/api/services/domain";
|
||||
import type { Redirect } from "@/server/api/services/redirect";
|
||||
import type { ApplicationNested } from "@/server/utils/builders";
|
||||
import { createRouterConfig } from "@/server/utils/traefik/domain";
|
||||
import { expect, test } from "vitest";
|
||||
|
||||
const baseApp: ApplicationNested = {
|
||||
applicationId: "",
|
||||
applicationStatus: "done",
|
||||
appName: "",
|
||||
autoDeploy: true,
|
||||
branch: null,
|
||||
buildArgs: null,
|
||||
buildPath: "/",
|
||||
buildType: "nixpacks",
|
||||
command: null,
|
||||
cpuLimit: null,
|
||||
cpuReservation: null,
|
||||
createdAt: "",
|
||||
customGitBranch: "",
|
||||
customGitBuildPath: "",
|
||||
customGitSSHKeyId: null,
|
||||
customGitUrl: "",
|
||||
description: "",
|
||||
dockerfile: null,
|
||||
dockerImage: null,
|
||||
dropBuildPath: null,
|
||||
enabled: null,
|
||||
env: null,
|
||||
healthCheckSwarm: null,
|
||||
labelsSwarm: null,
|
||||
memoryLimit: null,
|
||||
memoryReservation: null,
|
||||
modeSwarm: null,
|
||||
mounts: [],
|
||||
name: "",
|
||||
networkSwarm: null,
|
||||
owner: null,
|
||||
password: null,
|
||||
placementSwarm: null,
|
||||
ports: [],
|
||||
projectId: "",
|
||||
redirects: [],
|
||||
refreshToken: "",
|
||||
registry: null,
|
||||
registryId: null,
|
||||
replicas: 1,
|
||||
repository: null,
|
||||
restartPolicySwarm: null,
|
||||
rollbackConfigSwarm: null,
|
||||
security: [],
|
||||
sourceType: "git",
|
||||
subtitle: null,
|
||||
title: null,
|
||||
updateConfigSwarm: null,
|
||||
username: null,
|
||||
};
|
||||
|
||||
const baseDomain: Domain = {
|
||||
applicationId: "",
|
||||
certificateType: "none",
|
||||
createdAt: "",
|
||||
domainId: "",
|
||||
host: "",
|
||||
https: false,
|
||||
path: null,
|
||||
port: null,
|
||||
uniqueConfigKey: 1,
|
||||
};
|
||||
|
||||
const baseRedirect: Redirect = {
|
||||
redirectId: "",
|
||||
regex: "",
|
||||
replacement: "",
|
||||
permanent: false,
|
||||
uniqueConfigKey: 1,
|
||||
createdAt: "",
|
||||
applicationId: "",
|
||||
};
|
||||
|
||||
/** Middlewares */
|
||||
|
||||
test("Web entrypoint on http domain", async () => {
|
||||
const router = await createRouterConfig(
|
||||
baseApp,
|
||||
{ ...baseDomain, https: false },
|
||||
"web",
|
||||
);
|
||||
|
||||
expect(router.middlewares).not.toContain("redirect-to-https");
|
||||
});
|
||||
|
||||
test("Web entrypoint on http domain with redirect", async () => {
|
||||
const router = await createRouterConfig(
|
||||
{
|
||||
...baseApp,
|
||||
appName: "test",
|
||||
redirects: [{ ...baseRedirect, uniqueConfigKey: 1 }],
|
||||
},
|
||||
{ ...baseDomain, https: false },
|
||||
"web",
|
||||
);
|
||||
|
||||
expect(router.middlewares).not.toContain("redirect-to-https");
|
||||
expect(router.middlewares).toContain("redirect-test-1");
|
||||
});
|
||||
|
||||
test("Web entrypoint on http domain with multiple redirect", async () => {
|
||||
const router = await createRouterConfig(
|
||||
{
|
||||
...baseApp,
|
||||
appName: "test",
|
||||
redirects: [
|
||||
{ ...baseRedirect, uniqueConfigKey: 1 },
|
||||
{ ...baseRedirect, uniqueConfigKey: 2 },
|
||||
],
|
||||
},
|
||||
{ ...baseDomain, https: false },
|
||||
"web",
|
||||
);
|
||||
|
||||
expect(router.middlewares).not.toContain("redirect-to-https");
|
||||
expect(router.middlewares).toContain("redirect-test-1");
|
||||
expect(router.middlewares).toContain("redirect-test-2");
|
||||
});
|
||||
|
||||
test("Web entrypoint on https domain", async () => {
|
||||
const router = await createRouterConfig(
|
||||
baseApp,
|
||||
{ ...baseDomain, https: true },
|
||||
"web",
|
||||
);
|
||||
|
||||
expect(router.middlewares).toContain("redirect-to-https");
|
||||
});
|
||||
|
||||
test("Web entrypoint on https domain with redirect", async () => {
|
||||
const router = await createRouterConfig(
|
||||
{
|
||||
...baseApp,
|
||||
appName: "test",
|
||||
redirects: [{ ...baseRedirect, uniqueConfigKey: 1 }],
|
||||
},
|
||||
{ ...baseDomain, https: true },
|
||||
"web",
|
||||
);
|
||||
|
||||
expect(router.middlewares).toContain("redirect-to-https");
|
||||
expect(router.middlewares).not.toContain("redirect-test-1");
|
||||
});
|
||||
|
||||
test("Websecure entrypoint on https domain", async () => {
|
||||
const router = await createRouterConfig(
|
||||
baseApp,
|
||||
{ ...baseDomain, https: true },
|
||||
"websecure",
|
||||
);
|
||||
|
||||
expect(router.middlewares).not.toContain("redirect-to-https");
|
||||
});
|
||||
|
||||
test("Websecure entrypoint on https domain with redirect", async () => {
|
||||
const router = await createRouterConfig(
|
||||
{
|
||||
...baseApp,
|
||||
appName: "test",
|
||||
redirects: [{ ...baseRedirect, uniqueConfigKey: 1 }],
|
||||
},
|
||||
{ ...baseDomain, https: true },
|
||||
"websecure",
|
||||
);
|
||||
|
||||
expect(router.middlewares).not.toContain("redirect-to-https");
|
||||
expect(router.middlewares).toContain("redirect-test-1");
|
||||
});
|
||||
|
||||
/** Certificates */
|
||||
|
||||
test("CertificateType on websecure entrypoint", async () => {
|
||||
const router = await createRouterConfig(
|
||||
baseApp,
|
||||
{ ...baseDomain, certificateType: "letsencrypt" },
|
||||
"websecure",
|
||||
);
|
||||
|
||||
expect(router.tls?.certResolver).toBe("letsencrypt");
|
||||
});
|
||||
16
apps/dokploy/__test__/vitest.config.ts
Normal file
16
apps/dokploy/__test__/vitest.config.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import tsconfigPaths from "vite-tsconfig-paths";
|
||||
import { defineConfig } from "vitest/config";
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
tsconfigPaths({
|
||||
root: "./",
|
||||
projects: ["tsconfig.json"],
|
||||
}),
|
||||
],
|
||||
test: {
|
||||
include: ["__test__/**/*.test.ts"], // Incluir solo los archivos de test en el directorio __test__
|
||||
exclude: ["**/node_modules/**", "**/dist/**", "**/.docker/**"],
|
||||
pool: "forks",
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user