Docker compose support (#111)

* feat(WIP): compose implementation

* feat: add volumes, networks, services name hash generate

* feat: add compose config test unique

* feat: add tests for each unique config

* feat: implement lodash for docker compose parsing

* feat: add tests for generating compose file

* refactor: implement logs docker compose

* refactor: composeFile set not empty

* feat: implement providers for compose deployments

* feat: add Files volumes to compose

* feat: add stop compose button

* refactor: change strategie of building compose

* feat: create .env file in composepath

* refactor: simplify git and github function

* chore: update deps

* refactor: update migrations and add badge to recognize compose type

* chore: update lock yaml

* refactor: use code editor

* feat: add monitoring for app types

* refactor: reset stats on change appName

* refactor: add option to clean monitoring folder

* feat: show current command that will run

* feat: add prefix

* fix: add missing types

* refactor: add docker provider and expose by default as false

* refactor: customize error page

* refactor: unified deployments to be a single one

* feat: add vitest to ci/cd

* revert: back to initial version

* refactor: add maxconcurrency vitest

* refactor: add pool forks to vitest

* feat: add pocketbase template

* fix: update path resolution compose

* removed

* feat: add template pocketbase

* feat: add pocketbase template

* feat: add support button

* feat: add plausible template

* feat: add calcom template

* feat: add version to each template

* feat: add code editor to enviroment variables and swarm settings json

* refactor: add loader when download the image

* fix: use base64 to generate keys plausible

* feat: add recognized domain names by enviroment compose

* refactor: show alert to redeploy in each card advanced tab

* refactor: add validation to prevent create compose if not have permissions

* chore: add templates section to contributing

* chore: add example contributing
This commit is contained in:
Mauricio Siu
2024-06-02 15:26:28 -06:00
committed by GitHub
parent 1df6db738e
commit 8f9d21c0f8
139 changed files with 16513 additions and 1208 deletions

View File

@@ -0,0 +1,476 @@
import { expect, test } from "vitest";
import { load } from "js-yaml";
import { addPrefixToAllProperties } from "@/server/utils/docker/compose";
import type { ComposeSpecification } from "@/server/utils/docker/types";
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);
});

View 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);
});

View 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);
});

View 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,
);
});

View 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);
});

View File

@@ -0,0 +1,181 @@
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[`frontend-${prefix}`];
expect(networkConfig).toBeDefined();
expect(networkConfig?.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;
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");
});

View File

@@ -0,0 +1,254 @@
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;
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);
});

View File

@@ -0,0 +1,103 @@
import { expect, test } from "vitest";
import { load, dump } from "js-yaml";
import { generateRandomHash } from "@/server/utils/docker/compose";
import type { ComposeSpecification } from "@/server/utils/docker/types";
import { addPrefixToSecretsRoot } from "@/server/utils/docker/compose/secrets";
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();
}
}
});

View 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}`,
);
});

View 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);
});

View File

@@ -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",
);
});

View 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",
);
});

View 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",
);
});

View 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",
);
});

View 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");
});

View 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);
});

View 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 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");
});

File diff suppressed because it is too large Load Diff

View 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);
});

View 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",
},
]);
});

View 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);
});

16
__test__/vitest.config.ts Normal file
View File

@@ -0,0 +1,16 @@
import { defineConfig } from "vitest/config";
import tsconfigPaths from "vite-tsconfig-paths";
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",
},
});