diff --git a/packages/cli/global-setup.ts b/packages/cli/global-setup.ts index 87921dd..ba44f3d 100644 --- a/packages/cli/global-setup.ts +++ b/packages/cli/global-setup.ts @@ -4,6 +4,7 @@ import shell from "shelljs"; import { beforeEach, vi } from "vitest"; vi.mock("fs"); +vi.mock("fs/promises"); vi.mock("consola"); vi.mock("shelljs"); diff --git a/packages/cli/src/__snapshots__/on-create-action.test.ts.snap b/packages/cli/src/__snapshots__/on-create-action.test.ts.snap index a5e9209..6430c97 100644 --- a/packages/cli/src/__snapshots__/on-create-action.test.ts.snap +++ b/packages/cli/src/__snapshots__/on-create-action.test.ts.snap @@ -1,5 +1,281 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html +exports[`Actions - onCreateAction > failures > can not create with invalid domain 1`] = ` +[MockFunction writeFileSync] { + "calls": [ + [ + "/root/path/.local-ssl-management/nginx.conf", + "user nginx; +worker_processes 20; + +error_log /var/log/nginx/error.log warn; +pid /var/run/nginx.pid; + +events { + worker_connections 1024; +} + +http { + server { + listen 443 ssl; + server_name _; + ssl_certificate /etc/nginx/localhost-cert.pem; + ssl_certificate_key /etc/nginx/localhost-key.pem; + location / { + root /var/www/html; + } + } + + server { + listen 80 default_server; + server_name _; + + include /etc/nginx/mime.types; + default_type application/octet-stream; + + location / { + root /var/www/html; + } + } + + server { + listen 443 ssl; + + autoindex off; + + access_log /var/log/nginx/wrong.domain.access.log; + error_log /var/log/nginx/wrong.domain.error.log; + + server_tokens off; + server_name wrong.domain; + + ssl_certificate /etc/nginx/wrong.domain-cert.pem; + ssl_certificate_key /etc/nginx/wrong.domain-key.pem; + + gzip_static on; + + location ~ ^/(/?)(.*) { + gzip on; + gzip_disable "msie6"; + gzip_vary on; + gzip_proxied any; + gzip_comp_level 6; + gzip_buffers 16 8k; + gzip_http_version 1.1; + gzip_min_length 256; + gzip_types text/plain text/css application/json application/x-javascript application/javascript text/xml application/xml application/xml+rss text/javascript application/vnd.ms-fontobject application/x-font-ttf font/opentype image/svg+xml image/x-icon; + proxy_pass http://11.22.33.445:3000/$2; + proxy_redirect off; + proxy_http_version 1.1; + proxy_cache_bypass $http_upgrade; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header Host $host; + proxy_set_header 'Access-Control-Allow-Origin' '*'; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header 'Cache-Control' 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0'; + expires off; + } + } +}", + ], + [ + "/root/path/.local-ssl-management/Dockerfile", + "FROM nginx + +# RUN rm -f /etc/nginx/conf.d/default.conf + +# WORKDIR /var/www/html +# COPY index.html /var/www/html +# RUN chmod 755 /var/www/html/index.html + +COPY nginx.conf /etc/nginx/conf.d/ + +COPY ssl/wrong.domain-key.pem /etc/nginx/ +COPY ssl/wrong.domain-cert.pem /etc/nginx/ + +COPY ssl/localhost-key.pem /etc/nginx/ +COPY ssl/localhost-cert.pem /etc/nginx/ + +COPY nginx.conf /etc/nginx/ + +EXPOSE 80 443 + +CMD ["nginx", "-g", "daemon off;"]", + ], + [ + "/root/path/.local-ssl-management/config.json", + "[ + { + "id": "48d1a85c-377a-40ef-8a82-d1405f7a074f", + "domain": "wrong.domain", + "services": [ + { + "id": "da406b35-79b8-4909-9af1-07cfdcf37d00", + "location": "/", + "port": "3000" + } + ] + } +]", + ], + ], + "results": [ + { + "type": "return", + "value": undefined, + }, + { + "type": "return", + "value": undefined, + }, + { + "type": "return", + "value": undefined, + }, + ], +} +`; + +exports[`Actions - onCreateAction > failures > can not create with invalid port 1`] = ` +[MockFunction writeFileSync] { + "calls": [ + [ + "/root/path/.local-ssl-management/nginx.conf", + "user nginx; +worker_processes 20; + +error_log /var/log/nginx/error.log warn; +pid /var/run/nginx.pid; + +events { + worker_connections 1024; +} + +http { + server { + listen 443 ssl; + server_name _; + ssl_certificate /etc/nginx/localhost-cert.pem; + ssl_certificate_key /etc/nginx/localhost-key.pem; + location / { + root /var/www/html; + } + } + + server { + listen 80 default_server; + server_name _; + + include /etc/nginx/mime.types; + default_type application/octet-stream; + + location / { + root /var/www/html; + } + } + + server { + listen 443 ssl; + + autoindex off; + + access_log /var/log/nginx/some-domain.com.access.log; + error_log /var/log/nginx/some-domain.com.error.log; + + server_tokens off; + server_name some-domain.com; + + ssl_certificate /etc/nginx/some-domain.com-cert.pem; + ssl_certificate_key /etc/nginx/some-domain.com-key.pem; + + gzip_static on; + + location ~ ^/(/?)(.*) { + gzip on; + gzip_disable "msie6"; + gzip_vary on; + gzip_proxied any; + gzip_comp_level 6; + gzip_buffers 16 8k; + gzip_http_version 1.1; + gzip_min_length 256; + gzip_types text/plain text/css application/json application/x-javascript application/javascript text/xml application/xml application/xml+rss text/javascript application/vnd.ms-fontobject application/x-font-ttf font/opentype image/svg+xml image/x-icon; + proxy_pass http://11.22.33.445:666/$2; + proxy_redirect off; + proxy_http_version 1.1; + proxy_cache_bypass $http_upgrade; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header Host $host; + proxy_set_header 'Access-Control-Allow-Origin' '*'; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header 'Cache-Control' 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0'; + expires off; + } + } +}", + ], + [ + "/root/path/.local-ssl-management/Dockerfile", + "FROM nginx + +# RUN rm -f /etc/nginx/conf.d/default.conf + +# WORKDIR /var/www/html +# COPY index.html /var/www/html +# RUN chmod 755 /var/www/html/index.html + +COPY nginx.conf /etc/nginx/conf.d/ + +COPY ssl/some-domain.com-key.pem /etc/nginx/ +COPY ssl/some-domain.com-cert.pem /etc/nginx/ + +COPY ssl/localhost-key.pem /etc/nginx/ +COPY ssl/localhost-cert.pem /etc/nginx/ + +COPY nginx.conf /etc/nginx/ + +EXPOSE 80 443 + +CMD ["nginx", "-g", "daemon off;"]", + ], + [ + "/root/path/.local-ssl-management/config.json", + "[ + { + "id": "48d1a85c-377a-40ef-8a82-d1405f7a074f", + "domain": "some-domain.com", + "services": [ + { + "id": "da406b35-79b8-4909-9af1-07cfdcf37d00", + "location": "/", + "port": "666" + } + ] + } +]", + ], + ], + "results": [ + { + "type": "return", + "value": undefined, + }, + { + "type": "return", + "value": undefined, + }, + { + "type": "return", + "value": undefined, + }, + ], +} +`; + exports[`Actions - onCreateAction > success > multiple services > domain config created sucessfully (does not exists /ssl) 1`] = ` [MockFunction writeFileSync] { "calls": [ diff --git a/packages/cli/src/list-container.test.ts b/packages/cli/src/list-container.test.ts index e3c7718..aa63338 100644 --- a/packages/cli/src/list-container.test.ts +++ b/packages/cli/src/list-container.test.ts @@ -1,4 +1,5 @@ import consola from "consola"; +import fs from "fs"; import shell from "shelljs"; import listContainer from "@/list-container"; @@ -23,6 +24,12 @@ describe("Actions - listContainer", () => { expect(shell.echo).toHaveBeenCalledTimes(1); expect(shell.echo).toMatchSnapshot(); + + // read files + expect(fs.readFileSync).not.toBeCalled(); + + // write files + expect(fs.writeFileSync).not.toBeCalled(); }); }); @@ -41,6 +48,12 @@ describe("Actions - listContainer", () => { expect(consola.error).toBeCalledWith( "Something have been failure. Contact with the author.", ); + + // read files + expect(fs.readFileSync).not.toBeCalled(); + + // write files + expect(fs.writeFileSync).not.toBeCalled(); }); }); }); diff --git a/packages/cli/src/on-create-action.test.ts b/packages/cli/src/on-create-action.test.ts index 3deb619..0579a86 100644 --- a/packages/cli/src/on-create-action.test.ts +++ b/packages/cli/src/on-create-action.test.ts @@ -11,7 +11,6 @@ vi.mock("@/utils/domain-exists-in-hosts", () => ({ describe("Actions - onCreateAction", () => { beforeEach(() => { - vi.spyOn(fs, "readFileSync").mockReturnValue("[]"); vi.spyOn(fs, "existsSync").mockReturnValueOnce(true); }); @@ -20,6 +19,16 @@ describe("Actions - onCreateAction", () => { const domain = "wrong.domain"; const port = "3000"; + const hostMock = ` +127.0.0.1 localhost +127.0.0.1 other-domain.com +`; + vi.spyOn(fs, "readFileSync") + .mockReturnValueOnce(JSON.stringify([], null, 2)) + .mockReturnValueOnce(hostMock) + .mockReturnValueOnce(hostMock) + .mockReturnValueOnce(hostMock); + vi.spyOn(shell, "exec") // eslint-disable-next-line @typescript-eslint/no-explicit-any .mockImplementationOnce((): any => "") @@ -32,6 +41,27 @@ describe("Actions - onCreateAction", () => { await onCreateAction(domain, { port }); + // read files + expect(fs.readFileSync).toBeCalledTimes(4); + expect(fs.readFileSync).nthCalledWith( + 1, + "/root/path/.local-ssl-management/config.json", + { encoding: "utf8" }, + ); + expect(fs.readFileSync).nthCalledWith(2, "/etc/hosts", { + encoding: "utf8", + }); + expect(fs.readFileSync).nthCalledWith(3, "/etc/hosts", { + encoding: "utf8", + }); + expect(fs.readFileSync).nthCalledWith(4, "/etc/hosts", { + encoding: "utf8", + }); + + // write files + expect(fs.writeFileSync).toBeCalledTimes(3); + expect(fs.writeFileSync).toMatchSnapshot(); + expect(consola.error).toBeCalledWith( "Domain (https://wrong.domain) format is not valid", ); @@ -41,6 +71,16 @@ describe("Actions - onCreateAction", () => { const domain = "some-domain.com"; const port = "666"; + const hostMock = ` +127.0.0.1 localhost +127.0.0.1 other-domain.com +`; + vi.spyOn(fs, "readFileSync") + .mockReturnValueOnce(JSON.stringify([], null, 2)) + .mockReturnValueOnce(hostMock) + .mockReturnValueOnce(hostMock) + .mockReturnValueOnce(hostMock); + vi.spyOn(shell, "exec") // eslint-disable-next-line @typescript-eslint/no-explicit-any .mockImplementationOnce((): any => "") @@ -53,6 +93,27 @@ describe("Actions - onCreateAction", () => { await onCreateAction(domain, { port }); + // read files + expect(fs.readFileSync).toBeCalledTimes(4); + expect(fs.readFileSync).nthCalledWith( + 1, + "/root/path/.local-ssl-management/config.json", + { encoding: "utf8" }, + ); + expect(fs.readFileSync).nthCalledWith(2, "/etc/hosts", { + encoding: "utf8", + }); + expect(fs.readFileSync).nthCalledWith(3, "/etc/hosts", { + encoding: "utf8", + }); + expect(fs.readFileSync).nthCalledWith(4, "/etc/hosts", { + encoding: "utf8", + }); + + // write files + expect(fs.writeFileSync).toBeCalledTimes(3); + expect(fs.writeFileSync).toMatchSnapshot(); + expect(consola.error).toBeCalledWith( "Port (--port ) should be into the range 1025 to 65535", ); @@ -86,6 +147,17 @@ describe("Actions - onCreateAction", () => { await onCreateAction(domain, { port, location }); + // read files + expect(fs.readFileSync).toBeCalledTimes(1); + expect(fs.readFileSync).nthCalledWith( + 1, + "/root/path/.local-ssl-management/config.json", + { encoding: "utf8" }, + ); + + // write files + expect(fs.writeFileSync).not.toBeCalled(); + expect(consola.error).toBeCalledWith( 'Location "/app-name" already exists', ); @@ -117,6 +189,17 @@ describe("Actions - onCreateAction", () => { await onCreateAction(domain, {}); + // read files + expect(fs.readFileSync).toBeCalledTimes(1); + expect(fs.readFileSync).nthCalledWith( + 1, + "/root/path/.local-ssl-management/config.json", + { encoding: "utf8" }, + ); + + // write files + expect(fs.writeFileSync).not.toBeCalled(); + expect(consola.error).toBeCalledWith( 'Domain "some-domain.com" already created with the default location "/", but does not exist on your local `/etc/hosts`', ); @@ -140,6 +223,16 @@ describe("Actions - onCreateAction", () => { test("domain config created sucessfully", async () => { const domain = "some-domain.com"; const port = "3000"; + const hostMock = ` +127.0.0.1 localhost +127.0.0.1 other-domain.com +`; + + vi.spyOn(fs, "readFileSync") + .mockReturnValueOnce(JSON.stringify([])) + .mockReturnValueOnce(hostMock) + .mockReturnValueOnce(hostMock) + .mockReturnValueOnce(hostMock); await onCreateAction(domain, { port }); @@ -155,18 +248,29 @@ describe("Actions - onCreateAction", () => { { silent: true }, ); - expect(fs.readFileSync).toBeCalledTimes(1); - expect(fs.readFileSync).toHaveBeenNthCalledWith( + // read files + expect(fs.readFileSync).toBeCalledTimes(4); + expect(fs.readFileSync).nthCalledWith( 1, - expect.stringMatching(/.local-ssl-management\/config.json/), + "/root/path/.local-ssl-management/config.json", { encoding: "utf8" }, ); + expect(fs.readFileSync).nthCalledWith(2, "/etc/hosts", { + encoding: "utf8", + }); + expect(fs.readFileSync).nthCalledWith(3, "/etc/hosts", { + encoding: "utf8", + }); + expect(fs.readFileSync).nthCalledWith(4, "/etc/hosts", { + encoding: "utf8", + }); expect(fs.existsSync).toHaveBeenCalledWith( expect.stringMatching(/.local-ssl-management\/ssl/), ); expect(fs.mkdirSync).not.toHaveBeenCalled(); + // write files expect(fs.writeFileSync).toBeCalledTimes(3); expect(fs.writeFileSync).toMatchSnapshot(); expect(fs.writeFileSync).nthCalledWith( @@ -193,7 +297,15 @@ describe("Actions - onCreateAction", () => { }); test("domain config created sucessfully (does not exists /ssl)", async () => { - vi.spyOn(fs, "readFileSync").mockReturnValue(JSON.stringify([])); + const hostMock = ` +127.0.0.1 localhost +127.0.0.1 other-domain.com +`; + vi.spyOn(fs, "readFileSync") + .mockReturnValueOnce(JSON.stringify([], null, 2)) + .mockReturnValueOnce(hostMock) + .mockReturnValueOnce(hostMock) + .mockReturnValueOnce(hostMock); vi.spyOn(fs, "existsSync").mockReturnValue(false); const domain = "some-domain.com"; @@ -213,16 +325,29 @@ describe("Actions - onCreateAction", () => { { silent: true }, ); + // read files + expect(fs.readFileSync).toBeCalledTimes(4); expect(fs.readFileSync).toHaveBeenNthCalledWith( 1, expect.stringMatching(/.local-ssl-management\/config.json/), { encoding: "utf8" }, ); + expect(fs.readFileSync).toHaveBeenNthCalledWith(2, "/etc/hosts", { + encoding: "utf8", + }); + expect(fs.readFileSync).toHaveBeenNthCalledWith(3, "/etc/hosts", { + encoding: "utf8", + }); + expect(fs.readFileSync).toHaveBeenNthCalledWith(4, "/etc/hosts", { + encoding: "utf8", + }); + expect(fs.existsSync).toHaveBeenCalledWith( expect.stringMatching(/.local-ssl-management\/ssl/), ); expect(fs.mkdirSync).toHaveBeenCalled(); + // write files expect(fs.writeFileSync).toBeCalledTimes(3); expect(fs.writeFileSync).toMatchSnapshot(); expect(fs.writeFileSync).nthCalledWith( @@ -249,7 +374,7 @@ describe("Actions - onCreateAction", () => { }); test("domain config already exists", async () => { - vi.spyOn(fs, "readFileSync").mockReturnValue( + vi.spyOn(fs, "readFileSync").mockReturnValueOnce( JSON.stringify( [ { @@ -274,6 +399,16 @@ describe("Actions - onCreateAction", () => { await onCreateAction(domain, { port }); + // read files + expect(fs.readFileSync).toBeCalledTimes(1); + expect(fs.readFileSync).toBeCalledWith( + "/root/path/.local-ssl-management/config.json", + { encoding: "utf8" }, + ); + + // write files + expect(fs.writeFileSync).not.toBeCalled(); + expect(consola.error).toBeCalledWith( 'Domain "some-domain.com" already created with the default location "/", but does not exist on your local `/etc/hosts`', ); @@ -322,16 +457,29 @@ describe("Actions - onCreateAction", () => { { silent: true }, ); + // read files + expect(fs.readFileSync).toBeCalledTimes(4); expect(fs.readFileSync).toHaveBeenNthCalledWith( 1, expect.stringMatching(/.local-ssl-management\/config.json/), { encoding: "utf8" }, ); + expect(fs.readFileSync).toHaveBeenNthCalledWith(2, "/etc/hosts", { + encoding: "utf8", + }); + expect(fs.readFileSync).toHaveBeenNthCalledWith(3, "/etc/hosts", { + encoding: "utf8", + }); + expect(fs.readFileSync).toHaveBeenNthCalledWith(4, "/etc/hosts", { + encoding: "utf8", + }); + expect(fs.existsSync).toHaveBeenCalledWith( expect.stringMatching(/.local-ssl-management\/ssl/), ); expect(fs.mkdirSync).not.toHaveBeenCalled(); + // write files expect(fs.writeFileSync).toBeCalledTimes(3); expect(fs.writeFileSync).toMatchSnapshot(); expect(fs.writeFileSync).toHaveBeenNthCalledWith( @@ -383,16 +531,29 @@ describe("Actions - onCreateAction", () => { { silent: true }, ); + // read files + expect(fs.readFileSync).toHaveBeenCalledTimes(4); expect(fs.readFileSync).toHaveBeenNthCalledWith( 1, expect.stringMatching(/.local-ssl-management\/config.json/), { encoding: "utf8" }, ); + expect(fs.readFileSync).toHaveBeenNthCalledWith(2, "/etc/hosts", { + encoding: "utf8", + }); + expect(fs.readFileSync).toHaveBeenNthCalledWith(3, "/etc/hosts", { + encoding: "utf8", + }); + expect(fs.readFileSync).toHaveBeenNthCalledWith(4, "/etc/hosts", { + encoding: "utf8", + }); + expect(fs.existsSync).toHaveBeenCalledWith( expect.stringMatching(/.local-ssl-management\/ssl/), ); expect(fs.mkdirSync).toHaveBeenCalled(); + // write files expect(fs.writeFileSync).toBeCalledTimes(3); expect(fs.writeFileSync).toMatchSnapshot(); @@ -445,6 +606,17 @@ describe("Actions - onCreateAction", () => { await onCreateAction(domain, { port }); + // read files + expect(fs.readFileSync).toBeCalledTimes(1); + expect(fs.readFileSync).toHaveBeenNthCalledWith( + 1, + "/root/path/.local-ssl-management/config.json", + { encoding: "utf8" }, + ); + + // write files + expect(fs.writeFileSync).not.toBeCalled(); + expect(consola.error).toBeCalledWith( 'Domain "some-domain.com" already created with the default location "/", but does not exist on your local `/etc/hosts`', ); diff --git a/packages/cli/src/on-list-action.test.ts b/packages/cli/src/on-list-action.test.ts index 31a5e6f..513b683 100644 --- a/packages/cli/src/on-list-action.test.ts +++ b/packages/cli/src/on-list-action.test.ts @@ -61,5 +61,16 @@ describe("Actions - onListAction", () => { 'curl -s -o /dev/null -w "%{http_code}" https://local.some-domain.tld/app-name', { silent: true }, ); + + // read files + expect(fs.readFileSync).toBeCalledTimes(1); + expect(fs.readFileSync).nthCalledWith( + 1, + "/root/path/.local-ssl-management/config.json", + { encoding: "utf8" }, + ); + + // write files + expect(fs.writeFileSync).not.toBeCalled(); }); }); diff --git a/packages/cli/src/on-remove-action.test.ts b/packages/cli/src/on-remove-action.test.ts index f817173..75088f3 100644 --- a/packages/cli/src/on-remove-action.test.ts +++ b/packages/cli/src/on-remove-action.test.ts @@ -15,6 +15,17 @@ describe("Actions - onRemoveAction", () => { onRemoveAction("dummy"); + // read files + expect(fs.readFileSync).toBeCalledTimes(1); + expect(fs.readFileSync).nthCalledWith( + 1, + "/root/path/.local-ssl-management/config.json", + { encoding: "utf8" }, + ); + + // write files + expect(fs.writeFileSync).not.toBeCalled(); + expect(consola.error).toBeCalledWith('Domain "dummy" does not exists'); }); @@ -23,6 +34,17 @@ describe("Actions - onRemoveAction", () => { onRemoveAction("6eb61d17-ba78-4618-a2ac-47aeb4ba8b26"); + // read files + expect(fs.readFileSync).toBeCalledTimes(1); + expect(fs.readFileSync).nthCalledWith( + 1, + "/root/path/.local-ssl-management/config.json", + { encoding: "utf8" }, + ); + + // write files + expect(fs.writeFileSync).not.toBeCalled(); + expect(consola.error).toBeCalledWith( 'Domain with id "6eb61d17-ba78-4618-a2ac-47aeb4ba8b26" does not exists', ); @@ -53,6 +75,17 @@ describe("Actions - onRemoveAction", () => { location: "/something", }); + // read files + expect(fs.readFileSync).toBeCalledTimes(1); + expect(fs.readFileSync).nthCalledWith( + 1, + "/root/path/.local-ssl-management/config.json", + { encoding: "utf8" }, + ); + + // write files + expect(fs.writeFileSync).not.toBeCalled(); + expect(consola.error).toBeCalledWith( 'Location "/something" does not exists', ); @@ -80,6 +113,22 @@ describe("Actions - onRemoveAction", () => { onRemoveAction("6eb61d17-ba78-4618-a2ac-47aeb4ba8b26"); + // read files + expect(fs.readFileSync).toBeCalledTimes(1); + expect(fs.readFileSync).nthCalledWith( + 1, + "/root/path/.local-ssl-management/config.json", + { encoding: "utf8" }, + ); + + // write files + expect(fs.writeFileSync).toBeCalledTimes(1); + expect(fs.writeFileSync).nthCalledWith( + 1, + "/root/path/.local-ssl-management/config.json", + "[]", + ); + // unlink expect(fs.unlinkSync).toHaveBeenCalledTimes(2); expect(fs.unlinkSync).toHaveBeenNthCalledWith( @@ -144,14 +193,26 @@ describe("Actions - onRemoveAction", () => { 2, "/root/path/.local-ssl-management/ssl/local.some-domain.tld-key.pem", ); - expect(fs.writeFileSync).toHaveBeenCalledWith( - "/root/path/.local-ssl-management/config.json", - JSON.stringify([], null, 2), - ); expect(consola.success).nthCalledWith(1, "Domain removed succesful."); expect(consola.success).nthCalledWith(2, "Updating proxy image."); + // read files + expect(fs.readFileSync).toBeCalledTimes(1); + expect(fs.readFileSync).nthCalledWith( + 1, + "/root/path/.local-ssl-management/config.json", + { encoding: "utf8" }, + ); + + // write files + expect(fs.writeFileSync).toBeCalledTimes(1); + expect(fs.writeFileSync).nthCalledWith( + 1, + "/root/path/.local-ssl-management/config.json", + "[]", + ); + expect(generateProxyImage).toBeCalled(); }); @@ -197,9 +258,21 @@ describe("Actions - onRemoveAction", () => { 2, expect.stringMatching(/.*?\/demo.com_demo.es-key.pem$/g), ); - expect(fs.writeFileSync).toHaveBeenCalledWith( - expect.stringMatching(/.*?\/\.local-ssl-management\/config.json$/g), - JSON.stringify([], null, 2), + + // read files + expect(fs.readFileSync).toBeCalledTimes(1); + expect(fs.readFileSync).nthCalledWith( + 1, + "/root/path/.local-ssl-management/config.json", + { encoding: "utf8" }, + ); + + // write files + expect(fs.writeFileSync).toBeCalledTimes(1); + expect(fs.writeFileSync).nthCalledWith( + 1, + "/root/path/.local-ssl-management/config.json", + "[]", ); expect(consola.success).nthCalledWith(1, "Domain removed succesful."); @@ -250,9 +323,21 @@ describe("Actions - onRemoveAction", () => { 2, expect.stringMatching(/.*?\/demo.com_demo.es-key.pem$/g), ); - expect(fs.writeFileSync).toHaveBeenCalledWith( - expect.stringMatching(/.*?\/\.local-ssl-management\/config.json$/g), - JSON.stringify([], null, 2), + + // read files + expect(fs.readFileSync).toBeCalledTimes(1); + expect(fs.readFileSync).nthCalledWith( + 1, + "/root/path/.local-ssl-management/config.json", + { encoding: "utf8" }, + ); + + // write files + expect(fs.writeFileSync).toBeCalledTimes(1); + expect(fs.writeFileSync).nthCalledWith( + 1, + "/root/path/.local-ssl-management/config.json", + "[]", ); expect(consola.success).nthCalledWith(1, "Domain removed succesful."); @@ -304,6 +389,15 @@ describe("Actions - onRemoveAction", () => { expect.stringMatching(/.*?\/demo.com_demo.es-key.pem$/g), ); + // read files + expect(fs.readFileSync).toBeCalledTimes(1); + expect(fs.readFileSync).nthCalledWith( + 1, + "/root/path/.local-ssl-management/config.json", + { encoding: "utf8" }, + ); + + // write files expect(fs.writeFileSync).toBeCalledTimes(1); expect(fs.writeFileSync).toHaveBeenNthCalledWith( 1, diff --git a/packages/cli/src/on-reset-hosts.test.ts b/packages/cli/src/on-reset-hosts.test.ts index 193e048..3341327 100644 --- a/packages/cli/src/on-reset-hosts.test.ts +++ b/packages/cli/src/on-reset-hosts.test.ts @@ -17,6 +17,13 @@ ${HOSTS_END} `); await onResetHosts(); + // read files + expect(fs.readFileSync).toBeCalledTimes(1); + expect(fs.readFileSync).nthCalledWith(1, "/etc/hosts", { + encoding: "utf8", + }); + + // write files expect(fs.writeFileSync).toBeCalledWith( expect.stringMatching(/\/.tmp-hosts/i), ` diff --git a/packages/cli/src/on-update-action.test.ts b/packages/cli/src/on-update-action.test.ts index 4821d34..f1d3b52 100644 --- a/packages/cli/src/on-update-action.test.ts +++ b/packages/cli/src/on-update-action.test.ts @@ -36,6 +36,17 @@ describe("Actions - onUpdateAction", () => { onUpdateAction(domain, { port }); + // read files + expect(fs.readFileSync).toBeCalledTimes(1); + expect(fs.readFileSync).nthCalledWith( + 1, + "/root/path/.local-ssl-management/config.json", + { encoding: "utf8" }, + ); + + // write files + expect(fs.writeFileSync).not.toBeCalled(); + expect(consola.error).toBeCalledWith( 'Domain "foo-domain.com" does not exists', ); @@ -66,6 +77,17 @@ describe("Actions - onUpdateAction", () => { onUpdateAction(domain, { port }); + // read files + expect(fs.readFileSync).toBeCalledTimes(1); + expect(fs.readFileSync).nthCalledWith( + 1, + "/root/path/.local-ssl-management/config.json", + { encoding: "utf8" }, + ); + + // write files + expect(fs.writeFileSync).not.toBeCalled(); + expect(consola.error).toBeCalledWith( 'Domain with key "48d1a85c-377a-40ef-8a82-d1405f7a0722" does not exists', ); @@ -97,6 +119,17 @@ describe("Actions - onUpdateAction", () => { onUpdateAction(domain, { port }); + // read files + expect(fs.readFileSync).toBeCalledTimes(1); + expect(fs.readFileSync).nthCalledWith( + 1, + "/root/path/.local-ssl-management/config.json", + { encoding: "utf8" }, + ); + + // write files + expect(fs.writeFileSync).not.toBeCalled(); + expect(consola.error).toBeCalledWith("Location is mandatory"); }); @@ -125,6 +158,17 @@ describe("Actions - onUpdateAction", () => { onUpdateAction(domain, { location: "/not-exists,/app-name" }); + // read files + expect(fs.readFileSync).toBeCalledTimes(1); + expect(fs.readFileSync).nthCalledWith( + 1, + "/root/path/.local-ssl-management/config.json", + { encoding: "utf8" }, + ); + + // write files + expect(fs.writeFileSync).not.toBeCalled(); + expect(consola.error).toBeCalledWith( 'Location "/not-exists" does not exists', ); @@ -155,6 +199,17 @@ describe("Actions - onUpdateAction", () => { onUpdateAction(domain, { location: "/app-name" }); + // read files + expect(fs.readFileSync).toBeCalledTimes(1); + expect(fs.readFileSync).nthCalledWith( + 1, + "/root/path/.local-ssl-management/config.json", + { encoding: "utf8" }, + ); + + // write files + expect(fs.writeFileSync).not.toBeCalled(); + expect(consola.error).toBeCalledWith( 'Location "/app-name" does not exists', ); @@ -250,6 +305,15 @@ describe("Actions - onUpdateAction", () => { { silent: true }, ); + // read files + expect(fs.readFileSync).toBeCalledTimes(1); + expect(fs.readFileSync).nthCalledWith( + 1, + "/root/path/.local-ssl-management/config.json", + { encoding: "utf8" }, + ); + + // write files expect(fs.writeFileSync).toBeCalledTimes(3); expect(fs.writeFileSync).toMatchSnapshot(); @@ -320,6 +384,15 @@ describe("Actions - onUpdateAction", () => { { silent: true }, ); + // read files + expect(fs.readFileSync).toBeCalledTimes(1); + expect(fs.readFileSync).nthCalledWith( + 1, + "/root/path/.local-ssl-management/config.json", + { encoding: "utf8" }, + ); + + // write files expect(fs.writeFileSync).toBeCalledTimes(3); expect(fs.writeFileSync).toMatchSnapshot(); @@ -391,6 +464,15 @@ describe("Actions - onUpdateAction", () => { { silent: true }, ); + // read files + expect(fs.readFileSync).toBeCalledTimes(1); + expect(fs.readFileSync).nthCalledWith( + 1, + "/root/path/.local-ssl-management/config.json", + { encoding: "utf8" }, + ); + + // write files expect(fs.writeFileSync).toBeCalledTimes(3); expect(fs.writeFileSync).toMatchSnapshot(); @@ -460,6 +542,15 @@ describe("Actions - onUpdateAction", () => { { silent: true }, ); + // read files + expect(fs.readFileSync).toBeCalledTimes(1); + expect(fs.readFileSync).nthCalledWith( + 1, + "/root/path/.local-ssl-management/config.json", + { encoding: "utf8" }, + ); + + // write files expect(fs.writeFileSync).toBeCalledTimes(3); expect(fs.writeFileSync).toMatchSnapshot(); @@ -532,6 +623,15 @@ describe("Actions - onUpdateAction", () => { { silent: true }, ); + // read files + expect(fs.readFileSync).toBeCalledTimes(1); + expect(fs.readFileSync).nthCalledWith( + 1, + "/root/path/.local-ssl-management/config.json", + { encoding: "utf8" }, + ); + + // write files expect(fs.writeFileSync).toBeCalledTimes(3); expect(fs.writeFileSync).toMatchSnapshot(); diff --git a/packages/cli/src/run.ts b/packages/cli/src/run.ts index e245b66..bc84661 100644 --- a/packages/cli/src/run.ts +++ b/packages/cli/src/run.ts @@ -1,14 +1,14 @@ #! /usr/bin/env node -import fs from "fs/promises"; +import fs from "fs"; async function run() { const filename = process.argv[2]; - const data = await fs.readFile(filename, { encoding: "utf-8" }); + const data = await fs.readFileSync(filename, { encoding: "utf-8" }); - await fs.writeFile("/etc/hosts", data); - await fs.unlink(filename); + await fs.writeFileSync("/etc/hosts", data); + await fs.unlinkSync(filename); } run(); diff --git a/packages/cli/src/utils/__snapshots__/generate-proxy-image.test.ts.snap b/packages/cli/src/utils/__snapshots__/generate-proxy-image.test.ts.snap index 5d0caee..2dc3c84 100644 --- a/packages/cli/src/utils/__snapshots__/generate-proxy-image.test.ts.snap +++ b/packages/cli/src/utils/__snapshots__/generate-proxy-image.test.ts.snap @@ -1,6 +1,6 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`Generate proxy image > success > multiple service > create domain config succesful (domain certs does not exists) 1`] = ` +exports[`Utils - generateProxyImage > success > multiple service > create domain config succesful (domain certs does not exists) 1`] = ` [MockFunction writeFileSync] { "calls": [ [ @@ -142,7 +142,7 @@ CMD ["nginx", "-g", "daemon off;"]", } `; -exports[`Generate proxy image > success > multiple service > create domain config succesful (domain certs does not exists) 2`] = ` +exports[`Utils - generateProxyImage > success > multiple service > create domain config succesful (domain certs does not exists) 2`] = ` [MockFunction spy] { "calls": [ [ @@ -164,7 +164,7 @@ exports[`Generate proxy image > success > multiple service > create domain confi } `; -exports[`Generate proxy image > success > multiple service > create domain config succesful (localhost certs does not exists) 1`] = ` +exports[`Utils - generateProxyImage > success > multiple service > create domain config succesful (localhost certs does not exists) 1`] = ` [MockFunction writeFileSync] { "calls": [ [ @@ -306,7 +306,7 @@ CMD ["nginx", "-g", "daemon off;"]", } `; -exports[`Generate proxy image > success > multiple service > create domain config succesful (localhost certs does not exists) 2`] = ` +exports[`Utils - generateProxyImage > success > multiple service > create domain config succesful (localhost certs does not exists) 2`] = ` [MockFunction spy] { "calls": [ [ @@ -328,7 +328,7 @@ exports[`Generate proxy image > success > multiple service > create domain confi } `; -exports[`Generate proxy image > success > multiple service > does not exists localhost certs 1`] = ` +exports[`Utils - generateProxyImage > success > multiple service > does not exists localhost certs 1`] = ` [MockFunction writeFileSync] { "calls": [ [ @@ -470,7 +470,7 @@ CMD ["nginx", "-g", "daemon off;"]", } `; -exports[`Generate proxy image > success > multiple service > does not exists localhost certs 2`] = ` +exports[`Utils - generateProxyImage > success > multiple service > does not exists localhost certs 2`] = ` [MockFunction spy] { "calls": [ [ @@ -492,7 +492,7 @@ exports[`Generate proxy image > success > multiple service > does not exists loc } `; -exports[`Generate proxy image > success > single service > create domain config succesful (domain certs does not exists) 1`] = ` +exports[`Utils - generateProxyImage > success > single service > create domain config succesful (domain certs does not exists) 1`] = ` [MockFunction writeFileSync] { "calls": [ [ @@ -610,7 +610,7 @@ CMD ["nginx", "-g", "daemon off;"]", } `; -exports[`Generate proxy image > success > single service > create domain config succesful (domain certs does not exists) 2`] = ` +exports[`Utils - generateProxyImage > success > single service > create domain config succesful (domain certs does not exists) 2`] = ` [MockFunction spy] { "calls": [ [ @@ -632,7 +632,7 @@ exports[`Generate proxy image > success > single service > create domain config } `; -exports[`Generate proxy image > success > single service > create domain config succesful (localhost certs does not exists) 1`] = ` +exports[`Utils - generateProxyImage > success > single service > create domain config succesful (localhost certs does not exists) 1`] = ` [MockFunction writeFileSync] { "calls": [ [ @@ -750,7 +750,7 @@ CMD ["nginx", "-g", "daemon off;"]", } `; -exports[`Generate proxy image > success > single service > create domain config succesful (localhost certs does not exists) 2`] = ` +exports[`Utils - generateProxyImage > success > single service > create domain config succesful (localhost certs does not exists) 2`] = ` [MockFunction spy] { "calls": [ [ @@ -772,7 +772,7 @@ exports[`Generate proxy image > success > single service > create domain config } `; -exports[`Generate proxy image > success > single service > does not exists localhost certs 1`] = ` +exports[`Utils - generateProxyImage > success > single service > does not exists localhost certs 1`] = ` [MockFunction writeFileSync] { "calls": [ [ @@ -890,7 +890,7 @@ CMD ["nginx", "-g", "daemon off;"]", } `; -exports[`Generate proxy image > success > single service > does not exists localhost certs 2`] = ` +exports[`Utils - generateProxyImage > success > single service > does not exists localhost certs 2`] = ` [MockFunction spy] { "calls": [ [ diff --git a/packages/cli/src/utils/__snapshots__/list-configs.test.ts.snap b/packages/cli/src/utils/__snapshots__/list-configs.test.ts.snap new file mode 100644 index 0000000..7bf7bcb --- /dev/null +++ b/packages/cli/src/utils/__snapshots__/list-configs.test.ts.snap @@ -0,0 +1,27 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`Utils - listConfigs > list configs 1`] = ` +[MockFunction spy] { + "calls": [ + [ + " +┌──────────────────────────────────────┬───────────────────────┬───────────────────────────────┬───────────┬──────┬──────┐ +│ id │ key │ domains │ location │ port │ ping │ +├──────────────────────────────────────┼───────────────────────┼───────────────────────────────┼───────────┼──────┼──────┤ +│ d7274462-e2cc-4ed3-8b07-fea3e342e7aa │ local.some-domain.tld │ https://local.some-domain.tld │ │ │ │ +├──────────────────────────────────────┼───────────────────────┼───────────────────────────────┼───────────┼──────┼──────┤ +│ │ │ │ / │ 3333 │ 200 │ +├──────────────────────────────────────┼───────────────────────┼───────────────────────────────┼───────────┼──────┼──────┤ +│ │ │ │ /app-name │ 3000 │ 200 │ +└──────────────────────────────────────┴───────────────────────┴───────────────────────────────┴───────────┴──────┴──────┘ +", + ], + ], + "results": [ + { + "type": "return", + "value": undefined, + }, + ], +} +`; diff --git a/packages/cli/src/utils/domain-exists-in-hosts.test.ts b/packages/cli/src/utils/domain-exists-in-hosts.test.ts new file mode 100644 index 0000000..f03bc02 --- /dev/null +++ b/packages/cli/src/utils/domain-exists-in-hosts.test.ts @@ -0,0 +1,23 @@ +import fs from "fs"; + +import { domainExistsInHosts } from "@/utils"; + +describe("Utils - domainExistsInHosts", () => { + test("domain does not exists", async () => { + vi.spyOn(fs, "readFileSync").mockReturnValue(` +127.0.0.1 localhost +127.0.0.1 domain-exists.com +`); + + expect(await domainExistsInHosts("domain-does-not-exists.com")).toBe(false); + }); + + test("domain exists", async () => { + vi.spyOn(fs, "readFileSync").mockReturnValue(` +127.0.0.1 localhost +127.0.0.1 domain-exists.com +`); + + expect(await domainExistsInHosts("domain-exists.com")).toBe(true); + }); +}); diff --git a/packages/cli/src/utils/domain-exists-in-hosts.ts b/packages/cli/src/utils/domain-exists-in-hosts.ts index c0edafa..4f14f1b 100644 --- a/packages/cli/src/utils/domain-exists-in-hosts.ts +++ b/packages/cli/src/utils/domain-exists-in-hosts.ts @@ -1,11 +1,13 @@ -import fs from "fs/promises"; +import fs from "fs"; export async function domainExistsInHosts(domain: string) { - const hostsContent = await fs.readFile("/etc/hosts", { encoding: "utf8" }); + const hostsContent = await fs.readFileSync("/etc/hosts", { + encoding: "utf8", + }); - const [alreadyExistsInHosts] = + const [alreadyExistsInHosts = false] = hostsContent.match(new RegExp(`\\d+.\\d+.\\d+.\\d+.*?${domain}$`, "mi")) || []; - return alreadyExistsInHosts; + return Boolean(alreadyExistsInHosts); } diff --git a/packages/cli/src/utils/generate-proxy-image.test.ts b/packages/cli/src/utils/generate-proxy-image.test.ts index 772d8b4..668b652 100644 --- a/packages/cli/src/utils/generate-proxy-image.test.ts +++ b/packages/cli/src/utils/generate-proxy-image.test.ts @@ -4,12 +4,11 @@ import fs from "fs"; import shell from "shelljs"; import listContainer from "@/list-container"; - -import { generateProxyImage } from "."; +import { generateProxyImage } from "@/utils"; vi.mock("@/list-container"); -describe("Generate proxy image", () => { +describe("Utils - generateProxyImage", () => { beforeEach(() => { vi.spyOn(fs, "existsSync").mockReturnValue(false); }); diff --git a/packages/cli/src/utils/hosts.test.ts b/packages/cli/src/utils/hosts.test.ts index 0b30764..02fe18d 100644 --- a/packages/cli/src/utils/hosts.test.ts +++ b/packages/cli/src/utils/hosts.test.ts @@ -1,18 +1,16 @@ import consola from "consola"; -import fs from "fs/promises"; +import fs from "fs"; import { HOSTS_END, HOSTS_START } from "@/constants"; import { getContentFromHosts, setContentToHosts, updateHosts } from "./hosts"; -describe("Utils - hosts", () => { +describe("Utils - getContentFromHosts, setContentToHosts, updateHosts", () => { test("move domain if already exists without Local SSL config slot", async () => { - vi.spyOn(fs, "readFile").mockReturnValue( - Promise.resolve(` + vi.spyOn(fs, "readFileSync").mockReturnValue(` 127.0.0.1 localhost 127.0.0.1 other-domain.com -`), - ); +`); const result = await getContentFromHosts(); @@ -20,12 +18,10 @@ describe("Utils - hosts", () => { }); test("get hosts content without Local SSL config slot", async () => { - vi.spyOn(fs, "readFile").mockReturnValue( - Promise.resolve(` + vi.spyOn(fs, "readFileSync").mockReturnValue(` 127.0.0.1 localhost 127.0.0.1 other-domain.com -`), - ); +`); const result = await getContentFromHosts(); @@ -33,8 +29,7 @@ describe("Utils - hosts", () => { }); test("get hosts content with Local SSL config slot", async () => { - vi.spyOn(fs, "readFile").mockReturnValue( - Promise.resolve(` + vi.spyOn(fs, "readFileSync").mockReturnValue(` 127.0.0.1 localhost ${HOSTS_START} @@ -43,8 +38,7 @@ ${HOSTS_START} ${HOSTS_END} 127.0.0.1 other-domain.com -`), - ); +`); const result = await getContentFromHosts(); @@ -58,14 +52,12 @@ ${HOSTS_END} test("set hosts content without Local SSL config slot", async () => { vi.spyOn(consola, "prompt").mockReturnValue(Promise.resolve(true)); - vi.spyOn(fs, "readFile").mockReturnValue( - Promise.resolve(` + vi.spyOn(fs, "readFileSync").mockReturnValue(` 127.0.0.1 localhost 127.0.0.1 other-domain.com -`), - ); +`); - vi.spyOn(fs, "writeFile").mockImplementation(vi.fn()); + vi.spyOn(fs, "writeFileSync").mockImplementation(vi.fn()); await setContentToHosts( ` @@ -74,7 +66,13 @@ ${HOSTS_END} `.trim(), ); - expect(fs.writeFile).toBeCalledWith( + expect(fs.readFileSync).toBeCalledTimes(1); + expect(fs.readFileSync).toHaveBeenNthCalledWith(1, "/etc/hosts", { + encoding: "utf8", + }); + + expect(fs.writeFileSync).toBeCalledTimes(1); + expect(fs.writeFileSync).toBeCalledWith( expect.stringMatching(/\/root\/path\/.tmp-hosts/i), ` 127.0.0.1 localhost @@ -91,8 +89,7 @@ ${HOSTS_END} test("set hosts content with Local SSL config slot", async () => { vi.spyOn(consola, "prompt").mockReturnValue(Promise.resolve(true)); - vi.spyOn(fs, "readFile").mockReturnValue( - Promise.resolve(` + vi.spyOn(fs, "readFileSync").mockReturnValue(` 127.0.0.1 localhost ${HOSTS_START} @@ -101,10 +98,7 @@ ${HOSTS_START} ${HOSTS_END} 127.0.0.1 other-domain.com -`), - ); - - vi.spyOn(fs, "writeFile").mockImplementation(vi.fn()); +`); await setContentToHosts( ` @@ -113,7 +107,8 @@ ${HOSTS_END} `.trim(), ); - expect(fs.writeFile).toBeCalledWith( + expect(fs.writeFileSync).toBeCalledTimes(1); + expect(fs.writeFileSync).toBeCalledWith( expect.stringMatching(/\/root\/path\/.tmp-hosts/i), ` 127.0.0.1 localhost @@ -130,9 +125,7 @@ ${HOSTS_END} test("update hosts where a domain already exists outside Local SSL config slot", async () => { vi.spyOn(consola, "prompt").mockReturnValue(Promise.resolve(true)); - vi.spyOn(fs, "readFile") - .mockReturnValueOnce( - Promise.resolve(` + vi.spyOn(fs, "readFileSync").mockReturnValueOnce(` 127.0.0.1 localhost ${HOSTS_START} @@ -141,20 +134,14 @@ ${HOSTS_START} ${HOSTS_END} 127.0.0.1 other-domain.com -`), - ) - .mockReturnValueOnce( - Promise.resolve(` +`).mockReturnValueOnce(` 127.0.0.1 localhost ${HOSTS_START} 127.0.0.1 local.domain.com 127.0.0.1 local.domain.dev ${HOSTS_END} -`), - ) - .mockReturnValueOnce( - Promise.resolve(` +`).mockReturnValueOnce(` 127.0.0.1 localhost ${HOSTS_START} @@ -162,14 +149,27 @@ ${HOSTS_START} 127.0.0.1 local.domain.dev 127.0.0.1 other-domain.com ${HOSTS_END} -`), - ); +`); vi.spyOn(fs, "writeFile").mockImplementation(vi.fn()); await updateHosts("other-domain.com"); - expect(fs.writeFile).nthCalledWith( + // read files + expect(fs.readFileSync).toBeCalledTimes(3); + expect(fs.readFileSync).nthCalledWith(1, "/etc/hosts", { + encoding: "utf8", + }); + expect(fs.readFileSync).nthCalledWith(2, "/etc/hosts", { + encoding: "utf8", + }); + expect(fs.readFileSync).nthCalledWith(3, "/etc/hosts", { + encoding: "utf8", + }); + + // write files + expect(fs.writeFileSync).toBeCalledTimes(2); + expect(fs.writeFileSync).nthCalledWith( 1, expect.stringMatching(/\/root\/path\/.tmp-hosts/i), ` @@ -181,7 +181,7 @@ ${HOSTS_START} ${HOSTS_END} `, ); - expect(fs.writeFile).nthCalledWith( + expect(fs.writeFileSync).nthCalledWith( 2, expect.stringMatching(/\/root\/path\/.tmp-hosts/i), ` @@ -198,29 +198,21 @@ ${HOSTS_END} test("update hosts where a domain does not exists inside/outside Local SSL config slot", async () => { vi.spyOn(consola, "prompt").mockReturnValue(Promise.resolve(true)); - vi.spyOn(fs, "readFile") - .mockReturnValueOnce( - Promise.resolve(` + vi.spyOn(fs, "readFileSync").mockReturnValueOnce(` 127.0.0.1 localhost ${HOSTS_START} 127.0.0.1 local.domain.com 127.0.0.1 local.domain.dev ${HOSTS_END} -`), - ) - .mockReturnValueOnce( - Promise.resolve(` +`).mockReturnValueOnce(` 127.0.0.1 localhost ${HOSTS_START} 127.0.0.1 local.domain.com 127.0.0.1 local.domain.dev ${HOSTS_END} -`), - ) - .mockReturnValueOnce( - Promise.resolve(` +`).mockReturnValueOnce(` 127.0.0.1 localhost ${HOSTS_START} @@ -228,14 +220,25 @@ ${HOSTS_START} 127.0.0.1 local.domain.dev 127.0.0.1 other-domain.com ${HOSTS_END} -`), - ); - - vi.spyOn(fs, "writeFile").mockImplementation(vi.fn()); +`); await updateHosts("other-domain.com"); - expect(fs.writeFile).nthCalledWith( + // read files + expect(fs.readFileSync).toBeCalledTimes(3); + expect(fs.readFileSync).nthCalledWith(1, "/etc/hosts", { + encoding: "utf8", + }); + expect(fs.readFileSync).nthCalledWith(2, "/etc/hosts", { + encoding: "utf8", + }); + expect(fs.readFileSync).nthCalledWith(3, "/etc/hosts", { + encoding: "utf8", + }); + + // write files + expect(fs.writeFileSync).toBeCalledTimes(1); + expect(fs.writeFileSync).nthCalledWith( 1, expect.stringMatching(/\/root\/path\/.tmp-hosts/i), ` @@ -251,9 +254,7 @@ ${HOSTS_END} }); test("update hosts where a domain already exists into Local SSL slot", async () => { - vi.spyOn(fs, "readFile") - .mockReturnValueOnce( - Promise.resolve(` + vi.spyOn(fs, "readFileSync").mockReturnValueOnce(` 127.0.0.1 localhost ${HOSTS_START} @@ -262,10 +263,7 @@ ${HOSTS_START} 127.0.0.1 other-domain.com ${HOSTS_END} -`), - ) - .mockReturnValueOnce( - Promise.resolve(` +`).mockReturnValueOnce(` 127.0.0.1 localhost ${HOSTS_START} @@ -273,10 +271,7 @@ ${HOSTS_START} 127.0.0.1 local.domain.dev 127.0.0.1 other-domain.com ${HOSTS_END} -`), - ) - .mockReturnValueOnce( - Promise.resolve(` +`).mockReturnValueOnce(` 127.0.0.1 localhost ${HOSTS_START} @@ -284,13 +279,19 @@ ${HOSTS_START} 127.0.0.1 local.domain.dev 127.0.0.1 other-domain.com ${HOSTS_END} -`), - ); - - vi.spyOn(fs, "writeFile").mockImplementation(vi.fn()); +`); await updateHosts("other-domain.com"); - expect(fs.writeFile).not.toBeCalled(); + // read files + expect(fs.readFileSync).toBeCalledTimes(2); + expect(fs.readFileSync).nthCalledWith(1, "/etc/hosts", { + encoding: "utf8", + }); + expect(fs.readFileSync).nthCalledWith(2, "/etc/hosts", { + encoding: "utf8", + }); + + expect(fs.writeFileSync).not.toBeCalled(); }); }); diff --git a/packages/cli/src/utils/hosts.ts b/packages/cli/src/utils/hosts.ts index ec968c0..a0f4e98 100644 --- a/packages/cli/src/utils/hosts.ts +++ b/packages/cli/src/utils/hosts.ts @@ -1,5 +1,5 @@ import consola from "consola"; -import fs from "fs/promises"; +import fs from "fs"; import path from "path"; import { HOSTS_END, HOSTS_START } from "@/constants"; @@ -10,7 +10,9 @@ const distPath = path.resolve(__dirname, "./"); const tmpHostsPath = `${distPath}/.tmp-hosts`; export async function getContentFromHosts(): Promise { - const hostsContent = await fs.readFile("/etc/hosts", { encoding: "utf8" }); + const hostsContent = await fs.readFileSync("/etc/hosts", { + encoding: "utf8", + }); const [, localSSLHosts = ""] = hostsContent.match(new RegExp(`${HOSTS_START}([^#]+)${HOSTS_END}`, "im")) || @@ -20,7 +22,9 @@ export async function getContentFromHosts(): Promise { } export async function setContentToHosts(content: string): Promise { - const hostsContent = await fs.readFile("/etc/hosts", { encoding: "utf8" }); + const hostsContent = await fs.readFileSync("/etc/hosts", { + encoding: "utf8", + }); const [, localSSLHosts = ""] = hostsContent.match(new RegExp(`${HOSTS_START}([^#]+)${HOSTS_END}`, "im")) || []; @@ -45,7 +49,7 @@ ${HOSTS_START}\n${content}\n${HOSTS_END} }); if (answer) { - await fs.writeFile(tmpHostsPath, newContent); + await fs.writeFileSync(tmpHostsPath, newContent); updateSystemHosts(tmpHostsPath); } @@ -53,7 +57,9 @@ ${HOSTS_START}\n${content}\n${HOSTS_END} } export async function updateHosts(domain: string) { - const hostsContent = await fs.readFile("/etc/hosts", { encoding: "utf8" }); + const hostsContent = await fs.readFileSync("/etc/hosts", { + encoding: "utf8", + }); const currentLocalSSLHosts = await getContentFromHosts(); const [alreadyExistsInLocalSSLHosts] = @@ -77,7 +83,7 @@ export async function updateHosts(domain: string) { ); try { - await fs.writeFile(tmpHostsPath, `\n${hostsContentCleaned.trim()}\n`); + await fs.writeFileSync(tmpHostsPath, `\n${hostsContentCleaned.trim()}\n`); updateSystemHosts(tmpHostsPath); } catch (error) { // silent diff --git a/packages/cli/src/utils/list-configs.test.ts b/packages/cli/src/utils/list-configs.test.ts new file mode 100644 index 0000000..f78f1c9 --- /dev/null +++ b/packages/cli/src/utils/list-configs.test.ts @@ -0,0 +1,35 @@ +import shell from "shelljs"; + +import { listConfigs } from "@/utils/list-configs"; + +describe("Utils - listConfigs", () => { + test("list configs", () => { + const configs = [ + { + id: "d7274462-e2cc-4ed3-8b07-fea3e342e7aa", + domain: "local.some-domain.tld", + services: [ + { + id: "29ecf855-5262-4b53-b742-03c8505abf2f", + location: "/", + port: "3333", + }, + { + id: "3cbf00b7-4fdd-4d37-8634-575c969faa15", + location: "/app-name", + port: "3000", + }, + ], + }, + ]; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (vi.spyOn(shell, "exec") as any).mockImplementation(() => ({ + stdout: 200, + })); + + listConfigs(configs); + + expect(shell.echo).matchSnapshot(); + }); +}); diff --git a/packages/cli/src/utils/update-system-hosts.ts b/packages/cli/src/utils/update-system-hosts.ts index 255ef40..4a205dd 100644 --- a/packages/cli/src/utils/update-system-hosts.ts +++ b/packages/cli/src/utils/update-system-hosts.ts @@ -39,7 +39,7 @@ export function updateSystemHosts(tmpHostsPath: string) { const watchTmpHostsFile = chokidar.watch(tmpHostsPath).on("unlink", () => { watchTmpHostsFile.unwatch(tmpHostsPath); - consola.info(`Your hosts has been updated. Type \`cat/etc/hosts\` in your terminal to see the last updates on LOCAL SSL block. + consola.info(`Your hosts has been updated. Type \`cat /etc/hosts\` in your terminal to see the last updates on LOCAL SSL block. `); }); } diff --git a/packages/cli/src/utils/validate-domain.test.ts b/packages/cli/src/utils/validate-domain.test.ts index 18bf656..21c66e9 100644 --- a/packages/cli/src/utils/validate-domain.test.ts +++ b/packages/cli/src/utils/validate-domain.test.ts @@ -1,7 +1,7 @@ import consola from "consola"; import shell from "shelljs"; -import { validateDomain } from "."; +import { validateDomain } from "@/utils"; describe("Validate domain", () => { describe("wrong TLD", () => { diff --git a/packages/cli/src/utils/validate-location.test.ts b/packages/cli/src/utils/validate-location.test.ts index 64a12d1..9dc60d1 100644 --- a/packages/cli/src/utils/validate-location.test.ts +++ b/packages/cli/src/utils/validate-location.test.ts @@ -1,6 +1,6 @@ import consola from "consola"; -import { validateLocation } from "."; +import { validateLocation } from "@/utils"; describe("Validate location", () => { describe("failures", () => { diff --git a/packages/cli/src/utils/validate-port.test.ts b/packages/cli/src/utils/validate-port.test.ts index 44aaa9d..8b8c219 100644 --- a/packages/cli/src/utils/validate-port.test.ts +++ b/packages/cli/src/utils/validate-port.test.ts @@ -1,10 +1,11 @@ import consola from "consola"; -import { validatePort } from "."; +import { validatePort } from "@/utils"; describe("Validate port", () => { describe("success", () => { const ports = [["1025"], ["3000"], ["65535"]]; + test.each(ports)("Port %s is valid", (port) => { validatePort(port);