From 5f023d828731621158b54703c0829a1a0d01d88a Mon Sep 17 00:00:00 2001 From: Karol Wypchlo Date: Wed, 5 Oct 2022 23:50:39 +0200 Subject: [PATCH] backfill utils tests --- src/index.js | 8 +- src/{api => routes}/critical.js | 0 src/{api => routes}/disabled.js | 0 src/{api => routes}/extended.js | 0 src/{api => routes}/index.js | 0 src/utils.js | 2 +- src/utils.test.js | 203 ++++++++++++++++++++++++++++++++ src/whatismyip.js | 9 +- 8 files changed, 216 insertions(+), 6 deletions(-) rename src/{api => routes}/critical.js (100%) rename src/{api => routes}/disabled.js (100%) rename src/{api => routes}/extended.js (100%) rename src/{api => routes}/index.js (100%) diff --git a/src/index.js b/src/index.js index 61ad96d..d1656d2 100644 --- a/src/index.js +++ b/src/index.js @@ -34,16 +34,16 @@ server.use((req, res, next) => { // display current health check status (shows only failed checks if any) // note: response code will be 200 when status is up and 503 otherwise -server.get("/health-check", require("./api/index")); +server.get("/health-check", require("./routes/index")); // display critical checks (last 24 hours) -server.get("/health-check/critical", require("./api/critical")); +server.get("/health-check/critical", require("./routes/critical")); // display extended checks (last 24 hours) -server.get("/health-check/extended", require("./api/extended")); +server.get("/health-check/extended", require("./routes/extended")); // display information whether server is set to disabled -server.get("/health-check/disabled", require("./api/disabled")); +server.get("/health-check/disabled", require("./routes/disabled")); // prepare express server configuration options const host = process.env.HOSTNAME || "0.0.0.0"; diff --git a/src/api/critical.js b/src/routes/critical.js similarity index 100% rename from src/api/critical.js rename to src/routes/critical.js diff --git a/src/api/disabled.js b/src/routes/disabled.js similarity index 100% rename from src/api/disabled.js rename to src/routes/disabled.js diff --git a/src/api/extended.js b/src/routes/extended.js similarity index 100% rename from src/api/extended.js rename to src/routes/extended.js diff --git a/src/api/index.js b/src/routes/index.js similarity index 100% rename from src/api/index.js rename to src/routes/index.js diff --git a/src/utils.js b/src/utils.js index 2037ac1..0077ab0 100644 --- a/src/utils.js +++ b/src/utils.js @@ -48,7 +48,7 @@ function ensureValidJSON(object) { * isPortalModuleEnabled returns true if the given module is enabled */ function isPortalModuleEnabled(module) { - return process.env.PORTAL_MODULES && process.env.PORTAL_MODULES.indexOf(module) !== -1; + return Boolean(process.env.PORTAL_MODULES) && process.env.PORTAL_MODULES.indexOf(module) !== -1; } /** diff --git a/src/utils.test.js b/src/utils.test.js index c0d9a30..9128dbc 100644 --- a/src/utils.test.js +++ b/src/utils.test.js @@ -17,3 +17,206 @@ describe("ipRegex", () => { expect(ipRegex.test("")).toEqual(false); }); }); + +describe("calculateElapsedTime", () => { + const { calculateElapsedTime } = require("./utils"); + + test("should calculate elapsed time", () => { + jest.useFakeTimers(); + + const time = process.hrtime(); + + jest.advanceTimersByTime(1234); + + expect(calculateElapsedTime(time)).toEqual(1234); + }); +}); + +describe("getYesterdayISOString", () => { + const { getYesterdayISOString } = require("./utils"); + + test.each([ + ["2020-04-10T13:37:00.000Z", "2020-04-09T13:37:00.000Z"], + ["2020-04-01T13:37:00.000Z", "2020-03-31T13:37:00.000Z"], + ["2020-01-01T13:37:00.000Z", "2019-12-31T13:37:00.000Z"], + ])("should get yesterday date as iso string for %s", (date, yesterday) => { + jest.useFakeTimers().setSystemTime(new Date(date)); + + expect(getYesterdayISOString()).toEqual(yesterday); + }); +}); + +describe("getResponseContent", () => { + const { getResponseContent } = require("./utils"); + + describe("when body property is present", () => { + test("should try to parse as json", () => { + const response = { body: '{"foo":"bar"}' }; + + expect(getResponseContent(response)).toEqual({ foo: "bar" }); + }); + + test("should return raw if parsing as json failed", () => { + const response = { body: "foo bar" }; + + expect(getResponseContent(response)).toEqual("foo bar"); + }); + }); + + describe("when text property is present and body property is not", () => { + test("should try to parse as json", () => { + const response = { text: '{"foo":"bar"}' }; + + expect(getResponseContent(response)).toEqual({ foo: "bar" }); + }); + + test("should return raw if parsing as json failed", () => { + const response = { text: "foo bar" }; + + expect(getResponseContent(response)).toEqual("foo bar"); + }); + }); + + describe("when both body and text properties are present", () => { + test("should favour body property", () => { + const response = { body: "foo", text: "bar" }; + + expect(getResponseContent(response)).toEqual("foo"); + }); + }); +}); + +describe("ensureValidJSON", () => { + const { ensureValidJSON } = require("./utils"); + + test("should replace undefined values with a placeholder", () => { + const object = { foo: "bar", bar: undefined, fizz: { buzz: [1, undefined, 2] } }; + + expect(ensureValidJSON(object)).toEqual({ + foo: "bar", + bar: "--undefined--", + fizz: { buzz: [1, "--undefined--", 2] }, + }); + }); +}); + +describe("isPortalModuleEnabled", () => { + const { isPortalModuleEnabled } = require("./utils"); + const PORTAL_MODULES = process.env.PORTAL_MODULES; + + beforeEach(() => { + process.env.PORTAL_MODULES = PORTAL_MODULES; + }); + + afterAll(() => { + process.env.PORTAL_MODULES = PORTAL_MODULES; + }); + + test("should return false when portal modules are not defined", () => { + expect(isPortalModuleEnabled("a")).toEqual(false); + }); + + test("should return true when portal modules includes a module", () => { + process.env.PORTAL_MODULES = "abc"; + + expect(isPortalModuleEnabled("c")).toEqual(true); + }); + + test("should return false when portal modules does not include a module", () => { + process.env.PORTAL_MODULES = "abc"; + + expect(isPortalModuleEnabled("g")).toEqual(false); + }); +}); + +describe("getDisabledServerReason", () => { + const { getDisabledServerReason } = require("./utils"); + const DENY_PUBLIC_ACCESS = process.env.DENY_PUBLIC_ACCESS; + + beforeEach(() => { + process.env.DENY_PUBLIC_ACCESS = DENY_PUBLIC_ACCESS; + }); + + afterAll(() => { + process.env.DENY_PUBLIC_ACCESS = DENY_PUBLIC_ACCESS; + }); + + test("should return manual reason for disabled server", () => { + process.env.DENY_PUBLIC_ACCESS = false; + + expect(getDisabledServerReason("foo bar baz ?!")).toEqual("foo bar baz ?!"); + }); + + test("should return server access denied message when env variable is set", () => { + process.env.DENY_PUBLIC_ACCESS = true; + + expect(getDisabledServerReason()).toEqual("Server public access denied"); + }); + + test("should concatenate manual reason and server access denied message", () => { + process.env.DENY_PUBLIC_ACCESS = true; + + expect(getDisabledServerReason("foo bar baz ?!")).toEqual("foo bar baz ?! & Server public access denied"); + }); +}); + +describe("parseHeaderString", () => { + const { parseHeaderString } = require("./utils"); + + test("should return an object if string was a stringified object", () => { + expect(parseHeaderString('{"foo":"bar"}')).toEqual({ foo: "bar" }); + }); + + test("should return a string if the value is not an object", () => { + expect(parseHeaderString("123foo")).toEqual("123foo"); + }); +}); + +describe("getResponseErrorData", () => { + const { getResponseErrorData } = require("./utils"); + + test("should return an object with certain properties", () => { + const data = getResponseErrorData(new Error()); + + expect(data).toHaveProperty("statusCode"); + expect(data).toHaveProperty("errorMessage"); + expect(data).toHaveProperty("errorResponseContent"); + expect(data).toHaveProperty("ip"); + }); + + test("should find status code in response", () => { + const data = getResponseErrorData({ response: { statusCode: 201 } }); + + expect(data).toHaveProperty("statusCode", 201); + }); + + test("should find status code in error statusCode property", () => { + const data = getResponseErrorData({ statusCode: 202 }); + + expect(data).toHaveProperty("statusCode", 202); + }); + + test("should find status code in error status property", () => { + const data = getResponseErrorData({ status: 203 }); + + expect(data).toHaveProperty("statusCode", 203); + }); + + test("should assign error message", () => { + const data = getResponseErrorData({ message: "foo bar :(" }); + + expect(data).toHaveProperty("errorMessage", "foo bar :("); + }); + + test("should assign error response content if available", () => { + const data = getResponseErrorData({ response: { body: "oooooof" } }); + + expect(data).toHaveProperty("errorResponseContent", "oooooof"); + }); + + test("should assign error response ip if available", () => { + const data = getResponseErrorData({ response: { ip: "201.202.203.204" } }); + + expect(data).toHaveProperty("ip", "201.202.203.204"); + }); +}); diff --git a/src/whatismyip.js b/src/whatismyip.js index f91da4d..6c8092d 100644 --- a/src/whatismyip.js +++ b/src/whatismyip.js @@ -1,4 +1,11 @@ -const http = require("http"); +/** + * Simple node script to request external ip of the current machine and prints it to the console. + * It runs without any third party dependencies so can be used without installing node_modules. + * + * Execution example: node src/whatismyip.js + */ + +const http = require("node:http"); const { ipCheckService, ipRegex } = require("./utils"); const request = http.request({ host: ipCheckService }, (response) => {