From 65527bc39a1e959e7186e3581ee4d6e7387a9235 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sat, 17 Aug 2024 16:10:36 -0600 Subject: [PATCH] feat: add tests for labels and networks --- .../__test__/compose/domain/labels.test.ts | 74 ++++++++++++++++++ .../compose/domain/network-root.test.ts | 29 +++++++ .../compose/domain/network-service.test.ts | 24 ++++++ apps/dokploy/server/utils/docker/domain.ts | 75 +++++++++++++------ 4 files changed, 178 insertions(+), 24 deletions(-) create mode 100644 apps/dokploy/__test__/compose/domain/labels.test.ts create mode 100644 apps/dokploy/__test__/compose/domain/network-root.test.ts create mode 100644 apps/dokploy/__test__/compose/domain/network-service.test.ts diff --git a/apps/dokploy/__test__/compose/domain/labels.test.ts b/apps/dokploy/__test__/compose/domain/labels.test.ts new file mode 100644 index 000000000..750be2f42 --- /dev/null +++ b/apps/dokploy/__test__/compose/domain/labels.test.ts @@ -0,0 +1,74 @@ +import type { Domain } from "@/server/api/services/domain"; +import { createDomainLabels } from "@/server/utils/docker/domain"; +import { describe, it, expect } from "vitest"; + +describe("createDomainLabels", () => { + const appName = "test-app"; + const baseDomain: Domain = { + host: "example.com", + port: 8080, + https: false, + uniqueConfigKey: 1, + certificateType: "none", + applicationId: "", + composeId: "", + domainType: "compose", + serviceName: "test-app", + domainId: "", + path: "/", + createdAt: "", + }; + + it("should create basic labels for web entrypoint", async () => { + const labels = await createDomainLabels(appName, baseDomain, "web"); + + expect(labels).toContain( + "traefik.http.routers.test-app-1-web.rule=Host(`example.com`)", + ); + expect(labels).toContain( + "traefik.http.routers.test-app-1-web.entrypoints=web", + ); + expect(labels).toContain( + "traefik.http.services.test-app-1-web.loadbalancer.server.port=8080", + ); + }); + + it("should create labels for websecure entrypoint", async () => { + const labels = await createDomainLabels( + appName, + { ...baseDomain, https: true }, + "websecure", + ); + expect(labels).toContain( + "traefik.http.routers.test-app-1-websecure.rule=Host(`example.com`)", + ); + expect(labels).toContain( + "traefik.http.routers.test-app-1-websecure.entrypoints=websecure", + ); + expect(labels).not.toContain( + "traefik.http.services.test-app-1-websecure.loadbalancer.server.port=8080", + ); + }); + + it("should add redirect middleware for https on web entrypoint", async () => { + const labels = await createDomainLabels( + appName, + { ...baseDomain, https: true }, + "web", + ); + expect(labels).toContain( + "traefik.http.routers.test-app-1-web.middlewares=redirect-to-https@file", + ); + }); + + it("should add Let's Encrypt configuration for websecure with letsencrypt certificate", async () => { + const labels = await createDomainLabels( + appName, + { ...baseDomain, https: true, certificateType: "letsencrypt" }, + "websecure", + ); + expect(labels).toContain( + "traefik.http.routers.test-app-1-websecure.tls.certresolver=letsencrypt", + ); + }); +}); diff --git a/apps/dokploy/__test__/compose/domain/network-root.test.ts b/apps/dokploy/__test__/compose/domain/network-root.test.ts new file mode 100644 index 000000000..19a4b1923 --- /dev/null +++ b/apps/dokploy/__test__/compose/domain/network-root.test.ts @@ -0,0 +1,29 @@ +import { addDokployNetworkToRoot } from "@/server/utils/docker/domain"; +import { describe, it, expect } from "vitest"; + +describe("addDokployNetworkToRoot", () => { + it("should create network object if networks is undefined", () => { + const result = addDokployNetworkToRoot(undefined); + expect(result).toEqual({ "dokploy-network": { external: true } }); + }); + + it("should add network to an empty object", () => { + const result = addDokployNetworkToRoot({}); + expect(result).toEqual({ "dokploy-network": { external: true } }); + }); + + it("should not modify existing network configuration", () => { + const existing = { "dokploy-network": { external: false } }; + const result = addDokployNetworkToRoot(existing); + expect(result).toEqual({ "dokploy-network": { external: true } }); + }); + + it("should add network alongside existing networks", () => { + const existing = { "other-network": { external: true } }; + const result = addDokployNetworkToRoot(existing); + expect(result).toEqual({ + "other-network": { external: true }, + "dokploy-network": { external: true }, + }); + }); +}); diff --git a/apps/dokploy/__test__/compose/domain/network-service.test.ts b/apps/dokploy/__test__/compose/domain/network-service.test.ts new file mode 100644 index 000000000..e74f69455 --- /dev/null +++ b/apps/dokploy/__test__/compose/domain/network-service.test.ts @@ -0,0 +1,24 @@ +import { addDokployNetworkToService } from "@/server/utils/docker/domain"; +import { describe, it, expect } from "vitest"; + +describe("addDokployNetworkToService", () => { + it("should add network to an empty array", () => { + const result = addDokployNetworkToService([]); + expect(result).toEqual(["dokploy-network"]); + }); + + it("should not add duplicate network to an array", () => { + const result = addDokployNetworkToService(["dokploy-network"]); + expect(result).toEqual(["dokploy-network"]); + }); + + it("should add network to an existing array with other networks", () => { + const result = addDokployNetworkToService(["other-network"]); + expect(result).toEqual(["other-network", "dokploy-network"]); + }); + + it("should add network to an object if networks is an object", () => { + const result = addDokployNetworkToService({ "other-network": {} }); + expect(result).toEqual({ "other-network": {}, "dokploy-network": {} }); + }); +}); diff --git a/apps/dokploy/server/utils/docker/domain.ts b/apps/dokploy/server/utils/docker/domain.ts index c5af6f44b..f590c5b48 100644 --- a/apps/dokploy/server/utils/docker/domain.ts +++ b/apps/dokploy/server/utils/docker/domain.ts @@ -8,7 +8,11 @@ import { dump, load } from "js-yaml"; import { cloneGitRawRepository } from "../providers/git"; import { cloneRawGithubRepository } from "../providers/github"; import { createComposeFileRaw } from "../providers/raw"; -import type { ComposeSpecification } from "./types"; +import type { + ComposeSpecification, + DefinitionsService, + PropertiesNetworks, +} from "./types"; export const cloneCompose = async (compose: Compose) => { if (compose.sourceType === "github") { @@ -115,32 +119,14 @@ export const addDomainToCompose = async ( labels.push(...httpLabels); } - // Add the dokploy-network to the service but first check if it exists - if (!result.services[serviceName].networks) { - result.services[serviceName].networks = []; - } - const networks = result.services[serviceName].networks; - - if (Array.isArray(networks)) { - if (!networks.includes("dokploy-network")) { - networks.push("dokploy-network"); - } - } else if (networks && typeof networks === "object") { - if (!("dokploy-network" in networks)) { - networks["dokploy-network"] = {}; - } - } + // Add the dokploy-network to the service + result.services[serviceName].networks = addDokployNetworkToService( + result.services[serviceName].networks, + ); } // Add dokploy-network to the root of the compose file - if (!result.networks) { - result.networks = {}; - } - if (!result.networks["dokploy-network"]) { - result.networks["dokploy-network"] = { - external: true, - }; - } + result.networks = addDokployNetworkToRoot(result.networks); return result; }; @@ -195,3 +181,44 @@ export const createDomainLabels = async ( return labels; }; + +export const addDokployNetworkToService = ( + networkService: DefinitionsService["networks"], +) => { + let networks = networkService; + const network = "dokploy-network"; + if (!networks) { + networks = []; + } + + if (Array.isArray(networks)) { + if (!networks.includes(network)) { + networks.push(network); + } + } else if (networks && typeof networks === "object") { + if (!(network in networks)) { + networks[network] = {}; + } + } + + return networks; +}; + +export const addDokployNetworkToRoot = ( + networkRoot: PropertiesNetworks | undefined, +) => { + let networks = networkRoot; + const network = "dokploy-network"; + + if (!networks) { + networks = {}; + } + + if (networks[network] || !networks[network]) { + networks[network] = { + external: true, + }; + } + + return networks; +};