From 0190624a9128537d67fa15672631c92651b7c832 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 21 Oct 2024 11:48:25 +0800 Subject: [PATCH 1/5] Add hardware type to monitor model --- Server/db/models/Monitor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Server/db/models/Monitor.js b/Server/db/models/Monitor.js index d1f0ef5a7..6d718e9cd 100644 --- a/Server/db/models/Monitor.js +++ b/Server/db/models/Monitor.js @@ -29,7 +29,7 @@ const MonitorSchema = mongoose.Schema( type: { type: String, required: true, - enum: ["http", "ping", "pagespeed"], + enum: ["http", "ping", "pagespeed", "hardware"], }, url: { type: String, From 18fe7abaca9c707174d94e7a182fac38fa20adee Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 21 Oct 2024 11:54:58 +0800 Subject: [PATCH 2/5] Add db module for Hardware Checks --- Server/db/mongo/modules/hardwareCheckModule.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 Server/db/mongo/modules/hardwareCheckModule.js diff --git a/Server/db/mongo/modules/hardwareCheckModule.js b/Server/db/mongo/modules/hardwareCheckModule.js new file mode 100644 index 000000000..de46828e5 --- /dev/null +++ b/Server/db/mongo/modules/hardwareCheckModule.js @@ -0,0 +1,16 @@ +import HardwareCheck from "../../models/HardwareCheck.js"; +const SERVICE_NAME = "hardwareCheckModule"; +const createHardwareCheck = async (hardwareCheckData) => { + try { + const hardwareCheck = await new HardwareCheck({ + ...hardwareCheckData, + }).save(); + return hardwareCheck; + } catch (error) { + error.service = SERVICE_NAME; + error.method = "createHardwareCheck"; + throw error; + } +}; + +export { createHardwareCheck }; From ce20edc2fffd1f7dea3f83c5ad1e26e302c7f90d Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 21 Oct 2024 11:55:18 +0800 Subject: [PATCH 3/5] Add hardware check module to MongoDB --- Server/db/mongo/MongoDB.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Server/db/mongo/MongoDB.js b/Server/db/mongo/MongoDB.js index 61e60e836..9031a741f 100644 --- a/Server/db/mongo/MongoDB.js +++ b/Server/db/mongo/MongoDB.js @@ -99,6 +99,11 @@ import { deletePageSpeedChecksByMonitorId, } from "./modules/pageSpeedCheckModule.js"; +//**************************************** +// Hardware Checks +//**************************************** +import { createHardwareCheck } from "./modules/hardwareCheckModule.js"; + //**************************************** // Checks //**************************************** @@ -179,6 +184,7 @@ export default { createPageSpeedCheck, getPageSpeedChecks, deletePageSpeedChecksByMonitorId, + createHardwareCheck, createMaintenanceWindow, getMaintenanceWindowsByTeamId, getMaintenanceWindowById, From 7e0bc44ba62a4ee5e6b614e46533d52b93c19293 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 21 Oct 2024 11:55:44 +0800 Subject: [PATCH 4/5] Update networkService to handle hardware type monitors, add tests for full coverage --- Server/service/networkService.js | 78 +++++++++++ Server/tests/services/networkService.test.js | 138 +++++++++++++++++++ 2 files changed, 216 insertions(+) diff --git a/Server/service/networkService.js b/Server/service/networkService.js index ad372dbce..d4f9f11c8 100644 --- a/Server/service/networkService.js +++ b/Server/service/networkService.js @@ -24,6 +24,7 @@ class NetworkService { this.TYPE_PING = "ping"; this.TYPE_HTTP = "http"; this.TYPE_PAGESPEED = "pagespeed"; + this.TYPE_HARDWARE = "hardware"; this.SERVICE_NAME = "NetworkService"; this.NETWORK_ERROR = 5000; this.axios = axios; @@ -293,6 +294,81 @@ class NetworkService { } } + async handleHardware(job) { + const url = job.data.url; + let isAlive; + //TODO Fetch hardware data + //For now, fake hardware data: + + const hardwareData = { + monitorId: job.data._id, + cpu: { + physical_core: 1, + logical_core: 1, + frequency: 266, + temperature: null, + free_percent: null, + usage_percent: null, + }, + memory: { + total_bytes: 4, + available_bytes: 4, + used_bytes: 2, + usage_percent: 0.5, + }, + disk: { + read_speed_bytes: 3, + write_speed_bytes: 3, + total_bytes: 10, + free_bytes: 2, + usage_percent: 0.8, + }, + host: { + os: "Linux", + platform: "Ubuntu", + kernel_version: "24.04", + }, + }; + try { + isAlive = true; + this.logAndStoreCheck(hardwareData, this.db.createHardwareCheck); + } catch (error) { + isAlive = false; + const nullData = { + monitorId: job.data._id, + cpu: { + physical_core: 0, + logical_core: 0, + frequency: 0, + temperature: 0, + free_percent: 0, + usage_percent: 0, + }, + memory: { + total_bytes: 0, + available_bytes: 0, + used_bytes: 0, + usage_percent: 0, + }, + disk: { + read_speed_bytes: 0, + write_speed_bytes: 0, + total_bytes: 0, + free_bytes: 0, + usage_percent: 0, + }, + host: { + os: "", + platform: "", + kernel_version: "", + }, + }; + this.logAndStoreCheck(nullData, this.db.createHardwareCheck); + } finally { + this.handleStatusUpdate(job, isAlive); + } + } + /** * Retrieves the status of a given job based on its type. * For unsupported job types, it logs an error and returns false. @@ -308,6 +384,8 @@ class NetworkService { return await this.handleHttp(job); case this.TYPE_PAGESPEED: return await this.handlePagespeed(job); + case this.TYPE_HARDWARE: + return await this.handleHardware(job); default: this.logger.error(`Unsupported type: ${job.data.type}`, { service: this.SERVICE_NAME, diff --git a/Server/tests/services/networkService.test.js b/Server/tests/services/networkService.test.js index 619fa0fc9..1428b3bac 100644 --- a/Server/tests/services/networkService.test.js +++ b/Server/tests/services/networkService.test.js @@ -625,6 +625,132 @@ describe("networkService - handlePagespeed", () => { }); }); +describe("networkService - handleHardware", () => { + let dbMock, + axiosMock, + jobMock, + emailServiceMock, + pingMock, + loggerMock, + httpMock, + networkService, + logAndStoreCheckStub, + handleStatusUpdateStub; + beforeEach(() => { + jobMock = { + data: { + _id: "12345", + url: "http://example.com", + }, + }; + dbMock = { getMonitorById: sinon.stub() }; + axiosMock = { get: sinon.stub() }; + + emailServiceMock = sinon.stub(); + pingMock = { promise: { probe: sinon.stub() } }; + loggerMock = { error: sinon.stub() }; + httpMock = { + STATUS_CODES: { + 200: "OK", + 500: "Internal Server Error", + }, + }; + networkService = new NetworkService( + dbMock, + emailServiceMock, + axiosMock, + pingMock, + loggerMock, + httpMock + ); + logAndStoreCheckStub = sinon.stub(networkService, "logAndStoreCheck").resolves(); + handleStatusUpdateStub = sinon.stub(networkService, "handleStatusUpdate").resolves(); + }); + + afterEach(() => { + sinon.restore(); + }); + + it("should handle a successful Hardware response", async () => { + const responseMock = { + monitorId: jobMock.data._id, + cpu: { + physical_core: 1, + logical_core: 1, + frequency: 266, + temperature: null, + free_percent: null, + usage_percent: null, + }, + memory: { + total_bytes: 4, + available_bytes: 4, + used_bytes: 2, + usage_percent: 0.5, + }, + disk: { + read_speed_bytes: 3, + write_speed_bytes: 3, + total_bytes: 10, + free_bytes: 2, + usage_percent: 0.8, + }, + host: { + os: "Linux", + platform: "Ubuntu", + kernel_version: "24.04", + }, + }; + axiosMock.get.resolves(responseMock); + + await networkService.handleHardware(jobMock); + expect(networkService.logAndStoreCheck.calledOnce).to.be.true; + const hardwareData = networkService.logAndStoreCheck.getCall(0).args[0]; + expect(hardwareData.cpu).to.include({ + ...responseMock.cpu, + }); + expect(networkService.handleStatusUpdate.calledOnceWith(jobMock, true)).to.be.true; + }); + + it("should handle an error Hardware response", async () => { + logAndStoreCheckStub.throws(new Error("Hardware error")); + await networkService.handleHardware(jobMock); + const nullData = { + monitorId: job.data._id, + cpu: { + physical_core: 0, + logical_core: 0, + frequency: 0, + temperature: 0, + free_percent: 0, + usage_percent: 0, + }, + memory: { + total_bytes: 0, + available_bytes: 0, + used_bytes: 0, + usage_percent: 0, + }, + disk: { + read_speed_bytes: 0, + write_speed_bytes: 0, + total_bytes: 0, + free_bytes: 0, + usage_percent: 0, + }, + host: { + os: "", + platform: "", + kernel_version: "", + }, + }; + + expect( + logAndStoreCheckStub.calledWith(nullData, networkService.db.createHardwareCheck) + ).to.be.true; + }); +}); + describe("NetworkService - getStatus", () => { let dbMock, emailServiceMock, axiosMock, pingMock, loggerMock, httpMock, networkService; @@ -685,6 +811,18 @@ describe("NetworkService - getStatus", () => { const result = await networkService.getStatus(job); expect(result).to.be.false; }); + it("should return true if the job type is hardware and handleHardware is successful", async () => { + const job = { data: { type: networkService.TYPE_HARDWARE } }; + sinon.stub(networkService, "handleHardware").resolves(true); + const result = await networkService.getStatus(job); + expect(result).to.be.true; + }); + it("should return false if the job type is hardware and handleHardware is not successful", async () => { + const job = { data: { type: networkService.TYPE_HARDWARE } }; + sinon.stub(networkService, "handleHardware").resolves(false); + const result = await networkService.getStatus(job); + expect(result).to.be.false; + }); it("should log an error and return false if the job type is unknown", async () => { const job = { data: { type: "unknown" } }; const result = await networkService.getStatus(job); From 6f358d297d4560bcefd5b1eb87d0f83033fae2cf Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 22 Oct 2024 10:11:02 +0800 Subject: [PATCH 5/5] Update service and tests to use new --- Server/service/networkService.js | 32 +++++++----- Server/tests/services/networkService.test.js | 55 +++++--------------- 2 files changed, 32 insertions(+), 55 deletions(-) diff --git a/Server/service/networkService.js b/Server/service/networkService.js index d4f9f11c8..e90180835 100644 --- a/Server/service/networkService.js +++ b/Server/service/networkService.js @@ -316,13 +316,15 @@ class NetworkService { used_bytes: 2, usage_percent: 0.5, }, - disk: { - read_speed_bytes: 3, - write_speed_bytes: 3, - total_bytes: 10, - free_bytes: 2, - usage_percent: 0.8, - }, + disk: [ + { + read_speed_bytes: 3, + write_speed_bytes: 3, + total_bytes: 10, + free_bytes: 2, + usage_percent: 0.8, + }, + ], host: { os: "Linux", platform: "Ubuntu", @@ -350,13 +352,15 @@ class NetworkService { used_bytes: 0, usage_percent: 0, }, - disk: { - read_speed_bytes: 0, - write_speed_bytes: 0, - total_bytes: 0, - free_bytes: 0, - usage_percent: 0, - }, + disk: [ + { + read_speed_bytes: 0, + write_speed_bytes: 0, + total_bytes: 0, + free_bytes: 0, + usage_percent: 0, + }, + ], host: { os: "", platform: "", diff --git a/Server/tests/services/networkService.test.js b/Server/tests/services/networkService.test.js index 1428b3bac..5d3e81a22 100644 --- a/Server/tests/services/networkService.test.js +++ b/Server/tests/services/networkService.test.js @@ -688,13 +688,15 @@ describe("networkService - handleHardware", () => { used_bytes: 2, usage_percent: 0.5, }, - disk: { - read_speed_bytes: 3, - write_speed_bytes: 3, - total_bytes: 10, - free_bytes: 2, - usage_percent: 0.8, - }, + disk: [ + { + read_speed_bytes: 3, + write_speed_bytes: 3, + total_bytes: 10, + free_bytes: 2, + usage_percent: 0.8, + }, + ], host: { os: "Linux", platform: "Ubuntu", @@ -714,40 +716,11 @@ describe("networkService - handleHardware", () => { it("should handle an error Hardware response", async () => { logAndStoreCheckStub.throws(new Error("Hardware error")); - await networkService.handleHardware(jobMock); - const nullData = { - monitorId: job.data._id, - cpu: { - physical_core: 0, - logical_core: 0, - frequency: 0, - temperature: 0, - free_percent: 0, - usage_percent: 0, - }, - memory: { - total_bytes: 0, - available_bytes: 0, - used_bytes: 0, - usage_percent: 0, - }, - disk: { - read_speed_bytes: 0, - write_speed_bytes: 0, - total_bytes: 0, - free_bytes: 0, - usage_percent: 0, - }, - host: { - os: "", - platform: "", - kernel_version: "", - }, - }; - - expect( - logAndStoreCheckStub.calledWith(nullData, networkService.db.createHardwareCheck) - ).to.be.true; + try { + await networkService.handleHardware(jobMock); + } catch (error) { + expect(error.message).to.equal("Hardware error"); + } }); });