diff --git a/.gitignore b/.gitignore
index 600d2d33b..172702b40 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
-.vscode
\ No newline at end of file
+.vscode
+.VSCodeCounter
\ No newline at end of file
diff --git a/server/.gitignore b/server/.gitignore
index 4bc621f83..9ae4e58ed 100755
--- a/server/.gitignore
+++ b/server/.gitignore
@@ -8,4 +8,5 @@ coverage
.clinic
node_modules
.vscode/*
-public
\ No newline at end of file
+public
+dist
\ No newline at end of file
diff --git a/server/package-lock.json b/server/package-lock.json
index 3e1130dc4..e2affbca0 100644
--- a/server/package-lock.json
+++ b/server/package-lock.json
@@ -54,7 +54,8 @@
"mocha": "11.1.0",
"nodemon": "3.1.9",
"prettier": "^3.3.3",
- "sinon": "19.0.2"
+ "sinon": "19.0.2",
+ "tsx": "4.20.5"
}
},
"node_modules/@asamuzakjp/css-color": {
@@ -258,6 +259,448 @@
"tslib": "^2.4.0"
}
},
+ "node_modules/@esbuild/aix-ppc64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.10.tgz",
+ "integrity": "sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "aix"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.10.tgz",
+ "integrity": "sha512-dQAxF1dW1C3zpeCDc5KqIYuZ1tgAdRXNoZP7vkBIRtKZPYe2xVr/d3SkirklCHudW1B45tGiUlz2pUWDfbDD4w==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.10.tgz",
+ "integrity": "sha512-LSQa7eDahypv/VO6WKohZGPSJDq5OVOo3UoFR1E4t4Gj1W7zEQMUhI+lo81H+DtB+kP+tDgBp+M4oNCwp6kffg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-x64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.10.tgz",
+ "integrity": "sha512-MiC9CWdPrfhibcXwr39p9ha1x0lZJ9KaVfvzA0Wxwz9ETX4v5CHfF09bx935nHlhi+MxhA63dKRRQLiVgSUtEg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-arm64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.10.tgz",
+ "integrity": "sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-x64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.10.tgz",
+ "integrity": "sha512-tguWg1olF6DGqzws97pKZ8G2L7Ig1vjDmGTwcTuYHbuU6TTjJe5FXbgs5C1BBzHbJ2bo1m3WkQDbWO2PvamRcg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.10.tgz",
+ "integrity": "sha512-3ZioSQSg1HT2N05YxeJWYR+Libe3bREVSdWhEEgExWaDtyFbbXWb49QgPvFH8u03vUPX10JhJPcz7s9t9+boWg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-x64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.10.tgz",
+ "integrity": "sha512-LLgJfHJk014Aa4anGDbh8bmI5Lk+QidDmGzuC2D+vP7mv/GeSN+H39zOf7pN5N8p059FcOfs2bVlrRr4SK9WxA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.10.tgz",
+ "integrity": "sha512-oR31GtBTFYCqEBALI9r6WxoU/ZofZl962pouZRTEYECvNF/dtXKku8YXcJkhgK/beU+zedXfIzHijSRapJY3vg==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.10.tgz",
+ "integrity": "sha512-5luJWN6YKBsawd5f9i4+c+geYiVEw20FVW5x0v1kEMWNq8UctFjDiMATBxLvmmHA4bf7F6hTRaJgtghFr9iziQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ia32": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.10.tgz",
+ "integrity": "sha512-NrSCx2Kim3EnnWgS4Txn0QGt0Xipoumb6z6sUtl5bOEZIVKhzfyp/Lyw4C1DIYvzeW/5mWYPBFJU3a/8Yr75DQ==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-loong64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.10.tgz",
+ "integrity": "sha512-xoSphrd4AZda8+rUDDfD9J6FUMjrkTz8itpTITM4/xgerAZZcFW7Dv+sun7333IfKxGG8gAq+3NbfEMJfiY+Eg==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-mips64el": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.10.tgz",
+ "integrity": "sha512-ab6eiuCwoMmYDyTnyptoKkVS3k8fy/1Uvq7Dj5czXI6DF2GqD2ToInBI0SHOp5/X1BdZ26RKc5+qjQNGRBelRA==",
+ "cpu": [
+ "mips64el"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ppc64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.10.tgz",
+ "integrity": "sha512-NLinzzOgZQsGpsTkEbdJTCanwA5/wozN9dSgEl12haXJBzMTpssebuXR42bthOF3z7zXFWH1AmvWunUCkBE4EA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-riscv64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.10.tgz",
+ "integrity": "sha512-FE557XdZDrtX8NMIeA8LBJX3dC2M8VGXwfrQWU7LB5SLOajfJIxmSdyL/gU1m64Zs9CBKvm4UAuBp5aJ8OgnrA==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-s390x": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.10.tgz",
+ "integrity": "sha512-3BBSbgzuB9ajLoVZk0mGu+EHlBwkusRmeNYdqmznmMc9zGASFjSsxgkNsqmXugpPk00gJ0JNKh/97nxmjctdew==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-x64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.10.tgz",
+ "integrity": "sha512-QSX81KhFoZGwenVyPoberggdW1nrQZSvfVDAIUXr3WqLRZGZqWk/P4T8p2SP+de2Sr5HPcvjhcJzEiulKgnxtA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-arm64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.10.tgz",
+ "integrity": "sha512-AKQM3gfYfSW8XRk8DdMCzaLUFB15dTrZfnX8WXQoOUpUBQ+NaAFCP1kPS/ykbbGYz7rxn0WS48/81l9hFl3u4A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-x64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.10.tgz",
+ "integrity": "sha512-7RTytDPGU6fek/hWuN9qQpeGPBZFfB4zZgcz2VK2Z5VpdUxEI8JKYsg3JfO0n/Z1E/6l05n0unDCNc4HnhQGig==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-arm64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.10.tgz",
+ "integrity": "sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-x64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.10.tgz",
+ "integrity": "sha512-XkA4frq1TLj4bEMB+2HnI0+4RnjbuGZfet2gs/LNs5Hc7D89ZQBHQ0gL2ND6Lzu1+QVkjp3x1gIcPKzRNP8bXw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openharmony-arm64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.10.tgz",
+ "integrity": "sha512-AVTSBhTX8Y/Fz6OmIVBip9tJzZEUcY8WLh7I59+upa5/GPhh2/aM6bvOMQySspnCCHvFi79kMtdJS1w0DXAeag==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openharmony"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/sunos-x64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.10.tgz",
+ "integrity": "sha512-fswk3XT0Uf2pGJmOpDB7yknqhVkJQkAQOcW/ccVOtfx05LkbWOaRAtn5SaqXypeKQra1QaEa841PgrSL9ubSPQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-arm64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.10.tgz",
+ "integrity": "sha512-ah+9b59KDTSfpaCg6VdJoOQvKjI33nTaQr4UluQwW7aEwZQsbMCfTmfEO4VyewOxx4RaDT/xCy9ra2GPWmO7Kw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-ia32": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.10.tgz",
+ "integrity": "sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-x64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.10.tgz",
+ "integrity": "sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/@eslint-community/eslint-utils": {
"version": "4.8.0",
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.8.0.tgz",
@@ -3163,6 +3606,48 @@
"node": ">= 0.4"
}
},
+ "node_modules/esbuild": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.10.tgz",
+ "integrity": "sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "optionalDependencies": {
+ "@esbuild/aix-ppc64": "0.25.10",
+ "@esbuild/android-arm": "0.25.10",
+ "@esbuild/android-arm64": "0.25.10",
+ "@esbuild/android-x64": "0.25.10",
+ "@esbuild/darwin-arm64": "0.25.10",
+ "@esbuild/darwin-x64": "0.25.10",
+ "@esbuild/freebsd-arm64": "0.25.10",
+ "@esbuild/freebsd-x64": "0.25.10",
+ "@esbuild/linux-arm": "0.25.10",
+ "@esbuild/linux-arm64": "0.25.10",
+ "@esbuild/linux-ia32": "0.25.10",
+ "@esbuild/linux-loong64": "0.25.10",
+ "@esbuild/linux-mips64el": "0.25.10",
+ "@esbuild/linux-ppc64": "0.25.10",
+ "@esbuild/linux-riscv64": "0.25.10",
+ "@esbuild/linux-s390x": "0.25.10",
+ "@esbuild/linux-x64": "0.25.10",
+ "@esbuild/netbsd-arm64": "0.25.10",
+ "@esbuild/netbsd-x64": "0.25.10",
+ "@esbuild/openbsd-arm64": "0.25.10",
+ "@esbuild/openbsd-x64": "0.25.10",
+ "@esbuild/openharmony-arm64": "0.25.10",
+ "@esbuild/sunos-x64": "0.25.10",
+ "@esbuild/win32-arm64": "0.25.10",
+ "@esbuild/win32-ia32": "0.25.10",
+ "@esbuild/win32-x64": "0.25.10"
+ }
+ },
"node_modules/escalade": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
@@ -4079,6 +4564,19 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/get-tsconfig": {
+ "version": "4.10.1",
+ "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.1.tgz",
+ "integrity": "sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "resolve-pkg-maps": "^1.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1"
+ }
+ },
"node_modules/glob": {
"version": "10.4.5",
"resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
@@ -7578,6 +8076,16 @@
"node": ">=4"
}
},
+ "node_modules/resolve-pkg-maps": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz",
+ "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
+ }
+ },
"node_modules/responselike": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz",
@@ -8551,6 +9059,26 @@
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"license": "0BSD"
},
+ "node_modules/tsx": {
+ "version": "4.20.5",
+ "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.20.5.tgz",
+ "integrity": "sha512-+wKjMNU9w/EaQayHXb7WA7ZaHY6hN8WgfvHNQ3t1PnU91/7O8TcTnIhCDYTZwnt8JsO9IBqZ30Ln1r7pPF52Aw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "esbuild": "~0.25.0",
+ "get-tsconfig": "^4.7.5"
+ },
+ "bin": {
+ "tsx": "dist/cli.mjs"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.3"
+ }
+ },
"node_modules/tweetnacl": {
"version": "0.14.5",
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
diff --git a/server/package.json b/server/package.json
index d879776a8..c57c3a4ce 100755
--- a/server/package.json
+++ b/server/package.json
@@ -6,7 +6,9 @@
"type": "module",
"scripts": {
"test": "c8 mocha",
- "dev": "nodemon src/index.js",
+ "dev": "nodemon --exec tsx src/index.js",
+ "start": "nodemon ./dist/index.js",
+ "build": "tsc",
"lint": "eslint .",
"lint-fix": "eslint --fix .",
"format": "prettier --write .",
@@ -61,6 +63,7 @@
"mocha": "11.1.0",
"nodemon": "3.1.9",
"prettier": "^3.3.3",
- "sinon": "19.0.2"
+ "sinon": "19.0.2",
+ "tsx": "4.20.5"
}
}
diff --git a/server/src/config/routes.js b/server/src/config/routes.js
index 7056393f9..2ec93a2dc 100644
--- a/server/src/config/routes.js
+++ b/server/src/config/routes.js
@@ -1,17 +1,17 @@
import { verifyJWT } from "../middleware/verifyJWT.js";
import { authApiLimiter } from "../middleware/rateLimiter.js";
-import AuthRoutes from "../routes/authRoute.js";
-import InviteRoutes from "../routes/inviteRoute.js";
-import MonitorRoutes from "../routes/monitorRoute.js";
-import CheckRoutes from "../routes/checkRoute.js";
-import SettingsRoutes from "../routes/settingsRoute.js";
-import MaintenanceWindowRoutes from "../routes/maintenanceWindowRoute.js";
-import StatusPageRoutes from "../routes/statusPageRoute.js";
-import QueueRoutes from "../routes/queueRoute.js";
-import LogRoutes from "../routes/logRoutes.js";
-import DiagnosticRoutes from "../routes/diagnosticRoute.js";
-import NotificationRoutes from "../routes/notificationRoute.js";
+import AuthRoutes from "../routes/v1/authRoute.js";
+import InviteRoutes from "../routes/v1//inviteRoute.js";
+import MonitorRoutes from "../routes/v1/monitorRoute.js";
+import CheckRoutes from "../routes/v1/checkRoute.js";
+import SettingsRoutes from "../routes/v1/settingsRoute.js";
+import MaintenanceWindowRoutes from "../routes/v1/maintenanceWindowRoute.js";
+import StatusPageRoutes from "../routes/v1/statusPageRoute.js";
+import QueueRoutes from "../routes/v1/queueRoute.js";
+import LogRoutes from "../routes/v1/logRoutes.js";
+import DiagnosticRoutes from "../routes/v1//diagnosticRoute.js";
+import NotificationRoutes from "../routes/v1/notificationRoute.js";
export const setupRoutes = (app, controllers) => {
const authRoutes = new AuthRoutes(controllers.authController);
diff --git a/server/src/routes/announcementsRoute.js b/server/src/routes/v1/announcementsRoute.js
similarity index 100%
rename from server/src/routes/announcementsRoute.js
rename to server/src/routes/v1/announcementsRoute.js
diff --git a/server/src/routes/authRoute.js b/server/src/routes/v1/authRoute.js
similarity index 85%
rename from server/src/routes/authRoute.js
rename to server/src/routes/v1/authRoute.js
index e790c60b0..f69f94f43 100755
--- a/server/src/routes/authRoute.js
+++ b/server/src/routes/v1/authRoute.js
@@ -1,9 +1,7 @@
import { Router } from "express";
-import { verifyJWT } from "../middleware/verifyJWT.js";
-import { verifyOwnership } from "../middleware/verifyOwnership.js";
-import { isAllowed } from "../middleware/isAllowed.js";
+import { verifyJWT } from "../../middleware/verifyJWT.js";
+import { isAllowed } from "../../middleware/isAllowed.js";
import multer from "multer";
-import User from "../db/models/User.js";
const upload = multer();
diff --git a/server/src/routes/checkRoute.js b/server/src/routes/v1/checkRoute.js
similarity index 76%
rename from server/src/routes/checkRoute.js
rename to server/src/routes/v1/checkRoute.js
index 8bdb2d4fb..673fe51e0 100755
--- a/server/src/routes/checkRoute.js
+++ b/server/src/routes/v1/checkRoute.js
@@ -1,9 +1,6 @@
import { Router } from "express";
-import { verifyOwnership } from "../middleware/verifyOwnership.js";
-import { verifyTeamAccess } from "../middleware/verifyTeamAccess.js";
-import { isAllowed } from "../middleware/isAllowed.js";
-import Monitor from "../db/models/Monitor.js";
-import Check from "../db/models/Check.js";
+
+import { isAllowed } from "../../middleware/isAllowed.js";
class CheckRoutes {
constructor(checkController) {
diff --git a/server/src/routes/diagnosticRoute.js b/server/src/routes/v1/diagnosticRoute.js
similarity index 77%
rename from server/src/routes/diagnosticRoute.js
rename to server/src/routes/v1/diagnosticRoute.js
index a15f5a038..1b7cc06be 100755
--- a/server/src/routes/diagnosticRoute.js
+++ b/server/src/routes/v1/diagnosticRoute.js
@@ -1,6 +1,6 @@
import { Router } from "express";
-import { verifyJWT } from "../middleware/verifyJWT.js";
-import { isAllowed } from "../middleware/isAllowed.js";
+import { verifyJWT } from "../../middleware/verifyJWT.js";
+import { isAllowed } from "../../middleware/isAllowed.js";
class DiagnosticRoutes {
constructor(diagnosticController) {
diff --git a/server/src/routes/inviteRoute.js b/server/src/routes/v1/inviteRoute.js
similarity index 82%
rename from server/src/routes/inviteRoute.js
rename to server/src/routes/v1/inviteRoute.js
index d495c5476..74fcfeb91 100755
--- a/server/src/routes/inviteRoute.js
+++ b/server/src/routes/v1/inviteRoute.js
@@ -1,6 +1,6 @@
import { Router } from "express";
-import { verifyJWT } from "../middleware/verifyJWT.js";
-import { isAllowed } from "../middleware/isAllowed.js";
+import { verifyJWT } from "../../middleware/verifyJWT.js";
+import { isAllowed } from "../../middleware/isAllowed.js";
class InviteRoutes {
constructor(inviteController) {
diff --git a/server/src/routes/logRoutes.js b/server/src/routes/v1/logRoutes.js
similarity index 85%
rename from server/src/routes/logRoutes.js
rename to server/src/routes/v1/logRoutes.js
index 867826dde..feabe669a 100755
--- a/server/src/routes/logRoutes.js
+++ b/server/src/routes/v1/logRoutes.js
@@ -1,5 +1,5 @@
import { Router } from "express";
-import { isAllowed } from "../middleware/isAllowed.js";
+import { isAllowed } from "../../middleware/isAllowed.js";
class LogRoutes {
constructor(logController) {
this.router = Router();
diff --git a/server/src/routes/maintenanceWindowRoute.js b/server/src/routes/v1/maintenanceWindowRoute.js
similarity index 91%
rename from server/src/routes/maintenanceWindowRoute.js
rename to server/src/routes/v1/maintenanceWindowRoute.js
index 774434ed6..622e98f88 100755
--- a/server/src/routes/maintenanceWindowRoute.js
+++ b/server/src/routes/v1/maintenanceWindowRoute.js
@@ -1,5 +1,5 @@
import { Router } from "express";
-import MaintenanceWindow from "../db/models/MaintenanceWindow.js";
+import MaintenanceWindow from "../../db/models/MaintenanceWindow.js";
class MaintenanceWindowRoutes {
constructor(maintenanceWindowController) {
this.router = Router();
diff --git a/server/src/routes/monitorRoute.js b/server/src/routes/v1/monitorRoute.js
similarity index 94%
rename from server/src/routes/monitorRoute.js
rename to server/src/routes/v1/monitorRoute.js
index 043d361d1..f8f219b83 100755
--- a/server/src/routes/monitorRoute.js
+++ b/server/src/routes/v1/monitorRoute.js
@@ -1,7 +1,7 @@
import { Router } from "express";
-import { isAllowed } from "../middleware/isAllowed.js";
+import { isAllowed } from "../../middleware/isAllowed.js";
import multer from "multer";
-import { fetchMonitorCertificate } from "../controllers/controllerUtils.js";
+import { fetchMonitorCertificate } from "../../controllers/controllerUtils.js";
const upload = multer({
storage: multer.memoryStorage(), // Store file in memory as Buffer
});
diff --git a/server/src/routes/notificationRoute.js b/server/src/routes/v1/notificationRoute.js
similarity index 100%
rename from server/src/routes/notificationRoute.js
rename to server/src/routes/v1/notificationRoute.js
diff --git a/server/src/routes/queueRoute.js b/server/src/routes/v1/queueRoute.js
similarity index 93%
rename from server/src/routes/queueRoute.js
rename to server/src/routes/v1/queueRoute.js
index 55e829b91..59e1cb744 100755
--- a/server/src/routes/queueRoute.js
+++ b/server/src/routes/v1/queueRoute.js
@@ -1,5 +1,5 @@
import { Router } from "express";
-import { isAllowed } from "../middleware/isAllowed.js";
+import { isAllowed } from "../../middleware/isAllowed.js";
class QueueRoutes {
constructor(queueController) {
this.router = Router();
diff --git a/server/src/routes/settingsRoute.js b/server/src/routes/v1/settingsRoute.js
similarity index 90%
rename from server/src/routes/settingsRoute.js
rename to server/src/routes/v1/settingsRoute.js
index 88eb67e65..76556e923 100755
--- a/server/src/routes/settingsRoute.js
+++ b/server/src/routes/v1/settingsRoute.js
@@ -1,5 +1,5 @@
import { Router } from "express";
-import { isAllowed } from "../middleware/isAllowed.js";
+import { isAllowed } from "../../middleware/isAllowed.js";
class SettingsRoutes {
constructor(settingsController) {
diff --git a/server/src/routes/statusPageRoute.js b/server/src/routes/v1/statusPageRoute.js
similarity index 93%
rename from server/src/routes/statusPageRoute.js
rename to server/src/routes/v1/statusPageRoute.js
index 53eb21fba..8300066a8 100755
--- a/server/src/routes/statusPageRoute.js
+++ b/server/src/routes/v1/statusPageRoute.js
@@ -1,5 +1,5 @@
import { Router } from "express";
-import { verifyJWT } from "../middleware/verifyJWT.js";
+import { verifyJWT } from "../../middleware/verifyJWT.js";
import multer from "multer";
const upload = multer();
diff --git a/server/tests/controllers/authController.test.js b/server/tests/controllers/authController.test.js
deleted file mode 100755
index 341c8eda6..000000000
--- a/server/tests/controllers/authController.test.js
+++ /dev/null
@@ -1,962 +0,0 @@
-import {
- issueToken,
- registerUser,
- loginUser,
- editUser,
- checkSuperadminExists,
- requestRecovery,
- validateRecovery,
- resetPassword,
- deleteUser,
- getAllUsers,
-} from "../../controllers/authController.js";
-import jwt from "jsonwebtoken";
-import { errorMessages, successMessages } from "../../utils/messages.js";
-import sinon from "sinon";
-import { tokenType } from "../../utils/utils.js";
-import logger from "../../utils/logger.js";
-
-describe("Auth Controller - issueToken", function () {
- let stub;
-
- afterEach(function () {
- sinon.restore(); // Restore stubs after each test
- });
-
- it("should reject with an error if jwt.sign fails", function () {
- const error = new Error("jwt.sign error");
- stub = sinon.stub(jwt, "sign").throws(error);
- const payload = { id: "123" };
- const appSettings = { jwtSecret: "my_secret" };
- expect(() => issueToken(payload, tokenType.ACCESS_TOKEN, appSettings)).to.throw(error);
- });
-
- it("should return a token if jwt.sign is successful and appSettings.jwtTTL is not defined", function () {
- const payload = { id: "123" };
- const appSettings = { jwtSecret: "my_secret" };
- const expectedToken = "mockToken";
-
- stub = sinon.stub(jwt, "sign").returns(expectedToken);
- const token = issueToken(payload, tokenType.ACCESS_TOKEN, appSettings);
- expect(token).to.equal(expectedToken);
- });
-
- it("should return a token if jwt.sign is successful and appSettings.jwtTTL is defined", function () {
- const payload = { id: "123" };
- const appSettings = { jwtSecret: "my_secret", jwtTTL: "1s" };
- const expectedToken = "mockToken";
-
- stub = sinon.stub(jwt, "sign").returns(expectedToken);
- const token = issueToken(payload, tokenType.ACCESS_TOKEN, appSettings);
- expect(token).to.equal(expectedToken);
- });
-
- it("should return a refresh token if jwt.sign is successful and appSettings.refreshTokenTTL is not defined", function () {
- const payload = {};
- const appSettings = { refreshTokenSecret: "my_refresh_secret" };
- const expectedToken = "mockRefreshToken";
-
- stub = sinon.stub(jwt, "sign").returns(expectedToken);
- const token = issueToken(payload, tokenType.REFRESH_TOKEN, appSettings);
- expect(token).to.equal(expectedToken);
- });
-
- it("should return a refresh token if jwt.sign is successful and appSettings.refreshTokenTTL is defined", function () {
- const payload = {};
- const appSettings = {
- refreshTokenSecret: "my_refresh_secret",
- refreshTokenTTL: "7d",
- };
- const expectedToken = "mockRefreshToken";
-
- stub = sinon.stub(jwt, "sign").returns(expectedToken);
- const token = issueToken(payload, tokenType.REFRESH_TOKEN, appSettings);
- expect(token).to.equal(expectedToken);
- });
-});
-
-describe("Auth Controller - registerUser", function () {
- let req, res, next;
-
- beforeEach(function () {
- req = {
- body: {
- firstName: "firstname",
- lastName: "lastname",
- email: "test@test.com",
- password: "Uptime1!",
- role: ["admin"],
- teamId: "123",
- inviteToken: "invite",
- },
- db: {
- checkSuperadmin: sinon.stub(),
- getInviteTokenAndDelete: sinon.stub(),
- updateAppSettings: sinon.stub(),
- insertUser: sinon.stub(),
- },
- settingsService: {
- getSettings: sinon.stub().resolves({
- jwtSecret: "my_secret",
- refreshTokenSecret: "my_refresh_secret",
- }),
- },
- emailService: {
- buildAndSendEmail: sinon.stub(),
- },
- file: {},
- };
- res = {
- status: sinon.stub().returnsThis(),
- json: sinon.stub(),
- };
- next = sinon.stub();
- sinon.stub(logger, "error");
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- it("should reject with an error if body validation fails", async function () {
- req.body = {};
- await registerUser(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].status).to.equal(422);
- });
-
- it("should reject with an error if checkSuperadmin fails", async function () {
- req.db.checkSuperadmin.throws(new Error("checkSuperadmin error"));
- await registerUser(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("checkSuperadmin error");
- });
-
- it("should reject with an error if getInviteTokenAndDelete fails", async function () {
- req.db.checkSuperadmin.returns(true);
- req.db.getInviteTokenAndDelete.throws(new Error("getInviteTokenAndDelete error"));
- await registerUser(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("getInviteTokenAndDelete error");
- });
-
- it("should reject with an error if updateAppSettings fails", async function () {
- req.db.checkSuperadmin.returns(false);
- req.db.updateAppSettings.throws(new Error("updateAppSettings error"));
- await registerUser(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("updateAppSettings error");
- });
-
- it("should reject with an error if insertUser fails", async function () {
- req.db.checkSuperadmin.resolves(false);
- req.db.updateAppSettings.resolves();
- req.db.insertUser.rejects(new Error("insertUser error"));
- await registerUser(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("insertUser error");
- });
-
- it("should reject with an error if settingsService.getSettings fails", async function () {
- req.db.checkSuperadmin.resolves(false);
- req.db.updateAppSettings.resolves();
- req.db.insertUser.resolves({ _id: "123" });
- req.settingsService.getSettings.rejects(new Error("settingsService.getSettings error"));
- await registerUser(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("settingsService.getSettings error");
- });
-
- it("should log an error if emailService.buildAndSendEmail fails", async function () {
- req.db.checkSuperadmin.resolves(false);
- req.db.updateAppSettings.resolves();
- req.db.insertUser.returns({ _id: "123" });
- req.settingsService.getSettings.returns({
- jwtSecret: "my_secret",
- refreshTokenSecret: "my_secret",
- });
- req.emailService.buildAndSendEmail.rejects(new Error("emailService error"));
- await registerUser(req, res, next);
- expect(logger.error.calledOnce).to.be.true;
- expect(logger.error.firstCall.args[0].message).to.equal("emailService error");
- });
-
- it("should return a success message and data if all operations are successful", async function () {
- const user = { _id: "123" };
- req.db.checkSuperadmin.resolves(false);
- req.db.updateAppSettings.resolves();
- req.db.insertUser.returns(user);
- req.settingsService.getSettings.returns({
- jwtSecret: "my_secret",
- refreshTokenSecret: "my_secret",
- });
- req.emailService.buildAndSendEmail.resolves("message-id");
- await registerUser(req, res, next);
- expect(res.status.calledWith(200)).to.be.true;
- expect(
- res.json.calledWith({
- success: true,
- msg: successMessages.AUTH_CREATE_USER,
- data: { user, token: sinon.match.string, refreshToken: sinon.match.string },
- })
- ).to.be.true;
- expect(next.notCalled).to.be.true;
- });
-
- it("should return a success message and data if all operations are successful and superAdmin true", async function () {
- const user = { _id: "123" };
- req.db.checkSuperadmin.resolves(true);
- req.db.updateAppSettings.resolves();
- req.db.insertUser.returns(user);
- req.settingsService.getSettings.returns({
- jwtSecret: "my_secret",
- refreshTokenSecret: "my_secret",
- });
- req.emailService.buildAndSendEmail.resolves("message-id");
- await registerUser(req, res, next);
- expect(res.status.calledWith(200)).to.be.true;
- expect(
- res.json.calledWith({
- success: true,
- msg: successMessages.AUTH_CREATE_USER,
- data: { user, token: sinon.match.string, refreshToken: sinon.match.string },
- })
- ).to.be.true;
- expect(next.notCalled).to.be.true;
- });
-});
-
-describe("Auth Controller - loginUser", function () {
- let req, res, next, user;
-
- beforeEach(function () {
- req = {
- body: { email: "test@example.com", password: "Password123!" },
- db: {
- getUserByEmail: sinon.stub(),
- },
- settingsService: {
- getSettings: sinon.stub().resolves({
- jwtSecret: "my_secret",
- refreshTokenSecret: "my_refresh_token",
- }),
- },
- };
- res = {
- status: sinon.stub().returnsThis(),
- json: sinon.stub(),
- };
- next = sinon.stub();
- user = {
- _doc: {
- email: "test@example.com",
- },
- comparePassword: sinon.stub(),
- };
- });
-
- it("should reject with an error if validation fails", async function () {
- req.body = {};
- await loginUser(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].status).to.equal(422);
- });
-
- it("should reject with an error if getUserByEmail fails", async function () {
- req.db.getUserByEmail.rejects(new Error("getUserByEmail error"));
- await loginUser(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("getUserByEmail error");
- });
-
- it("should login user successfully", async function () {
- req.db.getUserByEmail.resolves(user);
- user.comparePassword.resolves(true);
- await loginUser(req, res, next);
- expect(res.status.calledWith(200)).to.be.true;
- expect(
- res.json.calledWith({
- success: true,
- msg: successMessages.AUTH_LOGIN_USER,
- data: {
- user: {
- email: "test@example.com",
- avatarImage: undefined,
- },
- token: sinon.match.string,
- refreshToken: sinon.match.string,
- },
- })
- ).to.be.true;
- expect(next.notCalled).to.be.true;
- });
-
- it("should reject a user with an incorrect password", async function () {
- req.body = {
- email: "test@test.com",
- password: "Password123!",
- };
- req.db.getUserByEmail.resolves(user);
- user.comparePassword.resolves(false);
- await loginUser(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal(errorMessages.AUTH_INCORRECT_PASSWORD);
- });
-});
-
-describe("Auth Controller - refreshAuthToken", function () {
- let req, res, next, issueTokenStub;
-
- beforeEach(function () {
- req = {
- headers: {
- "x-refresh-token": "valid_refresh_token",
- authorization: "Bearer old_auth_token",
- },
- settingsService: {
- getSettings: sinon.stub().resolves({
- jwtSecret: "my_secret",
- refreshTokenSecret: "my_refresh_secret",
- }),
- },
- };
- res = {
- status: sinon.stub().returnsThis(),
- json: sinon.stub(),
- };
- next = sinon.stub();
- sinon.stub(jwt, "verify");
-
- issueTokenStub = sinon.stub().returns("new_auth_token");
- sinon.replace({ issueToken }, "issueToken", issueTokenStub);
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- it("should reject if no refresh token is provided", async function () {
- delete req.headers["x-refresh-token"];
- await refreshAuthToken(req, res, next);
-
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal(errorMessages.NO_REFRESH_TOKEN);
- expect(next.firstCall.args[0].status).to.equal(401);
- });
-
- it("should reject if the refresh token is invalid", async function () {
- jwt.verify.yields(new Error("invalid token"));
- await refreshAuthToken(req, res, next);
-
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal(errorMessages.INVALID_REFRESH_TOKEN);
- expect(next.firstCall.args[0].status).to.equal(401);
- });
-
- it("should reject if the refresh token is expired", async function () {
- const error = new Error("Token expired");
- error.name = "TokenExpiredError";
- jwt.verify.yields(error);
- await refreshAuthToken(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal(errorMessages.EXPIRED_REFRESH_TOKEN);
- expect(next.firstCall.args[0].status).to.equal(401);
- });
-
- it("should reject if settingsService.getSettings fails", async function () {
- req.settingsService.getSettings.rejects(new Error("settingsService.getSettings error"));
- await refreshAuthToken(req, res, next);
-
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("settingsService.getSettings error");
- });
-
- it("should generate a new auth token if the refresh token is valid", async function () {
- const decodedPayload = { expiresIn: "60" };
- jwt.verify.callsFake(() => {
- return decodedPayload;
- });
- await refreshAuthToken(req, res, next);
-
- expect(res.status.calledWith(200)).to.be.true;
- expect(
- res.json.calledWith({
- success: true,
- msg: successMessages.AUTH_TOKEN_REFRESHED,
- data: {
- user: decodedPayload,
- token: sinon.match.string,
- refreshToken: "valid_refresh_token",
- },
- })
- ).to.be.true;
- });
-});
-
-describe("Auth Controller - editUser", function () {
- let req, res, next, stub, user;
-
- beforeEach(function () {
- req = {
- params: { userId: "123" },
- body: { password: "Password1!", newPassword: "Password2!" },
- headers: { authorization: "Bearer token" },
- user: { _id: "123" },
- settingsService: {
- getSettings: sinon.stub().returns({ jwtSecret: "my_secret" }),
- },
- db: {
- getUserByEmail: sinon.stub(),
- updateUser: sinon.stub(),
- },
- };
- res = {
- status: sinon.stub().returnsThis(),
- json: sinon.stub(),
- };
- next = sinon.stub();
- stub = sinon.stub(jwt, "verify").returns({ email: "test@example.com" });
- });
-
- afterEach(function () {
- sinon.restore();
- stub.restore();
- });
-
- it("should reject with an error if param validation fails", async function () {
- req.params = {};
- await editUser(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].status).to.equal(422);
- });
-
- it("should reject with an error if body validation fails", async function () {
- req.body = { invalid: 1 };
- await editUser(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].status).to.equal(422);
- });
-
- it("should reject with an error if param.userId !== req.user._id", async function () {
- req.params = { userId: "456" };
- await editUser(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].status).to.equal(401);
- });
-
- it("should reject with an error if !req.body.password and getUserByEmail fails", async function () {
- req.db.getUserByEmail.rejects(new Error("getUserByEmail error"));
- await editUser(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("getUserByEmail error");
- });
-
- it("should reject with an error if user.comparePassword fails", async function () {
- req.db.getUserByEmail.returns({
- comparePassword: sinon.stub().rejects(new Error("Bad Password Match")),
- });
- await editUser(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("Bad Password Match");
- });
-
- it("should reject with an error if user.comparePassword returns false", async function () {
- req.db.getUserByEmail.returns({
- comparePassword: sinon.stub().returns(false),
- });
- await editUser(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].status).to.equal(401);
- expect(next.firstCall.args[0].message).to.equal(errorMessages.AUTH_INCORRECT_PASSWORD);
- });
-
- it("should edit a user if it receives a proper request", async function () {
- const user = {
- comparePassword: sinon.stub().resolves(true),
- };
- req.db.getUserByEmail.resolves(user);
- req.db.updateUser.resolves({ email: "test@example.com" });
-
- await editUser(req, res, next);
-
- expect(req.db.getUserByEmail.calledOnce).to.be.true;
- expect(req.db.updateUser.calledOnce).to.be.true;
- expect(res.status.calledWith(200)).to.be.true;
- expect(
- res.json.calledWith({
- success: true,
- msg: successMessages.AUTH_UPDATE_USER,
- data: { email: "test@example.com" },
- })
- ).to.be.true;
- expect(next.notCalled).to.be.true;
- });
-
- it("should edit a user if it receives a proper request and both password fields are undefined", async function () {
- req.body.password = undefined;
- req.body.newPassword = undefined;
- req.db.getUserByEmail.resolves(user);
- req.db.updateUser.resolves({ email: "test@example.com" });
-
- await editUser(req, res, next);
- expect(res.status.calledWith(200)).to.be.true;
- expect(
- res.json.calledWith({
- success: true,
- msg: successMessages.AUTH_UPDATE_USER,
- data: { email: "test@example.com" },
- })
- ).to.be.true;
- expect(next.notCalled).to.be.true;
- });
-
- it("should reject an edit request if password format is incorrect", async function () {
- req.body = { password: "bad_password", newPassword: "bad_password" };
- const user = {
- comparePassword: sinon.stub().resolves(true),
- };
- req.db.getUserByEmail.resolves(user);
-
- await editUser(req, res, next);
-
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].status).to.equal(422);
- });
-});
-
-describe("Auth Controller - checkSuperadminExists", function () {
- let req, res, next;
-
- beforeEach(function () {
- req = {
- db: {
- checkSuperadmin: sinon.stub(),
- },
- };
- res = {
- status: sinon.stub().returnsThis(),
- json: sinon.stub(),
- };
- next = sinon.stub();
- });
-
- it("should reject with an error if checkSuperadmin fails", async function () {
- req.db.checkSuperadmin.rejects(new Error("checkSuperadmin error"));
- await checkSuperadminExists(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("checkSuperadmin error");
- });
-
- it("should return true if a superadmin exists", async function () {
- req.db.checkSuperadmin.resolves(true);
- await checkSuperadminExists(req, res, next);
- expect(res.status.calledWith(200)).to.be.true;
- expect(
- res.json.calledWith({
- success: true,
- msg: successMessages.AUTH_SUPERADMIN_EXISTS,
- data: true,
- })
- ).to.be.true;
- expect(next.notCalled).to.be.true;
- });
-
- it("should return false if a superadmin does not exist", async function () {
- req.db.checkSuperadmin.resolves(false);
- await checkSuperadminExists(req, res, next);
- expect(res.status.calledWith(200)).to.be.true;
- expect(
- res.json.calledWith({
- success: true,
- msg: successMessages.AUTH_SUPERADMIN_EXISTS,
- data: false,
- })
- ).to.be.true;
- expect(next.notCalled).to.be.true;
- });
-});
-
-describe("Auth Controller - requestRecovery", function () {
- let req, res, next;
-
- beforeEach(function () {
- req = {
- body: { email: "test@test.com" },
- db: {
- getUserByEmail: sinon.stub(),
- requestRecoveryToken: sinon.stub(),
- },
- settingsService: {
- getSettings: sinon.stub().returns({ clientHost: "http://localhost" }),
- },
- emailService: {
- buildAndSendEmail: sinon.stub(),
- },
- };
- res = {
- status: sinon.stub().returnsThis(),
- json: sinon.stub(),
- };
- next = sinon.stub();
- });
-
- it("should reject with an error if validation fails", async function () {
- req.body = {};
- await requestRecovery(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].status).to.equal(422);
- });
-
- it("should reject with an error if getUserByEmail fails", async function () {
- req.db.getUserByEmail.rejects(new Error("getUserByEmail error"));
- await requestRecovery(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("getUserByEmail error");
- });
-
- it("should throw an error if the user is not found", async function () {
- req.db.getUserByEmail.resolves(null);
- await requestRecovery(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- // expect(next.firstCall.args[0].message).to.equal(
- // errorMessages.FRIENDLY_ERROR
- // );
- });
-
- it("should throw an error if the email is not provided", async function () {
- req.body = {};
- await requestRecovery(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].status).to.equal(422);
- });
-
- it("should return a success message if the email is provided", async function () {
- const user = { firstName: "John" };
- const recoveryToken = { token: "recovery-token" };
- const msgId = "message-id";
- req.db.getUserByEmail.resolves(user);
- req.db.requestRecoveryToken.resolves(recoveryToken);
- req.emailService.buildAndSendEmail.resolves(msgId);
- await requestRecovery(req, res, next);
- expect(req.db.getUserByEmail.calledOnceWith("test@test.com")).to.be.true;
- expect(req.db.requestRecoveryToken.calledOnceWith(req, res)).to.be.true;
- expect(
- req.emailService.buildAndSendEmail.calledOnceWith(
- "passwordResetTemplate",
- {
- name: "John",
- email: "test@test.com",
- url: "http://localhost/set-new-password/recovery-token",
- },
- "test@test.com",
- "Checkmate Password Reset"
- )
- ).to.be.true;
- expect(res.status.calledOnceWith(200)).to.be.true;
- expect(
- res.json.calledOnceWith({
- success: true,
- msg: successMessages.AUTH_CREATE_RECOVERY_TOKEN,
- data: msgId,
- })
- ).to.be.true;
- expect(next.notCalled).to.be.true;
- });
-});
-
-describe("Auth Controller - validateRecovery", function () {
- let req, res, next;
-
- beforeEach(function () {
- req = {
- body: { recoveryToken: "recovery-token" },
- db: {
- validateRecoveryToken: sinon.stub(),
- },
- };
- res = {
- status: sinon.stub().returnsThis(),
- json: sinon.stub(),
- };
- next = sinon.stub();
- });
-
- it("should reject with an error if validation fails", async function () {
- req.body = {};
- await validateRecovery(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].status).to.equal(422);
- });
-
- it("should reject with an error if validateRecoveryToken fails", async function () {
- req.db.validateRecoveryToken.rejects(new Error("validateRecoveryToken error"));
- await validateRecovery(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("validateRecoveryToken error");
- });
-
- it("should return a success message if the token is valid", async function () {
- req.db.validateRecoveryToken.resolves();
- await validateRecovery(req, res, next);
- expect(res.status.calledOnceWith(200)).to.be.true;
- expect(
- res.json.calledOnceWith({
- success: true,
- msg: successMessages.AUTH_VERIFY_RECOVERY_TOKEN,
- })
- ).to.be.true;
- expect(next.notCalled).to.be.true;
- });
-});
-
-describe("Auth Controller - resetPassword", function () {
- let req, res, next, newPasswordValidation, handleValidationError, handleError;
-
- beforeEach(function () {
- req = {
- body: {
- recoveryToken: "recovery-token",
- password: "Password1!",
- },
- db: {
- resetPassword: sinon.stub(),
- },
- settingsService: {
- getSettings: sinon.stub(),
- },
- };
- res = {
- status: sinon.stub().returnsThis(),
- json: sinon.stub(),
- };
- next = sinon.stub();
- newPasswordValidation = {
- validateAsync: sinon.stub(),
- };
- handleValidationError = sinon.stub();
- handleError = sinon.stub();
- });
-
- it("should reject with an error if validation fails", async function () {
- req.body = { password: "bad_password" };
- await resetPassword(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].status).to.equal(422);
- });
-
- it("should reject with an error if resetPassword fails", async function () {
- const error = new Error("resetPassword error");
- newPasswordValidation.validateAsync.resolves();
- req.db.resetPassword.rejects(error);
- await resetPassword(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("resetPassword error");
- });
-
- it("should reset password successfully", async function () {
- const user = { _doc: {} };
- const appSettings = { jwtSecret: "my_secret" };
- const token = "token";
-
- newPasswordValidation.validateAsync.resolves();
- req.db.resetPassword.resolves(user);
- req.settingsService.getSettings.resolves(appSettings);
-
- await resetPassword(req, res, next);
-
- expect(req.db.resetPassword.calledOnceWith(req, res)).to.be.true;
- expect(req.settingsService.getSettings.calledOnce).to.be.true;
- expect(res.status.calledOnceWith(200)).to.be.true;
- expect(
- res.json.calledOnceWith({
- success: true,
- msg: successMessages.AUTH_RESET_PASSWORD,
- data: { user: sinon.match.object, token: sinon.match.string },
- })
- ).to.be.true;
- expect(next.notCalled).to.be.true;
- });
-});
-
-describe("Auth Controller - deleteUser", function () {
- let req, res, next, handleError;
-
- beforeEach(function () {
- req = {
- headers: {
- authorization: "Bearer token",
- },
- db: {
- getUserByEmail: sinon.stub(),
- getMonitorsByTeamId: sinon.stub(),
- deleteJob: sinon.stub(),
- deleteChecks: sinon.stub(),
- deletePageSpeedChecksByMonitorId: sinon.stub(),
- deleteNotificationsByMonitorId: sinon.stub(),
- deleteTeam: sinon.stub(),
- deleteAllOtherUsers: sinon.stub(),
- deleteMonitorsByUserId: sinon.stub(),
- deleteUser: sinon.stub(),
- },
- jobQueue: {
- deleteJob: sinon.stub(),
- },
- };
- res = {
- status: sinon.stub().returnsThis(),
- json: sinon.stub(),
- };
- next = sinon.stub();
-
- sinon.stub(jwt, "decode");
-
- handleError = sinon.stub();
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- it("should throw an error if user is not found", async function () {
- jwt.decode.returns({ email: "test@example.com" });
- req.db.getUserByEmail.throws(new Error(errorMessages.DB_USER_NOT_FOUND));
-
- await deleteUser(req, res, next);
-
- expect(req.db.getUserByEmail.calledOnceWith("test@example.com")).to.be.true;
- expect(next.calledOnce).to.be.true;
- expect(next.firstCall.args[0].message).to.equal(errorMessages.DB_USER_NOT_FOUND);
- expect(res.status.notCalled).to.be.true;
- expect(res.json.notCalled).to.be.true;
- });
-
- it("should delete user and associated data if user is superadmin", async function () {
- const user = {
- _id: "user_id",
- email: "test@example.com",
- role: ["superadmin"],
- teamId: "team_id",
- };
- const monitors = [{ _id: "monitor_id" }];
-
- jwt.decode.returns({ email: "test@example.com" });
- req.db.getUserByEmail.resolves(user);
- req.db.getMonitorsByTeamId.resolves({ monitors });
-
- await deleteUser(req, res, next);
-
- expect(req.db.getUserByEmail.calledOnceWith("test@example.com")).to.be.true;
- expect(
- req.db.getMonitorsByTeamId.calledOnceWith({
- params: { teamId: "team_id" },
- })
- ).to.be.true;
- expect(req.jobQueue.deleteJob.calledOnceWith(monitors[0])).to.be.true;
- expect(req.db.deleteChecks.calledOnceWith("monitor_id")).to.be.true;
- expect(req.db.deletePageSpeedChecksByMonitorId.calledOnceWith("monitor_id")).to.be.true;
- expect(req.db.deleteNotificationsByMonitorId.calledOnceWith("monitor_id")).to.be.true;
- expect(req.db.deleteTeam.calledOnceWith("team_id")).to.be.true;
- expect(req.db.deleteAllOtherUsers.calledOnce).to.be.true;
- expect(req.db.deleteMonitorsByUserId.calledOnceWith("user_id")).to.be.true;
- expect(req.db.deleteUser.calledOnceWith("user_id")).to.be.true;
- expect(res.status.calledOnceWith(200)).to.be.true;
- expect(
- res.json.calledOnceWith({
- success: true,
- msg: successMessages.AUTH_DELETE_USER,
- })
- ).to.be.true;
- expect(next.notCalled).to.be.true;
- });
-
- it("should delete user if user is not superadmin", async function () {
- const user = {
- _id: "user_id",
- email: "test@example.com",
- role: ["user"],
- teamId: "team_id",
- };
-
- jwt.decode.returns({ email: "test@example.com" });
- req.db.getUserByEmail.resolves(user);
-
- await deleteUser(req, res, next);
-
- expect(req.db.getUserByEmail.calledOnceWith("test@example.com")).to.be.true;
- expect(
- req.db.getMonitorsByTeamId.calledOnceWith({
- params: { teamId: "team_id" },
- })
- ).to.be.true;
- expect(req.db.deleteUser.calledOnceWith("user_id")).to.be.true;
- expect(res.status.calledOnceWith(200)).to.be.true;
- expect(
- res.json.calledOnceWith({
- success: true,
- msg: successMessages.AUTH_DELETE_USER,
- })
- ).to.be.true;
- expect(next.notCalled).to.be.true;
- });
-
- it("should handle errors", async function () {
- const error = new Error("Something went wrong");
- const SERVICE_NAME = "AuthController";
- jwt.decode.returns({ email: "test@example.com" });
- req.db.getUserByEmail.rejects(error);
- await deleteUser(req, res, next);
- expect(next.calledOnce).to.be.true;
- expect(next.firstCall.args[0].message).to.equal("Something went wrong");
- expect(res.status.notCalled).to.be.true;
- expect(res.json.notCalled).to.be.true;
- });
-});
-
-describe("Auth Controller - getAllUsers", function () {
- let req, res, next;
-
- beforeEach(function () {
- req = {
- db: {
- getAllUsers: sinon.stub(),
- },
- };
- res = {
- status: sinon.stub().returnsThis(),
- json: sinon.stub(),
- };
- next = sinon.stub();
- });
-
- afterEach(function () {
- sinon.restore(); // Restore the original methods after each test
- });
-
- it("should return 200 and all users", async function () {
- const allUsers = [{ id: 1, name: "John Doe" }];
- req.db.getAllUsers.resolves(allUsers);
-
- await getAllUsers(req, res, next);
-
- expect(req.db.getAllUsers.calledOnce).to.be.true;
- expect(res.status.calledOnceWith(200)).to.be.true;
- expect(
- res.json.calledOnceWith({
- success: true,
- msg: "Got all users",
- data: allUsers,
- })
- ).to.be.true;
- expect(next.notCalled).to.be.true;
- });
-
- it("should call next with error when an exception occurs", async function () {
- const error = new Error("Something went wrong");
- req.db.getAllUsers.rejects(error);
- await getAllUsers(req, res, next);
- expect(req.db.getAllUsers.calledOnce).to.be.true;
- expect(next.calledOnce).to.be.true;
- expect(res.status.notCalled).to.be.true;
- expect(res.json.notCalled).to.be.true;
- });
-});
diff --git a/server/tests/controllers/checkController.test.js b/server/tests/controllers/checkController.test.js
deleted file mode 100755
index c5fb57d50..000000000
--- a/server/tests/controllers/checkController.test.js
+++ /dev/null
@@ -1,372 +0,0 @@
-import { createCheck, getChecks, getTeamChecks, deleteChecks, deleteChecksByTeamId, updateChecksTTL } from "../../controllers/checkController.js";
-import jwt from "jsonwebtoken";
-import { errorMessages, successMessages } from "../../utils/messages.js";
-import sinon from "sinon";
-describe("Check Controller - createCheck", function () {
- let req, res, next, handleError;
-
- beforeEach(function () {
- req = {
- params: {},
- body: {},
- db: {
- createCheck: sinon.stub(),
- },
- };
- res = {
- status: sinon.stub().returnsThis(),
- json: sinon.stub(),
- };
- next = sinon.stub();
- handleError = sinon.stub();
- });
-
- afterEach(function () {
- sinon.restore(); // Restore the original methods after each test
- });
-
- it("should reject with a validation if params are invalid", async function () {
- await createCheck(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].status).to.equal(422);
- });
-
- it("should reject with a validation error if body is invalid", async function () {
- req.params = {
- monitorId: "monitorId",
- };
- await createCheck(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].status).to.equal(422);
- });
-
- it("should call next with error if data retrieval fails", async function () {
- req.params = {
- monitorId: "monitorId",
- };
- req.body = {
- monitorId: "monitorId",
- status: true,
- responseTime: 100,
- statusCode: 200,
- message: "message",
- };
- req.db.createCheck.rejects(new Error("error"));
- await createCheck(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- });
-
- it("should return a success message if check is created", async function () {
- req.params = {
- monitorId: "monitorId",
- };
- req.db.createCheck.resolves({ id: "123" });
- req.body = {
- monitorId: "monitorId",
- status: true,
- responseTime: 100,
- statusCode: 200,
- message: "message",
- };
- await createCheck(req, res, next);
- expect(res.status.calledWith(200)).to.be.true;
- expect(
- res.json.calledWith({
- success: true,
- msg: successMessages.CHECK_CREATE,
- data: { id: "123" },
- })
- ).to.be.true;
- expect(next.notCalled).to.be.true;
- });
-});
-
-describe("Check Controller - getChecks", function () {
- let req, res, next;
-
- beforeEach(function () {
- req = {
- params: {},
- query: {},
- db: {
- getChecks: sinon.stub(),
- getChecksCount: sinon.stub(),
- },
- };
- res = {
- status: sinon.stub().returnsThis(),
- json: sinon.stub(),
- };
- next = sinon.stub();
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- it("should reject with a validation error if params are invalid", async function () {
- await getChecks(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].status).to.equal(422);
- });
-
- it("should return a success message if checks are found", async function () {
- req.params = {
- monitorId: "monitorId",
- };
- req.db.getChecks.resolves([{ id: "123" }]);
- req.db.getChecksCount.resolves(1);
- await getChecks(req, res, next);
- expect(res.status.calledWith(200)).to.be.true;
- expect(
- res.json.calledWith({
- success: true,
- msg: successMessages.CHECK_GET,
- data: { checksCount: 1, checks: [{ id: "123" }] },
- })
- ).to.be.true;
- expect(next.notCalled).to.be.true;
- });
-
- it("should call next with error if data retrieval fails", async function () {
- req.params = {
- monitorId: "monitorId",
- };
- req.db.getChecks.rejects(new Error("error"));
- await getChecks(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- });
-});
-
-describe("Check Controller - getTeamChecks", function () {
- let req, res, next;
-
- beforeEach(function () {
- req = {
- params: {},
- query: {},
- db: {
- getTeamChecks: sinon.stub(),
- },
- };
- res = {
- status: sinon.stub().returnsThis(),
- json: sinon.stub(),
- };
- next = sinon.stub();
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- it("should reject with a validation error if params are invalid", async function () {
- await getTeamChecks(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].status).to.equal(422);
- });
-
- it("should return 200 and check data on successful validation and data retrieval", async function () {
- req.params = { teamId: "1" };
- const checkData = [{ id: 1, name: "Check 1" }];
- req.db.getTeamChecks.resolves(checkData);
-
- await getTeamChecks(req, res, next);
- expect(req.db.getTeamChecks.calledOnceWith(req)).to.be.true;
- expect(res.status.calledOnceWith(200)).to.be.true;
- expect(
- res.json.calledOnceWith({
- success: true,
- msg: successMessages.CHECK_GET,
- data: checkData,
- })
- ).to.be.true;
- });
-
- it("should call next with error if data retrieval fails", async function () {
- req.params = { teamId: "1" };
- req.db.getTeamChecks.rejects(new Error("Retrieval Error"));
- await getTeamChecks(req, res, next);
- expect(req.db.getTeamChecks.calledOnceWith(req)).to.be.true;
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(res.status.notCalled).to.be.true;
- expect(res.json.notCalled).to.be.true;
- });
-});
-
-describe("Check Controller - deleteChecks", function () {
- let req, res, next;
-
- beforeEach(function () {
- req = {
- params: {},
- db: {
- deleteChecks: sinon.stub(),
- },
- };
- res = {
- status: sinon.stub().returnsThis(),
- json: sinon.stub(),
- };
- next = sinon.stub();
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- it("should reject with an error if param validation fails", async function () {
- await deleteChecks(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].status).to.equal(422);
- });
-
- it("should call next with error if data retrieval fails", async function () {
- req.params = { monitorId: "1" };
- req.db.deleteChecks.rejects(new Error("Deletion Error"));
- await deleteChecks(req, res, next);
- expect(req.db.deleteChecks.calledOnceWith(req.params.monitorId)).to.be.true;
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(res.status.notCalled).to.be.true;
- expect(res.json.notCalled).to.be.true;
- });
-
- it("should delete checks successfully", async function () {
- req.params = { monitorId: "123" };
- req.db.deleteChecks.resolves(1);
- await deleteChecks(req, res, next);
- expect(req.db.deleteChecks.calledOnceWith(req.params.monitorId)).to.be.true;
- expect(res.status.calledOnceWith(200)).to.be.true;
- expect(
- res.json.calledOnceWith({
- success: true,
- msg: successMessages.CHECK_DELETE,
- data: { deletedCount: 1 },
- })
- ).to.be.true;
- });
-});
-
-describe("Check Controller - deleteChecksByTeamId", function () {
- let req, res, next;
-
- beforeEach(function () {
- req = {
- params: {},
- db: {
- deleteChecksByTeamId: sinon.stub(),
- },
- };
- res = {
- status: sinon.stub().returnsThis(),
- json: sinon.stub(),
- };
- next = sinon.stub();
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- it("should reject with an error if param validation fails", async function () {
- await deleteChecksByTeamId(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].status).to.equal(422);
- });
-
- it("should call next with error if data retrieval fails", async function () {
- req.params = { teamId: "1" };
- req.db.deleteChecksByTeamId.rejects(new Error("Deletion Error"));
- await deleteChecksByTeamId(req, res, next);
- expect(req.db.deleteChecksByTeamId.calledOnceWith(req.params.teamId)).to.be.true;
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(res.status.notCalled).to.be.true;
- expect(res.json.notCalled).to.be.true;
- });
-
- it("should delete checks successfully", async function () {
- req.params = { teamId: "123" };
- req.db.deleteChecksByTeamId.resolves(1);
- await deleteChecksByTeamId(req, res, next);
- expect(req.db.deleteChecksByTeamId.calledOnceWith(req.params.teamId)).to.be.true;
- expect(res.status.calledOnceWith(200)).to.be.true;
- expect(
- res.json.calledOnceWith({
- success: true,
- msg: successMessages.CHECK_DELETE,
- data: { deletedCount: 1 },
- })
- ).to.be.true;
- });
-});
-
-describe("Check Controller - updateCheckTTL", function () {
- let stub, req, res, next;
-
- beforeEach(function () {
- stub = sinon.stub(jwt, "verify").callsFake(() => {
- return { teamId: "123" };
- });
-
- req = {
- body: {},
- headers: { authorization: "Bearer token" },
- settingsService: {
- getSettings: sinon.stub().returns({ jwtSecret: "my_secret" }),
- },
- db: {
- updateChecksTTL: sinon.stub(),
- },
- };
- res = {
- status: sinon.stub().returnsThis(),
- json: sinon.stub(),
- };
- next = sinon.stub();
- });
-
- afterEach(function () {
- sinon.restore();
- stub.restore();
- });
-
- it("should reject if body validation fails", async function () {
- await updateChecksTTL(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].status).to.equal(422);
- });
-
- it("should throw a JwtError if verification fails", async function () {
- stub.restore();
- req.body = {
- ttl: 1,
- };
- await updateChecksTTL(req, res, next);
- expect(next.firstCall.args[0]).to.be.instanceOf(jwt.JsonWebTokenError);
- });
-
- it("should call next with error if data retrieval fails", async function () {
- req.body = {
- ttl: 1,
- };
- req.db.updateChecksTTL.rejects(new Error("Update Error"));
- await updateChecksTTL(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- });
-
- it("should update TTL successfully", async function () {
- req.body = {
- ttl: 1,
- };
- req.db.updateChecksTTL.resolves();
- await updateChecksTTL(req, res, next);
- expect(req.db.updateChecksTTL.calledOnceWith("123", 1 * 86400)).to.be.true;
- expect(res.status.calledOnceWith(200)).to.be.true;
- expect(
- res.json.calledOnceWith({
- success: true,
- msg: successMessages.CHECK_UPDATE_TTL,
- })
- ).to.be.true;
- });
-});
diff --git a/server/tests/controllers/controllerUtils.test.js b/server/tests/controllers/controllerUtils.test.js
deleted file mode 100755
index a55318857..000000000
--- a/server/tests/controllers/controllerUtils.test.js
+++ /dev/null
@@ -1,157 +0,0 @@
-import sinon from "sinon";
-
-import { handleValidationError, handleError, fetchMonitorCertificate } from "../../controllers/controllerUtils.js";
-import { expect } from "chai";
-import sslChecker from "ssl-checker";
-import { afterEach } from "node:test";
-import exp from "constants";
-
-describe("controllerUtils - handleValidationError", function () {
- it("should set status to 422", function () {
- const error = {};
- const serviceName = "TestService";
- const result = handleValidationError(error, serviceName);
- expect(result.status).to.equal(422);
- });
-
- it("should set service to the provided serviceName", function () {
- const error = {};
- const serviceName = "TestService";
- const result = handleValidationError(error, serviceName);
- expect(result.service).to.equal(serviceName);
- });
-
- it("should set message to error.details[0].message if present", function () {
- const error = {
- details: [{ message: "Detail message" }],
- };
- const serviceName = "TestService";
- const result = handleValidationError(error, serviceName);
- expect(result.message).to.equal("Detail message");
- });
-
- it("should set message to error.message if error.details is not present", function () {
- const error = {
- message: "Error message",
- };
- const serviceName = "TestService";
- const result = handleValidationError(error, serviceName);
- expect(result.message).to.equal("Error message");
- });
-
- it('should set message to "Validation Error" if neither error.details nor error.message is present', function () {
- const error = {};
- const serviceName = "TestService";
- const result = handleValidationError(error, serviceName);
- expect(result.message).to.equal("Validation Error");
- });
-});
-
-describe("controllerUtils - handleError", function () {
- it("should set stats to the provided status if error.code is undefined", function () {
- const error = {};
- const serviceName = "TestService";
- const method = "testMethod";
- const status = 400;
- const result = handleError(error, serviceName, method, status);
- expect(result.status).to.equal(status);
- });
-
- it("should not overwrite error.code if it is already defined", function () {
- const error = { status: 404 };
- const serviceName = "TestService";
- const method = "testMethod";
- const status = 400;
- const result = handleError(error, serviceName, method, status);
- expect(result.status).to.equal(404);
- });
-
- it("should set service to the provided serviceName if error.service is undefined", function () {
- const error = {};
- const serviceName = "TestService";
- const method = "testMethod";
- const result = handleError(error, serviceName, method);
- expect(result.service).to.equal(serviceName);
- });
-
- it("should not overwrite error.service if it is already defined", function () {
- const error = { service: "ExistingService" };
- const serviceName = "TestService";
- const method = "testMethod";
- const result = handleError(error, serviceName, method);
- expect(result.service).to.equal("ExistingService");
- });
-
- it("should set method to the provided method if error.method is undefined", function () {
- const error = {};
- const serviceName = "TestService";
- const method = "testMethod";
- const result = handleError(error, serviceName, method);
- expect(result.method).to.equal(method);
- });
-
- it("should not overwrite error.method if it is already defined", function () {
- const error = { method: "existingMethod" };
- const serviceName = "TestService";
- const method = "testMethod";
- const result = handleError(error, serviceName, method);
- expect(result.method).to.equal("existingMethod");
- });
-
- it("should set code to 500 if error.code is undefined and no code is provided", function () {
- const error = {};
- const serviceName = "TestService";
- const method = "testMethod";
- const result = handleError(error, serviceName, method);
- expect(result.status).to.equal(500);
- });
-});
-
-describe("controllerUtils - fetchMonitorCertificate", function () {
- let sslChecker, monitor;
-
- beforeEach(function () {
- monitor = {
- url: "https://www.google.com",
- };
- sslChecker = sinon.stub();
- });
-
- afterEach(() => {
- sinon.restore();
- });
-
- it("should reject with an error if a URL does not parse", async function () {
- monitor.url = "invalidurl";
- try {
- await fetchMonitorCertificate(sslChecker, monitor);
- } catch (error) {
- expect(error).to.be.an("error");
- expect(error.message).to.equal("Invalid URL");
- }
- });
-
- it("should reject with an error if sslChecker throws an error", async function () {
- sslChecker.rejects(new Error("Test error"));
- try {
- await fetchMonitorCertificate(sslChecker, monitor);
- } catch (error) {
- expect(error).to.be.an("error");
- expect(error.message).to.equal("Test error");
- }
- });
-
- it("should return a certificate if sslChecker resolves", async function () {
- sslChecker.resolves({ validTo: "2022-01-01" });
- const result = await fetchMonitorCertificate(sslChecker, monitor);
- expect(result).to.deep.equal({ validTo: "2022-01-01" });
- });
-
- it("should throw an error if a ssl-checker returns null", async function () {
- sslChecker.returns(null);
- await fetchMonitorCertificate(sslChecker, monitor).catch((error) => {
- expect(error).to.be.an("error");
- expect(error.message).to.equal("Certificate not found");
- });
- });
-});
diff --git a/server/tests/controllers/inviteController.test.js b/server/tests/controllers/inviteController.test.js
deleted file mode 100755
index 635bdf653..000000000
--- a/server/tests/controllers/inviteController.test.js
+++ /dev/null
@@ -1,202 +0,0 @@
-import { issueInvitation, inviteVerifyController } from "../../controllers/inviteController.js";
-import jwt from "jsonwebtoken";
-import sinon from "sinon";
-import joi from "joi";
-describe("inviteController - issueInvitation", function () {
- let req, res, next, stub;
-
- beforeEach(function () {
- req = {
- headers: { authorization: "Bearer token" },
- body: {
- email: "test@test.com",
- role: ["admin"],
- teamId: "123",
- },
- db: { requestInviteToken: sinon.stub() },
- settingsService: { getSettings: sinon.stub() },
- emailService: { buildAndSendEmail: sinon.stub() },
- };
- res = {
- status: sinon.stub().returnsThis(),
- json: sinon.stub(),
- };
- next = sinon.stub();
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- it("should reject with an error if role validation fails", async function () {
- stub = sinon.stub(jwt, "decode").callsFake(() => {
- return { role: ["bad_role"], firstname: "first_name", teamId: "1" };
- });
- await issueInvitation(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0]).to.be.instanceOf(joi.ValidationError);
- expect(next.firstCall.args[0].status).to.equal(422);
- stub.restore();
- });
-
- it("should reject with an error if body validation fails", async function () {
- stub = sinon.stub(jwt, "decode").callsFake(() => {
- return { role: ["admin"], firstname: "first_name", teamId: "1" };
- });
- req.body = {};
- await issueInvitation(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].status).to.equal(422);
- stub.restore();
- });
-
- it("should reject with an error if DB operations fail", async function () {
- stub = sinon.stub(jwt, "decode").callsFake(() => {
- return { role: ["admin"], firstname: "first_name", teamId: "1" };
- });
- req.db.requestInviteToken.throws(new Error("DB error"));
- await issueInvitation(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("DB error");
- stub.restore();
- });
-
- it("should send an invite successfully", async function () {
- const token = "token";
- const decodedToken = {
- role: "admin",
- firstname: "John",
- teamId: "team123",
- };
- const inviteToken = { token: "inviteToken" };
- const clientHost = "http://localhost";
-
- stub = sinon.stub(jwt, "decode").callsFake(() => {
- return decodedToken;
- });
- req.db.requestInviteToken.resolves(inviteToken);
- req.settingsService.getSettings.returns({ clientHost });
- req.emailService.buildAndSendEmail.resolves();
- await issueInvitation(req, res, next);
- expect(res.status.calledWith(200)).to.be.true;
- expect(
- res.json.calledWith({
- success: true,
- msg: "Invite sent",
- data: inviteToken,
- })
- ).to.be.true;
- stub.restore();
- });
-
- it("should send an email successfully", async function () {
- const token = "token";
- const decodedToken = {
- role: "admin",
- firstname: "John",
- teamId: "team123",
- };
- const inviteToken = { token: "inviteToken" };
- const clientHost = "http://localhost";
-
- stub = sinon.stub(jwt, "decode").callsFake(() => {
- return decodedToken;
- });
- req.db.requestInviteToken.resolves(inviteToken);
- req.settingsService.getSettings.returns({ clientHost });
- req.emailService.buildAndSendEmail.resolves();
-
- await issueInvitation(req, res, next);
- expect(req.emailService.buildAndSendEmail.calledOnce).to.be.true;
- expect(
- req.emailService.buildAndSendEmail.calledWith(
- "employeeActivationTemplate",
- {
- name: "John",
- link: "http://localhost/register/inviteToken",
- },
- "test@test.com",
- "Welcome to Uptime Monitor"
- )
- ).to.be.true;
- stub.restore();
- });
-
- it("should continue executing if sending an email fails", async function () {
- const token = "token";
- req.emailService.buildAndSendEmail.rejects(new Error("Email error"));
- const decodedToken = {
- role: "admin",
- firstname: "John",
- teamId: "team123",
- };
- const inviteToken = { token: "inviteToken" };
- const clientHost = "http://localhost";
-
- stub = sinon.stub(jwt, "decode").callsFake(() => {
- return decodedToken;
- });
- req.db.requestInviteToken.resolves(inviteToken);
- req.settingsService.getSettings.returns({ clientHost });
- await issueInvitation(req, res, next);
- expect(res.status.calledWith(200)).to.be.true;
- expect(
- res.json.calledWith({
- success: true,
- msg: "Invite sent",
- data: inviteToken,
- })
- ).to.be.true;
- stub.restore();
- });
-});
-
-describe("inviteController - inviteVerifyController", function () {
- let req, res, next;
-
- beforeEach(function () {
- req = {
- body: { token: "token" },
- db: {
- getInviteToken: sinon.stub(),
- },
- };
- res = {
- status: sinon.stub().returnsThis(),
- json: sinon.stub(),
- };
- next = sinon.stub();
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- it("should reject with an error if body validation fails", async function () {
- req.body = {};
- await inviteVerifyController(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].status).to.equal(422);
- });
-
- it("should reject with an error if DB operations fail", async function () {
- req.db.getInviteToken.throws(new Error("DB error"));
- await inviteVerifyController(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("DB error");
- });
-
- it("should return 200 and invite data when validation and invite retrieval are successful", async function () {
- req.db.getInviteToken.resolves({ invite: "data" });
- await inviteVerifyController(req, res, next);
- expect(res.status.calledWith(200)).to.be.true;
- expect(
- res.json.calledWith({
- status: "success",
- msg: "Invite verified",
- data: { invite: "data" },
- })
- ).to.be.true;
- expect(next.called).to.be.false;
- });
-});
diff --git a/server/tests/controllers/maintenanceWindowController.test.js b/server/tests/controllers/maintenanceWindowController.test.js
deleted file mode 100755
index 0ea07b389..000000000
--- a/server/tests/controllers/maintenanceWindowController.test.js
+++ /dev/null
@@ -1,422 +0,0 @@
-import {
- createMaintenanceWindows,
- getMaintenanceWindowById,
- getMaintenanceWindowsByTeamId,
- getMaintenanceWindowsByMonitorId,
- deleteMaintenanceWindow,
- editMaintenanceWindow,
-} from "../../controllers/maintenanceWindowController.js";
-
-import jwt from "jsonwebtoken";
-import { successMessages } from "../../utils/messages.js";
-import sinon from "sinon";
-
-describe("maintenanceWindowController - createMaintenanceWindows", function () {
- let req, res, next, stub;
-
- beforeEach(function () {
- req = {
- body: {
- monitors: ["66ff52e7c5911c61698ac724"],
- name: "window",
- active: true,
- start: "2024-10-11T05:27:13.747Z",
- end: "2024-10-11T05:27:14.747Z",
- repeat: "123",
- },
- headers: {
- authorization: "Bearer token",
- },
- settingsService: {
- getSettings: sinon.stub().returns({ jwtSecret: "jwtSecret" }),
- },
- db: {
- createMaintenanceWindow: sinon.stub(),
- },
- };
- res = {
- status: sinon.stub().returnsThis(),
- json: sinon.stub(),
- };
- next = sinon.stub();
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- it("should reject with an error if body validation fails", async function () {
- stub = sinon.stub(jwt, "verify").callsFake(() => {
- return { teamId: "123" };
- });
- req.body = {};
- await createMaintenanceWindows(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].status).to.equal(422);
- stub.restore();
- });
-
- it("should reject with an error if jwt.verify fails", async function () {
- stub = sinon.stub(jwt, "verify").throws(new jwt.JsonWebTokenError());
- await createMaintenanceWindows(req, res, next);
- expect(next.firstCall.args[0]).to.be.instanceOf(jwt.JsonWebTokenError);
- stub.restore();
- });
-
- it("should reject with an error DB operations fail", async function () {
- stub = sinon.stub(jwt, "verify").callsFake(() => {
- return { teamId: "123" };
- });
- req.db.createMaintenanceWindow.throws(new Error("DB error"));
- await createMaintenanceWindows(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("DB error");
- stub.restore();
- });
-
- it("should return success message if all operations are successful", async function () {
- stub = sinon.stub(jwt, "verify").callsFake(() => {
- return { teamId: "123" };
- });
- await createMaintenanceWindows(req, res, next);
- expect(res.status.firstCall.args[0]).to.equal(201);
- expect(
- res.json.calledOnceWith({
- success: true,
- msg: successMessages.MAINTENANCE_WINDOW_CREATE,
- })
- ).to.be.true;
- stub.restore();
- });
-
- it("should return success message if all operations are successful with active set to undefined", async function () {
- req.body.active = undefined;
- stub = sinon.stub(jwt, "verify").callsFake(() => {
- return { teamId: "123" };
- });
- await createMaintenanceWindows(req, res, next);
- expect(res.status.firstCall.args[0]).to.equal(201);
- expect(
- res.json.calledOnceWith({
- success: true,
- msg: successMessages.MAINTENANCE_WINDOW_CREATE,
- })
- ).to.be.true;
- stub.restore();
- });
-});
-
-describe("maintenanceWindowController - getMaintenanceWindowById", function () {
- let req, res, next;
-
- beforeEach(function () {
- req = {
- body: {},
- params: {
- id: "123",
- },
- headers: {
- authorization: "Bearer token",
- },
- settingsService: {
- getSettings: sinon.stub().returns({ jwtSecret: "jwtSecret" }),
- },
- db: {
- getMaintenanceWindowById: sinon.stub(),
- },
- };
- res = {
- status: sinon.stub().returnsThis(),
- json: sinon.stub(),
- };
- next = sinon.stub();
- });
-
- it("should reject if param validation fails", async function () {
- req.params = {};
- await getMaintenanceWindowById(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].status).to.equal(422);
- });
-
- it("should reject if DB operations fail", async function () {
- req.db.getMaintenanceWindowById.throws(new Error("DB error"));
- await getMaintenanceWindowById(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("DB error");
- });
-
- it("should return success message with data if all operations are successful", async function () {
- req.db.getMaintenanceWindowById.returns({ id: "123" });
- await getMaintenanceWindowById(req, res, next);
- expect(res.status.firstCall.args[0]).to.equal(200);
- expect(
- res.json.calledOnceWith({
- success: true,
- msg: successMessages.MAINTENANCE_WINDOW_GET_BY_ID,
- data: { id: "123" },
- })
- ).to.be.true;
- });
-});
-
-describe("maintenanceWindowController - getMaintenanceWindowsByTeamId", function () {
- let req, res, next, stub;
-
- beforeEach(function () {
- req = {
- body: {},
- params: {},
- query: {},
- headers: {
- authorization: "Bearer token",
- },
- settingsService: {
- getSettings: sinon.stub().returns({ jwtSecret: "jwtSecret" }),
- },
- db: {
- getMaintenanceWindowsByTeamId: sinon.stub(),
- },
- };
- res = {
- status: sinon.stub().returnsThis(),
- json: sinon.stub(),
- };
- next = sinon.stub();
- });
-
- it("should reject if query validation fails", async function () {
- req.query = {
- invalid: 1,
- };
- await getMaintenanceWindowsByTeamId(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].status).to.equal(422);
- });
-
- it("should reject if jwt.verify fails", async function () {
- stub = sinon.stub(jwt, "verify").throws(new jwt.JsonWebTokenError());
- await getMaintenanceWindowsByTeamId(req, res, next);
- expect(next.firstCall.args[0]).to.be.instanceOf(jwt.JsonWebTokenError);
- stub.restore();
- });
-
- it("should reject with an error if DB operations fail", async function () {
- stub = sinon.stub(jwt, "verify").callsFake(() => {
- return { teamId: "123" };
- });
- req.db.getMaintenanceWindowsByTeamId.throws(new Error("DB error"));
- await getMaintenanceWindowsByTeamId(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("DB error");
- stub.restore();
- });
-
- it("should return success message with data if all operations are successful", async function () {
- stub = sinon.stub(jwt, "verify").callsFake(() => {
- return { teamId: "123" };
- });
- req.db.getMaintenanceWindowsByTeamId.returns([{ id: "123" }]);
- await getMaintenanceWindowsByTeamId(req, res, next);
- expect(res.status.firstCall.args[0]).to.equal(200);
- expect(
- res.json.calledOnceWith({
- success: true,
- msg: successMessages.MAINTENANCE_WINDOW_GET_BY_TEAM,
- data: [{ id: jwt.verify().teamId }],
- })
- ).to.be.true;
- stub.restore();
- });
-});
-
-describe("maintenanceWindowController - getMaintenanceWindowsByMonitorId", function () {
- let req, res, next;
-
- beforeEach(function () {
- req = {
- body: {},
- params: {
- monitorId: "123",
- },
- query: {},
- headers: {
- authorization: "Bearer token",
- },
- settingsService: {
- getSettings: sinon.stub().returns({ jwtSecret: "jwtSecret" }),
- },
- db: {
- getMaintenanceWindowsByMonitorId: sinon.stub(),
- },
- };
- res = {
- status: sinon.stub().returnsThis(),
- json: sinon.stub(),
- };
- next = sinon.stub();
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- it("should reject if param validation fails", async function () {
- req.params = {};
- await getMaintenanceWindowsByMonitorId(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].status).to.equal(422);
- });
-
- it("should reject with an error if DB operations fail", async function () {
- req.db.getMaintenanceWindowsByMonitorId.throws(new Error("DB error"));
- await getMaintenanceWindowsByMonitorId(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("DB error");
- });
-
- it("should return success message with data if all operations are successful", async function () {
- const data = [{ monitorId: "123" }];
- req.db.getMaintenanceWindowsByMonitorId.returns(data);
- await getMaintenanceWindowsByMonitorId(req, res, next);
- expect(req.db.getMaintenanceWindowsByMonitorId.calledOnceWith(req.params.monitorId));
- expect(res.status.firstCall.args[0]).to.equal(200);
- expect(
- res.json.calledOnceWith({
- success: true,
- msg: successMessages.MAINTENANCE_WINDOW_GET_BY_MONITOR,
- data: data,
- })
- ).to.be.true;
- });
-});
-
-describe("maintenanceWindowController - deleteMaintenanceWindow", function () {
- let req, res, next;
-
- beforeEach(function () {
- req = {
- body: {},
- params: {
- id: "123",
- },
- query: {},
- headers: {
- authorization: "Bearer token",
- },
- settingsService: {
- getSettings: sinon.stub().returns({ jwtSecret: "jwtSecret" }),
- },
- db: {
- deleteMaintenanceWindowById: sinon.stub(),
- },
- };
- res = {
- status: sinon.stub().returnsThis(),
- json: sinon.stub(),
- };
- next = sinon.stub();
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- it("should reject if param validation fails", async function () {
- req.params = {};
- await deleteMaintenanceWindow(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].status).to.equal(422);
- });
-
- it("should reject with an error if DB operations fail", async function () {
- req.db.deleteMaintenanceWindowById.throws(new Error("DB error"));
- await deleteMaintenanceWindow(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("DB error");
- });
-
- it("should return success message if all operations are successful", async function () {
- await deleteMaintenanceWindow(req, res, next);
- expect(req.db.deleteMaintenanceWindowById.calledOnceWith(req.params.id));
- expect(res.status.firstCall.args[0]).to.equal(200);
- expect(
- res.json.calledOnceWith({
- success: true,
- msg: successMessages.MAINTENANCE_WINDOW_DELETE,
- })
- ).to.be.true;
- });
-});
-
-describe("maintenanceWindowController - editMaintenanceWindow", function () {
- let req, res, next;
-
- beforeEach(function () {
- req = {
- body: {
- active: true,
- name: "test",
- },
- params: {
- id: "123",
- },
- query: {},
- headers: {
- authorization: "Bearer token",
- },
- settingsService: {
- getSettings: sinon.stub().returns({ jwtSecret: "jwtSecret" }),
- },
- db: {
- editMaintenanceWindowById: sinon.stub(),
- },
- };
- res = {
- status: sinon.stub().returnsThis(),
- json: sinon.stub(),
- };
- next = sinon.stub();
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- it("should reject if param validation fails", async function () {
- req.params = {};
- await editMaintenanceWindow(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].status).to.equal(422);
- });
-
- it("should reject if body validation fails", async function () {
- req.body = { invalid: 1 };
- await editMaintenanceWindow(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].status).to.equal(422);
- });
-
- it("should reject with an error if DB operations fail", async function () {
- req.db.editMaintenanceWindowById.throws(new Error("DB error"));
- await editMaintenanceWindow(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("DB error");
- });
-
- it("should return success message with data if all operations are successful", async function () {
- const data = { id: "123" };
- req.db.editMaintenanceWindowById.returns(data);
-
- await editMaintenanceWindow(req, res, next);
- expect(req.db.editMaintenanceWindowById.calledOnceWith(req.params.id, req.body));
- expect(res.status.firstCall.args[0]).to.equal(200);
- expect(
- res.json.calledOnceWith({
- success: true,
- msg: successMessages.MAINTENANCE_WINDOW_EDIT,
- data: data,
- })
- ).to.be.true;
- });
-});
diff --git a/server/tests/controllers/monitorController.test.js b/server/tests/controllers/monitorController.test.js
deleted file mode 100755
index 963862579..000000000
--- a/server/tests/controllers/monitorController.test.js
+++ /dev/null
@@ -1,1116 +0,0 @@
-import {
- getAllMonitors,
- getAllMonitorsWithUptimeStats,
- getMonitorStatsById,
- getMonitorCertificate,
- getMonitorById,
- getMonitorsAndSummaryByTeamId,
- getMonitorsByTeamId,
- createMonitor,
- checkEndpointResolution,
- deleteMonitor,
- deleteAllMonitors,
- editMonitor,
- pauseMonitor,
- addDemoMonitors,
-} from "../../controllers/monitorController.js";
-import jwt from "jsonwebtoken";
-import sinon from "sinon";
-import { successMessages } from "../../utils/messages.js";
-import logger from "../../utils/logger.js";
-import axios from "axios";
-const SERVICE_NAME = "monitorController";
-
-describe("Monitor Controller - getAllMonitors", function () {
- let req, res, next;
-
- beforeEach(function () {
- req = {
- params: {},
- query: {},
- body: {},
- db: {
- getAllMonitors: sinon.stub(),
- },
- };
- res = {
- status: sinon.stub().returnsThis(),
- json: sinon.stub(),
- };
- next = sinon.stub();
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- it("should reject with an error if DB operations fail", async function () {
- req.db.getAllMonitors.throws(new Error("DB error"));
- await getAllMonitors(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("DB error");
- });
-
- it("should return success message and data if all operations succeed", async function () {
- const data = [{ monitor: "data" }];
- req.db.getAllMonitors.returns(data);
- await getAllMonitors(req, res, next);
- expect(res.status.firstCall.args[0]).to.equal(200);
- expect(
- res.json.calledOnceWith({
- success: true,
- msg: successMessages.MONITOR_GET_ALL,
- data: data,
- })
- ).to.be.true;
- });
-});
-describe("Monitor Controller - getAllMonitorsWithUptimeStats", function () {
- let req, res, next;
-
- beforeEach(function () {
- req = {
- params: {},
- query: {},
- body: {},
- db: {
- getAllMonitorsWithUptimeStats: sinon.stub(),
- },
- };
- res = {
- status: sinon.stub().returnsThis(),
- json: sinon.stub(),
- };
- next = sinon.stub();
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- it("should reject with an error if DB operations fail", async function () {
- req.db.getAllMonitorsWithUptimeStats.throws(new Error("DB error"));
- await getAllMonitorsWithUptimeStats(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("DB error");
- });
-
- it("should return success message and data if all operations succeed", async function () {
- const data = [{ monitor: "data" }];
- req.db.getAllMonitorsWithUptimeStats.returns(data);
- await getAllMonitorsWithUptimeStats(req, res, next);
- expect(res.status.firstCall.args[0]).to.equal(200);
- expect(
- res.json.calledOnceWith({
- success: true,
- msg: successMessages.MONITOR_GET_ALL,
- data: data,
- })
- ).to.be.true;
- });
-});
-
-describe("Monitor Controller - getMonitorStatsById", function () {
- let req, res, next;
-
- beforeEach(function () {
- req = {
- params: {
- monitorId: "123",
- },
- query: {},
- body: {},
- db: {
- getMonitorStatsById: sinon.stub(),
- },
- };
- res = {
- status: sinon.stub().returnsThis(),
- json: sinon.stub(),
- };
- next = sinon.stub();
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- it("should reject with an error if param validation fails", async function () {
- req.params = {};
- await getMonitorStatsById(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].status).to.equal(422);
- });
-
- it("should reject with an error if query validation fails", async function () {
- req.query = { invalid: 1 };
- await getMonitorStatsById(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].status).to.equal(422);
- });
-
- it("should reject with an error if DB operations fail", async function () {
- req.db.getMonitorStatsById.throws(new Error("DB error"));
- await getMonitorStatsById(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("DB error");
- });
-
- it("should return success message and data if all operations succeed", async function () {
- const data = [{ monitorStats: "data" }];
- req.db.getMonitorStatsById.returns(data);
- await getMonitorStatsById(req, res, next);
- expect(res.status.firstCall.args[0]).to.equal(200);
- expect(
- res.json.calledOnceWith({
- success: true,
- msg: successMessages.MONITOR_STATS_BY_ID,
- data: data,
- })
- ).to.be.true;
- });
-});
-
-describe("Monitor Controller - getMonitorCertificate", function () {
- let req, res, next, fetchMonitorCertificate;
-
- beforeEach(function () {
- req = {
- params: {
- monitorId: "123",
- },
- query: {},
- body: {},
- db: {
- getMonitorById: sinon.stub(),
- },
- };
- res = {
- status: sinon.stub().returnsThis(),
- json: sinon.stub(),
- };
- next = sinon.stub();
- fetchMonitorCertificate = sinon.stub();
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- it("should reject with an error if param validation fails", async function () {
- req.params = {};
- await getMonitorCertificate(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].status).to.equal(422);
- });
-
- it("should reject with an error if getMonitorById operation fails", async function () {
- req.db.getMonitorById.throws(new Error("DB error"));
- await getMonitorCertificate(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("DB error");
- });
-
- it("should return success message and data if all operations succeed with a valid cert", async function () {
- req.db.getMonitorById.returns({ url: "https://www.google.com" });
- const data = { certificate: "cert", validTo: "2024/08/08" };
- fetchMonitorCertificate.returns(data);
- await getMonitorCertificate(req, res, next, fetchMonitorCertificate);
- expect(res.status.firstCall.args[0]).to.equal(200);
- expect(
- res.json.calledOnceWith({
- success: true,
- msg: successMessages.MONITOR_CERTIFICATE,
- data: { certificateDate: new Date(data.validTo) },
- })
- ).to.be.true;
- });
-
- it("should return an error if fetchMonitorCertificate fails", async function () {
- req.db.getMonitorById.returns({ url: "https://www.google.com" });
- fetchMonitorCertificate.throws(new Error("Certificate error"));
- await getMonitorCertificate(req, res, next, fetchMonitorCertificate);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("Certificate error");
- });
-});
-
-describe("Monitor Controller - getMonitorById", function () {
- let req, res, next;
-
- beforeEach(function () {
- req = {
- params: {
- monitorId: "123",
- },
- query: {},
- body: {},
- db: {
- getMonitorById: sinon.stub(),
- },
- };
- res = {
- status: sinon.stub().returnsThis(),
- json: sinon.stub(),
- };
- next = sinon.stub();
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- it("should reject with an error if param validation fails", async function () {
- req.params = {};
- await getMonitorById(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].status).to.equal(422);
- });
-
- it("should reject with an error if query param validation fails", async function () {
- req.query = { invalid: 1 };
- await getMonitorById(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].status).to.equal(422);
- });
-
- it("should reject with an error if DB operations fail", async function () {
- req.db.getMonitorById.throws(new Error("DB error"));
- await getMonitorById(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("DB error");
- });
-
- it("should return 404 if a monitor is not found", async function () {
- const error = new Error("Monitor not found");
- error.status = 404;
- req.db.getMonitorById.throws(error);
- await getMonitorById(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].status).to.equal(404);
- });
-
- it("should return success message and data if all operations succeed", async function () {
- const data = { monitor: "data" };
- req.db.getMonitorById.returns(data);
- await getMonitorById(req, res, next);
- expect(res.status.firstCall.args[0]).to.equal(200);
- expect(
- res.json.calledOnceWith({
- success: true,
- msg: successMessages.MONITOR_GET_BY_ID,
- data: data,
- })
- ).to.be.true;
- });
-});
-
-describe("Monitor Controller - getMonitorsAndSummaryByTeamId", function () {
- let req, res, next;
-
- beforeEach(function () {
- req = {
- params: {
- teamId: "123",
- },
- query: {},
- body: {},
- db: {
- getMonitorsAndSummaryByTeamId: sinon.stub(),
- },
- };
- res = {
- status: sinon.stub().returnsThis(),
- json: sinon.stub(),
- };
- next = sinon.stub();
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- it("should reject with an error if param validation fails", async function () {
- req.params = {};
- await getMonitorsAndSummaryByTeamId(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].status).to.equal(422);
- });
-
- it("should reject with an error if query validation fails", async function () {
- req.query = { invalid: 1 };
- await getMonitorsAndSummaryByTeamId(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].status).to.equal(422);
- });
-
- it("should reject with an error if DB operations fail", async function () {
- req.db.getMonitorsAndSummaryByTeamId.throws(new Error("DB error"));
- await getMonitorsAndSummaryByTeamId(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("DB error");
- });
-
- it("should return success message and data if all operations succeed", async function () {
- const data = { monitors: "data", summary: "data" };
- req.db.getMonitorsAndSummaryByTeamId.returns(data);
- await getMonitorsAndSummaryByTeamId(req, res, next);
- expect(res.status.firstCall.args[0]).to.equal(200);
- expect(
- res.json.calledOnceWith({
- success: true,
- msg: successMessages.MONITOR_GET_BY_USER_ID(req.params.teamId),
- data: data,
- })
- ).to.be.true;
- });
-});
-
-describe("Monitor Controller - getMonitorsByTeamId", function () {
- let req, res, next;
-
- beforeEach(function () {
- req = {
- params: {
- teamId: "123",
- },
- query: {},
- body: {},
- db: {
- getMonitorsByTeamId: sinon.stub(),
- },
- };
- res = {
- status: sinon.stub().returnsThis(),
- json: sinon.stub(),
- };
- next = sinon.stub();
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- it("should reject with an error if param validation fails", async function () {
- req.params = {};
- await getMonitorsByTeamId(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].status).to.equal(422);
- });
-
- it("should reject with an error if query validation fails", async function () {
- req.query = { invalid: 1 };
- await getMonitorsByTeamId(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].status).to.equal(422);
- });
-
- it("should reject with an error if DB operations fail", async function () {
- req.db.getMonitorsByTeamId.throws(new Error("DB error"));
- await getMonitorsByTeamId(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("DB error");
- });
-
- it("should return success message and data if all operations succeed", async function () {
- const data = { monitors: "data" };
- req.db.getMonitorsByTeamId.returns(data);
- await getMonitorsByTeamId(req, res, next);
- expect(res.status.firstCall.args[0]).to.equal(200);
- expect(
- res.json.calledOnceWith({
- success: true,
- msg: successMessages.MONITOR_GET_BY_USER_ID(req.params.teamId),
- data: data,
- })
- ).to.be.true;
- });
-});
-
-describe("Monitor Controller - createMonitor", function () {
- let req, res, next;
-
- beforeEach(function () {
- req = {
- params: {},
- query: {},
- body: {
- userId: "123",
- teamId: "123",
- name: "test_monitor",
- description: "test_monitor_desc",
- type: "http",
- url: "https://example.com",
- notifications: [{ email: "example@example.com" }],
- },
- db: {
- createMonitor: sinon.stub(),
- createNotification: sinon.stub(),
- },
- jobQueue: {
- addJob: sinon.stub(),
- },
- };
- res = {
- status: sinon.stub().returnsThis(),
- json: sinon.stub(),
- };
- next = sinon.stub();
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- it("should reject with an error if body validation fails", async function () {
- req.body = {};
- await createMonitor(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].status).to.equal(422);
- });
-
- it("should reject with an error if DB createMonitor operation fail", async function () {
- req.db.createMonitor.throws(new Error("DB error"));
- await createMonitor(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("DB error");
- });
-
- it("should reject with an error if DB createNotification operation fail", async function () {
- req.db.createNotification.throws(new Error("DB error"));
- req.db.createMonitor.returns({ _id: "123" });
- await createMonitor(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("DB error");
- });
-
- it("should reject with an error if monitor.save operation fail", async function () {
- req.db.createMonitor.returns({
- _id: "123",
- save: sinon.stub().throws(new Error("Monitor save error")),
- });
- await createMonitor(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("Monitor save error");
- });
-
- it("should throw an error if addJob operation fails", async function () {
- req.db.createMonitor.returns({ _id: "123", save: sinon.stub() });
- req.jobQueue.addJob.throws(new Error("Job error"));
- await createMonitor(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("Job error");
- });
-
- it("should return success message and data if all operations succeed", async function () {
- const monitor = { _id: "123", save: sinon.stub() };
- req.db.createMonitor.returns(monitor);
- await createMonitor(req, res, next);
- expect(res.status.firstCall.args[0]).to.equal(201);
- expect(
- res.json.calledOnceWith({
- success: true,
- msg: successMessages.MONITOR_CREATE,
- data: monitor,
- })
- ).to.be.true;
- });
-});
-
-describe("Monitor Controller - checkEndpointResolution", function () {
- let req, res, next, axiosGetStub;
-
- beforeEach(function () {
- req = { query: { monitorURL: "https://example.com" } };
- res = { status: sinon.stub().returnsThis(), json: sinon.stub() };
- next = sinon.stub();
- axiosGetStub = sinon.stub(axios, "get");
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- it("should resolve the URL successfully", async function () {
- axiosGetStub.resolves({ status: 200, statusText: "OK" });
- await checkEndpointResolution(req, res, next);
- expect(res.status.calledWith(200)).to.be.true;
- expect(
- res.json.calledWith({
- success: true,
- code: 200,
- statusText: "OK",
- msg: "URL resolved successfully",
- })
- ).to.be.true;
- expect(next.called).to.be.false;
- });
-
- it("should return an error if endpoint resolution fails", async function () {
- const axiosError = new Error("resolution failed");
- axiosError.code = "ENOTFOUND";
- axiosGetStub.rejects(axiosError);
- await checkEndpointResolution(req, res, next);
- expect(next.calledOnce).to.be.true;
- const errorPassedToNext = next.getCall(0).args[0];
- expect(errorPassedToNext).to.be.an.instanceOf(Error);
- expect(errorPassedToNext.message).to.include("resolution failed");
- expect(errorPassedToNext.code).to.equal("ENOTFOUND");
- expect(errorPassedToNext.status).to.equal(500);
- });
-
- it("should reject with an error if query validation fails", async function () {
- req.query.monitorURL = "invalid-url";
- await checkEndpointResolution(req, res, next);
- expect(next.calledOnce).to.be.true;
- const error = next.getCall(0).args[0];
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].status).to.equal(422);
- expect(error.message).to.equal('"monitorURL" must be a valid uri');
- });
-});
-
-describe("Monitor Controller - deleteMonitor", function () {
- let req, res, next;
-
- beforeEach(function () {
- req = {
- params: {
- monitorId: "123",
- },
- query: {},
- body: {},
- db: {
- deleteMonitor: sinon.stub(),
- deleteChecks: sinon.stub(),
- deletePageSpeedChecksByMonitorId: sinon.stub(),
- deleteNotificationsByMonitorId: sinon.stub(),
- },
- jobQueue: {
- deleteJob: sinon.stub(),
- },
- };
- res = {
- status: sinon.stub().returnsThis(),
- json: sinon.stub(),
- };
- next = sinon.stub();
- sinon.stub(logger, "error");
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- it("should reject with an error if param validation fails", async function () {
- req.params = {};
- await deleteMonitor(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].status).to.equal(422);
- });
-
- it("should reject with an error if DB deleteMonitor operation fail", async function () {
- req.db.deleteMonitor.throws(new Error("DB error"));
- await deleteMonitor(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("DB error");
- });
-
- it("should log an error if deleteJob throws an error", async function () {
- const error = new Error("Job error");
- const monitor = { name: "test_monitor", _id: "123" };
- req.db.deleteMonitor.returns(monitor);
- req.jobQueue.deleteJob.rejects(error);
- await deleteMonitor(req, res, next);
- expect(logger.error.calledOnce).to.be.true;
- expect(logger.error.firstCall.args[0].message).to.equal(`Error deleting associated records for monitor ${monitor._id} with name ${monitor.name}`);
- });
-
- it("should log an error if deleteChecks throws an error", async function () {
- const error = new Error("Checks error");
- const monitor = { name: "test_monitor", _id: "123" };
- req.db.deleteMonitor.returns(monitor);
- req.db.deleteChecks.rejects(error);
- await deleteMonitor(req, res, next);
- expect(logger.error.calledOnce).to.be.true;
- expect(logger.error.firstCall.args[0].message).to.equal(`Error deleting associated records for monitor ${monitor._id} with name ${monitor.name}`);
- });
-
- it("should log an error if deletePageSpeedChecksByMonitorId throws an error", async function () {
- const error = new Error("PageSpeed error");
- const monitor = { name: "test_monitor", _id: "123" };
- req.db.deleteMonitor.returns(monitor);
- req.db.deletePageSpeedChecksByMonitorId.rejects(error);
- await deleteMonitor(req, res, next);
- expect(logger.error.calledOnce).to.be.true;
- expect(logger.error.firstCall.args[0].message).to.equal(`Error deleting associated records for monitor ${monitor._id} with name ${monitor.name}`);
- });
-
- it("should log an error if deleteNotificationsByMonitorId throws an error", async function () {
- const error = new Error("Notifications error");
- const monitor = { name: "test_monitor", _id: "123" };
- req.db.deleteMonitor.returns(monitor);
- req.db.deleteNotificationsByMonitorId.rejects(error);
- await deleteMonitor(req, res, next);
- expect(logger.error.calledOnce).to.be.true;
- expect(logger.error.firstCall.args[0].message).to.equal(`Error deleting associated records for monitor ${monitor._id} with name ${monitor.name}`);
- });
-
- it("should return success message if all operations succeed", async function () {
- const monitor = { name: "test_monitor", _id: "123" };
- req.db.deleteMonitor.returns(monitor);
- await deleteMonitor(req, res, next);
- expect(res.status.firstCall.args[0]).to.equal(200);
- expect(
- res.json.calledOnceWith({
- success: true,
- msg: successMessages.MONITOR_DELETE,
- })
- ).to.be.true;
- });
-});
-
-describe("Monitor Controller - deleteAllMonitors", function () {
- let req, res, next, stub;
-
- beforeEach(function () {
- stub = sinon.stub(jwt, "verify").callsFake(() => {
- return { teamId: "123" };
- });
- req = {
- headers: {
- authorization: "Bearer token",
- },
- params: {
- monitorId: "123",
- },
- query: {},
- body: {},
- db: {
- deleteAllMonitors: sinon.stub(),
- deleteChecks: sinon.stub(),
- deletePageSpeedChecksByMonitorId: sinon.stub(),
- deleteNotificationsByMonitorId: sinon.stub(),
- },
- jobQueue: {
- deleteJob: sinon.stub(),
- },
- settingsService: {
- getSettings: sinon.stub(),
- },
- };
- res = {
- status: sinon.stub().returnsThis(),
- json: sinon.stub(),
- };
- next = sinon.stub();
- sinon.stub(logger, "error");
- });
-
- afterEach(function () {
- sinon.restore();
- stub.restore();
- });
-
- it("should reject with an error if getTokenFromHeaders throws an error", async function () {
- req.headers = {};
- await deleteAllMonitors(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("No auth headers");
- expect(next.firstCall.args[0].status).to.equal(500);
- });
-
- it("should reject with an error if token validation fails", async function () {
- stub.restore();
- req.settingsService.getSettings.returns({ jwtSecret: "my_secret" });
- await deleteAllMonitors(req, res, next);
- expect(next.firstCall.args[0]).to.be.instanceOf(jwt.JsonWebTokenError);
- });
-
- it("should reject with an error if DB deleteAllMonitors operation fail", async function () {
- req.settingsService.getSettings.returns({ jwtSecret: "my_secret" });
- req.db.deleteAllMonitors.throws(new Error("DB error"));
- await deleteAllMonitors(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("DB error");
- });
-
- it("should log an error if deleteChecks throws an error", async function () {
- const monitors = [{ name: "test_monitor", _id: "123" }];
- req.settingsService.getSettings.returns({ jwtSecret: "my_secret" });
- req.db.deleteAllMonitors.returns({ monitors, deletedCount: 1 });
- const error = new Error("Check error");
- req.db.deleteChecks.rejects(error);
- await deleteAllMonitors(req, res, next);
- expect(logger.error.calledOnce).to.be.true;
- expect(logger.error.firstCall.args[0].message).to.equal(
- `Error deleting associated records for monitor ${monitors[0]._id} with name ${monitors[0].name}`
- );
- });
-
- it("should log an error if deletePageSpeedChecksByMonitorId throws an error", async function () {
- const monitors = [{ name: "test_monitor", _id: "123" }];
- req.settingsService.getSettings.returns({ jwtSecret: "my_secret" });
- req.db.deleteAllMonitors.returns({ monitors, deletedCount: 1 });
- const error = new Error("Pagespeed Check error");
- req.db.deletePageSpeedChecksByMonitorId.rejects(error);
- await deleteAllMonitors(req, res, next);
- expect(logger.error.calledOnce).to.be.true;
- expect(logger.error.firstCall.args[0].message).to.equal(
- `Error deleting associated records for monitor ${monitors[0]._id} with name ${monitors[0].name}`
- );
- });
-
- it("should log an error if deleteNotificationsByMonitorId throws an error", async function () {
- const monitors = [{ name: "test_monitor", _id: "123" }];
- req.settingsService.getSettings.returns({ jwtSecret: "my_secret" });
- req.db.deleteAllMonitors.returns({ monitors, deletedCount: 1 });
- const error = new Error("Notifications Check error");
- req.db.deleteNotificationsByMonitorId.rejects(error);
- await deleteAllMonitors(req, res, next);
- expect(logger.error.calledOnce).to.be.true;
- expect(logger.error.firstCall.args[0].message).to.equal(
- `Error deleting associated records for monitor ${monitors[0]._id} with name ${monitors[0].name}`
- );
- });
-
- it("should return success message if all operations succeed", async function () {
- req.settingsService.getSettings.returns({ jwtSecret: "my_secret" });
- req.db.deleteAllMonitors.returns({
- monitors: [{ name: "test_monitor", _id: "123" }],
- deletedCount: 1,
- });
- await deleteAllMonitors(req, res, next);
- expect(res.status.firstCall.args[0]).to.equal(200);
- expect(
- res.json.calledOnceWith({
- success: true,
- msg: "Deleted 1 monitors",
- })
- ).to.be.true;
- });
-});
-
-describe("Monitor Controller - editMonitor", function () {
- let req, res, next;
-
- beforeEach(function () {
- req = {
- headers: {},
- params: {
- monitorId: "123",
- },
- query: {},
- body: {
- notifications: [{ email: "example@example.com" }],
- },
- db: {
- getMonitorById: sinon.stub(),
- editMonitor: sinon.stub(),
- deleteNotificationsByMonitorId: sinon.stub(),
- createNotification: sinon.stub(),
- },
- jobQueue: {
- deleteJob: sinon.stub(),
- addJob: sinon.stub(),
- },
- settingsService: {
- getSettings: sinon.stub(),
- },
- };
- res = {
- status: sinon.stub().returnsThis(),
- json: sinon.stub(),
- };
- next = sinon.stub();
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- it("should reject with an error if param validation fails", async function () {
- req.params = {};
- await editMonitor(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].status).to.equal(422);
- });
-
- it("should reject with an error if body validation fails", async function () {
- req.body = { invalid: 1 };
- await editMonitor(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].status).to.equal(422);
- });
-
- it("should reject with an error if getMonitorById operation fails", async function () {
- req.db.getMonitorById.throws(new Error("DB error"));
- await editMonitor(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("DB error");
- });
-
- it("should reject with an error if editMonitor operation fails", async function () {
- req.db.getMonitorById.returns({ teamId: "123" });
- req.db.editMonitor.throws(new Error("DB error"));
- await editMonitor(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("DB error");
- });
-
- it("should reject with an error if deleteNotificationsByMonitorId operation fails", async function () {
- req.db.getMonitorById.returns({ teamId: "123" });
- req.db.editMonitor.returns({ _id: "123" });
- req.db.deleteNotificationsByMonitorId.throws(new Error("DB error"));
- await editMonitor(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("DB error");
- });
-
- it("should reject with an error if createNotification operation fails", async function () {
- req.db.getMonitorById.returns({ teamId: "123" });
- req.db.editMonitor.returns({ _id: "123" });
- req.db.createNotification.throws(new Error("DB error"));
- await editMonitor(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("DB error");
- });
-
- it("should reject with an error if deleteJob operation fails", async function () {
- req.db.getMonitorById.returns({ teamId: "123" });
- req.db.editMonitor.returns({ _id: "123" });
- req.jobQueue.deleteJob.throws(new Error("Job error"));
- await editMonitor(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("Job error");
- });
-
- it("should reject with an error if addJob operation fails", async function () {
- req.db.getMonitorById.returns({ teamId: "123" });
- req.db.editMonitor.returns({ _id: "123" });
- req.jobQueue.addJob.throws(new Error("Add Job error"));
- await editMonitor(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("Add Job error");
- });
-
- it("should return success message with data if all operations succeed", async function () {
- const monitor = { _id: "123" };
- req.db.getMonitorById.returns({ teamId: "123" });
- req.db.editMonitor.returns(monitor);
- await editMonitor(req, res, next);
- expect(res.status.firstCall.args[0]).to.equal(200);
- expect(
- res.json.calledOnceWith({
- success: true,
- msg: successMessages.MONITOR_EDIT,
- data: monitor,
- })
- ).to.be.true;
- });
-});
-
-describe("Monitor Controller - pauseMonitor", function () {
- let req, res, next;
-
- beforeEach(function () {
- req = {
- headers: {},
- params: {
- monitorId: "123",
- },
- query: {},
- body: {},
- db: {
- getMonitorById: sinon.stub(),
- },
- jobQueue: {
- deleteJob: sinon.stub(),
- addJob: sinon.stub(),
- },
- settingsService: {
- getSettings: sinon.stub(),
- },
- };
- res = {
- status: sinon.stub().returnsThis(),
- json: sinon.stub(),
- };
- next = sinon.stub();
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- it("should reject with an error if param validation fails", async function () {
- req.params = {};
- await pauseMonitor(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].status).to.equal(422);
- });
-
- it("should reject with an error if getMonitorById operation fails", async function () {
- req.db.getMonitorById.throws(new Error("DB error"));
- await pauseMonitor(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("DB error");
- });
-
- it("should reject with an error if deleteJob operation fails", async function () {
- const monitor = { _id: req.params.monitorId, isActive: true };
- req.db.getMonitorById.returns(monitor);
- req.jobQueue.deleteJob.throws(new Error("Delete Job error"));
- await pauseMonitor(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("Delete Job error");
- });
-
- it("should reject with an error if addJob operation fails", async function () {
- const monitor = { _id: req.params.monitorId, isActive: false };
- req.db.getMonitorById.returns(monitor);
- req.jobQueue.addJob.throws(new Error("Add Job error"));
- await pauseMonitor(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("Add Job error");
- });
-
- it("should reject with an error if monitor.save operation fails", async function () {
- const monitor = {
- _id: req.params.monitorId,
- active: false,
- save: sinon.stub().throws(new Error("Save error")),
- };
- req.db.getMonitorById.returns(monitor);
- await pauseMonitor(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("Save error");
- });
-
- it("should return success pause message with data if all operations succeed with inactive monitor", async function () {
- const monitor = {
- _id: req.params.monitorId,
- isActive: false,
- save: sinon.stub().resolves(),
- };
- req.db.getMonitorById.returns(monitor);
- await pauseMonitor(req, res, next);
- expect(res.status.firstCall.args[0]).to.equal(200);
- expect(
- res.json.calledOnceWith({
- success: true,
- msg: successMessages.MONITOR_PAUSE,
- data: monitor,
- })
- ).to.be.true;
- });
-
- it("should return success resume message with data if all operations succeed with active monitor", async function () {
- const monitor = {
- _id: req.params.monitorId,
- isActive: true,
- save: sinon.stub().resolves(),
- };
- req.db.getMonitorById.returns(monitor);
- await pauseMonitor(req, res, next);
- expect(res.status.firstCall.args[0]).to.equal(200);
- expect(
- res.json.calledOnceWith({
- success: true,
- msg: successMessages.MONITOR_RESUME,
- data: monitor,
- })
- ).to.be.true;
- });
-});
-
-describe("Monitor Controller - addDemoMonitors", function () {
- let req, res, next, stub;
-
- beforeEach(function () {
- stub = sinon.stub(jwt, "verify").callsFake(() => {
- return { _id: "123", teamId: "123" };
- });
- req = {
- headers: {
- authorization: "Bearer token",
- },
- params: {},
- query: {},
- body: {},
- db: {
- addDemoMonitors: sinon.stub(),
- },
- settingsService: {
- getSettings: sinon.stub(),
- },
- jobQueue: {
- addJob: sinon.stub(),
- },
- };
- res = {
- status: sinon.stub().returnsThis(),
- json: sinon.stub(),
- };
- next = sinon.stub();
- });
-
- afterEach(function () {
- sinon.restore();
- stub.restore();
- });
-
- it("should reject with an error if getTokenFromHeaders fails", async function () {
- req.headers = {};
- await addDemoMonitors(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("No auth headers");
- expect(next.firstCall.args[0].status).to.equal(500);
- });
-
- it("should reject with an error if getting settings fails", async function () {
- req.settingsService.getSettings.throws(new Error("Settings error"));
- await addDemoMonitors(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("Settings error");
- });
-
- it("should reject with an error if JWT validation fails", async function () {
- stub.restore();
- req.settingsService.getSettings.returns({ jwtSecret: "my_secret" });
- await addDemoMonitors(req, res, next);
- expect(next.firstCall.args[0]).to.be.instanceOf(jwt.JsonWebTokenError);
- });
-
- it("should reject with an error if addDemoMonitors operation fails", async function () {
- req.settingsService.getSettings.returns({ jwtSecret: "my_secret" });
- req.db.addDemoMonitors.throws(new Error("DB error"));
- await addDemoMonitors(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("DB error");
- });
-
- it("should reject with an error if addJob operation fails", async function () {
- req.settingsService.getSettings.returns({ jwtSecret: "my_secret" });
- req.db.addDemoMonitors.returns([{ _id: "123" }]);
- req.jobQueue.addJob.throws(new Error("Add Job error"));
- await addDemoMonitors(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("Add Job error");
- });
-
- it("should return success message with data if all operations succeed", async function () {
- const monitors = [{ _id: "123" }];
- req.settingsService.getSettings.returns({ jwtSecret: "my_secret" });
- req.db.addDemoMonitors.returns(monitors);
- await addDemoMonitors(req, res, next);
- expect(res.status.firstCall.args[0]).to.equal(200);
- expect(
- res.json.calledOnceWith({
- success: true,
- msg: successMessages.MONITOR_DEMO_ADDED,
- data: monitors.length,
- })
- ).to.be.true;
- });
-});
diff --git a/server/tests/controllers/queueController.test.js b/server/tests/controllers/queueController.test.js
deleted file mode 100755
index 6201bdb5a..000000000
--- a/server/tests/controllers/queueController.test.js
+++ /dev/null
@@ -1,176 +0,0 @@
-import { afterEach } from "node:test";
-import { getMetrics, getJobs, addJob, obliterateQueue } from "../../controllers/queueController.js";
-import { successMessages } from "../../utils/messages.js";
-import sinon from "sinon";
-
-describe("Queue Controller - getMetrics", function () {
- let req, res, next;
-
- beforeEach(function () {
- req = {
- headers: {},
- params: {},
- body: {},
- db: {},
- jobQueue: {
- getMetrics: sinon.stub(),
- },
- };
- res = {
- status: sinon.stub().returnsThis(),
- json: sinon.stub(),
- };
- next = sinon.stub();
- });
-
- afterEach(() => {
- sinon.restore();
- });
-
- it("should throw an error if getMetrics throws an error", async function () {
- req.jobQueue.getMetrics.throws(new Error("getMetrics error"));
- await getMetrics(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("getMetrics error");
- });
-
- it("should return a success message and data if getMetrics is successful", async function () {
- const data = { data: "metrics" };
- req.jobQueue.getMetrics.returns(data);
- await getMetrics(req, res, next);
- expect(res.status.firstCall.args[0]).to.equal(200);
- expect(res.json.firstCall.args[0]).to.deep.equal({
- success: true,
- msg: successMessages.QUEUE_GET_METRICS,
- data,
- });
- });
-});
-
-describe("Queue Controller - getJobs", function () {
- let req, res, next;
-
- beforeEach(function () {
- req = {
- headers: {},
- params: {},
- body: {},
- db: {},
- jobQueue: {
- getJobStats: sinon.stub(),
- },
- };
- res = {
- status: sinon.stub().returnsThis(),
- json: sinon.stub(),
- };
- next = sinon.stub();
- });
-
- afterEach(() => {
- sinon.restore();
- });
-
- it("should reject with an error if getJobs throws an error", async function () {
- req.jobQueue.getJobStats.throws(new Error("getJobs error"));
- await getJobs(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("getJobs error");
- });
-
- it("should return a success message and data if getJobs is successful", async function () {
- const data = { data: "jobs" };
- req.jobQueue.getJobStats.returns(data);
- await getJobs(req, res, next);
- expect(res.status.firstCall.args[0]).to.equal(200);
- expect(res.json.firstCall.args[0]).to.deep.equal({
- success: true,
- msg: successMessages.QUEUE_GET_METRICS,
- data,
- });
- });
-});
-
-describe("Queue Controller - addJob", function () {
- let req, res, next;
-
- beforeEach(function () {
- req = {
- headers: {},
- params: {},
- body: {},
- db: {},
- jobQueue: {
- addJob: sinon.stub(),
- },
- };
- res = {
- status: sinon.stub().returnsThis(),
- json: sinon.stub(),
- };
- next = sinon.stub();
- });
-
- afterEach(() => {
- sinon.restore();
- });
-
- it("should reject with an error if addJob throws an error", async function () {
- req.jobQueue.addJob.throws(new Error("addJob error"));
- await addJob(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("addJob error");
- });
-
- it("should return a success message if addJob is successful", async function () {
- req.jobQueue.addJob.resolves();
- await addJob(req, res, next);
- expect(res.status.firstCall.args[0]).to.equal(200);
- expect(res.json.firstCall.args[0]).to.deep.equal({
- success: true,
- msg: successMessages.QUEUE_ADD_JOB,
- });
- });
-});
-
-describe("Queue Controller - obliterateQueue", function () {
- let req, res, next;
-
- beforeEach(function () {
- req = {
- headers: {},
- params: {},
- body: {},
- db: {},
- jobQueue: {
- obliterate: sinon.stub(),
- },
- };
- res = {
- status: sinon.stub().returnsThis(),
- json: sinon.stub(),
- };
- next = sinon.stub();
- });
-
- afterEach(() => {
- sinon.restore();
- });
-
- it("should reject with an error if obliterateQueue throws an error", async function () {
- req.jobQueue.obliterate.throws(new Error("obliterateQueue error"));
- await obliterateQueue(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("obliterateQueue error");
- });
-
- it("should return a success message if obliterateQueue is successful", async function () {
- req.jobQueue.obliterate.resolves();
- await obliterateQueue(req, res, next);
- expect(res.status.firstCall.args[0]).to.equal(200);
- expect(res.json.firstCall.args[0]).to.deep.equal({
- success: true,
- msg: successMessages.QUEUE_OBLITERATE,
- });
- });
-});
diff --git a/server/tests/controllers/settingsController.test.js b/server/tests/controllers/settingsController.test.js
deleted file mode 100755
index 721c41c02..000000000
--- a/server/tests/controllers/settingsController.test.js
+++ /dev/null
@@ -1,109 +0,0 @@
-import { afterEach } from "node:test";
-import { getAppSettings, updateAppSettings } from "../../controllers/settingsController.js";
-
-import { successMessages } from "../../utils/messages.js";
-import sinon from "sinon";
-
-describe("Settings Controller - getAppSettings", function () {
- let req, res, next;
-
- beforeEach(function () {
- req = {
- headers: {},
- params: {},
- body: {},
- db: {},
- settingsService: {
- getSettings: sinon.stub(),
- },
- };
- res = {
- status: sinon.stub().returnsThis(),
- json: sinon.stub(),
- };
- next = sinon.stub();
- });
-
- afterEach(() => {
- sinon.restore();
- });
-
- it("should throw an error if getSettings throws an error", async function () {
- req.settingsService.getSettings.throws(new Error("getSettings error"));
- await getAppSettings(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("getSettings error");
- });
-
- it("should return a success message and data if getSettings is successful", async function () {
- const data = { data: "settings" };
- req.settingsService.getSettings.returns(data);
- await getAppSettings(req, res, next);
- expect(res.status.firstCall.args[0]).to.equal(200);
- expect(res.json.firstCall.args[0]).to.deep.equal({
- success: true,
- msg: successMessages.GET_APP_SETTINGS,
- data,
- });
- });
-});
-
-describe("Settings Controller - updateAppSettings", function () {
- let req, res, next;
-
- beforeEach(function () {
- req = {
- headers: {},
- params: {},
- body: {},
- db: {
- updateAppSettings: sinon.stub(),
- },
- settingsService: {
- reloadSettings: sinon.stub(),
- },
- };
- res = {
- status: sinon.stub().returnsThis(),
- json: sinon.stub(),
- };
- next = sinon.stub();
- });
-
- afterEach(() => {
- sinon.restore();
- });
-
- it("should reject with an error if body validation fails", async function () {
- req.body = { invalid: 1 };
- await updateAppSettings(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].status).to.equal(422);
- });
-
- it("should reject with an error if updateAppSettings throws an error", async function () {
- req.db.updateAppSettings.throws(new Error("updateAppSettings error"));
- await updateAppSettings(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("updateAppSettings error");
- });
-
- it("should reject with an error if reloadSettings throws an error", async function () {
- req.settingsService.reloadSettings.throws(new Error("reloadSettings error"));
- await updateAppSettings(req, res, next);
- expect(next.firstCall.args[0]).to.be.an("error");
- expect(next.firstCall.args[0].message).to.equal("reloadSettings error");
- });
-
- it("should return a success message and data if updateAppSettings is successful", async function () {
- const data = { data: "settings" };
- req.settingsService.reloadSettings.returns(data);
- await updateAppSettings(req, res, next);
- expect(res.status.firstCall.args[0]).to.equal(200);
- expect(res.json.firstCall.args[0]).to.deep.equal({
- success: true,
- msg: successMessages.UPDATE_APP_SETTINGS,
- data,
- });
- });
-});
diff --git a/server/tests/controllers/statusPageController.test.js b/server/tests/controllers/statusPageController.test.js
deleted file mode 100755
index cada662e0..000000000
--- a/server/tests/controllers/statusPageController.test.js
+++ /dev/null
@@ -1,127 +0,0 @@
-import sinon from "sinon";
-import { createStatusPage, getStatusPageByUrl } from "../../controllers/statusPageController.js";
-
-describe("statusPageController", function () {
- let req, res, next;
-
- beforeEach(function () {
- req = {
- params: {},
- body: {},
- db: {
- createStatusPage: sinon.stub(),
- getStatusPageByUrl: sinon.stub(),
- },
- };
- res = {
- status: sinon.stub().returnsThis(),
- json: sinon.stub(),
- };
- next = sinon.stub();
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- describe("createStatusPage", function () {
- beforeEach(function () {
- req.body = {
- companyName: "Test Company",
- url: "123456",
- timezone: "America/Toronto",
- color: "#000000",
- theme: "light",
- monitors: ["67309ca673788e808884c8ac", "67309ca673788e808884c8ac"],
- };
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- it("should handle a validation error", async function () {
- req.body = {
- // Invalid data that will trigger validation error
- companyName: "",
- url: "",
- timezone: "",
- color: "invalid",
- theme: "invalid",
- monitors: ["invalid-id"],
- };
- try {
- await createStatusPage(req, res, next);
- } catch (error) {
- expect(error).to.be.an.instanceOf(Error);
- expect(error.message).to.equal("Validation error");
- }
- });
-
- it("should handle a db error", async function () {
- const err = new Error("DB error");
- req.db.createStatusPage.throws(err);
-
- try {
- await createStatusPage(req, res, next);
- } catch (error) {
- expect(error).to.deep.equal(err);
- }
- });
-
- it("should insert a properly formatted status page", async function () {
- const result = await createStatusPage(req, res, next);
- expect(res.status.firstCall.args[0]).to.equal(200);
- expect(res.json.firstCall.args[0].success).to.be.true;
- });
- });
-
- describe("getStatusPageByUrl", function () {
- beforeEach(function () {
- req.params = {
- url: "123456",
- };
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- it("should handle a validation error", async function () {
- req.params = {
- url: "",
- };
-
- try {
- await getStatusPageByUrl(req, res, next);
- } catch (error) {
- expect(error).to.be.an.instanceOf(Error);
- expect(error.message).to.equal("Validation error");
- }
- });
-
- it("should handle a DB error", async function () {
- const err = new Error("DB error");
- req.db.getStatusPageByUrl.throws(err);
-
- try {
- await getStatusPageByUrl(req, res, next);
- } catch (error) {
- expect(error).to.deep.equal(err);
- }
- });
-
- it("should return a status page", async function () {
- const statusPage = {
- _id: "123456",
- companyName: "Test Company",
- url: "123456",
- };
- req.db.getStatusPageByUrl.resolves(statusPage);
- const result = await getStatusPageByUrl(req, res, next);
- expect(res.status.firstCall.args[0]).to.equal(200);
- expect(res.json.firstCall.args[0].success).to.be.true;
- expect(res.json.firstCall.args[0].data).to.deep.equal(statusPage);
- });
- });
-});
diff --git a/server/tests/db/checkModule.test.js b/server/tests/db/checkModule.test.js
deleted file mode 100755
index 6eef12445..000000000
--- a/server/tests/db/checkModule.test.js
+++ /dev/null
@@ -1,589 +0,0 @@
-import sinon from "sinon";
-import {
- createCheck,
- getChecksCount,
- getChecks,
- getTeamChecks,
- deleteChecks,
- deleteChecksByTeamId,
- updateChecksTTL,
-} from "../../db/mongo/modules/checkModule.js";
-import Check from "../../db/models/Check.js";
-import Monitor from "../../db/models/Monitor.js";
-import User from "../../db/models/User.js";
-import logger from "../../utils/logger.js";
-
-describe("checkModule", function () {
- describe("createCheck", function () {
- let checkCountDocumentsStub, checkSaveStub, monitorFindByIdStub, monitorSaveStub;
- const mockMonitor = {
- _id: "123",
- uptimePercentage: 0.5,
- status: true,
- save: () => this,
- };
- const mockCheck = { active: true };
-
- beforeEach(function () {
- checkSaveStub = sinon.stub(Check.prototype, "save");
- checkCountDocumentsStub = sinon.stub(Check, "countDocuments");
- monitorFindByIdStub = sinon.stub(Monitor, "findById");
- monitorSaveStub = sinon.stub(Monitor.prototype, "save");
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- it("should return undefined early if no monitor is found", async function () {
- monitorFindByIdStub.returns(null);
- const check = await createCheck({ monitorId: "123" });
- expect(check).to.be.undefined;
- });
-
- it("should return a check", async function () {
- monitorFindByIdStub.returns(mockMonitor);
- checkSaveStub.returns(mockCheck);
- monitorSaveStub.returns(mockMonitor);
- const check = await createCheck({ monitorId: "123", status: true });
- expect(check).to.deep.equal(mockCheck);
- });
-
- it("should return a check if status is down", async function () {
- mockMonitor.status = false;
- monitorFindByIdStub.returns(mockMonitor);
- checkSaveStub.returns(mockCheck);
- monitorSaveStub.returns(mockMonitor);
- const check = await createCheck({ monitorId: "123", status: false });
- expect(check).to.deep.equal(mockCheck);
- });
-
- it("should return a check if uptimePercentage is undefined", async function () {
- mockMonitor.uptimePercentage = undefined;
- monitorFindByIdStub.returns(mockMonitor);
- checkSaveStub.returns(mockCheck);
- monitorSaveStub.returns(mockMonitor);
- const check = await createCheck({ monitorId: "123", status: true });
- expect(check).to.deep.equal(mockCheck);
- });
-
- it("should return a check if uptimePercentage is undefined and status is down", async function () {
- mockMonitor.uptimePercentage = undefined;
- monitorFindByIdStub.returns(mockMonitor);
- checkSaveStub.returns(mockCheck);
- monitorSaveStub.returns(mockMonitor);
- const check = await createCheck({ monitorId: "123", status: false });
- expect(check).to.deep.equal(mockCheck);
- });
-
- it("should monitor save error", async function () {
- const err = new Error("Save Error");
- monitorSaveStub.throws(err);
- try {
- await createCheck({ monitorId: "123" });
- } catch (error) {
- expect(error).to.deep.equal(err);
- }
- });
-
- it("should handle errors", async function () {
- const err = new Error("DB Error");
- checkCountDocumentsStub.throws(err);
- try {
- await createCheck({ monitorId: "123" });
- } catch (error) {
- expect(error).to.deep.equal(err);
- }
- });
- });
-
- describe("getChecksCount", function () {
- let checkCountDocumentStub;
-
- beforeEach(function () {
- checkCountDocumentStub = sinon.stub(Check, "countDocuments");
- });
-
- afterEach(function () {
- checkCountDocumentStub.restore();
- });
-
- it("should return count with basic monitorId query", async function () {
- const req = {
- params: { monitorId: "test123" },
- query: {},
- };
- checkCountDocumentStub.resolves(5);
-
- const result = await getChecksCount(req);
-
- expect(result).to.equal(5);
- expect(checkCountDocumentStub.calledOnce).to.be.true;
- expect(checkCountDocumentStub.firstCall.args[0]).to.deep.equal({
- monitorId: "test123",
- });
- });
-
- it("should include dateRange in query when provided", async function () {
- const req = {
- params: { monitorId: "test123" },
- query: { dateRange: "day" },
- };
- checkCountDocumentStub.resolves(3);
-
- const result = await getChecksCount(req);
-
- expect(result).to.equal(3);
- expect(checkCountDocumentStub.firstCall.args[0]).to.have.property("createdAt");
- expect(checkCountDocumentStub.firstCall.args[0].createdAt).to.have.property("$gte");
- });
-
- it('should handle "all" filter correctly', async function () {
- const req = {
- params: { monitorId: "test123" },
- query: { filter: "all" },
- };
- checkCountDocumentStub.resolves(2);
-
- const result = await getChecksCount(req);
-
- expect(result).to.equal(2);
- expect(checkCountDocumentStub.firstCall.args[0]).to.deep.equal({
- monitorId: "test123",
- status: false,
- });
- });
-
- it('should handle "down" filter correctly', async function () {
- const req = {
- params: { monitorId: "test123" },
- query: { filter: "down" },
- };
- checkCountDocumentStub.resolves(2);
-
- const result = await getChecksCount(req);
-
- expect(result).to.equal(2);
- expect(checkCountDocumentStub.firstCall.args[0]).to.deep.equal({
- monitorId: "test123",
- status: false,
- });
- });
-
- it('should handle "resolve" filter correctly', async function () {
- const req = {
- params: { monitorId: "test123" },
- query: { filter: "resolve" },
- };
- checkCountDocumentStub.resolves(1);
-
- const result = await getChecksCount(req);
-
- expect(result).to.equal(1);
- expect(checkCountDocumentStub.firstCall.args[0]).to.deep.equal({
- monitorId: "test123",
- status: false,
- statusCode: 5000,
- });
- });
-
- it("should handle unknown filter correctly", async function () {
- const req = {
- params: { monitorId: "test123" },
- query: { filter: "unknown" },
- };
- checkCountDocumentStub.resolves(1);
-
- const result = await getChecksCount(req);
-
- expect(result).to.equal(1);
- expect(checkCountDocumentStub.firstCall.args[0]).to.deep.equal({
- monitorId: "test123",
- status: false,
- });
- });
-
- it("should combine dateRange and filter in query", async function () {
- const req = {
- params: { monitorId: "test123" },
- query: {
- dateRange: "week",
- filter: "down",
- },
- };
- checkCountDocumentStub.resolves(4);
-
- const result = await getChecksCount(req);
-
- expect(result).to.equal(4);
- expect(checkCountDocumentStub.firstCall.args[0]).to.have.all.keys("monitorId", "createdAt", "status");
- });
- });
-
- describe("getChecks", function () {
- let checkFindStub, monitorFindStub;
-
- beforeEach(function () {
- checkFindStub = sinon.stub(Check, "find").returns({
- skip: sinon.stub().returns({
- limit: sinon.stub().returns({
- sort: sinon.stub().returns([{ id: 1 }, { id: 2 }]),
- }),
- }),
- });
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- it("should return checks with basic monitorId query", async function () {
- const req = {
- params: { monitorId: "test123" },
- query: {},
- };
-
- const result = await getChecks(req);
-
- expect(result).to.deep.equal([{ id: 1 }, { id: 2 }]);
- });
-
- it("should return checks with limit query", async function () {
- const req = {
- params: { monitorId: "test123" },
- query: { limit: 10 },
- };
-
- const result = await getChecks(req);
-
- expect(result).to.deep.equal([{ id: 1 }, { id: 2 }]);
- });
-
- it("should handle pagination correctly", async function () {
- const req = {
- params: { monitorId: "test123" },
- query: {
- page: 2,
- rowsPerPage: 10,
- },
- };
-
- const result = await getChecks(req);
-
- expect(result).to.deep.equal([{ id: 1 }, { id: 2 }]);
- });
-
- it("should handle dateRange filter", async function () {
- const req = {
- params: { monitorId: "test123" },
- query: { dateRange: "week" },
- };
- const result = await getChecks(req);
-
- expect(result).to.deep.equal([{ id: 1 }, { id: 2 }]);
- });
-
- it('should handle "all" filter', async function () {
- const req = {
- params: { monitorId: "test123" },
- query: { filter: "all" },
- };
-
- await getChecks(req);
- const result = await getChecks(req);
- expect(result).to.deep.equal([{ id: 1 }, { id: 2 }]);
- });
-
- it('should handle "down" filter', async function () {
- const req = {
- params: { monitorId: "test123" },
- query: { filter: "down" },
- };
-
- await getChecks(req);
- const result = await getChecks(req);
- expect(result).to.deep.equal([{ id: 1 }, { id: 2 }]);
- });
-
- it('should handle "resolve" filter', async function () {
- const req = {
- params: { monitorId: "test123" },
- query: { filter: "resolve" },
- };
-
- await getChecks(req);
- const result = await getChecks(req);
- expect(result).to.deep.equal([{ id: 1 }, { id: 2 }]);
- });
-
- it('should handle "unknown" filter', async function () {
- const req = {
- params: { monitorId: "test123" },
- query: { filter: "unknown" },
- };
-
- await getChecks(req);
- const result = await getChecks(req);
- expect(result).to.deep.equal([{ id: 1 }, { id: 2 }]);
- });
-
- it("should handle ascending sort order", async function () {
- const req = {
- params: { monitorId: "test123" },
- query: { sortOrder: "asc" },
- };
-
- await getChecks(req);
- const result = await getChecks(req);
- expect(result).to.deep.equal([{ id: 1 }, { id: 2 }]);
- });
-
- it("should handle error case", async function () {
- const req = {
- params: { monitorId: "test123" },
- query: {},
- };
-
- checkFindStub.throws(new Error("Database error"));
-
- try {
- await getChecks(req);
- } catch (error) {
- expect(error.message).to.equal("Database error");
- expect(error.service).to.equal("checkModule");
- expect(error.method).to.equal("getChecks");
- }
- });
- });
-
- describe("getTeamChecks", function () {
- let checkFindStub, checkCountDocumentsStub, monitorFindStub;
- const mockMonitors = [{ _id: "123" }];
-
- beforeEach(function () {
- monitorFindStub = sinon.stub(Monitor, "find").returns({
- select: sinon.stub().returns(mockMonitors),
- });
- checkCountDocumentsStub = sinon.stub(Check, "countDocuments").returns(2);
- checkFindStub = sinon.stub(Check, "find").returns({
- skip: sinon.stub().returns({
- limit: sinon.stub().returns({
- sort: sinon.stub().returns({
- select: sinon.stub().returns([{ id: 1 }, { id: 2 }]),
- }),
- }),
- }),
- });
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- it("should return checks with basic monitorId query", async function () {
- const req = {
- params: { teamId: "test123" },
- query: {},
- };
-
- const result = await getTeamChecks(req);
- expect(result).to.deep.equal({ checksCount: 2, checks: [{ id: 1 }, { id: 2 }] });
- });
-
- it("should handle pagination correctly", async function () {
- const req = {
- params: { monitorId: "test123" },
- query: { limit: 1, page: 2, rowsPerPage: 10 },
- };
-
- const result = await getTeamChecks(req);
- expect(result).to.deep.equal({ checksCount: 2, checks: [{ id: 1 }, { id: 2 }] });
- });
-
- it("should handle dateRange filter", async function () {
- const req = {
- params: { monitorId: "test123" },
- query: { dateRange: "week" },
- };
- const result = await getTeamChecks(req);
- expect(result).to.deep.equal({ checksCount: 2, checks: [{ id: 1 }, { id: 2 }] });
- });
-
- it('should handle "all" filter', async function () {
- const req = {
- params: { monitorId: "test123" },
- query: { filter: "all" },
- };
-
- await getChecks(req);
- const result = await getTeamChecks(req);
- expect(result).to.deep.equal({ checksCount: 2, checks: [{ id: 1 }, { id: 2 }] });
- });
-
- it('should handle "down" filter', async function () {
- const req = {
- params: { monitorId: "test123" },
- query: { filter: "down" },
- };
-
- await getChecks(req);
- const result = await getTeamChecks(req);
- expect(result).to.deep.equal({ checksCount: 2, checks: [{ id: 1 }, { id: 2 }] });
- });
-
- it('should handle "resolve" filter', async function () {
- const req = {
- params: { monitorId: "test123" },
- query: { filter: "resolve" },
- };
-
- await getChecks(req);
- const result = await getTeamChecks(req);
- expect(result).to.deep.equal({ checksCount: 2, checks: [{ id: 1 }, { id: 2 }] });
- });
-
- it('should handle "unknown" filter', async function () {
- const req = {
- params: { monitorId: "test123" },
- query: { filter: "unknown" },
- };
-
- await getChecks(req);
- const result = await getTeamChecks(req);
- expect(result).to.deep.equal({ checksCount: 2, checks: [{ id: 1 }, { id: 2 }] });
- });
-
- it("should handle ascending sort order", async function () {
- const req = {
- params: { monitorId: "test123" },
- query: { sortOrder: "asc" },
- };
-
- await getChecks(req);
- const result = await getTeamChecks(req);
- expect(result).to.deep.equal({ checksCount: 2, checks: [{ id: 1 }, { id: 2 }] });
- });
-
- it("should handle error case", async function () {
- const req = {
- params: { monitorId: "test123" },
- query: {},
- };
-
- checkFindStub.throws(new Error("Database error"));
-
- try {
- await getTeamChecks(req);
- } catch (error) {
- expect(error.message).to.equal("Database error");
- expect(error.service).to.equal("checkModule");
- expect(error.method).to.equal("getTeamChecks");
- }
- });
- });
-
- describe("deleteChecks", function () {
- let checkDeleteManyStub;
-
- beforeEach(function () {
- checkDeleteManyStub = sinon.stub(Check, "deleteMany").resolves({ deletedCount: 1 });
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- it("should return a value if a check is deleted", async function () {
- const result = await deleteChecks("123");
- expect(result).to.equal(1);
- });
-
- it("should handle an error", async function () {
- checkDeleteManyStub.throws(new Error("Database error"));
- try {
- await deleteChecks("123");
- } catch (error) {
- expect(error.message).to.equal("Database error");
- expect(error.method).to.equal("deleteChecks");
- }
- });
- });
-
- describe("deleteChecksByTeamId", function () {
- let mockMonitors = [{ _id: 123, save: () => this }];
- let monitorFindStub, monitorSaveStub, checkDeleteManyStub;
-
- beforeEach(function () {
- monitorSaveStub = sinon.stub(Monitor.prototype, "save");
- monitorFindStub = sinon.stub(Monitor, "find").returns(mockMonitors);
- checkDeleteManyStub = sinon.stub(Check, "deleteMany").resolves({ deletedCount: 1 });
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- it("should return a deleted count", async function () {
- const result = await deleteChecksByTeamId("123");
- expect(result).to.equal(1);
- });
-
- it("should handle errors", async function () {
- const err = new Error("DB Error");
- monitorFindStub.throws(err);
- try {
- const result = await deleteChecksByTeamId("123");
- } catch (error) {
- expect(error).to.deep.equal(err);
- }
- });
- });
-
- describe("updateChecksTTL", function () {
- let userUpdateManyStub;
- let loggerStub;
-
- beforeEach(function () {
- loggerStub = sinon.stub(logger, "error");
- userUpdateManyStub = sinon.stub(User, "updateMany");
- Check.collection = { dropIndex: sinon.stub(), createIndex: sinon.stub() };
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- it("should return undefined", async function () {
- const result = await updateChecksTTL("123", 10);
- expect(result).to.be.undefined;
- });
-
- it("should log an error if dropIndex throws an error", async function () {
- const err = new Error("Drop Index Error");
- Check.collection.dropIndex.throws(err);
- await updateChecksTTL("123", 10);
- expect(loggerStub.calledOnce).to.be.true;
- expect(loggerStub.firstCall.args[0].message).to.equal(err.message);
- });
-
- it("should throw an error if createIndex throws an error", async function () {
- const err = new Error("Create Index Error");
- Check.collection.createIndex.throws(err);
- try {
- await updateChecksTTL("123", 10);
- } catch (error) {
- expect(error).to.deep.equal(err);
- }
- });
-
- it("should throw an error if User.updateMany throws an error", async function () {
- const err = new Error("Update Many Error");
- userUpdateManyStub.throws(err);
- try {
- await updateChecksTTL("123", 10);
- } catch (error) {
- expect(error).to.deep.equal(err);
- }
- });
- });
-});
diff --git a/server/tests/db/hardwareCheckModule.test.js b/server/tests/db/hardwareCheckModule.test.js
deleted file mode 100755
index 20ce197fb..000000000
--- a/server/tests/db/hardwareCheckModule.test.js
+++ /dev/null
@@ -1,136 +0,0 @@
-import sinon from "sinon";
-import HardwareCheck from "../../db/models/HardwareCheck.js";
-import { createHardwareCheck } from "../../db/mongo/modules/hardwareCheckModule.js";
-import Monitor from "../../db/models/Monitor.js";
-import logger from "../../utils/logger.js";
-
-const mockHardwareCheck = {
- data: {
- cpu: {
- physical_core: 4,
- logical_core: 8,
- frequency: 4800,
- current_frequency: 1411,
- temperature: [45, 50, 46, 47, 45, 50, 46, 47],
- free_percent: 0.8552990910595134,
- usage_percent: 0.14470090894048657,
- },
- memory: {
- total_bytes: 16467628032,
- available_bytes: 7895044096,
- used_bytes: 6599561216,
- usage_percent: 0.4008,
- },
- disk: [
- {
- read_speed_bytes: null,
- write_speed_bytes: null,
- total_bytes: 931258499072,
- free_bytes: 737097256960,
- usage_percent: 0.1661,
- },
- ],
- host: {
- os: "linux",
- platform: "ubuntu",
- kernel_version: "6.8.0-48-generic",
- },
- },
- errors: [
- {
- metric: ["cpu.temperature"],
- err: "unable to read CPU temperature",
- },
- ],
-};
-
-const mockMonitor = {
- _id: "123",
- uptimePercentage: 1,
- status: true,
- save: () => this,
-};
-
-describe("HardwareCheckModule", function () {
- let hardwareCheckSaveStub, hardwareCheckCountDocumentsStub, monitorFindByIdStub, loggerStub;
-
- beforeEach(function () {
- loggerStub = sinon.stub(logger, "error");
- hardwareCheckSaveStub = sinon.stub(HardwareCheck.prototype, "save");
- monitorFindByIdStub = sinon.stub(Monitor, "findById");
- hardwareCheckCountDocumentsStub = sinon.stub(HardwareCheck, "countDocuments");
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- describe("createHardwareCheck", function () {
- it("should return a hardware check", async function () {
- hardwareCheckSaveStub.resolves(mockHardwareCheck);
- monitorFindByIdStub.resolves(mockMonitor);
- hardwareCheckCountDocumentsStub.resolves(1);
- const hardwareCheck = await createHardwareCheck({ status: true });
- expect(hardwareCheck).to.exist;
- expect(hardwareCheck).to.deep.equal(mockHardwareCheck);
- });
-
- it("should return a hardware check for a check with status false", async function () {
- hardwareCheckSaveStub.resolves(mockHardwareCheck);
- monitorFindByIdStub.resolves(mockMonitor);
- hardwareCheckCountDocumentsStub.resolves(1);
- const hardwareCheck = await createHardwareCheck({ status: false });
- expect(hardwareCheck).to.exist;
- expect(hardwareCheck).to.deep.equal(mockHardwareCheck);
- });
-
- it("should handle an error", async function () {
- const err = new Error("test error");
- monitorFindByIdStub.resolves(mockMonitor);
- hardwareCheckSaveStub.rejects(err);
- try {
- await createHardwareCheck({});
- } catch (error) {
- expect(error).to.exist;
- expect(error).to.deep.equal(err);
- }
- });
-
- it("should log an error if a monitor is not found", async function () {
- monitorFindByIdStub.resolves(null);
- const res = await createHardwareCheck({});
- expect(loggerStub.calledOnce).to.be.true;
- expect(res).to.be.null;
- });
-
- it("should handle a monitor with undefined uptimePercentage", async function () {
- monitorFindByIdStub.resolves({ ...mockMonitor, uptimePercentage: undefined });
- hardwareCheckSaveStub.resolves(mockHardwareCheck);
- hardwareCheckCountDocumentsStub.resolves(1);
- const res = await createHardwareCheck({});
- expect(res).to.exist;
- });
-
- it("should handle a monitor with undefined uptimePercentage and true status", async function () {
- monitorFindByIdStub.resolves({
- ...mockMonitor,
- uptimePercentage: undefined,
- });
- hardwareCheckSaveStub.resolves(mockHardwareCheck);
- hardwareCheckCountDocumentsStub.resolves(1);
- const res = await createHardwareCheck({ status: true });
- expect(res).to.exist;
- });
-
- it("should handle a monitor with undefined uptimePercentage and false status", async function () {
- monitorFindByIdStub.resolves({
- ...mockMonitor,
- uptimePercentage: undefined,
- });
- hardwareCheckSaveStub.resolves(mockHardwareCheck);
- hardwareCheckCountDocumentsStub.resolves(1);
- const res = await createHardwareCheck({ status: false });
- expect(res).to.exist;
- });
- });
-});
diff --git a/server/tests/db/inviteModule.test.js b/server/tests/db/inviteModule.test.js
deleted file mode 100755
index e8913c983..000000000
--- a/server/tests/db/inviteModule.test.js
+++ /dev/null
@@ -1,103 +0,0 @@
-import sinon from "sinon";
-import InviteToken from "../../db/models/InviteToken.js";
-import { requestInviteToken, getInviteToken, getInviteTokenAndDelete } from "../../db/mongo/modules/inviteModule.js";
-import { errorMessages } from "../../utils/messages.js";
-
-describe("Invite Module", function () {
- const mockUserData = {
- email: "test@test.com",
- teamId: "123",
- role: ["admin"],
- token: "123",
- };
- const mockInviteToken = { _id: 123, time: 123 };
- let inviteTokenDeleteManyStub, inviteTokenSaveStub, inviteTokenFindOneStub, inviteTokenFindOneAndDeleteStub;
-
- beforeEach(function () {
- inviteTokenDeleteManyStub = sinon.stub(InviteToken, "deleteMany");
- inviteTokenSaveStub = sinon.stub(InviteToken.prototype, "save");
- inviteTokenFindOneStub = sinon.stub(InviteToken, "findOne");
- inviteTokenFindOneAndDeleteStub = sinon.stub(InviteToken, "findOneAndDelete");
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- describe("requestInviteToken", function () {
- it("should return a new invite token", async function () {
- inviteTokenDeleteManyStub.resolves();
- inviteTokenSaveStub.resolves();
- const inviteToken = await requestInviteToken(mockUserData);
- expect(inviteToken.email).to.equal(mockUserData.email);
- expect(inviteToken.role).to.deep.equal(mockUserData.role);
- expect(inviteToken.token).to.exist;
- });
-
- it("should handle an error", async function () {
- const err = new Error("test error");
- inviteTokenDeleteManyStub.rejects(err);
- try {
- await requestInviteToken(mockUserData);
- } catch (error) {
- expect(error).to.deep.equal(err);
- }
- });
- });
-
- describe("getInviteToken", function () {
- it("should return an invite token", async function () {
- inviteTokenFindOneStub.resolves(mockInviteToken);
- const inviteToken = await getInviteToken(mockUserData.token);
- expect(inviteToken).to.deep.equal(mockInviteToken);
- });
-
- it("should handle a token not found", async function () {
- inviteTokenFindOneStub.resolves(null);
- try {
- await getInviteToken(mockUserData.token);
- } catch (error) {
- expect(error.message).to.equal(errorMessages.AUTH_INVITE_NOT_FOUND);
- }
- });
-
- it("should handle DB errors", async function () {
- const err = new Error("test error");
- inviteTokenFindOneStub.rejects(err);
- try {
- await getInviteToken(mockUserData.token);
- } catch (error) {
- expect(error).to.deep.equal(err);
- expect(error.method).to.equal("getInviteToken");
- }
- });
- });
-
- describe("getInviteTokenAndDelete", function () {
- it("should return a deleted invite", async function () {
- inviteTokenFindOneAndDeleteStub.resolves(mockInviteToken);
- const deletedInvite = await getInviteTokenAndDelete(mockUserData.token);
- expect(deletedInvite).to.deep.equal(mockInviteToken);
- });
-
- it("should handle a token not found", async function () {
- inviteTokenFindOneAndDeleteStub.resolves(null);
- try {
- await getInviteTokenAndDelete(mockUserData.token);
- } catch (error) {
- expect(error.message).to.equal(errorMessages.AUTH_INVITE_NOT_FOUND);
- }
- });
-
- it("should handle DB errors", async function () {
- const err = new Error("test error");
- inviteTokenFindOneAndDeleteStub.rejects(err);
- try {
- await getInviteTokenAndDelete(mockUserData.token);
- } catch (error) {
- expect(error).to.deep.equal(err);
- expect(error.method).to.equal("getInviteTokenAndDelete");
- }
- });
- });
-});
diff --git a/server/tests/db/maintenanceWindowModule.test.js b/server/tests/db/maintenanceWindowModule.test.js
deleted file mode 100755
index 576c97f84..000000000
--- a/server/tests/db/maintenanceWindowModule.test.js
+++ /dev/null
@@ -1,255 +0,0 @@
-import sinon from "sinon";
-import MaintenanceWindow from "../../db/models/MaintenanceWindow.js";
-import {
- createMaintenanceWindow,
- getMaintenanceWindowById,
- getMaintenanceWindowsByTeamId,
- getMaintenanceWindowsByMonitorId,
- deleteMaintenanceWindowById,
- deleteMaintenanceWindowByMonitorId,
- deleteMaintenanceWindowByUserId,
- editMaintenanceWindowById,
-} from "../../db/mongo/modules/maintenanceWindowModule.js";
-
-describe("MaintenanceWindow Module", function () {
- const mockMaintenanceWindow = {
- monitorId: "123",
- active: true,
- oneTime: true,
- start: 1,
- end: 20000,
- };
-
- let mockMaintenanceWindows = [mockMaintenanceWindow];
- let maintenanceWindowSaveStub,
- maintenanceWindowFindByIdStub,
- maintenanceWindowCountDocumentsStub,
- maintenanceWindowFindStub,
- maintenanceWindowFindByIdAndDeleteStub,
- maintenanceWindowDeleteManyStub,
- maintenanceWindowFindByIdAndUpdateStub;
-
- beforeEach(function () {
- maintenanceWindowSaveStub = sinon.stub(MaintenanceWindow.prototype, "save");
- maintenanceWindowFindByIdStub = sinon.stub(MaintenanceWindow, "findById");
- maintenanceWindowCountDocumentsStub = sinon.stub(MaintenanceWindow, "countDocuments");
- maintenanceWindowFindStub = sinon.stub(MaintenanceWindow, "find").returns({
- skip: sinon.stub().returns({
- limit: sinon.stub().returns({
- sort: sinon.stub().returns(mockMaintenanceWindows),
- }),
- }),
- });
- maintenanceWindowFindByIdAndDeleteStub = sinon.stub(MaintenanceWindow, "findByIdAndDelete");
- maintenanceWindowDeleteManyStub = sinon.stub(MaintenanceWindow, "deleteMany");
- maintenanceWindowFindByIdAndUpdateStub = sinon.stub(MaintenanceWindow, "findByIdAndUpdate");
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- describe("createMaintenanceWindow", function () {
- it("should save a new maintenance window", async function () {
- maintenanceWindowSaveStub.resolves(mockMaintenanceWindow);
- const result = await createMaintenanceWindow(mockMaintenanceWindow);
- expect(result).to.deep.equal(mockMaintenanceWindow);
- });
-
- it("should handle an error", async function () {
- const err = new Error("test error");
- maintenanceWindowSaveStub.rejects(err);
- try {
- await createMaintenanceWindow(mockMaintenanceWindow);
- } catch (error) {
- expect(error).to.deep.equal(err);
- }
- });
- });
-
- describe("getMaintenanceWindowById", function () {
- it("should return a maintenance window", async function () {
- maintenanceWindowFindByIdStub.resolves(mockMaintenanceWindow);
- const result = await getMaintenanceWindowById(mockMaintenanceWindow.id);
- expect(result).to.deep.equal(mockMaintenanceWindow);
- });
-
- it("should handle an error", async function () {
- const err = new Error("test error");
- maintenanceWindowFindByIdStub.rejects(err);
- try {
- await getMaintenanceWindowById(mockMaintenanceWindow.id);
- } catch (error) {
- expect(error).to.deep.equal(err);
- }
- });
- });
-
- describe("getMaintenanceWindowsByTeamId", function () {
- let query;
-
- beforeEach(function () {
- query = {
- active: true,
- page: 1,
- rowsPerPage: 10,
- field: "name",
- order: "asc",
- };
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- it("should return a list of maintenance windows and count", async function () {
- maintenanceWindowCountDocumentsStub.resolves(1);
- const result = await getMaintenanceWindowsByTeamId(mockMaintenanceWindow.teamId, query);
- expect(result).to.deep.equal({
- maintenanceWindows: mockMaintenanceWindows,
- maintenanceWindowCount: 1,
- });
- });
-
- it("should return a list of maintenance windows and count with empty query", async function () {
- query = undefined;
- maintenanceWindowCountDocumentsStub.resolves(1);
- const result = await getMaintenanceWindowsByTeamId(mockMaintenanceWindow.teamId, query);
- expect(result).to.deep.equal({
- maintenanceWindows: mockMaintenanceWindows,
- maintenanceWindowCount: 1,
- });
- });
-
- it("should return a list of maintenance windows and count with no pagination provided", async function () {
- query.page = undefined;
- query.rowsPerPage = undefined;
- maintenanceWindowCountDocumentsStub.resolves(1);
- const result = await getMaintenanceWindowsByTeamId(mockMaintenanceWindow.teamId, query);
- expect(result).to.deep.equal({
- maintenanceWindows: mockMaintenanceWindows,
- maintenanceWindowCount: 1,
- });
- });
-
- it("should return a list of maintenance windows and count with field and desc order", async function () {
- query.order = "desc";
- maintenanceWindowCountDocumentsStub.resolves(1);
- const result = await getMaintenanceWindowsByTeamId(mockMaintenanceWindow.teamId, query);
- expect(result).to.deep.equal({
- maintenanceWindows: mockMaintenanceWindows,
- maintenanceWindowCount: 1,
- });
- });
-
- it("should return a list of maintenance windows and count no field", async function () {
- query.field = undefined;
- maintenanceWindowCountDocumentsStub.resolves(1);
- const result = await getMaintenanceWindowsByTeamId(mockMaintenanceWindow.teamId, query);
- expect(result).to.deep.equal({
- maintenanceWindows: mockMaintenanceWindows,
- maintenanceWindowCount: 1,
- });
- });
-
- it("should handle an error", async function () {
- const err = new Error("test error");
- maintenanceWindowCountDocumentsStub.rejects(err);
- try {
- await getMaintenanceWindowsByTeamId(mockMaintenanceWindow.teamId, query);
- } catch (error) {
- expect(error).to.deep.equal(err);
- }
- });
- });
-
- describe("getMaintenanceWindowsByMonitorId", function () {
- it("should return a list of maintenance windows", async function () {
- maintenanceWindowFindStub.resolves(mockMaintenanceWindows);
- const result = await getMaintenanceWindowsByMonitorId(mockMaintenanceWindow.monitorId);
- expect(result).to.deep.equal(mockMaintenanceWindows);
- });
-
- it("should handle an error", async function () {
- const err = new Error("test error");
- maintenanceWindowFindStub.rejects(err);
- try {
- await getMaintenanceWindowsByMonitorId(mockMaintenanceWindow.monitorId);
- } catch (error) {
- expect(error).to.deep.equal(err);
- }
- });
- });
-
- describe("deleteMaintenanceWindowById", function () {
- it("should delete a maintenance window", async function () {
- maintenanceWindowFindByIdAndDeleteStub.resolves(mockMaintenanceWindow);
- const result = await deleteMaintenanceWindowById(mockMaintenanceWindow.id);
- expect(result).to.deep.equal(mockMaintenanceWindow);
- });
-
- it("should handle an error", async function () {
- const err = new Error("test error");
- maintenanceWindowFindByIdAndDeleteStub.rejects(err);
- try {
- await deleteMaintenanceWindowById(mockMaintenanceWindow.id);
- } catch (error) {
- expect(error).to.deep.equal(err);
- }
- });
- });
-
- describe("deleteMaintenanceWindowByMonitorId", function () {
- it("should return the number of documents deleted", async function () {
- maintenanceWindowDeleteManyStub.resolves({ deletedCount: 1 });
- const result = await deleteMaintenanceWindowByMonitorId(mockMaintenanceWindow.monitorId);
- expect(result).to.deep.equal({ deletedCount: 1 });
- });
-
- it("should handle an error", async function () {
- const err = new Error("test error");
- maintenanceWindowDeleteManyStub.rejects(err);
- try {
- await deleteMaintenanceWindowByMonitorId(mockMaintenanceWindow.monitorId);
- } catch (error) {
- expect(error).to.deep.equal(err);
- }
- });
- });
-
- describe("deleteMaintenanceWindowByUserId", function () {
- it("should return the number of documents deleted", async function () {
- maintenanceWindowDeleteManyStub.resolves({ deletedCount: 1 });
- const result = await deleteMaintenanceWindowByUserId(mockMaintenanceWindow.userId);
- expect(result).to.deep.equal({ deletedCount: 1 });
- });
-
- it("should handle an error", async function () {
- const err = new Error("test error");
- maintenanceWindowDeleteManyStub.rejects(err);
- try {
- await deleteMaintenanceWindowByUserId(mockMaintenanceWindow.userId);
- } catch (error) {
- expect(error).to.deep.equal(err);
- }
- });
- });
-
- describe("editMaintenanceWindowById", function () {
- it("should return the updated maintenance window", async function () {
- maintenanceWindowFindByIdAndUpdateStub.resolves(mockMaintenanceWindow);
- const result = await editMaintenanceWindowById(mockMaintenanceWindow.id, mockMaintenanceWindow);
- expect(result).to.deep.equal(mockMaintenanceWindow);
- });
-
- it("should handle an error", async function () {
- const err = new Error("test error");
- maintenanceWindowFindByIdAndUpdateStub.rejects(err);
- try {
- await editMaintenanceWindowById(mockMaintenanceWindow.id, mockMaintenanceWindow);
- } catch (error) {
- expect(error).to.deep.equal(err);
- }
- });
- });
-});
diff --git a/server/tests/db/monitorModule.test.js b/server/tests/db/monitorModule.test.js
deleted file mode 100755
index e59c352cf..000000000
--- a/server/tests/db/monitorModule.test.js
+++ /dev/null
@@ -1,1865 +0,0 @@
-import sinon from "sinon";
-import Monitor from "../../db/models/Monitor.js";
-import Check from "../../db/models/Check.js";
-import PageSpeedCheck from "../../db/models/PageSpeedCheck.js";
-import HardwareCheck from "../../db/models/HardwareCheck.js";
-import Notification from "../../db/models/Notification.js";
-
-import { errorMessages } from "../../utils/messages.js";
-import {
- getAllMonitors,
- getAllMonitorsWithUptimeStats,
- getMonitorStatsById,
- getMonitorById,
- getMonitorsAndSummaryByTeamId,
- getMonitorsByTeamId,
- createMonitor,
- deleteMonitor,
- deleteAllMonitors,
- deleteMonitorsByUserId,
- editMonitor,
- addDemoMonitors,
- calculateUptimeDuration,
- getLastChecked,
- getLatestResponseTime,
- getAverageResponseTime,
- getUptimePercentage,
- getIncidents,
- getMonitorChecks,
- processChecksForDisplay,
- groupChecksByTime,
- calculateGroupStats,
-} from "../../db/mongo/modules/monitorModule.js";
-
-describe("monitorModule", function () {
- let monitorFindStub,
- monitorFindByIdStub,
- monitorFindByIdAndUpdateStub,
- monitorFindByIdAndDeleteStub,
- monitorDeleteManyStub,
- monitorCountStub,
- monitorInsertManyStub,
- checkFindStub,
- pageSpeedCheckFindStub,
- hardwareCheckFindStub;
-
- beforeEach(function () {
- monitorFindStub = sinon.stub(Monitor, "find");
- monitorFindByIdStub = sinon.stub(Monitor, "findById");
- monitorFindByIdAndUpdateStub = sinon.stub(Monitor, "findByIdAndUpdate");
- monitorFindByIdAndDeleteStub = sinon.stub(Monitor, "findByIdAndDelete");
- monitorDeleteManyStub = sinon.stub(Monitor, "deleteMany");
- monitorCountStub = sinon.stub(Monitor, "countDocuments");
-
- monitorInsertManyStub = sinon.stub(Monitor, "insertMany");
- checkFindStub = sinon.stub(Check, "find").returns({
- sort: sinon.stub(),
- });
- pageSpeedCheckFindStub = sinon.stub(PageSpeedCheck, "find").returns({
- sort: sinon.stub(),
- });
- hardwareCheckFindStub = sinon.stub(HardwareCheck, "find").returns({
- sort: sinon.stub(),
- });
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- describe("getAllMonitors", function () {
- it("should return all monitors", async function () {
- const mockMonitors = [
- { _id: "1", name: "Monitor 1", url: "test1.com" },
- { _id: "2", name: "Monitor 2", url: "test2.com" },
- ];
- monitorFindStub.returns(mockMonitors);
- const result = await getAllMonitors();
-
- expect(result).to.deep.equal(mockMonitors);
- expect(monitorFindStub.calledOnce).to.be.true;
- expect(monitorFindStub.firstCall.args).to.deep.equal([]);
- });
-
- it("should handle empty results", async function () {
- monitorFindStub.returns([]);
- const result = await getAllMonitors();
- expect(result).to.be.an("array").that.is.empty;
- });
-
- it("should throw error when database fails", async function () {
- // Arrange
- const error = new Error("Database error");
- error.service = "MonitorModule";
- error.method = "getAllMonitors";
- monitorFindStub.rejects(error);
- // Act & Assert
- try {
- await getAllMonitors();
- expect.fail("Should have thrown an error");
- } catch (err) {
- expect(err).to.equal(error);
- expect(err.service).to.equal("monitorModule");
- expect(err.method).to.equal("getAllMonitors");
- }
- });
- });
-
- describe("getAllMonitorsWithUptimeStats", function () {
- it("should return monitors with uptime stats for different time periods", async function () {
- // Mock data
- const mockMonitors = [
- {
- _id: "monitor1",
- type: "http",
- toObject: () => ({
- _id: "monitor1",
- type: "http",
- name: "Test Monitor",
- }),
- },
- ];
-
- const mockChecks = [{ status: true }, { status: true }, { status: false }, { status: true }];
-
- monitorFindStub.resolves(mockMonitors);
- checkFindStub.resolves(mockChecks);
-
- const result = await getAllMonitorsWithUptimeStats();
-
- expect(result).to.be.an("array");
- expect(result).to.have.lengthOf(1);
-
- const monitor = result[0];
- expect(monitor).to.have.property("_id", "monitor1");
- expect(monitor).to.have.property("name", "Test Monitor");
-
- // Check uptime percentages exist for all time periods
- expect(monitor).to.have.property("1");
- expect(monitor).to.have.property("7");
- expect(monitor).to.have.property("30");
- expect(monitor).to.have.property("90");
-
- // Verify uptime percentage calculation (3 successful out of 4 = 75%)
- expect(monitor["1"]).to.equal(75);
- expect(monitor["7"]).to.equal(75);
- expect(monitor["30"]).to.equal(75);
- expect(monitor["90"]).to.equal(75);
- });
-
- it("should return monitors with stats for pagespeed type", async function () {
- // Mock data
- const mockMonitors = [
- {
- _id: "monitor1",
- type: "pagespeed",
- toObject: () => ({
- _id: "monitor1",
- type: "pagespeed",
- name: "Test Monitor",
- }),
- },
- ];
-
- const mockChecks = [{ status: true }, { status: true }, { status: false }, { status: true }];
-
- monitorFindStub.resolves(mockMonitors);
- pageSpeedCheckFindStub.resolves(mockChecks);
-
- const result = await getAllMonitorsWithUptimeStats();
-
- expect(result).to.be.an("array");
- expect(result).to.have.lengthOf(1);
-
- const monitor = result[0];
- expect(monitor).to.have.property("_id", "monitor1");
- expect(monitor).to.have.property("name", "Test Monitor");
-
- // Check uptime percentages exist for all time periods
- expect(monitor).to.have.property("1");
- expect(monitor).to.have.property("7");
- expect(monitor).to.have.property("30");
- expect(monitor).to.have.property("90");
-
- // Verify uptime percentage calculation (3 successful out of 4 = 75%)
- expect(monitor["1"]).to.equal(75);
- expect(monitor["7"]).to.equal(75);
- expect(monitor["30"]).to.equal(75);
- expect(monitor["90"]).to.equal(75);
- });
-
- it("should return monitors with stats for hardware type", async function () {
- // Mock data
- const mockMonitors = [
- {
- _id: "monitor1",
- type: "hardware",
- toObject: () => ({
- _id: "monitor1",
- type: "hardware",
- name: "Test Monitor",
- }),
- },
- ];
-
- const mockChecks = [{ status: true }, { status: true }, { status: false }, { status: true }];
-
- monitorFindStub.resolves(mockMonitors);
- hardwareCheckFindStub.resolves(mockChecks);
-
- const result = await getAllMonitorsWithUptimeStats();
-
- expect(result).to.be.an("array");
- expect(result).to.have.lengthOf(1);
-
- const monitor = result[0];
- expect(monitor).to.have.property("_id", "monitor1");
- expect(monitor).to.have.property("name", "Test Monitor");
-
- // Check uptime percentages exist for all time periods
- expect(monitor).to.have.property("1");
- expect(monitor).to.have.property("7");
- expect(monitor).to.have.property("30");
- expect(monitor).to.have.property("90");
-
- // Verify uptime percentage calculation (3 successful out of 4 = 75%)
- expect(monitor["1"]).to.equal(75);
- expect(monitor["7"]).to.equal(75);
- expect(monitor["30"]).to.equal(75);
- expect(monitor["90"]).to.equal(75);
- });
-
- it("should handle errors appropriately", async function () {
- // Setup stub to throw error
- monitorFindStub.rejects(new Error("Database error"));
-
- try {
- await getAllMonitorsWithUptimeStats();
- } catch (error) {
- expect(error).to.be.an("error");
- expect(error.message).to.equal("Database error");
- expect(error.service).to.equal("monitorModule");
- expect(error.method).to.equal("getAllMonitorsWithUptimeStats");
- }
- });
-
- it("should handle empty monitor list", async function () {
- monitorFindStub.resolves([]);
-
- const result = await getAllMonitorsWithUptimeStats();
-
- expect(result).to.be.an("array");
- expect(result).to.have.lengthOf(0);
- });
-
- it("should handle monitor with no checks", async function () {
- const mockMonitors = [
- {
- _id: "monitor1",
- type: "http",
- toObject: () => ({
- _id: "monitor1",
- type: "http",
- name: "Test Monitor",
- }),
- },
- ];
-
- monitorFindStub.resolves(mockMonitors);
- checkFindStub.resolves([]);
-
- const result = await getAllMonitorsWithUptimeStats();
-
- expect(result[0]).to.have.property("1", 0);
- expect(result[0]).to.have.property("7", 0);
- expect(result[0]).to.have.property("30", 0);
- expect(result[0]).to.have.property("90", 0);
- });
- });
-
- describe("calculateUptimeDuration", function () {
- let clock;
- const NOW = new Date("2024-01-01T12:00:00Z").getTime();
-
- beforeEach(function () {
- // Fix the current time
- clock = sinon.useFakeTimers(NOW);
- });
-
- afterEach(function () {
- clock.restore();
- });
-
- it("should return 0 when checks array is empty", function () {
- expect(calculateUptimeDuration([])).to.equal(0);
- });
-
- it("should return 0 when checks array is null", function () {
- expect(calculateUptimeDuration(null)).to.equal(0);
- });
-
- it("should calculate uptime from last down check to most recent check", function () {
- const checks = [
- { status: true, createdAt: "2024-01-01T11:00:00Z" }, // Most recent
- { status: true, createdAt: "2024-01-01T10:00:00Z" },
- { status: false, createdAt: "2024-01-01T09:00:00Z" }, // Last down
- { status: true, createdAt: "2024-01-01T08:00:00Z" },
- ];
-
- // Expected: 2 hours (from 09:00 to 11:00) = 7200000ms
- expect(calculateUptimeDuration(checks)).to.equal(7200000);
- });
-
- it("should calculate uptime from first check when no down checks exist", function () {
- const checks = [
- { status: true, createdAt: "2024-01-01T11:00:00Z" },
- { status: true, createdAt: "2024-01-01T10:00:00Z" },
- { status: true, createdAt: "2024-01-01T09:00:00Z" },
- ];
-
- // Expected: Current time (12:00) - First check (09:00) = 3 hours = 10800000ms
- expect(calculateUptimeDuration(checks)).to.equal(10800000);
- });
- });
-
- describe("getLastChecked", function () {
- let clock;
- const NOW = new Date("2024-01-01T12:00:00Z").getTime();
-
- beforeEach(function () {
- // Fix the current time
- clock = sinon.useFakeTimers(NOW);
- });
-
- afterEach(function () {
- clock.restore();
- });
-
- it("should return 0 when checks array is empty", function () {
- expect(getLastChecked([])).to.equal(0);
- });
-
- it("should return 0 when checks array is null", function () {
- expect(getLastChecked(null)).to.equal(0);
- });
-
- it("should return time difference between now and most recent check", function () {
- const checks = [
- { createdAt: "2024-01-01T11:30:00Z" }, // 30 minutes ago
- { createdAt: "2024-01-01T11:00:00Z" },
- { createdAt: "2024-01-01T10:30:00Z" },
- ];
-
- // Expected: 30 minutes = 1800000ms
- expect(getLastChecked(checks)).to.equal(1800000);
- });
-
- it("should handle checks from different days", function () {
- const checks = [
- { createdAt: "2023-12-31T12:00:00Z" }, // 24 hours ago
- { createdAt: "2023-12-30T12:00:00Z" },
- ];
-
- // Expected: 24 hours = 86400000ms
- expect(getLastChecked(checks)).to.equal(86400000);
- });
- });
-
- describe("getLatestResponseTime", function () {
- it("should return 0 when checks array is empty", function () {
- expect(getLatestResponseTime([])).to.equal(0);
- });
-
- it("should return 0 when checks array is null", function () {
- expect(getLatestResponseTime(null)).to.equal(0);
- });
-
- it("should return response time from most recent check", function () {
- const checks = [
- { responseTime: 150, createdAt: "2024-01-01T11:30:00Z" }, // Most recent
- { responseTime: 200, createdAt: "2024-01-01T11:00:00Z" },
- { responseTime: 250, createdAt: "2024-01-01T10:30:00Z" },
- ];
-
- expect(getLatestResponseTime(checks)).to.equal(150);
- });
-
- it("should handle missing responseTime in checks", function () {
- const checks = [{ createdAt: "2024-01-01T11:30:00Z" }, { responseTime: 200, createdAt: "2024-01-01T11:00:00Z" }];
-
- expect(getLatestResponseTime(checks)).to.equal(0);
- });
- });
-
- describe("getAverageResponseTime", function () {
- it("should return 0 when checks array is empty", function () {
- expect(getAverageResponseTime([])).to.equal(0);
- });
-
- it("should return 0 when checks array is null", function () {
- expect(getAverageResponseTime(null)).to.equal(0);
- });
-
- it("should calculate average response time from all checks", function () {
- const checks = [
- { responseTime: 100, createdAt: "2024-01-01T11:30:00Z" },
- { responseTime: 200, createdAt: "2024-01-01T11:00:00Z" },
- { responseTime: 300, createdAt: "2024-01-01T10:30:00Z" },
- ];
-
- // Average: (100 + 200 + 300) / 3 = 200
- expect(getAverageResponseTime(checks)).to.equal(200);
- });
-
- it("should handle missing responseTime in some checks", function () {
- const checks = [
- { responseTime: 100, createdAt: "2024-01-01T11:30:00Z" },
- { createdAt: "2024-01-01T11:00:00Z" },
- { responseTime: 300, createdAt: "2024-01-01T10:30:00Z" },
- ];
-
- // Average: (100 + 300) / 2 = 200
- expect(getAverageResponseTime(checks)).to.equal(200);
- });
-
- it("should return 0 when no checks have responseTime", function () {
- const checks = [{ createdAt: "2024-01-01T11:30:00Z" }, { createdAt: "2024-01-01T11:00:00Z" }];
-
- expect(getAverageResponseTime(checks)).to.equal(0);
- });
- });
-
- describe("getUptimePercentage", function () {
- it("should return 0 when checks array is empty", function () {
- expect(getUptimePercentage([])).to.equal(0);
- });
-
- it("should return 0 when checks array is null", function () {
- expect(getUptimePercentage(null)).to.equal(0);
- });
-
- it("should return 100 when all checks are up", function () {
- const checks = [{ status: true }, { status: true }, { status: true }];
- expect(getUptimePercentage(checks)).to.equal(100);
- });
-
- it("should return 0 when all checks are down", function () {
- const checks = [{ status: false }, { status: false }, { status: false }];
- expect(getUptimePercentage(checks)).to.equal(0);
- });
-
- it("should calculate correct percentage for mixed status checks", function () {
- const checks = [{ status: true }, { status: false }, { status: true }, { status: true }];
- // 3 up out of 4 total = 75%
- expect(getUptimePercentage(checks)).to.equal(75);
- });
-
- it("should handle undefined status values", function () {
- const checks = [{ status: true }, { status: undefined }, { status: true }];
- // 2 up out of 3 total ≈ 66.67%
- expect(getUptimePercentage(checks)).to.equal((2 / 3) * 100);
- });
- });
-
- describe("getIncidents", function () {
- it("should return 0 when checks array is empty", function () {
- expect(getIncidents([])).to.equal(0);
- });
-
- it("should return 0 when checks array is null", function () {
- expect(getIncidents(null)).to.equal(0);
- });
-
- it("should return 0 when all checks are up", function () {
- const checks = [{ status: true }, { status: true }, { status: true }];
- expect(getIncidents(checks)).to.equal(0);
- });
-
- it("should count all incidents when all checks are down", function () {
- const checks = [{ status: false }, { status: false }, { status: false }];
- expect(getIncidents(checks)).to.equal(3);
- });
-
- it("should count correct number of incidents for mixed status checks", function () {
- const checks = [{ status: true }, { status: false }, { status: true }, { status: false }, { status: true }];
- expect(getIncidents(checks)).to.equal(2);
- });
-
- it("should handle undefined status values", function () {
- const checks = [{ status: true }, { status: undefined }, { status: false }, { status: false }];
- // Only counts explicit false values
- expect(getIncidents(checks)).to.equal(2);
- });
- });
-
- describe("getMonitorChecks", function () {
- let mockModel;
-
- beforeEach(function () {
- // Create a mock model with chainable methods
- const mockChecks = [
- { monitorId: "123", createdAt: new Date("2024-01-01") },
- { monitorId: "123", createdAt: new Date("2024-01-02") },
- ];
-
- mockModel = {
- find: sinon.stub().returns({
- sort: sinon.stub().returns(mockChecks),
- }),
- };
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- it("should return all checks and date-ranged checks", async function () {
- // Arrange
- const monitorId = "123";
- const dateRange = {
- start: new Date("2024-01-01"),
- end: new Date("2024-01-02"),
- };
- const sortOrder = -1;
-
- // Act
- const result = await getMonitorChecks(monitorId, mockModel, dateRange, sortOrder);
-
- // Assert
- expect(result).to.have.keys(["checksAll", "checksForDateRange"]);
-
- // Verify find was called with correct parameters
- expect(mockModel.find.firstCall.args[0]).to.deep.equal({ monitorId });
- expect(mockModel.find.secondCall.args[0]).to.deep.equal({
- monitorId,
- createdAt: { $gte: dateRange.start, $lte: dateRange.end },
- });
-
- // Verify sort was called with correct parameters
- const sortCalls = mockModel.find().sort.getCalls();
- sortCalls.forEach((call) => {
- expect(call.args[0]).to.deep.equal({ createdAt: sortOrder });
- });
- });
-
- it("should handle empty results", async function () {
- // Arrange
- const emptyModel = {
- find: sinon.stub().returns({
- sort: sinon.stub().returns([]),
- }),
- };
-
- // Act
- const result = await getMonitorChecks(
- "123",
- emptyModel,
- {
- start: new Date(),
- end: new Date(),
- },
- -1
- );
-
- // Assert
- expect(result.checksAll).to.be.an("array").that.is.empty;
- expect(result.checksForDateRange).to.be.an("array").that.is.empty;
- });
-
- it("should maintain sort order", async function () {
- // Arrange
- const sortedChecks = [
- { monitorId: "123", createdAt: new Date("2024-01-02") },
- { monitorId: "123", createdAt: new Date("2024-01-01") },
- ];
-
- const sortedModel = {
- find: sinon.stub().returns({
- sort: sinon.stub().returns(sortedChecks),
- }),
- };
-
- // Act
- const result = await getMonitorChecks(
- "123",
- sortedModel,
- {
- start: new Date("2024-01-01"),
- end: new Date("2024-01-02"),
- },
- -1
- );
-
- // Assert
- expect(result.checksAll[0].createdAt).to.be.greaterThan(result.checksAll[1].createdAt);
- expect(result.checksForDateRange[0].createdAt).to.be.greaterThan(result.checksForDateRange[1].createdAt);
- });
- });
-
- describe("processChecksForDisplay", function () {
- let normalizeStub;
-
- beforeEach(function () {
- normalizeStub = sinon.stub();
- });
-
- it("should return original checks when numToDisplay is not provided", function () {
- const checks = [1, 2, 3, 4, 5];
- const result = processChecksForDisplay(normalizeStub, checks);
- expect(result).to.deep.equal(checks);
- });
-
- it("should return original checks when numToDisplay is greater than checks length", function () {
- const checks = [1, 2, 3];
- const result = processChecksForDisplay(normalizeStub, checks, 5);
- expect(result).to.deep.equal(checks);
- });
-
- it("should filter checks based on numToDisplay", function () {
- const checks = [1, 2, 3, 4, 5, 6];
- const result = processChecksForDisplay(normalizeStub, checks, 3);
- // Should return [1, 3, 5] as n = ceil(6/3) = 2
- expect(result).to.deep.equal([1, 3, 5]);
- });
-
- it("should handle empty checks array", function () {
- const checks = [];
- const result = processChecksForDisplay(normalizeStub, checks, 3);
- expect(result).to.be.an("array").that.is.empty;
- });
-
- it("should call normalizeData when normalize is true", function () {
- const checks = [1, 2, 3];
- normalizeStub.returns([10, 20, 30]);
-
- const result = processChecksForDisplay(normalizeStub, checks, null, true);
-
- expect(normalizeStub.args[0]).to.deep.equal([checks, 1, 100]);
- expect(result).to.deep.equal([10, 20, 30]);
- });
-
- it("should handle both filtering and normalization", function () {
- const checks = [1, 2, 3, 4, 5, 6];
- normalizeStub.returns([10, 30, 50]);
-
- const result = processChecksForDisplay(normalizeStub, checks, 3, true);
-
- expect(normalizeStub.args[0][0]).to.deep.equal([1, 3, 5]);
- expect(result).to.deep.equal([10, 30, 50]);
- });
- });
-
- describe("groupChecksByTime", function () {
- const mockChecks = [
- { createdAt: "2024-01-15T10:30:45Z" },
- { createdAt: "2024-01-15T10:45:15Z" },
- { createdAt: "2024-01-15T11:15:00Z" },
- { createdAt: "2024-01-16T10:30:00Z" },
- ];
-
- it("should group checks by hour when dateRange is 'day'", function () {
- const result = groupChecksByTime(mockChecks, "day");
-
- // Get timestamps for 10:00 and 11:00 on Jan 15
- const time1 = new Date("2024-01-15T10:00:00Z").getTime();
- const time2 = new Date("2024-01-15T11:00:00Z").getTime();
- const time3 = new Date("2024-01-16T10:00:00Z").getTime();
-
- expect(Object.keys(result)).to.have.lengthOf(3);
-
- expect(result[time1].checks).to.have.lengthOf(2);
- expect(result[time2].checks).to.have.lengthOf(1);
- expect(result[time3].checks).to.have.lengthOf(1);
- });
-
- it("should group checks by day when dateRange is not 'day'", function () {
- const result = groupChecksByTime(mockChecks, "week");
-
- expect(Object.keys(result)).to.have.lengthOf(2);
- expect(result["2024-01-15"].checks).to.have.lengthOf(3);
- expect(result["2024-01-16"].checks).to.have.lengthOf(1);
- });
-
- it("should handle empty checks array", function () {
- const result = groupChecksByTime([], "day");
- expect(result).to.deep.equal({});
- });
-
- it("should handle single check", function () {
- const singleCheck = [{ createdAt: "2024-01-15T10:30:45Z" }];
- const result = groupChecksByTime(singleCheck, "day");
-
- const expectedTime = new Date("2024-01-15T10:00:00Z").getTime();
- expect(Object.keys(result)).to.have.lengthOf(1);
- expect(result[expectedTime].checks).to.have.lengthOf(1);
- });
-
- it("should skip invalid dates and process valid ones", function () {
- const checksWithInvalidDate = [
- { createdAt: "invalid-date" },
- { createdAt: "2024-01-15T10:30:45Z" },
- { createdAt: null },
- { createdAt: undefined },
- { createdAt: "" },
- ];
-
- const result = groupChecksByTime(checksWithInvalidDate, "day");
-
- const expectedTime = new Date("2024-01-15T10:00:00Z").getTime();
- expect(Object.keys(result)).to.have.lengthOf(1);
- expect(result[expectedTime].checks).to.have.lengthOf(1);
- expect(result[expectedTime].checks[0].createdAt).to.equal("2024-01-15T10:30:45Z");
- });
-
- it("should handle checks in same time group", function () {
- const checksInSameHour = [{ createdAt: "2024-01-15T10:15:00Z" }, { createdAt: "2024-01-15T10:45:00Z" }];
-
- const result = groupChecksByTime(checksInSameHour, "day");
-
- const expectedTime = new Date("2024-01-15T10:00:00Z").getTime();
- expect(Object.keys(result)).to.have.lengthOf(1);
- expect(result[expectedTime].checks).to.have.lengthOf(2);
- });
- });
-
- describe("calculateGroupStats", function () {
- // Mock getUptimePercentage function
- let uptimePercentageStub;
-
- beforeEach(function () {
- uptimePercentageStub = sinon.stub();
- uptimePercentageStub.returns(95); // Default return value
- });
-
- it("should calculate stats correctly for a group of checks", function () {
- const mockGroup = {
- time: "2024-01-15",
- checks: [
- { status: true, responseTime: 100 },
- { status: false, responseTime: 200 },
- { status: true, responseTime: 300 },
- ],
- };
-
- const result = calculateGroupStats(mockGroup, uptimePercentageStub);
-
- expect(result).to.deep.equal({
- time: "2024-01-15",
- uptimePercentage: (2 / 3) * 100,
- totalChecks: 3,
- totalIncidents: 1,
- avgResponseTime: 200, // (100 + 200 + 300) / 3
- });
- });
-
- it("should handle empty checks array", function () {
- const mockGroup = {
- time: "2024-01-15",
- checks: [],
- };
-
- const result = calculateGroupStats(mockGroup, uptimePercentageStub);
-
- expect(result).to.deep.equal({
- time: "2024-01-15",
- uptimePercentage: 0,
- totalChecks: 0,
- totalIncidents: 0,
- avgResponseTime: 0,
- });
- });
-
- it("should handle missing responseTime values", function () {
- const mockGroup = {
- time: "2024-01-15",
- checks: [{ status: true }, { status: false, responseTime: 200 }, { status: true, responseTime: undefined }],
- };
-
- const result = calculateGroupStats(mockGroup, uptimePercentageStub);
-
- expect(result).to.deep.equal({
- time: "2024-01-15",
- uptimePercentage: (2 / 3) * 100,
- totalChecks: 3,
- totalIncidents: 1,
- avgResponseTime: 200, // 200 / 1
- });
- });
-
- it("should handle all checks with status false", function () {
- const mockGroup = {
- time: "2024-01-15",
- checks: [
- { status: false, responseTime: 100 },
- { status: false, responseTime: 200 },
- { status: false, responseTime: 300 },
- ],
- };
-
- const result = calculateGroupStats(mockGroup, uptimePercentageStub);
-
- expect(result).to.deep.equal({
- time: "2024-01-15",
- uptimePercentage: 0,
- totalChecks: 3,
- totalIncidents: 3,
- avgResponseTime: 200,
- });
- });
-
- it("should handle all checks with status true", function () {
- const mockGroup = {
- time: "2024-01-15",
- checks: [
- { status: true, responseTime: 100 },
- { status: true, responseTime: 200 },
- { status: true, responseTime: 300 },
- ],
- };
-
- const result = calculateGroupStats(mockGroup, uptimePercentageStub);
-
- expect(result).to.deep.equal({
- time: "2024-01-15",
- uptimePercentage: 100,
- totalChecks: 3,
- totalIncidents: 0,
- avgResponseTime: 200,
- });
- });
- });
-
- describe("getMonitorStatsById", function () {
- const now = new Date();
- const oneHourAgo = new Date(now - 3600000);
- const twoHoursAgo = new Date(now - 7200000);
-
- const mockMonitor = {
- _id: "monitor123",
- type: "http",
- name: "Test Monitor",
- url: "https://test.com",
- toObject: () => ({
- _id: "monitor123",
- type: "http",
- name: "Test Monitor",
- url: "https://test.com",
- }),
- };
-
- const mockMonitorPing = {
- _id: "monitor123",
- type: "ping",
- name: "Test Monitor",
- url: "https://test.com",
- toObject: () => ({
- _id: "monitor123",
- type: "http",
- name: "Test Monitor",
- url: "https://test.com",
- }),
- };
- const mockMonitorDocker = {
- _id: "monitor123",
- type: "docker",
- name: "Test Monitor",
- url: "https://test.com",
- toObject: () => ({
- _id: "monitor123",
- type: "http",
- name: "Test Monitor",
- url: "https://test.com",
- }),
- };
-
- const checkDocs = [
- {
- monitorId: "monitor123",
- status: true,
- responseTime: 100,
- createdAt: new Date("2024-01-01T12:00:00Z"),
- toObject: function () {
- return {
- monitorId: this.monitorId,
- status: this.status,
- responseTime: this.responseTime,
- createdAt: this.createdAt,
- };
- },
- },
- {
- monitorId: "monitor123",
- status: true,
- responseTime: 150,
- createdAt: new Date("2024-01-01T11:00:00Z"),
- toObject: function () {
- return {
- monitorId: this.monitorId,
- status: this.status,
- responseTime: this.responseTime,
- createdAt: this.createdAt,
- };
- },
- },
- {
- monitorId: "monitor123",
- status: false,
- responseTime: 200,
- createdAt: new Date("2024-01-01T10:00:00Z"),
- toObject: function () {
- return {
- monitorId: this.monitorId,
- status: this.status,
- responseTime: this.responseTime,
- createdAt: this.createdAt,
- };
- },
- },
- ];
- const req = {
- params: { monitorId: "monitor123" },
- query: {
- dateRange: "day",
- sortOrder: "desc",
- numToDisplay: 10,
- normalize: true,
- },
- };
-
- beforeEach(function () {
- checkFindStub.returns({
- sort: () => checkDocs,
- });
- monitorFindByIdStub.returns(mockMonitor);
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- it("should return monitor stats with calculated values, sort order desc", async function () {
- req.query.sortOrder = "desc";
- const result = await getMonitorStatsById(req);
- expect(result).to.include.keys([
- "_id",
- "type",
- "name",
- "url",
- "uptimeDuration",
- "lastChecked",
- "latestResponseTime",
- "periodIncidents",
- "periodTotalChecks",
- "periodAvgResponseTime",
- "periodUptime",
- "aggregateData",
- ]);
- expect(result.latestResponseTime).to.equal(100);
- expect(result.periodTotalChecks).to.equal(3);
- expect(result.periodIncidents).to.equal(1);
- expect(result.periodUptime).to.be.a("number");
- expect(result.aggregateData).to.be.an("array");
- });
-
- it("should return monitor stats with calculated values, ping type", async function () {
- monitorFindByIdStub.returns(mockMonitorPing);
- req.query.sortOrder = "desc";
- const result = await getMonitorStatsById(req);
- expect(result).to.include.keys([
- "_id",
- "type",
- "name",
- "url",
- "uptimeDuration",
- "lastChecked",
- "latestResponseTime",
- "periodIncidents",
- "periodTotalChecks",
- "periodAvgResponseTime",
- "periodUptime",
- "aggregateData",
- ]);
- expect(result.latestResponseTime).to.equal(100);
- expect(result.periodTotalChecks).to.equal(3);
- expect(result.periodIncidents).to.equal(1);
- expect(result.periodUptime).to.be.a("number");
- expect(result.aggregateData).to.be.an("array");
- });
-
- it("should return monitor stats with calculated values, docker type", async function () {
- monitorFindByIdStub.returns(mockMonitorDocker);
- req.query.sortOrder = "desc";
- const result = await getMonitorStatsById(req);
- expect(result).to.include.keys([
- "_id",
- "type",
- "name",
- "url",
- "uptimeDuration",
- "lastChecked",
- "latestResponseTime",
- "periodIncidents",
- "periodTotalChecks",
- "periodAvgResponseTime",
- "periodUptime",
- "aggregateData",
- ]);
- expect(result.latestResponseTime).to.equal(100);
- expect(result.periodTotalChecks).to.equal(3);
- expect(result.periodIncidents).to.equal(1);
- expect(result.periodUptime).to.be.a("number");
- expect(result.aggregateData).to.be.an("array");
- });
-
- it("should return monitor stats with calculated values", async function () {
- req.query.sortOrder = "asc";
- const result = await getMonitorStatsById(req);
- expect(result).to.include.keys([
- "_id",
- "type",
- "name",
- "url",
- "uptimeDuration",
- "lastChecked",
- "latestResponseTime",
- "periodIncidents",
- "periodTotalChecks",
- "periodAvgResponseTime",
- "periodUptime",
- "aggregateData",
- ]);
- expect(result.latestResponseTime).to.equal(100);
- expect(result.periodTotalChecks).to.equal(3);
- expect(result.periodIncidents).to.equal(1);
- expect(result.periodUptime).to.be.a("number");
- expect(result.aggregateData).to.be.an("array");
- });
-
- it("should throw error when monitor is not found", async function () {
- monitorFindByIdStub.returns(Promise.resolve(null));
-
- const req = {
- params: { monitorId: "nonexistent" },
- };
-
- try {
- await getMonitorStatsById(req);
- expect.fail("Should have thrown an error");
- } catch (error) {
- expect(error).to.be.an("Error");
- expect(error.service).to.equal("monitorModule");
- expect(error.method).to.equal("getMonitorStatsById");
- }
- });
- });
-
- describe("getMonitorById", function () {
- let notificationFindStub;
- let monitorSaveStub;
-
- beforeEach(function () {
- // Create stubs
- notificationFindStub = sinon.stub(Notification, "find");
- monitorSaveStub = sinon.stub().resolves();
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- it("should return monitor with notifications when found", async function () {
- // Arrange
- const monitorId = "123";
- const mockMonitor = {
- _id: monitorId,
- name: "Test Monitor",
- save: monitorSaveStub,
- };
- const mockNotifications = [
- { _id: "notif1", message: "Test notification 1" },
- { _id: "notif2", message: "Test notification 2" },
- ];
-
- monitorFindByIdStub.resolves(mockMonitor);
- notificationFindStub.resolves(mockNotifications);
-
- const result = await getMonitorById(monitorId);
- expect(result._id).to.equal(monitorId);
- expect(result.name).to.equal("Test Monitor");
- expect(monitorFindByIdStub.calledWith(monitorId)).to.be.true;
- expect(notificationFindStub.calledWith({ monitorId })).to.be.true;
- expect(monitorSaveStub.calledOnce).to.be.true;
- });
-
- it("should throw 404 error when monitor not found", async function () {
- // Arrange
- const monitorId = "nonexistent";
- monitorFindByIdStub.resolves(null);
-
- // Act & Assert
- try {
- await getMonitorById(monitorId);
- expect.fail("Should have thrown an error");
- } catch (error) {
- expect(error.message).to.equal(errorMessages.DB_FIND_MONITOR_BY_ID(monitorId));
- expect(error.status).to.equal(404);
- expect(error.service).to.equal("monitorModule");
- expect(error.method).to.equal("getMonitorById");
- }
- });
-
- it("should handle database errors properly", async function () {
- // Arrange
- const monitorId = "123";
- const dbError = new Error("Database connection failed");
- monitorFindByIdStub.rejects(dbError);
-
- // Act & Assert
- try {
- await getMonitorById(monitorId);
- expect.fail("Should have thrown an error");
- } catch (error) {
- expect(error.service).to.equal("monitorModule");
- expect(error.method).to.equal("getMonitorById");
- expect(error.message).to.equal("Database connection failed");
- }
- });
-
- it("should handle notification fetch errors", async function () {
- // Arrange
- const monitorId = "123";
- const mockMonitor = {
- _id: monitorId,
- name: "Test Monitor",
- save: monitorSaveStub,
- };
- const notificationError = new Error("Notification fetch failed");
-
- monitorFindByIdStub.resolves(mockMonitor);
- notificationFindStub.rejects(notificationError);
-
- // Act & Assert
- try {
- await getMonitorById(monitorId);
- expect.fail("Should have thrown an error");
- } catch (error) {
- expect(error.service).to.equal("monitorModule");
- expect(error.method).to.equal("getMonitorById");
- expect(error.message).to.equal("Notification fetch failed");
- }
- });
-
- it("should handle monitor save errors", async function () {
- // Arrange
- const monitorId = "123";
- const mockMonitor = {
- _id: monitorId,
- name: "Test Monitor",
- save: sinon.stub().rejects(new Error("Save failed")),
- };
- const mockNotifications = [];
-
- monitorFindByIdStub.resolves(mockMonitor);
- notificationFindStub.resolves(mockNotifications);
-
- // Act & Assert
- try {
- await getMonitorById(monitorId);
- expect.fail("Should have thrown an error");
- } catch (error) {
- expect(error.service).to.equal("monitorModule");
- expect(error.method).to.equal("getMonitorById");
- expect(error.message).to.equal("Save failed");
- }
- });
- });
-
- describe("getMonitorsAndSummaryByTeamId", function () {
- it("should return monitors and correct summary counts", async function () {
- // Arrange
- const teamId = "team123";
- const type = "http";
- const mockMonitors = [
- { teamId, type, status: true, isActive: true }, // up
- { teamId, type, status: false, isActive: true }, // down
- { teamId, type, status: null, isActive: false }, // paused
- { teamId, type, status: true, isActive: true }, // up
- ];
- monitorFindStub.resolves(mockMonitors);
-
- // Act
- const result = await getMonitorsAndSummaryByTeamId(teamId, type);
-
- // Assert
- expect(result.monitors).to.have.lengthOf(4);
- expect(result.monitorCounts).to.deep.equal({
- up: 2,
- down: 1,
- paused: 1,
- total: 4,
- });
- expect(monitorFindStub.calledOnceWith({ teamId, type })).to.be.true;
- });
-
- it("should return empty results for non-existent team", async function () {
- // Arrange
- monitorFindStub.resolves([]);
-
- // Act
- const result = await getMonitorsAndSummaryByTeamId("nonexistent", "http");
-
- // Assert
- expect(result.monitors).to.have.lengthOf(0);
- expect(result.monitorCounts).to.deep.equal({
- up: 0,
- down: 0,
- paused: 0,
- total: 0,
- });
- });
-
- it("should handle database errors", async function () {
- // Arrange
- const error = new Error("Database error");
- error.service = "MonitorModule";
- error.method = "getMonitorsAndSummaryByTeamId";
- monitorFindStub.rejects(error);
-
- // Act & Assert
- try {
- await getMonitorsAndSummaryByTeamId("team123", "http");
- expect.fail("Should have thrown an error");
- } catch (err) {
- expect(err).to.equal(error);
- expect(err.service).to.equal("monitorModule");
- expect(err.method).to.equal("getMonitorsAndSummaryByTeamId");
- }
- });
- });
-
- describe("getMonitorsByTeamId", function () {
- beforeEach(function () {
- // Chain stubs for Monitor.find().skip().limit().sort()
-
- // Stub for CHECK_MODEL_LOOKUP model find
- checkFindStub.returns({
- sort: sinon.stub().returns({
- limit: sinon.stub().returns([]),
- }),
- });
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- it("should return monitors with basic query parameters", async function () {
- const mockMonitors = [
- { _id: "1", type: "http", toObject: () => ({ _id: "1", type: "http" }) },
- { _id: "2", type: "ping", toObject: () => ({ _id: "2", type: "ping" }) },
- ];
- monitorFindStub.returns({
- skip: sinon.stub().returns({
- limit: sinon.stub().returns({
- sort: sinon.stub().returns(mockMonitors),
- }),
- }),
- });
-
- const req = {
- params: { teamId: "team123" },
- query: {
- type: "http",
- page: 0,
- rowsPerPage: 10,
- field: "name",
- status: false,
- checkOrder: "desc",
- },
- };
-
- monitorCountStub.resolves(2);
-
- const result = await getMonitorsByTeamId(req);
-
- expect(result).to.have.property("monitors");
- expect(result).to.have.property("monitorCount", 2);
- });
-
- it("should return monitors with basic query parameters", async function () {
- const mockMonitors = [
- { _id: "1", type: "http", toObject: () => ({ _id: "1", type: "http" }) },
- { _id: "2", type: "ping", toObject: () => ({ _id: "2", type: "ping" }) },
- ];
- monitorFindStub.returns({
- skip: sinon.stub().returns({
- limit: sinon.stub().returns({
- sort: sinon.stub().returns(mockMonitors),
- }),
- }),
- });
-
- const req = {
- params: { teamId: "team123" },
- query: {
- type: "http",
- page: 0,
- rowsPerPage: 10,
- field: "name",
- status: true,
- checkOrder: "asc",
- },
- };
-
- monitorCountStub.resolves(2);
-
- const result = await getMonitorsByTeamId(req);
-
- expect(result).to.have.property("monitors");
- expect(result).to.have.property("monitorCount", 2);
- });
-
- it("should handle type filter with array input", async function () {
- const req = {
- params: { teamId: "team123" },
- query: {
- type: ["http", "ping"],
- },
- };
-
- monitorFindStub.returns({
- skip: sinon.stub().returns({
- limit: sinon.stub().returns({
- sort: sinon.stub().returns([]),
- }),
- }),
- });
- monitorCountStub.resolves(0);
-
- await getMonitorsByTeamId(req);
-
- expect(Monitor.find.firstCall.args[0]).to.deep.equal({
- teamId: "team123",
- type: { $in: ["http", "ping"] },
- });
- });
-
- it("should handle text search filter", async function () {
- const req = {
- params: { teamId: "team123" },
- query: {
- filter: "search",
- },
- };
-
- monitorFindStub.returns({
- skip: sinon.stub().returns({
- limit: sinon.stub().returns({
- sort: sinon.stub().returns([]),
- }),
- }),
- });
- monitorCountStub.resolves(0);
-
- await getMonitorsByTeamId(req);
-
- expect(Monitor.find.firstCall.args[0]).to.deep.equal({
- teamId: "team123",
- $or: [{ name: { $regex: "search", $options: "i" } }, { url: { $regex: "search", $options: "i" } }],
- });
- });
-
- it("should handle pagination parameters", async function () {
- const req = {
- params: { teamId: "team123" },
- query: {
- page: 2,
- rowsPerPage: 5,
- },
- };
-
- monitorFindStub.returns({
- skip: sinon.stub().returns({
- limit: sinon.stub().returns({
- sort: sinon.stub().returns([]),
- }),
- }),
- });
- monitorCountStub.resolves(0);
-
- const result = await getMonitorsByTeamId(req);
- expect(result).to.deep.equal({
- monitors: [],
- monitorCount: 0,
- });
- });
-
- it("should handle sorting parameters", async function () {
- const req = {
- params: { teamId: "team123" },
- query: {
- field: "name",
- order: "asc",
- },
- };
-
- monitorFindStub.returns({
- skip: sinon.stub().returns({
- limit: sinon.stub().returns({
- sort: sinon.stub().returns([]),
- }),
- }),
- });
- monitorCountStub.resolves(0);
-
- await getMonitorsByTeamId(req);
-
- const result = await getMonitorsByTeamId(req);
- expect(result).to.deep.equal({
- monitors: [],
- monitorCount: 0,
- });
- });
-
- it("should return early when limit is -1", async function () {
- // Arrange
- const req = {
- params: { teamId: "team123" },
- query: {
- limit: "-1",
- },
- };
-
- const mockMonitors = [
- { _id: "1", type: "http" },
- { _id: "2", type: "ping" },
- ];
-
- monitorFindStub.returns({
- skip: sinon.stub().returns({
- limit: sinon.stub().returns({
- sort: sinon.stub().returns(mockMonitors),
- }),
- }),
- });
-
- monitorCountStub.resolves(2);
-
- // Act
- const result = await getMonitorsByTeamId(req);
-
- // Assert
- expect(result).to.deep.equal({
- monitors: mockMonitors,
- monitorCount: 2,
- });
- });
-
- it("should normalize checks when normalize parameter is provided", async function () {
- const req = {
- params: { teamId: "team123" },
- query: { normalize: "true" },
- };
- monitorCountStub.resolves(2);
-
- const mockMonitors = [
- { _id: "1", type: "http", toObject: () => ({ _id: "1", type: "http" }) },
- { _id: "2", type: "ping", toObject: () => ({ _id: "2", type: "ping" }) },
- ];
-
- monitorFindStub.returns({
- skip: sinon.stub().returns({
- limit: sinon.stub().returns({
- sort: sinon.stub().returns(mockMonitors),
- }),
- }),
- });
-
- const result = await getMonitorsByTeamId(req);
- expect(result.monitorCount).to.equal(2);
- expect(result.monitors).to.have.lengthOf(2);
- });
-
- it("should handle database errors", async function () {
- const req = {
- params: { teamId: "team123" },
- query: {},
- };
-
- const error = new Error("Database error");
- monitorFindStub.returns({
- skip: sinon.stub().returns({
- limit: sinon.stub().returns({
- sort: sinon.stub().throws(error),
- }),
- }),
- });
-
- try {
- await getMonitorsByTeamId(req);
- expect.fail("Should have thrown an error");
- } catch (err) {
- expect(err.service).to.equal("monitorModule");
- expect(err.method).to.equal("getMonitorsByTeamId");
- expect(err.message).to.equal("Database error");
- }
- });
- });
-
- describe("createMonitor", function () {
- it("should create a monitor without notifications", async function () {
- let monitorSaveStub = sinon.stub(Monitor.prototype, "save").resolves();
-
- const req = {
- body: {
- name: "Test Monitor",
- url: "http://test.com",
- type: "http",
- notifications: ["someNotification"],
- },
- };
-
- const expectedMonitor = {
- name: "Test Monitor",
- url: "http://test.com",
- type: "http",
- notifications: undefined,
- save: monitorSaveStub,
- };
-
- const result = await createMonitor(req);
- expect(result.name).to.equal(expectedMonitor.name);
- expect(result.url).to.equal(expectedMonitor.url);
- });
-
- it("should handle database errors", async function () {
- const req = {
- body: {
- name: "Test Monitor",
- },
- };
-
- try {
- await createMonitor(req);
- expect.fail("Should have thrown an error");
- } catch (err) {
- expect(err.service).to.equal("monitorModule");
- expect(err.method).to.equal("createMonitor");
- }
- });
- });
-
- describe("deleteMonitor", function () {
- it("should delete a monitor successfully", async function () {
- const monitorId = "123456789";
- const mockMonitor = {
- _id: monitorId,
- name: "Test Monitor",
- url: "http://test.com",
- };
-
- const req = {
- params: { monitorId },
- };
-
- monitorFindByIdAndDeleteStub.resolves(mockMonitor);
-
- const result = await deleteMonitor(req);
-
- expect(result).to.deep.equal(mockMonitor);
- sinon.assert.calledWith(monitorFindByIdAndDeleteStub, monitorId);
- });
-
- it("should throw error when monitor not found", async function () {
- const monitorId = "nonexistent123";
- const req = {
- params: { monitorId },
- };
-
- monitorFindByIdAndDeleteStub.resolves(null);
-
- try {
- await deleteMonitor(req);
- expect.fail("Should have thrown an error");
- } catch (err) {
- expect(err.message).to.equal(errorMessages.DB_FIND_MONITOR_BY_ID(monitorId));
- expect(err.service).to.equal("monitorModule");
- expect(err.method).to.equal("deleteMonitor");
- }
- });
-
- it("should handle database errors", async function () {
- const monitorId = "123456789";
- const req = {
- params: { monitorId },
- };
-
- const dbError = new Error("Database connection error");
- monitorFindByIdAndDeleteStub.rejects(dbError);
-
- try {
- await deleteMonitor(req);
- expect.fail("Should have thrown an error");
- } catch (err) {
- expect(err.message).to.equal("Database connection error");
- expect(err.service).to.equal("monitorModule");
- expect(err.method).to.equal("deleteMonitor");
- }
- });
- });
-
- describe("deleteAllMonitors", function () {
- it("should delete all monitors for a team successfully", async function () {
- const teamId = "team123";
- const mockMonitors = [
- { _id: "1", name: "Monitor 1", teamId },
- { _id: "2", name: "Monitor 2", teamId },
- ];
-
- monitorFindStub.resolves(mockMonitors);
- monitorDeleteManyStub.resolves({ deletedCount: 2 });
-
- const result = await deleteAllMonitors(teamId);
-
- expect(result).to.deep.equal({
- monitors: mockMonitors,
- deletedCount: 2,
- });
- sinon.assert.calledWith(monitorFindStub, { teamId });
- sinon.assert.calledWith(monitorDeleteManyStub, { teamId });
- });
-
- it("should return empty array when no monitors found", async function () {
- const teamId = "emptyTeam";
-
- monitorFindStub.resolves([]);
- monitorDeleteManyStub.resolves({ deletedCount: 0 });
-
- const result = await deleteAllMonitors(teamId);
-
- expect(result).to.deep.equal({
- monitors: [],
- deletedCount: 0,
- });
- sinon.assert.calledWith(monitorFindStub, { teamId });
- sinon.assert.calledWith(monitorDeleteManyStub, { teamId });
- });
-
- it("should handle database errors", async function () {
- const teamId = "team123";
- const dbError = new Error("Database connection error");
- monitorFindStub.rejects(dbError);
-
- try {
- await deleteAllMonitors(teamId);
- } catch (err) {
- expect(err.message).to.equal("Database connection error");
- expect(err.service).to.equal("monitorModule");
- expect(err.method).to.equal("deleteAllMonitors");
- }
- });
-
- it("should handle deleteMany errors", async function () {
- const teamId = "team123";
- monitorFindStub.resolves([{ _id: "1", name: "Monitor 1" }]);
- monitorDeleteManyStub.rejects(new Error("Delete operation failed"));
-
- try {
- await deleteAllMonitors(teamId);
- } catch (err) {
- expect(err.message).to.equal("Delete operation failed");
- expect(err.service).to.equal("monitorModule");
- expect(err.method).to.equal("deleteAllMonitors");
- }
- });
- });
-
- describe("deleteMonitorsByUserId", function () {
- beforeEach(function () {});
-
- afterEach(function () {
- sinon.restore();
- });
-
- it("should delete all monitors for a user successfully", async function () {
- // Arrange
- const userId = "user123";
- const mockResult = {
- deletedCount: 3,
- acknowledged: true,
- };
-
- monitorDeleteManyStub.resolves(mockResult);
-
- // Act
- const result = await deleteMonitorsByUserId(userId);
-
- // Assert
- expect(result).to.deep.equal(mockResult);
- sinon.assert.calledWith(monitorDeleteManyStub, { userId: userId });
- });
-
- it("should return zero deletedCount when no monitors found", async function () {
- // Arrange
- const userId = "nonexistentUser";
- const mockResult = {
- deletedCount: 0,
- acknowledged: true,
- };
-
- monitorDeleteManyStub.resolves(mockResult);
-
- // Act
- const result = await deleteMonitorsByUserId(userId);
-
- // Assert
- expect(result.deletedCount).to.equal(0);
- sinon.assert.calledWith(monitorDeleteManyStub, { userId: userId });
- });
-
- it("should handle database errors", async function () {
- // Arrange
- const userId = "user123";
- const dbError = new Error("Database connection error");
- monitorDeleteManyStub.rejects(dbError);
-
- // Act & Assert
- try {
- await deleteMonitorsByUserId(userId);
- expect.fail("Should have thrown an error");
- } catch (err) {
- expect(err.message).to.equal("Database connection error");
- expect(err.service).to.equal("monitorModule");
- expect(err.method).to.equal("deleteMonitorsByUserId");
- }
- });
- });
-
- describe("editMonitor", function () {
- it("should edit a monitor successfully", async function () {
- // Arrange
- const candidateId = "monitor123";
- const candidateMonitor = {
- name: "Updated Monitor",
- url: "http://updated.com",
- type: "http",
- notifications: ["someNotification"],
- };
-
- const expectedUpdateData = {
- name: "Updated Monitor",
- url: "http://updated.com",
- type: "http",
- notifications: undefined,
- };
-
- const mockUpdatedMonitor = {
- _id: candidateId,
- ...expectedUpdateData,
- };
-
- monitorFindByIdAndUpdateStub.resolves(mockUpdatedMonitor);
-
- // Act
- const result = await editMonitor(candidateId, candidateMonitor);
-
- // Assert
- expect(result).to.deep.equal(mockUpdatedMonitor);
- sinon.assert.calledWith(monitorFindByIdAndUpdateStub, candidateId, expectedUpdateData, {
- new: true,
- });
- });
-
- it("should return null when monitor not found", async function () {
- // Arrange
- const candidateId = "nonexistent123";
- const candidateMonitor = {
- name: "Updated Monitor",
- };
-
- monitorFindByIdAndUpdateStub.resolves(null);
-
- // Act
- const result = await editMonitor(candidateId, candidateMonitor);
-
- // Assert
- expect(result).to.be.null;
- sinon.assert.calledWith(monitorFindByIdAndUpdateStub, candidateId, { name: "Updated Monitor", notifications: undefined }, { new: true });
- });
-
- it("should remove notifications from update data", async function () {
- // Arrange
- const candidateId = "monitor123";
- const candidateMonitor = {
- name: "Updated Monitor",
- notifications: ["notification1", "notification2"],
- };
-
- const expectedUpdateData = {
- name: "Updated Monitor",
- notifications: undefined,
- };
-
- monitorFindByIdAndUpdateStub.resolves({
- _id: candidateId,
- ...expectedUpdateData,
- });
-
- // Act
- await editMonitor(candidateId, candidateMonitor);
-
- // Assert
- sinon.assert.calledWith(monitorFindByIdAndUpdateStub, candidateId, expectedUpdateData, {
- new: true,
- });
- });
-
- it("should handle database errors", async function () {
- // Arrange
- const candidateId = "monitor123";
- const candidateMonitor = {
- name: "Updated Monitor",
- };
-
- const dbError = new Error("Database connection error");
- monitorFindByIdAndUpdateStub.rejects(dbError);
-
- // Act & Assert
- try {
- await editMonitor(candidateId, candidateMonitor);
- expect.fail("Should have thrown an error");
- } catch (err) {
- expect(err.message).to.equal("Database connection error");
- expect(err.service).to.equal("monitorModule");
- expect(err.method).to.equal("editMonitor");
- }
- });
- });
-
- describe("addDemoMonitors", function () {
- it("should add demo monitors successfully", async function () {
- // Arrange
- const userId = "user123";
- const teamId = "team123";
- monitorInsertManyStub.resolves([{ _id: "123" }]);
- const result = await addDemoMonitors(userId, teamId);
- expect(result).to.deep.equal([{ _id: "123" }]);
- });
-
- it("should handle database errors", async function () {
- const userId = "user123";
- const teamId = "team123";
-
- const dbError = new Error("Database connection error");
- monitorInsertManyStub.rejects(dbError);
-
- try {
- await addDemoMonitors(userId, teamId);
- } catch (err) {
- expect(err.message).to.equal("Database connection error");
- expect(err.service).to.equal("monitorModule");
- expect(err.method).to.equal("addDemoMonitors");
- }
- });
- });
-});
diff --git a/server/tests/db/notificationModule.test.js b/server/tests/db/notificationModule.test.js
deleted file mode 100755
index fbb97f33a..000000000
--- a/server/tests/db/notificationModule.test.js
+++ /dev/null
@@ -1,76 +0,0 @@
-import sinon from "sinon";
-import Notification from "../../db/models/Notification.js";
-import { createNotification, getNotificationsByMonitorId, deleteNotificationsByMonitorId } from "../../db/mongo/modules/notificationModule.js";
-
-describe("notificationModule", function () {
- const mockNotification = {
- monitorId: "123",
- };
- const mockNotifications = [mockNotification];
- let notificationSaveStub, notificationFindStub, notificationDeleteManyStub;
-
- beforeEach(function () {
- notificationSaveStub = sinon.stub(Notification.prototype, "save").resolves();
- notificationFindStub = sinon.stub(Notification, "find").resolves();
- notificationDeleteManyStub = sinon.stub(Notification, "deleteMany").resolves();
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- describe("createNotification", function () {
- it("should create a new notification", async function () {
- const notificationData = { _id: "123", name: "test" };
- notificationSaveStub.resolves(notificationData);
- const res = await createNotification(notificationData);
- expect(res).to.deep.equal(notificationData);
- });
-
- it("should handle an error", async function () {
- const err = new Error("test error");
- notificationSaveStub.rejects(err);
- try {
- await createNotification(mockNotification);
- } catch (error) {
- expect(error).to.deep.equal(err);
- }
- });
- });
-
- describe("getNotificationsByMonitorId", function () {
- it("should return notifications by monitor ID", async function () {
- notificationFindStub.resolves(mockNotifications);
- const res = await getNotificationsByMonitorId(mockNotification.monitorId);
- expect(res).to.deep.equal(mockNotifications);
- });
-
- it("should handle an error", async function () {
- const err = new Error("test error");
- notificationFindStub.rejects(err);
- try {
- await getNotificationsByMonitorId(mockNotification.monitorId);
- } catch (error) {
- expect(error).to.deep.equal(err);
- }
- });
- });
-
- describe("deleteNotificationsByMonitorId", function () {
- it("should delete notifications by monitor ID", async function () {
- notificationDeleteManyStub.resolves({ deletedCount: mockNotifications.length });
- const res = await deleteNotificationsByMonitorId(mockNotification.monitorId);
- expect(res).to.deep.equal(mockNotifications.length);
- });
-
- it("should handle an error", async function () {
- const err = new Error("test error");
- notificationDeleteManyStub.rejects(err);
- try {
- await deleteNotificationsByMonitorId(mockNotification.monitorId);
- } catch (error) {
- expect(error).to.deep.equal(err);
- }
- });
- });
-});
diff --git a/server/tests/db/pageSpeedCheckModule.test.js b/server/tests/db/pageSpeedCheckModule.test.js
deleted file mode 100755
index 45135135d..000000000
--- a/server/tests/db/pageSpeedCheckModule.test.js
+++ /dev/null
@@ -1,63 +0,0 @@
-import sinon from "sinon";
-import PageSpeedCheck from "../../db/models/PageSpeedCheck.js";
-import { createPageSpeedCheck, deletePageSpeedChecksByMonitorId } from "../../db/mongo/modules/pageSpeedCheckModule.js";
-
-const mockPageSpeedCheck = {
- monitorId: "monitorId",
- bestPractices: 1,
- seo: 1,
- performance: 1,
-};
-
-const mockDeletedResult = { deletedCount: 1 };
-
-describe("pageSpeedCheckModule", function () {
- let pageSpeedCheckSaveStub, pageSpeedCheckDeleteManyStub;
-
- beforeEach(function () {
- pageSpeedCheckSaveStub = sinon.stub(PageSpeedCheck.prototype, "save");
- pageSpeedCheckDeleteManyStub = sinon.stub(PageSpeedCheck, "deleteMany");
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- describe("createPageSpeedCheck", function () {
- it("should return a page speed check", async function () {
- pageSpeedCheckSaveStub.resolves(mockPageSpeedCheck);
- const pageSpeedCheck = await createPageSpeedCheck(mockPageSpeedCheck);
- expect(pageSpeedCheck).to.deep.equal(mockPageSpeedCheck);
- });
-
- it("should handle an error", async function () {
- const err = new Error("test error");
- pageSpeedCheckSaveStub.rejects(err);
- try {
- await expect(createPageSpeedCheck(mockPageSpeedCheck));
- } catch (error) {
- expect(error).to.exist;
- expect(error).to.deep.equal(err);
- }
- });
- });
-
- describe("deletePageSpeedChecksByMonitorId", function () {
- it("should return the number of deleted checks", async function () {
- pageSpeedCheckDeleteManyStub.resolves(mockDeletedResult);
- const result = await deletePageSpeedChecksByMonitorId("monitorId");
- expect(result).to.deep.equal(mockDeletedResult.deletedCount);
- });
-
- it("should handle an error", async function () {
- const err = new Error("test error");
- pageSpeedCheckDeleteManyStub.rejects(err);
- try {
- await expect(deletePageSpeedChecksByMonitorId("monitorId"));
- } catch (error) {
- expect(error).to.exist;
- expect(error).to.deep.equal(err);
- }
- });
- });
-});
diff --git a/server/tests/db/recoveryModule.test.js b/server/tests/db/recoveryModule.test.js
deleted file mode 100755
index 88afa257a..000000000
--- a/server/tests/db/recoveryModule.test.js
+++ /dev/null
@@ -1,168 +0,0 @@
-import sinon from "sinon";
-import RecoveryToken from "../../db/models/RecoveryToken.js";
-import User from "../../db/models/User.js";
-import { requestRecoveryToken, validateRecoveryToken, resetPassword } from "../../db/mongo/modules/recoveryModule.js";
-import { errorMessages } from "../../utils/messages.js";
-
-const mockRecoveryToken = {
- email: "test@test.com",
- token: "1234567890",
-};
-
-const mockUser = {
- email: "test@test.com",
- password: "oldPassword",
-};
-
-const mockUserWithoutPassword = {
- email: "test@test.com",
-};
-
-// Create a query builder that logs
-const createQueryChain = (finalResult, comparePasswordResult = false) => ({
- select: () => ({
- select: async () => {
- if (finalResult === mockUser) {
- // Return a new object with all required methods
- return {
- email: "test@test.com",
- password: "oldPassword",
- comparePassword: sinon.stub().resolves(comparePasswordResult),
- save: sinon.stub().resolves(),
- };
- }
- return finalResult;
- },
- }),
- // Add methods to the top level too
- comparePassword: sinon.stub().resolves(comparePasswordResult),
- save: sinon.stub().resolves(),
-});
-
-describe("recoveryModule", function () {
- let deleteManyStub, saveStub, findOneStub, userCompareStub, userSaveStub, userFindOneStub;
- let req, res;
-
- beforeEach(function () {
- req = {
- body: { email: "test@test.com" },
- };
- deleteManyStub = sinon.stub(RecoveryToken, "deleteMany");
- saveStub = sinon.stub(RecoveryToken.prototype, "save");
- findOneStub = sinon.stub(RecoveryToken, "findOne");
- userCompareStub = sinon.stub(User.prototype, "comparePassword");
- userSaveStub = sinon.stub(User.prototype, "save");
- userFindOneStub = sinon.stub().resolves();
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- describe("requestRecoveryToken", function () {
- it("should return a recovery token", async function () {
- deleteManyStub.resolves();
- saveStub.resolves(mockRecoveryToken);
- const result = await requestRecoveryToken(req, res);
- expect(result.email).to.equal(mockRecoveryToken.email);
- });
-
- it("should handle an error", async function () {
- const err = new Error("Test error");
- deleteManyStub.rejects(err);
- try {
- await requestRecoveryToken(req, res);
- } catch (error) {
- expect(error).to.exist;
- expect(error).to.deep.equal(err);
- }
- });
- });
-
- describe("validateRecoveryToken", function () {
- it("should return a recovery token if found", async function () {
- findOneStub.resolves(mockRecoveryToken);
- const result = await validateRecoveryToken(req, res);
- expect(result).to.deep.equal(mockRecoveryToken);
- });
-
- it("should thrown an error if a token is not found", async function () {
- findOneStub.resolves(null);
- try {
- await validateRecoveryToken(req, res);
- } catch (error) {
- expect(error).to.exist;
- expect(error.message).to.equal(errorMessages.DB_TOKEN_NOT_FOUND);
- }
- });
-
- it("should handle DB errors", async function () {
- const err = new Error("Test error");
- findOneStub.rejects(err);
- try {
- await validateRecoveryToken(req, res);
- } catch (error) {
- expect(error).to.exist;
- expect(error).to.deep.equal(err);
- }
- });
- });
-
- describe("resetPassword", function () {
- beforeEach(function () {
- req.body = {
- password: "test",
- newPassword: "test1",
- };
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- it("should thrown an error if a recovery token is not found", async function () {
- findOneStub.resolves(null);
- try {
- await resetPassword(req, res);
- } catch (error) {
- expect(error).to.exist;
- expect(error.message).to.equal(errorMessages.DB_TOKEN_NOT_FOUND);
- }
- });
-
- it("should throw an error if a user is not found", async function () {
- findOneStub.resolves(mockRecoveryToken);
- userFindOneStub = sinon.stub(User, "findOne").resolves(null);
- try {
- await resetPassword(req, res);
- } catch (error) {
- expect(error).to.exist;
- expect(error.message).to.equal(errorMessages.DB_USER_NOT_FOUND);
- }
- });
-
- it("should throw an error if the passwords match", async function () {
- findOneStub.resolves(mockRecoveryToken);
- saveStub.resolves();
- userFindOneStub = sinon.stub(User, "findOne").returns(createQueryChain(mockUser, true));
- try {
- await resetPassword(req, res);
- } catch (error) {
- expect(error).to.exist;
- expect(error.message).to.equal(errorMessages.DB_RESET_PASSWORD_BAD_MATCH);
- }
- });
-
- it("should return a user without password if successful", async function () {
- findOneStub.resolves(mockRecoveryToken);
- saveStub.resolves();
- userFindOneStub = sinon
- .stub(User, "findOne")
- .returns(createQueryChain(mockUser)) // First call will resolve to mockUser
- .onSecondCall()
- .returns(createQueryChain(mockUserWithoutPassword));
- const result = await resetPassword(req, res);
- expect(result).to.deep.equal(mockUserWithoutPassword);
- });
- });
-});
diff --git a/server/tests/db/settingsModule.test.js b/server/tests/db/settingsModule.test.js
deleted file mode 100755
index 9d1a80c3e..000000000
--- a/server/tests/db/settingsModule.test.js
+++ /dev/null
@@ -1,56 +0,0 @@
-import sinon from "sinon";
-import { getAppSettings, updateAppSettings } from "../../db/mongo/modules/settingsModule.js";
-import AppSettings from "../../db/models/AppSettings.js";
-
-const mockAppSettings = {
- appName: "Test App",
-};
-
-describe("SettingsModule", function () {
- let appSettingsFindOneStub, appSettingsFindOneAndUpdateStub;
-
- beforeEach(function () {
- appSettingsFindOneStub = sinon.stub(AppSettings, "findOne");
- appSettingsFindOneAndUpdateStub = sinon.stub(AppSettings, "findOneAndUpdate");
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- describe("getAppSettings", function () {
- it("should return app settings", async function () {
- appSettingsFindOneStub.resolves(mockAppSettings);
- const result = await getAppSettings();
- expect(result).to.deep.equal(mockAppSettings);
- });
-
- it("should handle an error", async function () {
- const err = new Error("Test error");
- appSettingsFindOneStub.throws(err);
- try {
- await getAppSettings();
- } catch (error) {
- expect(error).to.deep.equal(err);
- }
- });
- });
-
- describe("updateAppSettings", function () {
- it("should update app settings", async function () {
- appSettingsFindOneAndUpdateStub.resolves(mockAppSettings);
- const result = await updateAppSettings(mockAppSettings);
- expect(result).to.deep.equal(mockAppSettings);
- });
-
- it("should handle an error", async function () {
- const err = new Error("Test error");
- appSettingsFindOneAndUpdateStub.throws(err);
- try {
- await updateAppSettings(mockAppSettings);
- } catch (error) {
- expect(error).to.deep.equal(err);
- }
- });
- });
-});
diff --git a/server/tests/db/statusPageModule.test.js b/server/tests/db/statusPageModule.test.js
deleted file mode 100755
index 54e1a287f..000000000
--- a/server/tests/db/statusPageModule.test.js
+++ /dev/null
@@ -1,70 +0,0 @@
-import sinon from "sinon";
-import { createStatusPage, getStatusPageByUrl } from "../../db/mongo/modules/statusPageModule.js";
-import StatusPage from "../../db/models/StatusPage.js";
-import { errorMessages } from "../../utils/messages.js";
-
-describe("statusPageModule", function () {
- let statusPageFindOneStub, statusPageSaveStub, statusPageFindStub;
-
- beforeEach(function () {
- statusPageSaveStub = sinon.stub(StatusPage.prototype, "save");
- statusPageFindOneStub = sinon.stub(StatusPage, "findOne");
- statusPageFindStub = sinon.stub(StatusPage, "find");
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- describe("createStatusPage", function () {
- it("should throw an error if a non-unique url is provided", async function () {
- statusPageFindOneStub.resolves(true);
- try {
- await createStatusPage({ url: "test" });
- } catch (error) {
- expect(error.status).to.equal(400);
- expect(error.message).to.equal(errorMessages.STATUS_PAGE_URL_NOT_UNIQUE);
- }
- });
-
- it("should handle duplicate URL errors", async function () {
- const err = new Error("test");
- err.code = 11000;
- statusPageSaveStub.rejects(err);
- try {
- await createStatusPage({ url: "test" });
- } catch (error) {
- expect(error).to.deep.equal(err);
- }
- });
-
- it("should return a status page if a unique url is provided", async function () {
- statusPageFindOneStub.resolves(null);
- statusPageFindStub.resolves([]);
- const mockStatusPage = { url: "test" };
- const statusPage = await createStatusPage(mockStatusPage);
- expect(statusPage).to.exist;
- expect(statusPage.url).to.equal(mockStatusPage.url);
- });
- });
-
- describe("getStatusPageByUrl", function () {
- it("should throw an error if a status page is not found", async function () {
- statusPageFindOneStub.resolves(null);
- try {
- await getStatusPageByUrl("test");
- } catch (error) {
- expect(error.status).to.equal(404);
- expect(error.message).to.equal(errorMessages.STATUS_PAGE_NOT_FOUND);
- }
- });
-
- it("should return a status page if a status page is found", async function () {
- const mockStatusPage = { url: "test" };
- statusPageFindOneStub.resolves(mockStatusPage);
- const statusPage = await getStatusPageByUrl(mockStatusPage.url);
- expect(statusPage).to.exist;
- expect(statusPage).to.deep.equal(mockStatusPage);
- });
- });
-});
diff --git a/server/tests/db/userModule.test.js b/server/tests/db/userModule.test.js
deleted file mode 100755
index d0f5ecb3e..000000000
--- a/server/tests/db/userModule.test.js
+++ /dev/null
@@ -1,294 +0,0 @@
-import sinon from "sinon";
-import UserModel from "../../db/models/User.js";
-import TeamModel from "../../db/models/Team.js";
-import {
- insertUser,
- getUserByEmail,
- updateUser,
- deleteUser,
- deleteTeam,
- deleteAllOtherUsers,
- getAllUsers,
- logoutUser,
-} from "../../db/mongo/modules/userModule.js";
-import { errorMessages } from "../../utils/messages.js";
-
-const mockUser = {
- email: "test@test.com",
- password: "password",
- role: ["user"],
-};
-const mockSuperUser = {
- email: "test@test.com",
- password: "password",
- role: ["superadmin"],
-};
-const imageFile = {
- image: 1,
-};
-
-describe("userModule", function () {
- let teamSaveStub,
- teamFindByIdAndDeleteStub,
- userSaveStub,
- userFindStub,
- userFindOneStub,
- userFindByIdAndUpdateStub,
- userFindByIdAndDeleteStub,
- userDeleteManyStub,
- userUpdateOneStub,
- generateAvatarImageStub,
- parseBooleanStub;
-
- beforeEach(function () {
- teamSaveStub = sinon.stub(TeamModel.prototype, "save");
- teamFindByIdAndDeleteStub = sinon.stub(TeamModel, "findByIdAndDelete");
- userSaveStub = sinon.stub(UserModel.prototype, "save");
- userFindStub = sinon.stub(UserModel, "find");
- userFindOneStub = sinon.stub(UserModel, "findOne");
- userFindByIdAndUpdateStub = sinon.stub(UserModel, "findByIdAndUpdate");
- userFindByIdAndDeleteStub = sinon.stub(UserModel, "findByIdAndDelete");
- userDeleteManyStub = sinon.stub(UserModel, "deleteMany");
- userUpdateOneStub = sinon.stub(UserModel, "updateOne");
- generateAvatarImageStub = sinon.stub().resolves({ image: 2 });
- parseBooleanStub = sinon.stub().returns(true);
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- describe("insertUser", function () {
- it("should insert a regular user", async function () {
- userSaveStub.resolves(mockUser);
- userFindOneStub.returns({
- select: sinon.stub().returns({
- select: sinon.stub().resolves(mockUser),
- }),
- });
- const result = await insertUser(mockUser, imageFile, generateAvatarImageStub);
- expect(result).to.deep.equal(mockUser);
- });
-
- it("should insert a superadmin user", async function () {
- userSaveStub.resolves(mockSuperUser);
- userFindOneStub.returns({
- select: sinon.stub().returns({
- select: sinon.stub().resolves(mockSuperUser),
- }),
- });
- const result = await insertUser(mockSuperUser, imageFile, generateAvatarImageStub);
- expect(result).to.deep.equal(mockSuperUser);
- });
-
- it("should handle an error", async function () {
- const err = new Error("test error");
- userSaveStub.rejects(err);
- try {
- await insertUser(mockUser, imageFile, generateAvatarImageStub);
- } catch (error) {
- expect(error).to.exist;
- expect(error).to.deep.equal(err);
- }
- });
-
- it("should handle a duplicate key error", async function () {
- const err = new Error("test error");
- err.code = 11000;
- userSaveStub.rejects(err);
- try {
- await insertUser(mockUser, imageFile, generateAvatarImageStub);
- } catch (error) {
- expect(error).to.exist;
- expect(error).to.deep.equal(err);
- }
- });
- });
-
- describe("getUserByEmail", function () {
- it("should return a user", async function () {
- userFindOneStub.returns({
- select: sinon.stub().resolves(mockUser),
- });
- const result = await getUserByEmail(mockUser.email);
- expect(result).to.deep.equal(mockUser);
- });
- });
-
- describe("getUserByEmail", function () {
- it("throw an error if a user is not found", async function () {
- userFindOneStub.returns({
- select: sinon.stub().resolves(null),
- });
- try {
- await getUserByEmail(mockUser.email);
- } catch (error) {
- expect(error.message).to.equal(errorMessages.DB_USER_NOT_FOUND);
- }
- });
- });
-
- describe("updateUser", function () {
- let req, res;
-
- beforeEach(function () {
- req = {
- params: {
- userId: "testId",
- },
- body: {
- deleteProfileImage: "false",
- email: "test@test.com",
- },
- file: {
- buffer: "test",
- mimetype: "test",
- },
- };
- res = {};
- });
-
- afterEach(function () {});
-
- it("should update a user", async function () {
- parseBooleanStub.returns(false);
- userFindByIdAndUpdateStub.returns({
- select: sinon.stub().returns({
- select: sinon.stub().resolves(mockUser),
- }),
- });
- const result = await updateUser(req, res, parseBooleanStub, generateAvatarImageStub);
- expect(result).to.deep.equal(mockUser);
- });
-
- it("should delete a user profile image", async function () {
- req.body.deleteProfileImage = "true";
- userFindByIdAndUpdateStub.returns({
- select: sinon.stub().returns({
- select: sinon.stub().resolves(mockUser),
- }),
- });
- const result = await updateUser(req, res, parseBooleanStub, generateAvatarImageStub);
- expect(result).to.deep.equal(mockUser);
- });
-
- it("should handle an error", async function () {
- const err = new Error("test error");
- userFindByIdAndUpdateStub.throws(err);
- try {
- await updateUser(req, res, parseBooleanStub, generateAvatarImageStub);
- } catch (error) {
- expect(error).to.exist;
- expect(error).to.deep.equal(err);
- }
- });
- });
-
- describe("deleteUser", function () {
- it("should return a deleted user", async function () {
- userFindByIdAndDeleteStub.resolves(mockUser);
- const result = await deleteUser("testId");
- expect(result).to.deep.equal(mockUser);
- });
-
- it("should throw an error if a user is not found", async function () {
- try {
- await deleteUser("testId");
- } catch (error) {
- expect(error).to.exist;
- expect(error.message).to.equal(errorMessages.DB_USER_NOT_FOUND);
- }
- });
-
- it("should handle an error", async function () {
- const err = new Error("test error");
- userFindByIdAndDeleteStub.throws(err);
- try {
- await deleteUser("testId");
- } catch (error) {
- expect(error).to.exist;
- expect(error).to.deep.equal(err);
- }
- });
- });
-
- describe("deleteTeam", function () {
- it("should return true if team deleted", async function () {
- teamFindByIdAndDeleteStub.resolves();
- const result = await deleteTeam("testId");
- expect(result).to.equal(true);
- });
-
- it("should handle an error", async function () {
- const err = new Error("test error");
- teamFindByIdAndDeleteStub.throws(err);
- try {
- await deleteTeam("testId");
- } catch (error) {
- expect(error).to.exist;
- expect(error).to.deep.equal(err);
- }
- });
- });
-
- describe("deleteAllOtherUsers", function () {
- it("should return true if all other users deleted", async function () {
- userDeleteManyStub.resolves(true);
- const result = await deleteAllOtherUsers();
- expect(result).to.equal(true);
- });
-
- it("should handle an error", async function () {
- const err = new Error("test error");
- userDeleteManyStub.throws(err);
- try {
- await deleteAllOtherUsers();
- } catch (error) {
- expect(error).to.exist;
- expect(error).to.deep.equal(err);
- }
- });
- });
-
- describe("getAllUsers", function () {
- it("should return all users", async function () {
- userFindStub.returns({
- select: sinon.stub().returns({
- select: sinon.stub().resolves([mockUser]),
- }),
- });
- const result = await getAllUsers();
- expect(result).to.deep.equal([mockUser]);
- });
-
- it("should handle an error", async function () {
- const err = new Error("test error");
- userFindStub.throws(err);
- try {
- await getAllUsers();
- } catch (error) {
- expect(error).to.exist;
- expect(error).to.deep.equal(err);
- }
- });
- });
-
- describe("logoutUser", function () {
- it("should return true if user logged out", async function () {
- userUpdateOneStub.resolves(true);
- const result = await logoutUser("testId");
- expect(result).to.equal(true);
- });
-
- it("should handle an error", async function () {
- const err = new Error("test error");
- userUpdateOneStub.throws(err);
- try {
- await logoutUser("testId");
- } catch (error) {
- expect(error).to.exist;
- expect(error).to.deep.equal(err);
- }
- });
- });
-});
diff --git a/server/tests/services/emailService.test.js b/server/tests/services/emailService.test.js
deleted file mode 100755
index cca86896a..000000000
--- a/server/tests/services/emailService.test.js
+++ /dev/null
@@ -1,168 +0,0 @@
-import sinon from "sinon";
-import EmailService from "../../service/emailService.js";
-
-describe("EmailService - Constructor", function () {
- let settingsServiceMock;
- let fsMock;
- let pathMock;
- let compileMock;
- let mjml2htmlMock;
- let nodemailerMock;
- let loggerMock;
-
- beforeEach(function () {
- settingsServiceMock = {
- getSettings: sinon.stub().returns({
- systemEmailHost: "smtp.example.com",
- systemEmailPort: 465,
- systemEmailAddress: "test@example.com",
- systemEmailPassword: "password",
- }),
- };
-
- fsMock = {
- readFileSync: sinon.stub().returns(""),
- };
-
- pathMock = {
- join: sinon.stub().callsFake((...args) => args.join("/")),
- };
-
- compileMock = sinon.stub().returns(() => "");
-
- mjml2htmlMock = sinon.stub().returns({ html: "" });
-
- nodemailerMock = {
- createTransport: sinon.stub().returns({
- sendMail: sinon.stub().resolves({ messageId: "12345" }),
- }),
- };
-
- loggerMock = {
- error: sinon.stub(),
- };
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- it("should initialize template loaders and email transporter", function () {
- const emailService = new EmailService(settingsServiceMock, fsMock, pathMock, compileMock, mjml2htmlMock, nodemailerMock, loggerMock);
-
- // Verify that the settingsService is assigned correctly
- expect(emailService.settingsService).to.equal(settingsServiceMock);
-
- // Verify that the template loaders are initialized
- expect(emailService.templateLookup.welcomeEmailTemplate).to.be.a("function");
- expect(emailService.templateLookup.employeeActivationTemplate).to.be.a("function");
-
- // Verify that the email transporter is initialized
- expect(nodemailerMock.createTransport.calledOnce).to.be.true;
- const emailConfig = nodemailerMock.createTransport.getCall(0).args[0];
- expect(emailConfig).to.deep.equal({
- host: "smtp.example.com",
- port: 465,
- secure: true,
- auth: {
- user: "test@example.com",
- pass: "password",
- },
- });
- });
-
- it("should have undefined templates if FS fails", function () {
- fsMock = {
- readFileSync: sinon.stub().throws(new Error("File read error")),
- };
- const emailService = new EmailService(settingsServiceMock, fsMock, pathMock, compileMock, mjml2htmlMock, nodemailerMock, loggerMock);
- expect(loggerMock.error.called).to.be.true;
- expect(loggerMock.error.firstCall.args[0].message).to.equal("File read error");
- });
-});
-
-describe("EmailService - buildAndSendEmail", function () {
- let settingsServiceMock;
- let fsMock;
- let pathMock;
- let compileMock;
- let mjml2htmlMock;
- let nodemailerMock;
- let loggerMock;
- let emailService;
-
- beforeEach(function () {
- settingsServiceMock = {
- getSettings: sinon.stub().returns({
- systemEmailHost: "smtp.example.com",
- systemEmailPort: 465,
- systemEmailAddress: "test@example.com",
- systemEmailPassword: "password",
- }),
- };
-
- fsMock = {
- readFileSync: sinon.stub().returns(""),
- };
-
- pathMock = {
- join: sinon.stub().callsFake((...args) => args.join("/")),
- };
-
- compileMock = sinon.stub().returns(() => "");
-
- mjml2htmlMock = sinon.stub().returns({ html: "" });
-
- nodemailerMock = {
- createTransport: sinon.stub().returns({
- sendMail: sinon.stub().resolves({ messageId: "12345" }),
- }),
- };
-
- loggerMock = {
- error: sinon.stub(),
- };
-
- emailService = new EmailService(settingsServiceMock, fsMock, pathMock, compileMock, mjml2htmlMock, nodemailerMock, loggerMock);
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- it("should build and send email successfully", async function () {
- const messageId = await emailService.buildAndSendEmail("welcomeEmailTemplate", {}, "recipient@example.com", "Welcome");
-
- expect(messageId).to.equal("12345");
- expect(nodemailerMock.createTransport().sendMail.calledOnce).to.be.true;
- });
-
- it("should log error if building HTML fails", async function () {
- mjml2htmlMock.throws(new Error("MJML error"));
-
- const messageId = await emailService.buildAndSendEmail("welcomeEmailTemplate", {}, "recipient@example.com", "Welcome");
- expect(loggerMock.error.calledOnce).to.be.true;
- expect(loggerMock.error.getCall(0).args[0].message).to.equal("MJML error");
- });
-
- it("should log error if sending email fails", async function () {
- nodemailerMock.createTransport().sendMail.rejects(new Error("SMTP error"));
- await emailService.buildAndSendEmail("welcomeEmailTemplate", {}, "recipient@example.com", "Welcome");
- expect(loggerMock.error.calledOnce).to.be.true;
- expect(loggerMock.error.getCall(0).args[0].message).to.equal("SMTP error");
- });
-
- it("should log error if both building HTML and sending email fail", async function () {
- mjml2htmlMock.throws(new Error("MJML error"));
- nodemailerMock.createTransport().sendMail.rejects(new Error("SMTP error"));
-
- const messageId = await emailService.buildAndSendEmail("welcomeEmailTemplate", {}, "recipient@example.com", "Welcome");
-
- expect(messageId).to.be.undefined;
- expect(loggerMock.error.calledTwice).to.be.true;
- expect(loggerMock.error.getCall(0).args[0].message).to.equal("MJML error");
- expect(loggerMock.error.getCall(1).args[0].message).to.equal("SMTP error");
- });
-
- it("should log an error if buildHtml fails", async function () {});
-});
diff --git a/server/tests/services/jobQueue.test.js b/server/tests/services/jobQueue.test.js
deleted file mode 100755
index 155f9119e..000000000
--- a/server/tests/services/jobQueue.test.js
+++ /dev/null
@@ -1,813 +0,0 @@
-import sinon from "sinon";
-import JobQueue from "../../service/jobQueue.js";
-import { log } from "console";
-
-class QueueStub {
- constructor(queueName, options) {
- this.queueName = queueName;
- this.options = options;
- this.workers = [];
- this.jobs = [];
- }
-
- // Add any methods that are expected to be called on the Queue instance
- add(job) {
- this.jobs.push(job);
- }
-
- removeRepeatable(id) {
- const removedJob = this.jobs.find((job) => job.data._id === id);
- this.jobs = this.jobs.filter((job) => job.data._id !== id);
- if (removedJob) {
- return true;
- }
- return false;
- }
-
- getRepeatableJobs() {
- return this.jobs;
- }
- async getJobs() {
- return this.jobs;
- }
-
- async pause() {
- return true;
- }
-
- async obliterate() {
- return true;
- }
-}
-
-class WorkerStub {
- constructor(QUEUE_NAME, workerTask) {
- this.queueName = QUEUE_NAME;
- this.workerTask = async () => workerTask({ data: { _id: 1 } });
- }
-
- async close() {
- return true;
- }
-}
-
-describe("JobQueue", function () {
- let settingsService, logger, db, networkService, statusService, notificationService, jobQueue;
-
- beforeEach(async function () {
- settingsService = { getSettings: sinon.stub() };
- statusService = { updateStatus: sinon.stub() };
- notificationService = { handleNotifications: sinon.stub() };
-
- logger = { error: sinon.stub(), info: sinon.stub() };
- db = {
- getAllMonitors: sinon.stub().returns([]),
- getMaintenanceWindowsByMonitorId: sinon.stub().returns([]),
- };
- networkService = { getStatus: sinon.stub() };
- jobQueue = await JobQueue.createJobQueue(db, networkService, statusService, notificationService, settingsService, logger, QueueStub, WorkerStub);
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- describe("createJobQueue", function () {
- it("should create a new JobQueue and add jobs for active monitors", async function () {
- db.getAllMonitors.returns([
- { id: 1, isActive: true },
- { id: 2, isActive: true },
- ]);
- const jobQueue = await JobQueue.createJobQueue(
- db,
- networkService,
- statusService,
- notificationService,
- settingsService,
- logger,
- QueueStub,
- WorkerStub
- );
- // There should be double the jobs, as one is meant to be instantly executed
- // And one is meant to be enqueued
- expect(jobQueue.queue.jobs.length).to.equal(4);
- });
-
- it("should reject with an error if an error occurs", async function () {
- db.getAllMonitors.throws("Error");
- try {
- const jobQueue = await JobQueue.createJobQueue(
- db,
- networkService,
- statusService,
- notificationService,
- settingsService,
- logger,
- QueueStub,
- WorkerStub
- );
- } catch (error) {
- expect(error.service).to.equal("JobQueue");
- expect(error.method).to.equal("createJobQueue");
- }
- });
-
- it("should reject with an error if an error occurs, should not overwrite error data", async function () {
- const error = new Error("Error");
- error.service = "otherService";
- error.method = "otherMethod";
- db.getAllMonitors.throws(error);
-
- try {
- const jobQueue = await JobQueue.createJobQueue(
- db,
- networkService,
- statusService,
- notificationService,
- settingsService,
- logger,
- QueueStub,
- WorkerStub
- );
- } catch (error) {
- expect(error.service).to.equal("otherService");
- expect(error.method).to.equal("otherMethod");
- }
- });
- });
-
- describe("Constructor", function () {
- it("should construct a new JobQueue with default port and host if not provided", async function () {
- settingsService.getSettings.returns({});
-
- expect(jobQueue.connection.host).to.equal("127.0.0.1");
- expect(jobQueue.connection.port).to.equal(6379);
- });
-
- it("should construct a new JobQueue with provided port and host", async function () {
- settingsService.getSettings.returns({ redisHost: "localhost", redisPort: 1234 });
- const jobQueue = await JobQueue.createJobQueue(
- db,
- networkService,
- statusService,
- notificationService,
- settingsService,
- logger,
- QueueStub,
- WorkerStub
- );
- expect(jobQueue.connection.host).to.equal("localhost");
- expect(jobQueue.connection.port).to.equal(1234);
- });
- });
-
- describe("isMaintenanceWindow", function () {
- it("should throw an error if error occurs", async function () {
- db.getMaintenanceWindowsByMonitorId.throws("Error");
- const jobQueue = await JobQueue.createJobQueue(
- db,
- networkService,
- statusService,
- notificationService,
- settingsService,
- logger,
- QueueStub,
- WorkerStub
- );
- try {
- jobQueue.isInMaintenanceWindow(1);
- } catch (error) {
- expect(error.service).to.equal("JobQueue");
- expect(error.method).to.equal("createWorker");
- }
- });
-
- it("should return true if in maintenance window with no repeat", async function () {
- db.getMaintenanceWindowsByMonitorId.returns([
- {
- active: true,
- start: new Date(Date.now() - 1000).toISOString(),
- end: new Date(Date.now() + 1000).toISOString(),
- repeat: 0,
- },
- ]);
- const jobQueue = await JobQueue.createJobQueue(
- db,
- networkService,
- statusService,
- notificationService,
- settingsService,
- logger,
- QueueStub,
- WorkerStub
- );
- const inWindow = await jobQueue.isInMaintenanceWindow(1);
- expect(inWindow).to.be.true;
- });
-
- it("should return true if in maintenance window with repeat", async function () {
- db.getMaintenanceWindowsByMonitorId.returns([
- {
- active: true,
- start: new Date(Date.now() - 10000).toISOString(),
- end: new Date(Date.now() - 5000).toISOString(),
- repeat: 1000,
- },
- ]);
- const jobQueue = await JobQueue.createJobQueue(
- db,
- networkService,
- statusService,
- notificationService,
- settingsService,
- logger,
- QueueStub,
- WorkerStub
- );
- const inWindow = await jobQueue.isInMaintenanceWindow(1);
- expect(inWindow).to.be.true;
- });
-
- it("should return false if in end < start", async function () {
- db.getMaintenanceWindowsByMonitorId.returns([
- {
- active: true,
- start: new Date(Date.now() - 5000).toISOString(),
- end: new Date(Date.now() - 10000).toISOString(),
- repeat: 1000,
- },
- ]);
- const jobQueue = await JobQueue.createJobQueue(
- db,
- networkService,
- statusService,
- notificationService,
- settingsService,
- logger,
- QueueStub,
- WorkerStub
- );
- const inWindow = await jobQueue.isInMaintenanceWindow(1);
- expect(inWindow).to.be.false;
- });
-
- it("should return false if not in maintenance window", async function () {
- db.getMaintenanceWindowsByMonitorId.returns([
- {
- active: false,
- start: new Date(Date.now() - 5000).toISOString(),
- end: new Date(Date.now() - 10000).toISOString(),
- repeat: 1000,
- },
- ]);
- const jobQueue = await JobQueue.createJobQueue(
- db,
- networkService,
- statusService,
- notificationService,
- settingsService,
- logger,
- QueueStub,
- WorkerStub
- );
- const inWindow = await jobQueue.isInMaintenanceWindow(1);
- expect(inWindow).to.be.false;
- });
- });
-
- describe("createJobHandler", function () {
- it("resolve to an error if an error is thrown within", async function () {
- const jobQueue = await JobQueue.createJobQueue(
- db,
- networkService,
- statusService,
- notificationService,
- settingsService,
- logger,
- QueueStub,
- WorkerStub
- );
- jobQueue.isInMaintenanceWindow = sinon.stub().throws("Error");
- try {
- const handler = jobQueue.createJobHandler();
- await handler({ data: { _id: 1 } });
- } catch (error) {
- expect(error.service).to.equal("JobQueue");
- expect(error.details).to.equal(`Error processing job 1: Error`);
- }
- });
-
- it("should log info if job is in maintenance window", async function () {
- const jobQueue = await JobQueue.createJobQueue(
- db,
- networkService,
- statusService,
- notificationService,
- settingsService,
- logger,
- QueueStub,
- WorkerStub
- );
- jobQueue.isInMaintenanceWindow = sinon.stub().returns(true);
- const handler = jobQueue.createJobHandler();
- await handler({ data: { _id: 1 } });
- expect(logger.info.calledOnce).to.be.true;
- expect(logger.info.firstCall.args[0].message).to.equal("Monitor 1 is in maintenance window");
- });
-
- it("should return if status has not changed", async function () {
- const jobQueue = await JobQueue.createJobQueue(
- db,
- networkService,
- statusService,
- notificationService,
- settingsService,
- logger,
- QueueStub,
- WorkerStub
- );
- jobQueue.isInMaintenanceWindow = sinon.stub().returns(false);
- statusService.updateStatus = sinon.stub().returns({ statusChanged: false });
- const handler = jobQueue.createJobHandler();
- await handler({ data: { _id: 1 } });
- expect(jobQueue.notificationService.handleNotifications.notCalled).to.be.true;
- });
-
- it("should return if status has changed, but prevStatus was undefined (monitor paused)", async function () {
- const jobQueue = await JobQueue.createJobQueue(
- db,
- networkService,
- statusService,
- notificationService,
- settingsService,
- logger,
- QueueStub,
- WorkerStub
- );
- jobQueue.isInMaintenanceWindow = sinon.stub().returns(false);
- statusService.updateStatus = sinon.stub().returns({ statusChanged: true, prevStatus: undefined });
- const handler = jobQueue.createJobHandler();
- await handler({ data: { _id: 1 } });
- expect(jobQueue.notificationService.handleNotifications.notCalled).to.be.true;
- });
-
- it("should call notification service if status changed and monitor was not paused", async function () {
- const jobQueue = await JobQueue.createJobQueue(
- db,
- networkService,
- statusService,
- notificationService,
- settingsService,
- logger,
- QueueStub,
- WorkerStub
- );
- jobQueue.isInMaintenanceWindow = sinon.stub().returns(false);
- statusService.updateStatus = sinon.stub().returns({ statusChanged: true, prevStatus: false });
- const handler = jobQueue.createJobHandler();
- await handler({ data: { _id: 1 } });
- expect(jobQueue.notificationService.handleNotifications.calledOnce).to.be.true;
- });
- });
-
- describe("getWorkerStats", function () {
- it("should throw an error if getRepeatable Jobs fails", async function () {
- const jobQueue = await JobQueue.createJobQueue(
- db,
- networkService,
- statusService,
- notificationService,
- settingsService,
- logger,
- QueueStub,
- WorkerStub
- );
- jobQueue.queue.getRepeatableJobs = async () => {
- throw new Error("Error");
- };
- try {
- const stats = await jobQueue.getWorkerStats();
- } catch (error) {
- expect(error.service).to.equal("JobQueue");
- expect(error.method).to.equal("getWorkerStats");
- }
- });
-
- it("should throw an error if getRepeatable Jobs fails but respect existing error data", async function () {
- const jobQueue = await JobQueue.createJobQueue(
- db,
- networkService,
- statusService,
- notificationService,
- settingsService,
- logger,
- QueueStub,
- WorkerStub
- );
- jobQueue.queue.getRepeatableJobs = async () => {
- const error = new Error("Existing Error");
- error.service = "otherService";
- error.method = "otherMethod";
- throw error;
- };
- try {
- await jobQueue.getWorkerStats();
- } catch (error) {
- expect(error.service).to.equal("otherService");
- expect(error.method).to.equal("otherMethod");
- }
- });
- });
-
- describe("scaleWorkers", function () {
- it("should scale workers to 5 if no workers", async function () {
- const jobQueue = await JobQueue.createJobQueue(
- db,
- networkService,
- statusService,
- notificationService,
- settingsService,
- logger,
- QueueStub,
- WorkerStub
- );
- expect(jobQueue.workers.length).to.equal(5);
- });
-
- it("should scale workers up", async function () {
- const jobQueue = await JobQueue.createJobQueue(
- db,
- networkService,
- statusService,
- notificationService,
- settingsService,
- logger,
- QueueStub,
- WorkerStub
- );
- jobQueue.scaleWorkers({
- load: 100,
- jobs: Array.from({ length: 100 }, (_, i) => i + 1),
- });
- expect(jobQueue.workers.length).to.equal(20);
- });
-
- it("should scale workers down, even with error of worker.close fails", async function () {
- WorkerStub.prototype.close = async () => {
- throw new Error("Error");
- };
- const jobQueue = await JobQueue.createJobQueue(
- db,
- networkService,
- statusService,
- notificationService,
- settingsService,
- logger,
- QueueStub,
- WorkerStub
- );
- await jobQueue.scaleWorkers({
- load: 100,
- jobs: Array.from({ length: 100 }, (_, i) => i + 1),
- });
-
- const res = await jobQueue.scaleWorkers({
- load: 0,
- jobs: [],
- });
- expect(jobQueue.workers.length).to.equal(5);
- });
-
- it("should scale workers down", async function () {
- WorkerStub.prototype.close = async () => {
- return true;
- };
- const jobQueue = await JobQueue.createJobQueue(
- db,
- networkService,
- statusService,
- notificationService,
- settingsService,
- logger,
- QueueStub,
- WorkerStub
- );
- await jobQueue.scaleWorkers({
- load: 40,
- jobs: Array.from({ length: 40 }, (_, i) => i + 1),
- });
-
- const res = await jobQueue.scaleWorkers({
- load: 0,
- jobs: [],
- });
- expect(jobQueue.workers.length).to.equal(5);
- });
-
- it("should return false if scaling doesn't happen", async function () {
- const jobQueue = await JobQueue.createJobQueue(
- db,
- networkService,
- statusService,
- notificationService,
- settingsService,
- logger,
- QueueStub,
- WorkerStub
- );
- const res = await jobQueue.scaleWorkers({ load: 5 });
- expect(jobQueue.workers.length).to.equal(5);
- expect(res).to.be.false;
- });
- });
-
- describe("getJobs", function () {
- it("should return jobs", async function () {
- const jobQueue = await JobQueue.createJobQueue(
- db,
- networkService,
- statusService,
- notificationService,
- settingsService,
- logger,
- QueueStub,
- WorkerStub
- );
- const jobs = await jobQueue.getJobs();
- expect(jobs.length).to.equal(0);
- });
-
- it("should throw an error if getRepeatableJobs fails", async function () {
- const jobQueue = await JobQueue.createJobQueue(
- db,
- networkService,
- statusService,
- notificationService,
- settingsService,
- logger,
- QueueStub,
- WorkerStub
- );
- try {
- jobQueue.queue.getRepeatableJobs = async () => {
- throw new Error("error");
- };
-
- await jobQueue.getJobs(true);
- } catch (error) {
- expect(error.service).to.equal("JobQueue");
- expect(error.method).to.equal("getJobs");
- }
- });
-
- it("should throw an error if getRepeatableJobs fails but respect existing error data", async function () {
- const jobQueue = await JobQueue.createJobQueue(
- db,
- networkService,
- statusService,
- notificationService,
- settingsService,
- logger,
- QueueStub,
- WorkerStub
- );
- try {
- jobQueue.queue.getRepeatableJobs = async () => {
- const error = new Error("Existing error");
- error.service = "otherService";
- error.method = "otherMethod";
- throw error;
- };
-
- await jobQueue.getJobs(true);
- } catch (error) {
- expect(error.service).to.equal("otherService");
- expect(error.method).to.equal("otherMethod");
- }
- });
- });
-
- describe("getJobStats", function () {
- it("should return job stats for no jobs", async function () {
- const jobStats = await jobQueue.getJobStats();
- expect(jobStats).to.deep.equal({ jobs: [], workers: 5 });
- });
-
- it("should return job stats for jobs", async function () {
- jobQueue.queue.getJobs = async () => {
- return [{ data: { url: "test" }, getState: async () => "completed" }];
- };
- const jobStats = await jobQueue.getJobStats();
- expect(jobStats).to.deep.equal({
- jobs: [{ url: "test", state: "completed" }],
- workers: 5,
- });
- });
-
- it("should reject with an error if mapping jobs fails", async function () {
- jobQueue.queue.getJobs = async () => {
- return [
- {
- data: { url: "test" },
- getState: async () => {
- throw new Error("Mapping Error");
- },
- },
- ];
- };
- try {
- await jobQueue.getJobStats();
- } catch (error) {
- expect(error.message).to.equal("Mapping Error");
- expect(error.service).to.equal("JobQueue");
- expect(error.method).to.equal("getJobStats");
- }
- });
-
- it("should reject with an error if mapping jobs fails but respect existing error data", async function () {
- jobQueue.queue.getJobs = async () => {
- return [
- {
- data: { url: "test" },
- getState: async () => {
- const error = new Error("Mapping Error");
- error.service = "otherService";
- error.method = "otherMethod";
- throw error;
- },
- },
- ];
- };
- try {
- await jobQueue.getJobStats();
- } catch (error) {
- expect(error.message).to.equal("Mapping Error");
- expect(error.service).to.equal("otherService");
- expect(error.method).to.equal("otherMethod");
- }
- });
- });
-
- describe("addJob", function () {
- it("should add a job to the queue", async function () {
- jobQueue.addJob("test", { url: "test" });
- expect(jobQueue.queue.jobs.length).to.equal(1);
- });
-
- it("should reject with an error if adding fails", async function () {
- jobQueue.queue.add = async () => {
- throw new Error("Error adding job");
- };
- try {
- await jobQueue.addJob("test", { url: "test" });
- } catch (error) {
- expect(error.message).to.equal("Error adding job");
- expect(error.service).to.equal("JobQueue");
- expect(error.method).to.equal("addJob");
- }
- });
-
- it("should reject with an error if adding fails but respect existing error data", async function () {
- jobQueue.queue.add = async () => {
- const error = new Error("Error adding job");
- error.service = "otherService";
- error.method = "otherMethod";
- throw error;
- };
- try {
- await jobQueue.addJob("test", { url: "test" });
- } catch (error) {
- expect(error.message).to.equal("Error adding job");
- expect(error.service).to.equal("otherService");
- expect(error.method).to.equal("otherMethod");
- }
- });
- });
-
- describe("deleteJob", function () {
- it("should delete a job from the queue", async function () {
- jobQueue.getWorkerStats = sinon.stub().returns({ load: 1, jobs: [{}] });
- jobQueue.scaleWorkers = sinon.stub();
- const monitor = { _id: 1 };
- const job = { data: monitor };
- jobQueue.queue.jobs = [job];
- await jobQueue.deleteJob(monitor);
- // expect(jobQueue.queue.jobs.length).to.equal(0);
- // expect(logger.info.calledOnce).to.be.true;
- // expect(jobQueue.getWorkerStats.calledOnce).to.be.true;
- // expect(jobQueue.scaleWorkers.calledOnce).to.be.true;
- });
-
- it("should log an error if job is not found", async function () {
- jobQueue.getWorkerStats = sinon.stub().returns({ load: 1, jobs: [{}] });
- jobQueue.scaleWorkers = sinon.stub();
- const monitor = { _id: 1 };
- const job = { data: monitor };
- jobQueue.queue.jobs = [job];
- await jobQueue.deleteJob({ id_: 2 });
- expect(logger.error.calledOnce).to.be.true;
- });
-
- it("should reject with an error if removeRepeatable fails", async function () {
- jobQueue.queue.removeRepeatable = async () => {
- const error = new Error("removeRepeatable error");
- throw error;
- };
-
- try {
- await jobQueue.deleteJob({ _id: 1 });
- } catch (error) {
- expect(error.message).to.equal("removeRepeatable error");
- expect(error.service).to.equal("JobQueue");
- expect(error.method).to.equal("deleteJob");
- }
- });
-
- it("should reject with an error if removeRepeatable fails but respect existing error data", async function () {
- jobQueue.queue.removeRepeatable = async () => {
- const error = new Error("removeRepeatable error");
- error.service = "otherService";
- error.method = "otherMethod";
- throw error;
- };
-
- try {
- await jobQueue.deleteJob({ _id: 1 });
- } catch (error) {
- expect(error.message).to.equal("removeRepeatable error");
- expect(error.service).to.equal("otherService");
- expect(error.method).to.equal("otherMethod");
- }
- });
- });
-
- describe("getMetrics", function () {
- it("should return metrics for the job queue", async function () {
- jobQueue.queue.getWaitingCount = async () => 1;
- jobQueue.queue.getActiveCount = async () => 2;
- jobQueue.queue.getCompletedCount = async () => 3;
- jobQueue.queue.getFailedCount = async () => 4;
- jobQueue.queue.getDelayedCount = async () => 5;
- jobQueue.queue.getRepeatableJobs = async () => [1, 2, 3];
- const metrics = await jobQueue.getMetrics();
- expect(metrics).to.deep.equal({
- waiting: 1,
- active: 2,
- completed: 3,
- failed: 4,
- delayed: 5,
- repeatableJobs: 3,
- });
- });
-
- it("should log an error if metrics operations fail", async function () {
- jobQueue.queue.getWaitingCount = async () => {
- throw new Error("Error");
- };
- await jobQueue.getMetrics();
- expect(logger.error.calledOnce).to.be.true;
- expect(logger.error.firstCall.args[0].message).to.equal("Error");
- });
- });
-
- describe("obliterate", function () {
- it("should return true if obliteration is successful", async function () {
- jobQueue.queue.pause = async () => true;
- jobQueue.getJobs = async () => [{ key: 1, id: 1 }];
- jobQueue.queue.removeRepeatableByKey = async () => true;
- jobQueue.queue.remove = async () => true;
- jobQueue.queue.obliterate = async () => true;
- const obliteration = await jobQueue.obliterate();
- expect(obliteration).to.be.true;
- });
-
- it("should throw an error if obliteration fails", async function () {
- jobQueue.getMetrics = async () => {
- throw new Error("Error");
- };
-
- try {
- await jobQueue.obliterate();
- } catch (error) {
- expect(error.service).to.equal("JobQueue");
- expect(error.method).to.equal("obliterate");
- }
- });
-
- it("should throw an error if obliteration fails but respect existing error data", async function () {
- jobQueue.getMetrics = async () => {
- const error = new Error("Error");
- error.service = "otherService";
- error.method = "otherMethod";
- throw error;
- };
-
- try {
- await jobQueue.obliterate();
- } catch (error) {
- expect(error.service).to.equal("otherService");
- expect(error.method).to.equal("otherMethod");
- }
- });
- });
-});
diff --git a/server/tests/services/networkService.test.js b/server/tests/services/networkService.test.js
deleted file mode 100755
index cb48ed9b2..000000000
--- a/server/tests/services/networkService.test.js
+++ /dev/null
@@ -1,439 +0,0 @@
-import sinon from "sinon";
-import NetworkService from "../../service/networkService.js";
-import { expect } from "chai";
-import http from "http";
-import { errorMessages } from "../../utils/messages.js";
-describe("Network Service", function () {
- let axios, ping, Docker, logger, networkService;
-
- beforeEach(function () {
- axios = {
- get: sinon.stub().resolves({
- data: { foo: "bar" },
- status: 200,
- }),
- };
- Docker = class {
- listContainers = sinon.stub().resolves([
- {
- Names: ["http://test.com"],
- Id: "http://test.com",
- },
- ]);
- getContainer = sinon.stub().returns({
- inspect: sinon.stub().resolves({ State: { Status: "running" } }),
- });
- };
- ping = {
- promise: {
- probe: sinon.stub().resolves({ response: { alive: true }, responseTime: 100, alive: true }),
- },
- };
- logger = { error: sinon.stub() };
- networkService = new NetworkService(axios, ping, logger, http, Docker);
- });
-
- describe("constructor", function () {
- it("should create a new NetworkService instance", function () {
- const networkService = new NetworkService();
- expect(networkService).to.be.an.instanceOf(NetworkService);
- });
- });
-
- describe("timeRequest", function () {
- it("should time an asynchronous operation", async function () {
- const operation = sinon.stub().resolves("success");
- const { response, responseTime } = await networkService.timeRequest(operation);
- expect(response).to.equal("success");
- expect(responseTime).to.be.a("number");
- });
-
- it("should handle errors if operation throws error", async function () {
- const error = new Error("Test error");
- const operation = sinon.stub().throws(error);
- const { response, responseTime } = await networkService.timeRequest(operation);
- expect(response).to.be.null;
- expect(responseTime).to.be.a("number");
- expect(error.message).to.equal("Test error");
- });
- });
-
- describe("requestPing", function () {
- it("should return a response object if ping successful", async function () {
- const pingResult = await networkService.requestPing({
- data: { url: "http://test.com", _id: "123" },
- });
- expect(pingResult.monitorId).to.equal("123");
- expect(pingResult.type).to.equal("ping");
- expect(pingResult.responseTime).to.be.a("number");
- expect(pingResult.status).to.be.true;
- });
-
- it("should return a response object if ping unsuccessful", async function () {
- const error = new Error("Test error");
- networkService.timeRequest = sinon.stub().resolves({ response: null, responseTime: 1, error });
- const pingResult = await networkService.requestPing({
- data: { url: "http://test.com", _id: "123" },
- });
- expect(pingResult.monitorId).to.equal("123");
- expect(pingResult.type).to.equal("ping");
- expect(pingResult.responseTime).to.be.a("number");
- expect(pingResult.status).to.be.false;
- expect(pingResult.code).to.equal(networkService.PING_ERROR);
- });
-
- it("should throw an error if ping cannot resolve", async function () {
- const error = new Error("test error");
- networkService.timeRequest = sinon.stub().throws(error);
- try {
- await networkService.requestPing({
- data: { url: "http://test.com", _id: "123" },
- });
- } catch (error) {
- expect(error).to.exist;
- expect(error.method).to.equal("requestPing");
- }
- });
- });
-
- describe("requestHttp", function () {
- it("should return a response object if http successful", async function () {
- const job = { data: { url: "http://test.com", _id: "123", type: "http" } };
- const httpResult = await networkService.requestHttp(job);
- expect(httpResult.monitorId).to.equal("123");
- expect(httpResult.type).to.equal("http");
- expect(httpResult.responseTime).to.be.a("number");
- expect(httpResult.status).to.be.true;
- });
-
- it("should return a response object if http unsuccessful", async function () {
- const error = new Error("Test error");
- error.response = { status: 404 };
- networkService.timeRequest = sinon.stub().resolves({ response: null, responseTime: 1, error });
- const job = { data: { url: "http://test.com", _id: "123", type: "http" } };
- const httpResult = await networkService.requestHttp(job);
- expect(httpResult.monitorId).to.equal("123");
- expect(httpResult.type).to.equal("http");
- expect(httpResult.responseTime).to.be.a("number");
- expect(httpResult.status).to.be.false;
- expect(httpResult.code).to.equal(404);
- });
-
- it("should return a response object if http unsuccessful with unknown code", async function () {
- const error = new Error("Test error");
- error.response = {};
- networkService.timeRequest = sinon.stub().resolves({ response: null, responseTime: 1, error });
- const job = { data: { url: "http://test.com", _id: "123", type: "http" } };
- const httpResult = await networkService.requestHttp(job);
- expect(httpResult.monitorId).to.equal("123");
- expect(httpResult.type).to.equal("http");
- expect(httpResult.responseTime).to.be.a("number");
- expect(httpResult.status).to.be.false;
- expect(httpResult.code).to.equal(networkService.NETWORK_ERROR);
- });
-
- it("should throw an error if an error occurs", async function () {
- const error = new Error("test error");
- networkService.timeRequest = sinon.stub().throws(error);
- try {
- await networkService.requestHttp({
- data: { url: "http://test.com", _id: "123" },
- });
- } catch (error) {
- expect(error).to.exist;
- expect(error.method).to.equal("requestHttp");
- }
- });
- });
-
- describe("requestPagespeed", function () {
- it("should return a response object if pagespeed successful", async function () {
- const job = { data: { url: "http://test.com", _id: "123", type: "pagespeed" } };
- const pagespeedResult = await networkService.requestPagespeed(job);
- expect(pagespeedResult.monitorId).to.equal("123");
- expect(pagespeedResult.type).to.equal("pagespeed");
- expect(pagespeedResult.responseTime).to.be.a("number");
- expect(pagespeedResult.status).to.be.true;
- });
-
- it("should return a response object if pagespeed unsuccessful", async function () {
- const error = new Error("Test error");
- error.response = { status: 404 };
- networkService.timeRequest = sinon.stub().resolves({ response: null, responseTime: 1, error });
- const job = { data: { url: "http://test.com", _id: "123", type: "pagespeed" } };
- const pagespeedResult = await networkService.requestPagespeed(job);
- expect(pagespeedResult.monitorId).to.equal("123");
- expect(pagespeedResult.type).to.equal("pagespeed");
- expect(pagespeedResult.responseTime).to.be.a("number");
- expect(pagespeedResult.status).to.be.false;
- expect(pagespeedResult.code).to.equal(404);
- });
-
- it("should return a response object if pagespeed unsuccessful with an unknown code", async function () {
- const error = new Error("Test error");
- error.response = {};
- networkService.timeRequest = sinon.stub().resolves({ response: null, responseTime: 1, error });
- const job = { data: { url: "http://test.com", _id: "123", type: "pagespeed" } };
- const pagespeedResult = await networkService.requestPagespeed(job);
- expect(pagespeedResult.monitorId).to.equal("123");
- expect(pagespeedResult.type).to.equal("pagespeed");
- expect(pagespeedResult.responseTime).to.be.a("number");
- expect(pagespeedResult.status).to.be.false;
- expect(pagespeedResult.code).to.equal(networkService.NETWORK_ERROR);
- });
-
- it("should throw an error if pagespeed cannot resolve", async function () {
- const error = new Error("test error");
- networkService.timeRequest = sinon.stub().throws(error);
- try {
- await networkService.requestPagespeed({
- data: { url: "http://test.com", _id: "123" },
- });
- } catch (error) {
- expect(error).to.exist;
- expect(error.method).to.equal("requestPagespeed");
- }
- });
- });
-
- describe("requestHardware", function () {
- it("should return a response object if hardware successful", async function () {
- const job = { data: { url: "http://test.com", _id: "123", type: "hardware" } };
- const httpResult = await networkService.requestHardware(job);
- expect(httpResult.monitorId).to.equal("123");
- expect(httpResult.type).to.equal("hardware");
- expect(httpResult.responseTime).to.be.a("number");
- expect(httpResult.status).to.be.true;
- });
-
- it("should return a response object if hardware successful and job has a secret", async function () {
- const job = {
- data: {
- url: "http://test.com",
- _id: "123",
- type: "hardware",
- secret: "my_secret",
- },
- };
- const httpResult = await networkService.requestHardware(job);
- expect(httpResult.monitorId).to.equal("123");
- expect(httpResult.type).to.equal("hardware");
- expect(httpResult.responseTime).to.be.a("number");
- expect(httpResult.status).to.be.true;
- });
-
- it("should return a response object if hardware unsuccessful", async function () {
- const error = new Error("Test error");
- error.response = { status: 404 };
- networkService.timeRequest = sinon.stub().resolves({ response: null, responseTime: 1, error });
- const job = { data: { url: "http://test.com", _id: "123", type: "hardware" } };
- const httpResult = await networkService.requestHardware(job);
- expect(httpResult.monitorId).to.equal("123");
- expect(httpResult.type).to.equal("hardware");
- expect(httpResult.responseTime).to.be.a("number");
- expect(httpResult.status).to.be.false;
- expect(httpResult.code).to.equal(404);
- });
-
- it("should return a response object if hardware unsuccessful with unknown code", async function () {
- const error = new Error("Test error");
- error.response = {};
- networkService.timeRequest = sinon.stub().resolves({ response: null, responseTime: 1, error });
- const job = { data: { url: "http://test.com", _id: "123", type: "hardware" } };
- const httpResult = await networkService.requestHardware(job);
- expect(httpResult.monitorId).to.equal("123");
- expect(httpResult.type).to.equal("hardware");
- expect(httpResult.responseTime).to.be.a("number");
- expect(httpResult.status).to.be.false;
- expect(httpResult.code).to.equal(networkService.NETWORK_ERROR);
- });
-
- it("should throw an error if hardware cannot resolve", async function () {
- const error = new Error("test error");
- networkService.timeRequest = sinon.stub().throws(error);
- try {
- await networkService.requestHardware({
- data: { url: "http://test.com", _id: "123" },
- });
- } catch (error) {
- expect(error).to.exist;
- expect(error.method).to.equal("requestHardware");
- }
- });
- });
-
- describe("requestDocker", function () {
- it("should return a response object if docker successful", async function () {
- const job = { data: { url: "http://test.com", _id: "123", type: "docker" } };
- const dockerResult = await networkService.requestDocker(job);
- expect(dockerResult.monitorId).to.equal("123");
- expect(dockerResult.type).to.equal("docker");
- expect(dockerResult.responseTime).to.be.a("number");
- expect(dockerResult.status).to.be.true;
- });
-
- it("should return a response object with status false if container not running", async function () {
- Docker = class {
- listContainers = sinon.stub().resolves([
- {
- Names: ["/my_container"],
- Id: "abc123",
- },
- ]);
- getContainer = sinon.stub().returns({
- inspect: sinon.stub().resolves({ State: { Status: "stopped" } }),
- });
- };
- networkService = new NetworkService(axios, ping, logger, http, Docker);
- const job = { data: { url: "abc123", _id: "123", type: "docker" } };
- const dockerResult = await networkService.requestDocker(job);
- expect(dockerResult.status).to.be.false;
- expect(dockerResult.code).to.equal(200);
- });
-
- it("should handle an error when fetching the container", async function () {
- Docker = class {
- listContainers = sinon.stub().resolves([
- {
- Names: ["/my_container"],
- Id: "abc123",
- },
- ]);
- getContainer = sinon.stub().returns({
- inspect: sinon.stub().throws(new Error("test error")),
- });
- };
- networkService = new NetworkService(axios, ping, logger, http, Docker);
- const job = { data: { url: "abc123", _id: "123", type: "docker" } };
- const dockerResult = await networkService.requestDocker(job);
- expect(dockerResult.status).to.be.false;
- expect(dockerResult.code).to.equal(networkService.NETWORK_ERROR);
- });
-
- it("should throw an error if operations fail", async function () {
- Docker = class {
- listContainers = sinon.stub().resolves([
- {
- Names: ["/my_container"],
- Id: "abc123",
- },
- ]);
- getContainer = sinon.stub().throws(new Error("test error"));
- };
- networkService = new NetworkService(axios, ping, logger, http, Docker);
- const job = { data: { url: "abc123", _id: "123", type: "docker" } };
- try {
- await networkService.requestDocker(job);
- } catch (error) {
- expect(error.message).to.equal("test error");
- }
- });
-
- it("should throw an error if no matching images found", async function () {
- Docker = class {
- listContainers = sinon.stub().resolves([]);
- getContainer = sinon.stub().throws(new Error("test error"));
- };
- networkService = new NetworkService(axios, ping, logger, http, Docker);
- const job = { data: { url: "abc123", _id: "123", type: "docker" } };
- try {
- await networkService.requestDocker(job);
- } catch (error) {
- expect(error.message).to.equal(errorMessages.DOCKER_NOT_FOUND);
- }
- });
- });
-
- describe("getStatus", function () {
- beforeEach(function () {
- networkService.requestPing = sinon.stub();
- networkService.requestHttp = sinon.stub();
- networkService.requestPagespeed = sinon.stub();
- networkService.requestHardware = sinon.stub();
- networkService.requestDocker = sinon.stub();
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- it("should call requestPing if type is ping", async function () {
- await networkService.getStatus({ data: { type: "ping" } });
- expect(networkService.requestPing.calledOnce).to.be.true;
- expect(networkService.requestDocker.notCalled).to.be.true;
- expect(networkService.requestHttp.notCalled).to.be.true;
- expect(networkService.requestPagespeed.notCalled).to.be.true;
- });
-
- it("should call requestHttp if type is http", async function () {
- await networkService.getStatus({ data: { type: "http" } });
- expect(networkService.requestPing.notCalled).to.be.true;
- expect(networkService.requestDocker.notCalled).to.be.true;
- expect(networkService.requestHttp.calledOnce).to.be.true;
- expect(networkService.requestPagespeed.notCalled).to.be.true;
- });
-
- it("should call requestPagespeed if type is pagespeed", async function () {
- await networkService.getStatus({ data: { type: "pagespeed" } });
- expect(networkService.requestPing.notCalled).to.be.true;
- expect(networkService.requestDocker.notCalled).to.be.true;
- expect(networkService.requestHttp.notCalled).to.be.true;
- expect(networkService.requestPagespeed.calledOnce).to.be.true;
- });
-
- it("should call requestHardware if type is hardware", async function () {
- await networkService.getStatus({ data: { type: "hardware" } });
- expect(networkService.requestHardware.calledOnce).to.be.true;
- expect(networkService.requestDocker.notCalled).to.be.true;
- expect(networkService.requestPing.notCalled).to.be.true;
- expect(networkService.requestPagespeed.notCalled).to.be.true;
- });
-
- it("should call requestDocker if type is Docker", async function () {
- await networkService.getStatus({ data: { type: "docker" } });
- expect(networkService.requestDocker.calledOnce).to.be.true;
- expect(networkService.requestHardware.notCalled).to.be.true;
- expect(networkService.requestPing.notCalled).to.be.true;
- expect(networkService.requestPagespeed.notCalled).to.be.true;
- });
-
- it("should throw an error if an unknown type is provided", async function () {
- try {
- await networkService.getStatus({ data: { type: "unknown" } });
- } catch (error) {
- expect(error.service).to.equal("NetworkService");
- expect(error.method).to.equal("getStatus");
- expect(error.message).to.equal("Unsupported type: unknown");
- }
- });
-
- it("should throw an error if job type is undefined", async function () {
- try {
- await networkService.getStatus({ data: { type: undefined } });
- } catch (error) {
- expect(error.service).to.equal("NetworkService");
- expect(error.method).to.equal("getStatus");
- expect(error.message).to.equal("Unsupported type: unknown");
- }
- });
-
- it("should throw an error if job is empty", async function () {
- try {
- await networkService.getStatus({});
- } catch (error) {
- expect(error.method).to.equal("getStatus");
- expect(error.message).to.equal("Unsupported type: unknown");
- }
- });
-
- it("should throw an error if job is null", async function () {
- try {
- await networkService.getStatus(null);
- } catch (error) {
- expect(error.service).to.equal("NetworkService");
- expect(error.method).to.equal("getStatus");
- expect(error.message).to.equal("Unsupported type: unknown");
- }
- });
- });
-});
diff --git a/server/tests/services/notificationService.test.js b/server/tests/services/notificationService.test.js
deleted file mode 100755
index 211cc8b46..000000000
--- a/server/tests/services/notificationService.test.js
+++ /dev/null
@@ -1,285 +0,0 @@
-import sinon from "sinon";
-import NotificationService from "../../service/notificationService.js";
-import { expect } from "chai";
-
-describe("NotificationService", function () {
- let emailService, db, logger, notificationService;
-
- beforeEach(function () {
- db = {
- getNotificationsByMonitorId: sinon.stub(),
- };
- emailService = {
- buildAndSendEmail: sinon.stub(),
- };
- logger = {
- warn: sinon.stub(),
- };
-
- notificationService = new NotificationService(emailService, db, logger);
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- describe("constructor", function () {
- it("should create a new instance of NotificationService", function () {
- expect(notificationService).to.be.an.instanceOf(NotificationService);
- });
- });
-
- describe("sendEmail", function () {
- it("should send an email notification with Up Template", async function () {
- const networkResponse = {
- monitor: {
- name: "Test Monitor",
- url: "http://test.com",
- },
- status: true,
- prevStatus: false,
- };
- const address = "test@test.com";
- await notificationService.sendEmail(networkResponse, address);
- expect(notificationService.emailService.buildAndSendEmail.calledOnce).to.be.true;
- expect(
- notificationService.emailService.buildAndSendEmail.calledWith("serverIsUpTemplate", { monitor: "Test Monitor", url: "http://test.com" })
- );
- });
-
- it("should send an email notification with Down Template", async function () {
- const networkResponse = {
- monitor: {
- name: "Test Monitor",
- url: "http://test.com",
- },
- status: false,
- prevStatus: true,
- };
- const address = "test@test.com";
- await notificationService.sendEmail(networkResponse, address);
- expect(notificationService.emailService.buildAndSendEmail.calledOnce).to.be.true;
- });
-
- it("should send an email notification with Up Template", async function () {
- const networkResponse = {
- monitor: {
- name: "Test Monitor",
- url: "http://test.com",
- },
- status: true,
- prevStatus: false,
- };
- const address = "test@test.com";
- await notificationService.sendEmail(networkResponse, address);
- expect(notificationService.emailService.buildAndSendEmail.calledOnce).to.be.true;
- });
- });
-
- describe("handleNotifications", function () {
- it("should handle notifications based on the network response", async function () {
- notificationService.sendEmail = sinon.stub();
- const res = await notificationService.handleNotifications({
- monitor: {
- type: "email",
- address: "www.google.com",
- },
- });
- expect(res).to.be.true;
- });
-
- it("should handle hardware notifications", async function () {
- notificationService.sendEmail = sinon.stub();
- const res = await notificationService.handleNotifications({
- monitor: {
- type: "hardware",
- address: "www.google.com",
- },
- });
- expect(res).to.be.true;
- });
-
- it("should handle an error when getting notifications", async function () {
- const testError = new Error("Test Error");
- notificationService.db.getNotificationsByMonitorId.rejects(testError);
- await notificationService.handleNotifications({ monitorId: "123" });
- expect(notificationService.logger.warn.calledOnce).to.be.true;
- });
- });
-
- describe("sendHardwareEmail", function () {
- let networkResponse, address, alerts;
-
- beforeEach(function () {
- networkResponse = {
- monitor: {
- name: "Test Monitor",
- url: "http://test.com",
- },
- status: true,
- prevStatus: false,
- };
- address = "test@test.com";
- alerts = ["test"];
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- it("should send an email notification with Hardware Template", async function () {
- emailService.buildAndSendEmail.resolves(true);
- const res = await notificationService.sendHardwareEmail(networkResponse, address, alerts);
- expect(res).to.be.true;
- });
-
- it("should return false if no alerts are provided", async function () {
- alerts = [];
- emailService.buildAndSendEmail.resolves(true);
- const res = await notificationService.sendHardwareEmail(networkResponse, address, alerts);
- expect(res).to.be.false;
- });
- });
-
- describe("handleStatusNotifications", function () {
- let networkResponse;
-
- beforeEach(function () {
- networkResponse = {
- monitor: {
- name: "Test Monitor",
- url: "http://test.com",
- },
- statusChanged: true,
- status: true,
- prevStatus: false,
- };
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- it("should handle status notifications", async function () {
- db.getNotificationsByMonitorId.resolves([{ type: "email", address: "test@test.com" }]);
- const res = await notificationService.handleStatusNotifications(networkResponse);
- expect(res).to.be.true;
- });
-
- it("should return false if status hasn't changed", async function () {
- networkResponse.statusChanged = false;
- const res = await notificationService.handleStatusNotifications(networkResponse);
- expect(res).to.be.false;
- });
-
- it("should return false if prevStatus is undefined", async function () {
- networkResponse.prevStatus = undefined;
- const res = await notificationService.handleStatusNotifications(networkResponse);
- expect(res).to.be.false;
- });
-
- it("should handle an error", async function () {
- const testError = new Error("Test Error");
- db.getNotificationsByMonitorId.rejects(testError);
- try {
- await notificationService.handleStatusNotifications(networkResponse);
- } catch (error) {
- expect(error).to.be.an.instanceOf(Error);
- expect(error.message).to.equal("Test Error");
- }
- });
- });
-
- describe("handleHardwareNotifications", function () {
- let networkResponse;
-
- beforeEach(function () {
- networkResponse = {
- monitor: {
- name: "Test Monitor",
- url: "http://test.com",
- thresholds: {
- usage_cpu: 1,
- usage_memory: 1,
- usage_disk: 1,
- },
- },
- payload: {
- data: {
- cpu: {
- usage_percent: 0.655,
- },
- memory: {
- usage_percent: 0.783,
- },
- disk: [
- {
- name: "/dev/sda1",
- usage_percent: 0.452,
- },
- {
- name: "/dev/sdb1",
- usage_percent: 0.627,
- },
- ],
- },
- },
- };
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- describe("it should return false if no thresholds are set", function () {
- it("should return false if no thresholds are set", async function () {
- networkResponse.monitor.thresholds = undefined;
- const res = await notificationService.handleHardwareNotifications(networkResponse);
- expect(res).to.be.false;
- });
-
- it("should return false if metrics are null", async function () {
- networkResponse.payload.data = null;
- const res = await notificationService.handleHardwareNotifications(networkResponse);
- expect(res).to.be.false;
- });
-
- it("should return true if request is well formed and thresholds > 0", async function () {
- db.getNotificationsByMonitorId.resolves([
- {
- type: "email",
- address: "test@test.com",
- alertThreshold: 1,
- cpuAlertThreshold: 1,
- memoryAlertThreshold: 1,
- diskAlertThreshold: 1,
- save: sinon.stub().resolves(),
- },
- ]);
- const res = await notificationService.handleHardwareNotifications(networkResponse);
- expect(res).to.be.true;
- });
-
- it("should return true if thresholds are exceeded", async function () {
- db.getNotificationsByMonitorId.resolves([
- {
- type: "email",
- address: "test@test.com",
- alertThreshold: 1,
- cpuAlertThreshold: 1,
- memoryAlertThreshold: 1,
- diskAlertThreshold: 1,
- save: sinon.stub().resolves(),
- },
- ]);
- networkResponse.monitor.thresholds = {
- usage_cpu: 0.01,
- usage_memory: 0.01,
- usage_disk: 0.01,
- };
- const res = await notificationService.handleHardwareNotifications(networkResponse);
- expect(res).to.be.true;
- });
- });
- });
-});
diff --git a/server/tests/services/settingsService.test.js b/server/tests/services/settingsService.test.js
deleted file mode 100755
index 6c9960e5e..000000000
--- a/server/tests/services/settingsService.test.js
+++ /dev/null
@@ -1,140 +0,0 @@
-import sinon from "sinon";
-import SettingsService from "../../service/settingsService.js";
-import { expect } from "chai";
-import NetworkService from "../../service/networkService.js";
-const SERVICE_NAME = "SettingsService";
-
-describe("SettingsService", function () {
- let sandbox, mockAppSettings;
-
- beforeEach(function () {
- sandbox = sinon.createSandbox();
- sandbox.stub(process.env, "CLIENT_HOST").value("http://localhost");
- sandbox.stub(process.env, "JWT_SECRET").value("secret");
- sandbox.stub(process.env, "REFRESH_TOKEN_SECRET").value("refreshSecret");
- sandbox.stub(process.env, "DB_TYPE").value("postgres");
- sandbox.stub(process.env, "DB_CONNECTION_STRING").value("postgres://user:pass@localhost/db");
- sandbox.stub(process.env, "REDIS_HOST").value("localhost");
- sandbox.stub(process.env, "REDIS_PORT").value("6379");
- sandbox.stub(process.env, "TOKEN_TTL").value("3600");
- sandbox.stub(process.env, "REFRESH_TOKEN_TTL").value("86400");
- sandbox.stub(process.env, "PAGESPEED_API_KEY").value("apiKey");
- sandbox.stub(process.env, "SYSTEM_EMAIL_HOST").value("smtp.mailtrap.io");
- sandbox.stub(process.env, "SYSTEM_EMAIL_PORT").value("2525");
- sandbox.stub(process.env, "SYSTEM_EMAIL_ADDRESS").value("test@example.com");
- sandbox.stub(process.env, "SYSTEM_EMAIL_PASSWORD").value("password");
- });
-
- mockAppSettings = {
- settingOne: 123,
- settingTwo: 456,
- };
-
- afterEach(function () {
- sandbox.restore();
- sinon.restore();
- });
-
- describe("constructor", function () {
- it("should construct a new SettingsService", function () {
- const settingsService = new SettingsService(mockAppSettings);
- expect(settingsService.appSettings).to.equal(mockAppSettings);
- });
- });
-
- describe("loadSettings", function () {
- it("should load settings from DB when environment variables are not set", async function () {
- const dbSettings = { logLevel: "debug", apiBaseUrl: "http://localhost" };
- const appSettings = { findOne: sinon.stub().returns(dbSettings) };
- const settingsService = new SettingsService(appSettings);
- settingsService.settings = {};
- const result = await settingsService.loadSettings();
- expect(result).to.deep.equal(dbSettings);
- });
-
- it("should throw an error if settings are not found", async function () {
- const appSettings = { findOne: sinon.stub().returns(null) };
- const settingsService = new SettingsService(appSettings);
- settingsService.settings = null;
-
- try {
- await settingsService.loadSettings();
- } catch (error) {
- expect(error.message).to.equal("Settings not found");
- expect(error.service).to.equal(SERVICE_NAME);
- expect(error.method).to.equal("loadSettings");
- }
- });
-
- it("should add its method and service name to error if not present", async function () {
- const appSettings = { findOne: sinon.stub().throws(new Error("Test error")) };
- const settingsService = new SettingsService(appSettings);
- try {
- await settingsService.loadSettings();
- } catch (error) {
- expect(error.message).to.equal("Test error");
- expect(error.service).to.equal(SERVICE_NAME);
- expect(error.method).to.equal("loadSettings");
- }
- });
-
- it("should not add its method and service name to error if present", async function () {
- const error = new Error("Test error");
- error.method = "otherMethod";
- error.service = "OTHER_SERVICE";
- const appSettings = { findOne: sinon.stub().throws(error) };
- const settingsService = new SettingsService(appSettings);
- try {
- await settingsService.loadSettings();
- } catch (error) {
- expect(error.message).to.equal("Test error");
- expect(error.service).to.equal("OTHER_SERVICE");
- expect(error.method).to.equal("otherMethod");
- }
- });
-
- it("should merge DB settings with environment variables", async function () {
- const dbSettings = { logLevel: "debug", apiBaseUrl: "http://localhost" };
- const appSettings = { findOne: sinon.stub().returns(dbSettings) };
- const settingsService = new SettingsService(appSettings);
- const result = await settingsService.loadSettings();
- expect(result).to.deep.equal(settingsService.settings);
- expect(settingsService.settings.logLevel).to.equal("debug");
- expect(settingsService.settings.apiBaseUrl).to.equal("http://localhost");
- });
- });
-
- describe("reloadSettings", function () {
- it("should call loadSettings", async function () {
- const dbSettings = { logLevel: "debug", apiBaseUrl: "http://localhost" };
- const appSettings = { findOne: sinon.stub().returns(dbSettings) };
- const settingsService = new SettingsService(appSettings);
- settingsService.settings = {};
- const result = await settingsService.reloadSettings();
- expect(result).to.deep.equal(dbSettings);
- });
- });
-
- describe("getSettings", function () {
- it("should return the current settings", function () {
- const dbSettings = { logLevel: "debug", apiBaseUrl: "http://localhost" };
- const appSettings = { findOne: sinon.stub().returns(dbSettings) };
- const settingsService = new SettingsService(appSettings);
- settingsService.settings = dbSettings;
- const result = settingsService.getSettings();
- expect(result).to.deep.equal(dbSettings);
- });
-
- it("should throw an error if settings have not been loaded", function () {
- const appSettings = { findOne: sinon.stub().returns(null) };
- const settingsService = new SettingsService(appSettings);
- settingsService.settings = null;
-
- try {
- settingsService.getSettings();
- } catch (error) {
- expect(error.message).to.equal("Settings have not been loaded");
- }
- });
- });
-});
diff --git a/server/tests/services/statusService.test.js b/server/tests/services/statusService.test.js
deleted file mode 100755
index 289a36884..000000000
--- a/server/tests/services/statusService.test.js
+++ /dev/null
@@ -1,255 +0,0 @@
-import sinon from "sinon";
-import StatusService from "../../service/statusService.js";
-import { afterEach, describe } from "node:test";
-
-describe("StatusService", () => {
- let db, logger, statusService;
-
- beforeEach(function () {
- db = {
- getMonitorById: sinon.stub(),
- createCheck: sinon.stub(),
- createPagespeedCheck: sinon.stub(),
- };
- logger = {
- info: sinon.stub(),
- error: sinon.stub(),
- };
- statusService = new StatusService(db, logger);
- });
-
- afterEach(() => {
- sinon.restore();
- });
-
- describe("constructor", () => {
- it("should create an instance of StatusService", function () {
- expect(statusService).to.be.an.instanceOf(StatusService);
- });
- });
-
- describe("getStatusString", () => {
- it("should return 'up' if status is true", function () {
- expect(statusService.getStatusString(true)).to.equal("up");
- });
-
- it("should return 'down' if status is false", function () {
- expect(statusService.getStatusString(false)).to.equal("down");
- });
-
- it("should return 'unknown' if status is undefined or null", function () {
- expect(statusService.getStatusString(undefined)).to.equal("unknown");
- });
- });
-
- describe("updateStatus", () => {
- beforeEach(function () {
- // statusService.insertCheck = sinon.stub().resolves;
- });
-
- afterEach(() => {
- sinon.restore();
- });
-
- it("should throw an error if an error occurs", async function () {
- const error = new Error("Test error");
- statusService.db.getMonitorById = sinon.stub().throws(error);
- try {
- await statusService.updateStatus({ monitorId: "test", status: true });
- } catch (error) {
- expect(error.message).to.equal("Test error");
- }
- // expect(statusService.insertCheck.calledOnce).to.be.true;
- });
-
- it("should return {statusChanged: false} if status hasn't changed", async function () {
- statusService.db.getMonitorById = sinon.stub().returns({ status: true });
- const result = await statusService.updateStatus({
- monitorId: "test",
- status: true,
- });
- expect(result).to.deep.equal({ statusChanged: false });
- // expect(statusService.insertCheck.calledOnce).to.be.true;
- });
-
- it("should return {statusChanged: true} if status has changed from down to up", async function () {
- statusService.db.getMonitorById = sinon.stub().returns({ status: false, save: sinon.stub() });
- const result = await statusService.updateStatus({
- monitorId: "test",
- status: true,
- });
- expect(result.statusChanged).to.be.true;
- expect(result.monitor.status).to.be.true;
- expect(result.prevStatus).to.be.false;
- // expect(statusService.insertCheck.calledOnce).to.be.true;
- });
-
- it("should return {statusChanged: true} if status has changed from up to down", async function () {
- statusService.db.getMonitorById = sinon.stub().returns({ status: true, save: sinon.stub() });
- const result = await statusService.updateStatus({
- monitorId: "test",
- status: false,
- });
- expect(result.statusChanged).to.be.true;
- expect(result.monitor.status).to.be.false;
- expect(result.prevStatus).to.be.true;
- // expect(statusService.insertCheck.calledOnce).to.be.true;
- });
- });
-
- describe("buildCheck", () => {
- it("should build a check object", function () {
- const check = statusService.buildCheck({
- monitorId: "test",
- type: "test",
- status: true,
- responseTime: 100,
- code: 200,
- message: "Test message",
- payload: { test: "test" },
- });
- expect(check.monitorId).to.equal("test");
- expect(check.status).to.be.true;
- expect(check.statusCode).to.equal(200);
- expect(check.responseTime).to.equal(100);
- expect(check.message).to.equal("Test message");
- });
-
- it("should build a check object for pagespeed type", function () {
- const check = statusService.buildCheck({
- monitorId: "test",
- type: "pagespeed",
- status: true,
- responseTime: 100,
- code: 200,
- message: "Test message",
- payload: {
- lighthouseResult: {
- categories: {
- accessibility: { score: 1 },
- "best-practices": { score: 1 },
- performance: { score: 1 },
- seo: { score: 1 },
- },
- audits: {
- "cumulative-layout-shift": { score: 1 },
- "speed-index": { score: 1 },
- "first-contentful-paint": { score: 1 },
- "largest-contentful-paint": { score: 1 },
- "total-blocking-time": { score: 1 },
- },
- },
- },
- });
- expect(check.monitorId).to.equal("test");
- expect(check.status).to.be.true;
- expect(check.statusCode).to.equal(200);
- expect(check.responseTime).to.equal(100);
- expect(check.message).to.equal("Test message");
- expect(check.accessibility).to.equal(100);
- expect(check.bestPractices).to.equal(100);
- expect(check.performance).to.equal(100);
- expect(check.seo).to.equal(100);
- expect(check.audits).to.deep.equal({
- cls: { score: 1 },
- si: { score: 1 },
- fcp: { score: 1 },
- lcp: { score: 1 },
- tbt: { score: 1 },
- });
- });
-
- it("should build a check object for pagespeed type with missing data", function () {
- const check = statusService.buildCheck({
- monitorId: "test",
- type: "pagespeed",
- status: true,
- responseTime: 100,
- code: 200,
- message: "Test message",
- payload: {
- lighthouseResult: {
- categories: {},
- audits: {},
- },
- },
- });
- expect(check.monitorId).to.equal("test");
- expect(check.status).to.be.true;
- expect(check.statusCode).to.equal(200);
- expect(check.responseTime).to.equal(100);
- expect(check.message).to.equal("Test message");
- expect(check.accessibility).to.equal(0);
- expect(check.bestPractices).to.equal(0);
- expect(check.performance).to.equal(0);
- expect(check.seo).to.equal(0);
- expect(check.audits).to.deep.equal({
- cls: 0,
- si: 0,
- fcp: 0,
- lcp: 0,
- tbt: 0,
- });
- });
-
- it("should build a check for hardware type", function () {
- const check = statusService.buildCheck({
- monitorId: "test",
- type: "hardware",
- status: true,
- responseTime: 100,
- code: 200,
- message: "Test message",
- payload: { data: { cpu: "cpu", memory: "memory", disk: "disk", host: "host" } },
- });
- expect(check.monitorId).to.equal("test");
- expect(check.status).to.be.true;
- expect(check.statusCode).to.equal(200);
- expect(check.responseTime).to.equal(100);
- expect(check.message).to.equal("Test message");
- expect(check.cpu).to.equal("cpu");
- expect(check.memory).to.equal("memory");
- expect(check.disk).to.equal("disk");
- expect(check.host).to.equal("host");
- });
-
- it("should build a check for hardware type with missing data", function () {
- const check = statusService.buildCheck({
- monitorId: "test",
- type: "hardware",
- status: true,
- responseTime: 100,
- code: 200,
- message: "Test message",
- payload: {},
- });
- expect(check.monitorId).to.equal("test");
- expect(check.status).to.be.true;
- expect(check.statusCode).to.equal(200);
- expect(check.responseTime).to.equal(100);
- expect(check.message).to.equal("Test message");
- expect(check.cpu).to.deep.equal({});
- expect(check.memory).to.deep.equal({});
- expect(check.disk).to.deep.equal({});
- expect(check.host).to.deep.equal({});
- });
- });
-
- describe("insertCheck", () => {
- it("should log an error if one is thrown", async function () {
- const testError = new Error("Test error");
- statusService.db.createCheck = sinon.stub().throws(testError);
- try {
- await statusService.insertCheck({ monitorId: "test" });
- } catch (error) {
- expect(error.message).to.equal(testError.message);
- }
- expect(statusService.logger.error.calledOnce).to.be.true;
- });
-
- it("should insert a check into the database", async function () {
- await statusService.insertCheck({ monitorId: "test", type: "http" });
- expect(statusService.db.createCheck.calledOnce).to.be.true;
- });
- });
-});
diff --git a/server/tests/utils/dataUtils.test.js b/server/tests/utils/dataUtils.test.js
deleted file mode 100755
index ec9eabb40..000000000
--- a/server/tests/utils/dataUtils.test.js
+++ /dev/null
@@ -1,61 +0,0 @@
-import { NormalizeData, calculatePercentile } from "../../utils/dataUtils.js";
-import sinon from "sinon";
-
-describe("NormalizeData", function () {
- it("should normalize response times when checks length is greater than 1", function () {
- const checks = [
- { responseTime: 20, _doc: { id: 1 } },
- { responseTime: 40, _doc: { id: 2 } },
- { responseTime: 60, _doc: { id: 3 } },
- ];
- const rangeMin = 1;
- const rangeMax = 100;
-
- const result = NormalizeData(checks, rangeMin, rangeMax);
-
- expect(result).to.be.an("array");
- expect(result).to.have.lengthOf(3);
- result.forEach((check) => {
- expect(check).to.have.property("responseTime").that.is.a("number");
- expect(check).to.have.property("originalResponseTime").that.is.a("number");
- });
- });
-
- it("should return checks with original response times when checks length is 1", function () {
- const checks = [{ responseTime: 20, _doc: { id: 1 } }];
- const rangeMin = 1;
- const rangeMax = 100;
-
- const result = NormalizeData(checks, rangeMin, rangeMax);
- expect(result).to.be.an("array");
- expect(result).to.have.lengthOf(1);
- expect(result[0]).to.have.property("originalResponseTime", 20);
- });
-
- it("should handle edge cases with extreme response times", function () {
- const checks = [
- { responseTime: 5, _doc: { id: 1 } },
- { responseTime: 95, _doc: { id: 2 } },
- ];
- const rangeMin = 1;
- const rangeMax = 100;
-
- const result = NormalizeData(checks, rangeMin, rangeMax);
-
- expect(result).to.be.an("array");
- expect(result).to.have.lengthOf(2);
- expect(result[0]).to.have.property("responseTime").that.is.at.least(rangeMin);
- expect(result[1]).to.have.property("responseTime").that.is.at.most(rangeMax);
- });
-});
-
-describe("calculatePercentile", function () {
- it("should return the lower value when upper is greater than or equal to the length of the sorted array", function () {
- const checks = [{ responseTime: 10 }, { responseTime: 20 }, { responseTime: 30 }, { responseTime: 40 }, { responseTime: 50 }];
-
- const percentile = 100;
- const result = calculatePercentile(checks, percentile);
- const expected = 50;
- expect(result).to.equal(expected);
- });
-});
diff --git a/server/tests/utils/imageProcessing.test.js b/server/tests/utils/imageProcessing.test.js
deleted file mode 100755
index 09330c317..000000000
--- a/server/tests/utils/imageProcessing.test.js
+++ /dev/null
@@ -1,53 +0,0 @@
-import { expect } from "chai";
-import sinon from "sinon";
-import sharp from "sharp";
-import { GenerateAvatarImage } from "../../utils/imageProcessing.js";
-
-describe("imageProcessing - GenerateAvatarImage", function () {
- it("should resize the image to 64x64 and return a base64 string", async function () {
- const file = {
- buffer: Buffer.from("test image buffer"),
- };
-
- // Stub the sharp function
- const toBufferStub = sinon.stub().resolves(Buffer.from("resized image buffer"));
- const resizeStub = sinon.stub().returns({ toBuffer: toBufferStub });
- const sharpStub = sinon.stub(sharp.prototype, "resize").returns({ toBuffer: toBufferStub });
-
- const result = await GenerateAvatarImage(file);
-
- // Verify the result
- const expected = Buffer.from("resized image buffer").toString("base64");
- expect(result).to.equal(expected);
-
- // Verify that the sharp function was called with the correct arguments
- expect(sharpStub.calledOnceWith({ width: 64, height: 64, fit: "cover" })).to.be.true;
- expect(toBufferStub.calledOnce).to.be.true;
-
- // Restore the stubbed functions
- sharpStub.restore();
- });
-
- it("should throw an error if resizing fails", async function () {
- const file = {
- buffer: Buffer.from("test image buffer"),
- };
-
- // Stub the sharp function to throw an error
- const toBufferStub = sinon.stub().rejects(new Error("Resizing failed"));
- const resizeStub = sinon.stub().returns({ toBuffer: toBufferStub });
- const sharpStub = sinon.stub(sharp.prototype, "resize").returns({ toBuffer: toBufferStub });
-
- try {
- await GenerateAvatarImage(file);
- // If no error is thrown, fail the test
- expect.fail("Expected error to be thrown");
- } catch (error) {
- // Verify that the error message is correct
- expect(error.message).to.equal("Resizing failed");
- }
-
- // Restore the stubbed functions
- sharpStub.restore();
- });
-});
diff --git a/server/tests/utils/logger.test.js b/server/tests/utils/logger.test.js
deleted file mode 100755
index 2d5bd82a9..000000000
--- a/server/tests/utils/logger.test.js
+++ /dev/null
@@ -1,139 +0,0 @@
-import sinon from "sinon";
-import logger from "../../utils/logger.js";
-import { Logger } from "../../utils/logger.js";
-import winston from "winston";
-
-describe("Logger", function () {
- let infoStub, warnStub, errorStub;
-
- beforeEach(function () {
- infoStub = sinon.stub(logger.logger, "info");
- warnStub = sinon.stub(logger.logger, "warn");
- errorStub = sinon.stub(logger.logger, "error");
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- describe("constructor", function () {
- let createLoggerStub;
-
- beforeEach(function () {
- createLoggerStub = sinon.stub(winston, "createLogger");
- });
-
- afterEach(function () {
- sinon.restore();
- });
-
- it("should convert message to JSON string if it is an object", function () {
- const logMessage = { key: "value" };
- const expectedMessage = JSON.stringify(logMessage, null, 2);
-
- createLoggerStub.callsFake((config) => {
- const consoleTransport = config.transports[0];
- const logEntry = {
- level: "info",
- message: logMessage,
- timestamp: new Date().toISOString(),
- };
- const formattedMessage = consoleTransport.format.transform(logEntry);
- expect(formattedMessage).to.include(expectedMessage);
- return { log: sinon.spy() };
- });
-
- const logger = new Logger();
- logger.logger.info(logMessage);
- });
-
- it("should convert details to JSON string if it is an object", function () {
- const logDetails = { key: "value" };
- const expectedDetails = JSON.stringify(logDetails, null, 2); // Removed .s
-
- createLoggerStub.callsFake((config) => {
- const consoleTransport = config.transports[0];
- const logEntry = {
- level: "info",
- message: "", // Add empty message since it's required
- details: logDetails,
- timestamp: new Date().toISOString(),
- };
- const formattedMessage = consoleTransport.format.transform(logEntry);
- expect(formattedMessage).to.include(expectedDetails);
- return { info: sinon.spy() }; // Changed to return info method
- });
-
- const logger = new Logger();
- logger.logger.info("", { details: logDetails }); // Updated to pass details properly
- });
- });
-
- describe("info", function () {
- it("should log an informational message", function () {
- const config = {
- message: "Info message",
- service: "TestService",
- method: "TestMethod",
- details: { key: "value" },
- };
-
- logger.info(config);
-
- expect(infoStub.calledOnce).to.be.true;
- expect(
- infoStub.calledWith(config.message, {
- service: config.service,
- method: config.method,
- details: config.details,
- })
- ).to.be.true;
- });
- });
-
- describe("warn", function () {
- it("should log a warning message", function () {
- const config = {
- message: "Warning message",
- service: "TestService",
- method: "TestMethod",
- details: { key: "value" },
- };
-
- logger.warn(config);
-
- expect(warnStub.calledOnce).to.be.true;
- expect(
- warnStub.calledWith(config.message, {
- service: config.service,
- method: config.method,
- details: config.details,
- })
- ).to.be.true;
- });
- });
-
- describe("error", function () {
- it("should log an error message", function () {
- const config = {
- message: "Error message",
- service: "TestService",
- method: "TestMethod",
- details: { key: "value" },
- stack: "Error stack trace",
- };
-
- logger.error(config);
-
- expect(errorStub.calledOnce).to.be.true;
- expect(
- errorStub.calledWith(config.message, {
- service: config.service,
- method: config.method,
- details: config.details,
- stack: config.stack,
- })
- ).to.be.true;
- });
- });
-});
diff --git a/server/tests/utils/messages.test.js b/server/tests/utils/messages.test.js
deleted file mode 100755
index a7e98c477..000000000
--- a/server/tests/utils/messages.test.js
+++ /dev/null
@@ -1,23 +0,0 @@
-import { errorMessages, successMessages } from "../../utils/messages.js";
-describe("Messages", function () {
- describe("messages - errorMessages", function () {
- it("should have a DB_FIND_MONITOR_BY_ID function", function () {
- const monitorId = "12345";
- expect(errorMessages.DB_FIND_MONITOR_BY_ID(monitorId)).to.equal(`Monitor with id ${monitorId} not found`);
- });
-
- it("should have a DB_DELETE_CHECKS function", function () {
- const monitorId = "12345";
- expect(errorMessages.DB_DELETE_CHECKS(monitorId)).to.equal(`No checks found for monitor with id ${monitorId}`);
- });
- });
-
- describe("messages - successMessages", function () {
- it("should have a MONITOR_GET_BY_USER_ID function", function () {
- const userId = "12345";
- expect(successMessages.MONITOR_GET_BY_USER_ID(userId)).to.equal(`Got monitor for ${userId} successfully"`);
- });
-
- // Add more tests for other success messages as needed
- });
-});
diff --git a/server/tests/utils/utils.test.js b/server/tests/utils/utils.test.js
deleted file mode 100755
index 2630bb8e6..000000000
--- a/server/tests/utils/utils.test.js
+++ /dev/null
@@ -1,50 +0,0 @@
-import { ParseBoolean, getTokenFromHeaders } from "../../utils/utils.js";
-
-describe("utils - ParseBoolean", function () {
- it("should return true", function () {
- const result = ParseBoolean("true");
- expect(result).to.be.true;
- });
-
- it("should return false", function () {
- const result = ParseBoolean("false");
- expect(result).to.be.false;
- });
-
- it("should return false", function () {
- const result = ParseBoolean(null);
- expect(result).to.be.false;
- });
-
- it("should return false", function () {
- const result = ParseBoolean(undefined);
- expect(result).to.be.false;
- });
-});
-
-describe("utils - getTokenFromHeaders", function () {
- it("should throw an error if authorization header is missing", function () {
- const headers = {};
- expect(() => getTokenFromHeaders(headers)).to.throw("No auth headers");
- });
-
- it("should throw an error if authorization header does not start with Bearer", function () {
- const headers = { authorization: "Basic abcdef" };
- expect(() => getTokenFromHeaders(headers)).to.throw("Invalid auth headers");
- });
-
- it("should return the token if authorization header is correctly formatted", function () {
- const headers = { authorization: "Bearer abcdef" };
- expect(getTokenFromHeaders(headers)).to.equal("abcdef");
- });
-
- it("should throw an error if authorization header has more than two parts", function () {
- const headers = { authorization: "Bearer abc def" };
- expect(() => getTokenFromHeaders(headers)).to.throw("Invalid auth headers");
- });
-
- it("should throw an error if authorization header has less than two parts", function () {
- const headers = { authorization: "Bearer" };
- expect(() => getTokenFromHeaders(headers)).to.throw("Invalid auth headers");
- });
-});
diff --git a/server/tsconfig.json b/server/tsconfig.json
new file mode 100644
index 000000000..3aa773ab1
--- /dev/null
+++ b/server/tsconfig.json
@@ -0,0 +1,26 @@
+{
+ "compilerOptions": {
+ "rootDir": "./src",
+ "outDir": "./dist",
+ "module": "nodenext",
+ "target": "esnext",
+ "types": ["node"],
+ "sourceMap": true,
+ "declaration": false,
+ "declarationMap": false,
+ "noUncheckedIndexedAccess": true,
+ "exactOptionalPropertyTypes": true,
+ "strict": true,
+ "isolatedModules": true,
+ "noUncheckedSideEffectImports": true,
+ "moduleDetection": "force",
+ "skipLibCheck": true,
+ "allowSyntheticDefaultImports": true,
+ "esModuleInterop": true,
+ "resolveJsonModule": true,
+ "forceConsistentCasingInFileNames": true,
+ "allowJs": true,
+ "checkJs": false
+ },
+ "exclude": ["node_modules", "dist", "**/*.config.js"]
+}