Merge branch 'develop' into 1067-fe-hardware-monitoring-create-hardware-monitor
This commit is contained in:
commit
2e51f025f9
23 files changed
+1097
-21
No files matched your search
Generated
+3
-3
@@ -6275,9 +6275,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "5.4.10",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.10.tgz",
|
||||
"integrity": "sha512-1hvaPshuPUtxeQ0hsVH3Mud0ZanOLwVTneA1EgbAM5LhaZEqyPWGRQ7BtaMvUrTDeEaC8pxtj6a6jku3x4z6SQ==",
|
||||
"version": "5.4.11",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.11.tgz",
|
||||
"integrity": "sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"esbuild": "^0.21.3",
|
||||
|
||||
+1
-6
@@ -1,11 +1,6 @@
|
||||
{
|
||||
"all": true,
|
||||
"include": [
|
||||
"controllers/*.js",
|
||||
"utils/*.js",
|
||||
"service/*.js",
|
||||
"db/mongo/modules/monitorModule.js"
|
||||
],
|
||||
"include": ["controllers/*.js", "utils/*.js", "service/*.js", "db/mongo/modules/*.js"],
|
||||
"exclude": ["**/*.test.js"],
|
||||
"reporter": ["html", "text", "lcov"],
|
||||
"sourceMap": false,
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
import { handleError, handleValidationError } from "./controllerUtils.js";
|
||||
import {
|
||||
createStatusPageBodyValidation,
|
||||
getStatusPageParamValidation,
|
||||
} from "../validation/joi.js";
|
||||
import { successMessages } from "../utils/messages.js";
|
||||
|
||||
const SERVICE_NAME = "statusPageController";
|
||||
|
||||
const createStatusPage = async (req, res, next) => {
|
||||
try {
|
||||
await createStatusPageBodyValidation.validateAsync(req.body);
|
||||
} catch (error) {
|
||||
next(handleValidationError(error, SERVICE_NAME));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const statusPage = await req.db.createStatusPage(req.body);
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
msg: successMessages.STATUS_PAGE_CREATE,
|
||||
data: statusPage,
|
||||
});
|
||||
} catch (error) {
|
||||
next(handleError(error, SERVICE_NAME, "createStatusPage"));
|
||||
}
|
||||
};
|
||||
|
||||
const getStatusPageByUrl = async (req, res, next) => {
|
||||
try {
|
||||
await getStatusPageParamValidation.validateAsync(req.params);
|
||||
} catch (error) {
|
||||
next(handleValidationError(error, SERVICE_NAME));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const { url } = req.params;
|
||||
const statusPage = await req.db.getStatusPageByUrl(url);
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
msg: successMessages.STATUS_PAGE_BY_URL,
|
||||
data: statusPage,
|
||||
});
|
||||
} catch (error) {
|
||||
next(handleError(error, SERVICE_NAME, "getStatusPage"));
|
||||
}
|
||||
};
|
||||
|
||||
export { createStatusPage, getStatusPageByUrl };
|
||||
@@ -30,6 +30,11 @@ const hostSchema = mongoose.Schema({
|
||||
kernel_version: { type: String, default: "" },
|
||||
});
|
||||
|
||||
const errorSchema = mongoose.Schema({
|
||||
metric: { type: [String], default: [] },
|
||||
err: { type: String, default: "" },
|
||||
});
|
||||
|
||||
const HardwareCheckSchema = mongoose.Schema(
|
||||
{
|
||||
...BaseCheckSchema.obj,
|
||||
@@ -49,6 +54,10 @@ const HardwareCheckSchema = mongoose.Schema(
|
||||
type: hostSchema,
|
||||
default: () => ({}),
|
||||
},
|
||||
errors: {
|
||||
type: [errorSchema],
|
||||
default: () => [],
|
||||
},
|
||||
},
|
||||
{ timestamps: true }
|
||||
);
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
import mongoose from "mongoose";
|
||||
|
||||
const StatusPageSchema = mongoose.Schema(
|
||||
{
|
||||
companyName: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: "",
|
||||
},
|
||||
url: {
|
||||
type: String,
|
||||
unique: true,
|
||||
required: true,
|
||||
default: "",
|
||||
},
|
||||
timezone: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: "America/Toronto",
|
||||
},
|
||||
color: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: "#4169E1",
|
||||
},
|
||||
theme: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: "light",
|
||||
},
|
||||
monitors: [
|
||||
{
|
||||
type: mongoose.Schema.Types.ObjectId,
|
||||
ref: "Monitor",
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{ timestamps: true }
|
||||
);
|
||||
|
||||
export default mongoose.model("StatusPage", StatusPageSchema);
|
||||
@@ -169,6 +169,11 @@ import {
|
||||
//****************************************
|
||||
import { getAppSettings, updateAppSettings } from "./modules/settingsModule.js";
|
||||
|
||||
//****************************************
|
||||
// Status Page
|
||||
//****************************************
|
||||
import { createStatusPage, getStatusPageByUrl } from "./modules/statusPageModule.js";
|
||||
|
||||
export default {
|
||||
connect,
|
||||
disconnect,
|
||||
@@ -223,4 +228,6 @@ export default {
|
||||
deleteNotificationsByMonitorId,
|
||||
getAppSettings,
|
||||
updateAppSettings,
|
||||
createStatusPage,
|
||||
getStatusPageByUrl,
|
||||
};
|
||||
@@ -78,7 +78,7 @@ const getInviteTokenAndDelete = async (token) => {
|
||||
return invite;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "getInviteToken";
|
||||
error.method = "getInviteTokenAndDelete";
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -203,7 +203,7 @@ const deleteMaintenanceWindowByUserId = async (userId) => {
|
||||
|
||||
const editMaintenanceWindowById = async (maintenanceWindowId, maintenanceWindowData) => {
|
||||
try {
|
||||
const editedMaintenanceWindow = MaintenanceWindow.findByIdAndUpdate(
|
||||
const editedMaintenanceWindow = await MaintenanceWindow.findByIdAndUpdate(
|
||||
maintenanceWindowId,
|
||||
maintenanceWindowData,
|
||||
{ new: true }
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
import StatusPage from "../../models/StatusPage.js";
|
||||
import { errorMessages } from "../../../utils/messages.js";
|
||||
|
||||
const SERVICE_NAME = "statusPageModule";
|
||||
|
||||
const createStatusPage = async (statusPageData) => {
|
||||
try {
|
||||
const statusPage = new StatusPage({ ...statusPageData });
|
||||
await statusPage.save();
|
||||
return statusPage;
|
||||
} catch (error) {
|
||||
if (error?.code === 11000) {
|
||||
// Handle duplicate URL errors
|
||||
error.status = 400;
|
||||
error.message = errorMessages.STATUS_PAGE_URL_NOT_UNIQUE;
|
||||
}
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "createStatusPage";
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
const getStatusPageByUrl = async (url) => {
|
||||
try {
|
||||
const statusPage = await StatusPage.findOne({ url });
|
||||
if (statusPage === null || statusPage === undefined) {
|
||||
const error = new Error(errorMessages.STATUS_PAGE_NOT_FOUND);
|
||||
error.status = 404;
|
||||
|
||||
throw error;
|
||||
}
|
||||
return statusPage;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "getStatusPageByUrl";
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export { createStatusPage, getStatusPageByUrl };
|
||||
@@ -14,6 +14,7 @@ import monitorRouter from "./routes/monitorRoute.js";
|
||||
import checkRouter from "./routes/checkRoute.js";
|
||||
import maintenanceWindowRouter from "./routes/maintenanceWindowRoute.js";
|
||||
import settingsRouter from "./routes/settingsRoute.js";
|
||||
import statusPageRouter from "./routes/statusPageRoute.js";
|
||||
import { fileURLToPath } from "url";
|
||||
|
||||
import queueRouter from "./routes/queueRoute.js";
|
||||
@@ -88,6 +89,7 @@ const startApp = async () => {
|
||||
app.use("/api/v1/checks", verifyJWT, checkRouter);
|
||||
app.use("/api/v1/maintenance-window", verifyJWT, maintenanceWindowRouter);
|
||||
app.use("/api/v1/queue", verifyJWT, queueRouter);
|
||||
app.use("/api/v1/status-page", statusPageRouter);
|
||||
|
||||
//health check
|
||||
app.use("/api/v1/healthy", (req, res) => {
|
||||
|
||||
@@ -84,6 +84,10 @@
|
||||
{
|
||||
"name": "queue",
|
||||
"description": "Queue"
|
||||
},
|
||||
{
|
||||
"name": "status-page",
|
||||
"description": "Status Page"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
@@ -2239,6 +2243,118 @@
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/status-page/{url}": {
|
||||
"get": {
|
||||
"tags": ["status-page"],
|
||||
"description": "Get a status page by URL",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "url",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": { "type": "string" }
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": { "$ref": "#/components/schemas/SuccessResponse" }
|
||||
}
|
||||
}
|
||||
},
|
||||
"422": {
|
||||
"description": "Unprocessable Content",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": { "$ref": "#/components/schemas/ErrorResponse" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"tags": ["status-page"],
|
||||
"description": "Create a status page",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/CreateStatusPageBody"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/SuccessResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"422": {
|
||||
"description": "Unprocessable Content",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Duplicate URL",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"bearerAuth": []
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
@@ -2425,6 +2541,21 @@
|
||||
"format": "date-time"
|
||||
}
|
||||
}
|
||||
},
|
||||
"CreateStatusPageBody": {
|
||||
"type": "object",
|
||||
"required": ["companyName", "url", "timezone", "color", "theme", "monitors"],
|
||||
"properties": {
|
||||
"companyName": { "type": "string" },
|
||||
"url": { "type": "string" },
|
||||
"timezone": { "type": "string" },
|
||||
"color": { "type": "string" },
|
||||
"theme": { "type": "string" },
|
||||
"monitors": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+4
-4
@@ -12,7 +12,7 @@
|
||||
"@sendgrid/mail": "^8.1.3",
|
||||
"axios": "^1.7.2",
|
||||
"bcrypt": "^5.1.1",
|
||||
"bullmq": "5.25.4",
|
||||
"bullmq": "5.25.6",
|
||||
"cors": "^2.8.5",
|
||||
"dotenv": "^16.4.5",
|
||||
"express": "^4.19.2",
|
||||
@@ -1164,9 +1164,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/bullmq": {
|
||||
"version": "5.25.4",
|
||||
"resolved": "https://registry.npmjs.org/bullmq/-/bullmq-5.25.4.tgz",
|
||||
"integrity": "sha512-f9M5qfFOg9hdoMWmux9x9rZm9ZUPTMFfdDMO2zRsi7IOzgvZ0UxB6oTk77PlC9YSDYoufAgBw82xU1nwvnsKSA==",
|
||||
"version": "5.25.6",
|
||||
"resolved": "https://registry.npmjs.org/bullmq/-/bullmq-5.25.6.tgz",
|
||||
"integrity": "sha512-jxpa/DB02V20CqBAgyqpQazT630CJm0r4fky8EchH3mcJAomRtKXLS6tRA0J8tb29BDGlr/LXhlUuZwdBJBSdA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cron-parser": "^4.6.0",
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@
|
||||
"@sendgrid/mail": "^8.1.3",
|
||||
"axios": "^1.7.2",
|
||||
"bcrypt": "^5.1.1",
|
||||
"bullmq": "5.25.4",
|
||||
"bullmq": "5.25.6",
|
||||
"cors": "^2.8.5",
|
||||
"dotenv": "^16.4.5",
|
||||
"express": "^4.19.2",
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import express from "express";
|
||||
import { verifyJWT } from "../middleware/verifyJWT.js";
|
||||
import {
|
||||
createStatusPage,
|
||||
getStatusPageByUrl,
|
||||
} from "../controllers/statusPageController.js";
|
||||
const router = express.Router();
|
||||
|
||||
router.get("/:url", getStatusPageByUrl);
|
||||
router.post("/:url", verifyJWT, createStatusPage);
|
||||
export default router;
|
||||
@@ -83,6 +83,7 @@ class StatusService {
|
||||
responseTime,
|
||||
message,
|
||||
};
|
||||
|
||||
if (type === "pagespeed") {
|
||||
const categories = payload.lighthouseResult?.categories;
|
||||
const audits = payload.lighthouseResult?.audits;
|
||||
@@ -101,10 +102,13 @@ class StatusService {
|
||||
}
|
||||
|
||||
if (type === "hardware") {
|
||||
check.cpu = payload?.cpu ?? {};
|
||||
check.memory = payload?.memory ?? {};
|
||||
check.disk = payload?.disk ?? {};
|
||||
check.host = payload?.host ?? {};
|
||||
const { cpu, memory, disk, host } = payload?.data ?? {};
|
||||
const { errors } = payload;
|
||||
check.cpu = cpu ?? {};
|
||||
check.memory = memory ?? {};
|
||||
check.disk = disk ?? {};
|
||||
check.host = host ?? {};
|
||||
check.errors = errors ?? [];
|
||||
}
|
||||
return check;
|
||||
};
|
||||
@@ -131,6 +135,7 @@ class StatusService {
|
||||
hardware: this.db.createHardwareCheck,
|
||||
};
|
||||
const operation = operationMap[networkResponse.type];
|
||||
|
||||
const check = this.buildCheck(networkResponse);
|
||||
await operation(check);
|
||||
} catch (error) {
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
import sinon from "sinon";
|
||||
import {
|
||||
createStatusPage,
|
||||
getStatusPageByUrl,
|
||||
} from "../../controllers/statusPageController.js";
|
||||
|
||||
describe("statusPageController", () => {
|
||||
let req, res, next;
|
||||
beforeEach(() => {
|
||||
req = {
|
||||
params: {},
|
||||
body: {},
|
||||
db: {
|
||||
createStatusPage: sinon.stub(),
|
||||
getStatusPageByUrl: sinon.stub(),
|
||||
},
|
||||
};
|
||||
res = {
|
||||
status: sinon.stub().returnsThis(),
|
||||
json: sinon.stub(),
|
||||
};
|
||||
next = sinon.stub();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
sinon.restore();
|
||||
});
|
||||
|
||||
describe("createStatusPage", () => {
|
||||
beforeEach(() => {
|
||||
req.body = {
|
||||
companyName: "Test Company",
|
||||
url: "123456",
|
||||
timezone: "America/Toronto",
|
||||
color: "#000000",
|
||||
theme: "light",
|
||||
monitors: ["67309ca673788e808884c8ac", "67309ca673788e808884c8ac"],
|
||||
};
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
sinon.restore();
|
||||
});
|
||||
|
||||
it("should handle a validation error", async () => {
|
||||
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 () => {
|
||||
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 () => {
|
||||
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", () => {
|
||||
beforeEach(() => {
|
||||
req.params = {
|
||||
url: "123456",
|
||||
};
|
||||
});
|
||||
afterEach(() => {
|
||||
sinon.restore();
|
||||
});
|
||||
|
||||
it("should handle a validation error", async () => {
|
||||
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 () => {
|
||||
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 () => {
|
||||
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);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,108 @@
|
||||
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", () => {
|
||||
const mockUserData = {
|
||||
email: "test@test.com",
|
||||
teamId: "123",
|
||||
role: ["admin"],
|
||||
token: "123",
|
||||
};
|
||||
const mockInviteToken = { _id: 123, time: 123 };
|
||||
let inviteTokenDeleteManyStub,
|
||||
inviteTokenSaveStub,
|
||||
inviteTokenFindOneStub,
|
||||
inviteTokenFindOneAndDeleteStub;
|
||||
beforeEach(() => {
|
||||
inviteTokenDeleteManyStub = sinon.stub(InviteToken, "deleteMany");
|
||||
inviteTokenSaveStub = sinon.stub(InviteToken.prototype, "save");
|
||||
inviteTokenFindOneStub = sinon.stub(InviteToken, "findOne");
|
||||
inviteTokenFindOneAndDeleteStub = sinon.stub(InviteToken, "findOneAndDelete");
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
sinon.restore();
|
||||
});
|
||||
describe("requestInviteToken", () => {
|
||||
it("should return a new invite token", async () => {
|
||||
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 () => {
|
||||
const err = new Error("test error");
|
||||
inviteTokenDeleteManyStub.rejects(err);
|
||||
try {
|
||||
await requestInviteToken(mockUserData);
|
||||
} catch (error) {
|
||||
expect(error).to.deep.equal(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("getInviteToken", () => {
|
||||
it("should return an invite token", async () => {
|
||||
inviteTokenFindOneStub.resolves(mockInviteToken);
|
||||
const inviteToken = await getInviteToken(mockUserData.token);
|
||||
expect(inviteToken).to.deep.equal(mockInviteToken);
|
||||
});
|
||||
|
||||
it("should handle a token not found", async () => {
|
||||
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 () => {
|
||||
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", () => {
|
||||
it("should return a deleted invite", async () => {
|
||||
inviteTokenFindOneAndDeleteStub.resolves(mockInviteToken);
|
||||
const deletedInvite = await getInviteTokenAndDelete(mockUserData.token);
|
||||
expect(deletedInvite).to.deep.equal(mockInviteToken);
|
||||
});
|
||||
|
||||
it("should handle a token not found", async () => {
|
||||
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 () => {
|
||||
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");
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,267 @@
|
||||
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", () => {
|
||||
const mockMaintenanceWindow = {
|
||||
monitorId: "123",
|
||||
active: true,
|
||||
oneTime: true,
|
||||
start: 1,
|
||||
end: 20000,
|
||||
};
|
||||
|
||||
let mockMaintenanceWindows = [mockMaintenanceWindow];
|
||||
let maintenanceWindowSaveStub,
|
||||
maintenanceWindowFindByIdStub,
|
||||
maintenanceWindowCountDocumentsStub,
|
||||
maintenanceWindowFindStub,
|
||||
maintenanceWindowFindByIdAndDeleteStub,
|
||||
maintenanceWindowDeleteManyStub,
|
||||
maintenanceWindowFindByIdAndUpdateStub;
|
||||
|
||||
beforeEach(() => {
|
||||
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(() => {
|
||||
sinon.restore();
|
||||
});
|
||||
|
||||
describe("createMaintenanceWindow", () => {
|
||||
it("should save a new maintenance window", async () => {
|
||||
maintenanceWindowSaveStub.resolves(mockMaintenanceWindow);
|
||||
const result = await createMaintenanceWindow(mockMaintenanceWindow);
|
||||
expect(result).to.deep.equal(mockMaintenanceWindow);
|
||||
});
|
||||
|
||||
it("should handle an error", async () => {
|
||||
const err = new Error("test error");
|
||||
maintenanceWindowSaveStub.rejects(err);
|
||||
try {
|
||||
await createMaintenanceWindow(mockMaintenanceWindow);
|
||||
} catch (error) {
|
||||
expect(error).to.deep.equal(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
describe("getMaintenanceWindowById", () => {
|
||||
it("should return a maintenance window", async () => {
|
||||
maintenanceWindowFindByIdStub.resolves(mockMaintenanceWindow);
|
||||
const result = await getMaintenanceWindowById(mockMaintenanceWindow.id);
|
||||
expect(result).to.deep.equal(mockMaintenanceWindow);
|
||||
});
|
||||
it("should handle an error", async () => {
|
||||
const err = new Error("test error");
|
||||
maintenanceWindowFindByIdStub.rejects(err);
|
||||
try {
|
||||
await getMaintenanceWindowById(mockMaintenanceWindow.id);
|
||||
} catch (error) {
|
||||
expect(error).to.deep.equal(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("getMaintenanceWindowsByTeamId", () => {
|
||||
let query;
|
||||
beforeEach(() => {
|
||||
query = {
|
||||
active: true,
|
||||
page: 1,
|
||||
rowsPerPage: 10,
|
||||
field: "name",
|
||||
order: "asc",
|
||||
};
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
sinon.restore();
|
||||
});
|
||||
|
||||
it("should return a list of maintenance windows and count", async () => {
|
||||
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 () => {
|
||||
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 () => {
|
||||
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 () => {
|
||||
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 () => {
|
||||
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 () => {
|
||||
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", () => {
|
||||
it("should return a list of maintenance windows", async () => {
|
||||
maintenanceWindowFindStub.resolves(mockMaintenanceWindows);
|
||||
const result = await getMaintenanceWindowsByMonitorId(
|
||||
mockMaintenanceWindow.monitorId
|
||||
);
|
||||
expect(result).to.deep.equal(mockMaintenanceWindows);
|
||||
});
|
||||
it("should handle an error", async () => {
|
||||
const err = new Error("test error");
|
||||
maintenanceWindowFindStub.rejects(err);
|
||||
try {
|
||||
await getMaintenanceWindowsByMonitorId(mockMaintenanceWindow.monitorId);
|
||||
} catch (error) {
|
||||
expect(error).to.deep.equal(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
describe("deleteMaintenanceWindowById", () => {
|
||||
it("should delete a maintenance window", async () => {
|
||||
maintenanceWindowFindByIdAndDeleteStub.resolves(mockMaintenanceWindow);
|
||||
const result = await deleteMaintenanceWindowById(mockMaintenanceWindow.id);
|
||||
expect(result).to.deep.equal(mockMaintenanceWindow);
|
||||
});
|
||||
it("should handle an error", async () => {
|
||||
const err = new Error("test error");
|
||||
maintenanceWindowFindByIdAndDeleteStub.rejects(err);
|
||||
try {
|
||||
await deleteMaintenanceWindowById(mockMaintenanceWindow.id);
|
||||
} catch (error) {
|
||||
expect(error).to.deep.equal(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("deleteMaintenanceWindowByMonitorId", () => {
|
||||
it("should return the number of documents deleted", async () => {
|
||||
maintenanceWindowDeleteManyStub.resolves({ deletedCount: 1 });
|
||||
const result = await deleteMaintenanceWindowByMonitorId(
|
||||
mockMaintenanceWindow.monitorId
|
||||
);
|
||||
expect(result).to.deep.equal({ deletedCount: 1 });
|
||||
});
|
||||
it("should handle an error", async () => {
|
||||
const err = new Error("test error");
|
||||
maintenanceWindowDeleteManyStub.rejects(err);
|
||||
try {
|
||||
await deleteMaintenanceWindowByMonitorId(mockMaintenanceWindow.monitorId);
|
||||
} catch (error) {
|
||||
expect(error).to.deep.equal(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("deleteMaintenanceWindowByUserId", () => {
|
||||
it("should return the number of documents deleted", async () => {
|
||||
maintenanceWindowDeleteManyStub.resolves({ deletedCount: 1 });
|
||||
const result = await deleteMaintenanceWindowByUserId(mockMaintenanceWindow.userId);
|
||||
expect(result).to.deep.equal({ deletedCount: 1 });
|
||||
});
|
||||
it("should handle an error", async () => {
|
||||
const err = new Error("test error");
|
||||
maintenanceWindowDeleteManyStub.rejects(err);
|
||||
try {
|
||||
await deleteMaintenanceWindowByUserId(mockMaintenanceWindow.userId);
|
||||
} catch (error) {
|
||||
expect(error).to.deep.equal(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
describe("editMaintenanceWindowById", () => {
|
||||
it("should return the updated maintenance window", async () => {
|
||||
maintenanceWindowFindByIdAndUpdateStub.resolves(mockMaintenanceWindow);
|
||||
const result = await editMaintenanceWindowById(
|
||||
mockMaintenanceWindow.id,
|
||||
mockMaintenanceWindow
|
||||
);
|
||||
expect(result).to.deep.equal(mockMaintenanceWindow);
|
||||
});
|
||||
it("should handle an error", async () => {
|
||||
const err = new Error("test error");
|
||||
maintenanceWindowFindByIdAndUpdateStub.rejects(err);
|
||||
try {
|
||||
await editMaintenanceWindowById(mockMaintenanceWindow.id, mockMaintenanceWindow);
|
||||
} catch (error) {
|
||||
expect(error).to.deep.equal(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,6 +1,8 @@
|
||||
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";
|
||||
@@ -37,7 +39,9 @@ describe("monitorModule", () => {
|
||||
monitorDeleteManyStub,
|
||||
monitorCountStub,
|
||||
monitorInsertManyStub,
|
||||
checkFindStub;
|
||||
checkFindStub,
|
||||
pageSpeedCheckFindStub,
|
||||
hardwareCheckFindStub;
|
||||
beforeEach(() => {
|
||||
monitorFindStub = sinon.stub(Monitor, "find");
|
||||
monitorFindByIdStub = sinon.stub(Monitor, "findById");
|
||||
@@ -50,6 +54,12 @@ describe("monitorModule", () => {
|
||||
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(() => {
|
||||
sinon.restore();
|
||||
@@ -137,6 +147,96 @@ describe("monitorModule", () => {
|
||||
expect(monitor["30"]).to.equal(75);
|
||||
expect(monitor["90"]).to.equal(75);
|
||||
});
|
||||
it("should return monitors with stats for pagespeed type", async () => {
|
||||
// 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 () => {
|
||||
// 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 () => {
|
||||
// Setup stub to throw error
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
import sinon from "sinon";
|
||||
import Notification from "../../db/models/Notification.js";
|
||||
import {
|
||||
createNotification,
|
||||
getNotificationsByMonitorId,
|
||||
deleteNotificationsByMonitorId,
|
||||
} from "../../db/mongo/modules/notificationModule.js";
|
||||
|
||||
describe("notificationModule", () => {
|
||||
const mockNotification = {
|
||||
monitorId: "123",
|
||||
};
|
||||
const mockNotifications = [mockNotification];
|
||||
let notificationSaveStub, notificationFindStub, notificationDeleteManyStub;
|
||||
|
||||
beforeEach(() => {
|
||||
notificationSaveStub = sinon.stub(Notification.prototype, "save").resolves();
|
||||
notificationFindStub = sinon.stub(Notification, "find").resolves();
|
||||
notificationDeleteManyStub = sinon.stub(Notification, "deleteMany").resolves();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
sinon.restore();
|
||||
});
|
||||
|
||||
describe("createNotification", () => {
|
||||
it("should create a new notification", async () => {
|
||||
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 () => {
|
||||
const err = new Error("test error");
|
||||
notificationSaveStub.rejects(err);
|
||||
try {
|
||||
await createNotification(mockNotification);
|
||||
} catch (error) {
|
||||
expect(error).to.deep.equal(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("getNotificationsByMonitorId", () => {
|
||||
it("should return notifications by monitor ID", async () => {
|
||||
notificationFindStub.resolves(mockNotifications);
|
||||
const res = await getNotificationsByMonitorId(mockNotification.monitorId);
|
||||
expect(res).to.deep.equal(mockNotifications);
|
||||
});
|
||||
it("should handle an error", async () => {
|
||||
const err = new Error("test error");
|
||||
notificationFindStub.rejects(err);
|
||||
try {
|
||||
await getNotificationsByMonitorId(mockNotification.monitorId);
|
||||
} catch (error) {
|
||||
expect(error).to.deep.equal(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("deleteNotificationsByMonitorId", () => {
|
||||
it("should delete notifications by monitor ID", async () => {
|
||||
notificationDeleteManyStub.resolves({ deletedCount: mockNotifications.length });
|
||||
const res = await deleteNotificationsByMonitorId(mockNotification.monitorId);
|
||||
expect(res).to.deep.equal(mockNotifications.length);
|
||||
});
|
||||
it("should handle an error", async () => {
|
||||
const err = new Error("test error");
|
||||
notificationDeleteManyStub.rejects(err);
|
||||
try {
|
||||
await deleteNotificationsByMonitorId(mockNotification.monitorId);
|
||||
} catch (error) {
|
||||
expect(error).to.deep.equal(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,67 @@
|
||||
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", () => {
|
||||
let statusPageFindOneStub, statusPageSaveStub, statusPageFindStub;
|
||||
beforeEach(() => {
|
||||
statusPageSaveStub = sinon.stub(StatusPage.prototype, "save");
|
||||
statusPageFindOneStub = sinon.stub(StatusPage, "findOne");
|
||||
statusPageFindStub = sinon.stub(StatusPage, "find");
|
||||
});
|
||||
afterEach(() => {
|
||||
sinon.restore();
|
||||
});
|
||||
describe("createStatusPage", () => {
|
||||
it("should throw an error if a non-unique url is provided", async () => {
|
||||
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 () => {
|
||||
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 () => {
|
||||
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", () => {
|
||||
it("should throw an error if a status page is not found", async () => {
|
||||
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 () => {
|
||||
const mockStatusPage = { url: "test" };
|
||||
statusPageFindOneStub.resolves(mockStatusPage);
|
||||
const statusPage = await getStatusPageByUrl(mockStatusPage.url);
|
||||
expect(statusPage).to.exist;
|
||||
expect(statusPage).to.deep.equal(mockStatusPage);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -51,6 +51,10 @@ const errorMessages = {
|
||||
|
||||
// PING Operations
|
||||
PING_CANNOT_RESOLVE: "No response",
|
||||
|
||||
// Status Page Errors
|
||||
STATUS_PAGE_NOT_FOUND: "Status page not found",
|
||||
STATUS_PAGE_URL_NOT_UNIQUE: "Status page url must be unique",
|
||||
};
|
||||
|
||||
const successMessages = {
|
||||
@@ -115,6 +119,10 @@ const successMessages = {
|
||||
// App Settings
|
||||
GET_APP_SETTINGS: "Got app settings successfully",
|
||||
UPDATE_APP_SETTINGS: "Updated app settings successfully",
|
||||
|
||||
// Status Page
|
||||
STATUS_PAGE_BY_URL: "Got status page by url successfully",
|
||||
STATUS_PAGE_CREATE: "Status page created successfully",
|
||||
};
|
||||
|
||||
export { errorMessages, successMessages };
|
||||
@@ -410,6 +410,32 @@ const updateAppSettingsBodyValidation = joi.object({
|
||||
systemEmailPassword: joi.string().allow(""),
|
||||
});
|
||||
|
||||
//****************************************
|
||||
// Status Page Validation
|
||||
//****************************************
|
||||
|
||||
const getStatusPageParamValidation = joi.object({
|
||||
url: joi.string().required(),
|
||||
});
|
||||
|
||||
const createStatusPageBodyValidation = joi.object({
|
||||
companyName: joi.string().required(),
|
||||
url: joi.string().required(),
|
||||
timezone: joi.string().required(),
|
||||
color: joi.string().required(),
|
||||
theme: joi.string().required(),
|
||||
monitors: joi
|
||||
.array()
|
||||
.items(joi.string().pattern(/^[0-9a-fA-F]{24}$/))
|
||||
.required()
|
||||
.messages({
|
||||
"string.pattern.base": "Must be a valid monitor ID",
|
||||
"array.base": "Monitors must be an array",
|
||||
"array.empty": "At least one monitor is required",
|
||||
"any.required": "Monitors are required",
|
||||
}),
|
||||
});
|
||||
|
||||
export {
|
||||
roleValidatior,
|
||||
loginValidation,
|
||||
@@ -465,4 +491,6 @@ export {
|
||||
editMaintenanceWindowByIdParamValidation,
|
||||
editMaintenanceByIdWindowBodyValidation,
|
||||
updateAppSettingsBodyValidation,
|
||||
createStatusPageBodyValidation,
|
||||
getStatusPageParamValidation,
|
||||
};
|
||||
Reference in new issue
Block a user