Add tests for util functions

This commit is contained in:
Alex Holliday committed 2024-10-17 13:09:50 +08:00
1 parent d8e2b06eca
commit c0ae2fac77
6 files changed
+245 -45

No files matched your search

+6 -6
View File
@@ -1,8 +1,8 @@
{
"all": true,
"include": ["controllers/*.js"],
"exclude": ["**/*.test.js"],
"reporter": ["html", "text", "lcov"],
"sourceMap": false,
"instrument": true
"all": true,
"include": ["controllers/*.js", "utils/*.js"],
"exclude": ["**/*.test.js"],
"reporter": ["html", "text", "lcov"],
"sourceMap": false,
"instrument": true
}
+68
View File
@@ -0,0 +1,68 @@
import { NormalizeData, calculatePercentile } from "../../utils/dataUtils.js";
import sinon from "sinon";
describe("NormalizeData", () => {
it("should normalize response times when checks length is greater than 1", () => {
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", () => {
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", () => {
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", () => {
it("should return the lower value when upper is greater than or equal to the length of the sorted array", () => {
const checks = [
{ responseTime: 10 },
{ responseTime: 20 },
{ responseTime: 30 },
{ responseTime: 40 },
{ responseTime: 50 },
];
const percentile = 100;
const result = calculatePercentile(checks, percentile);
const expected = 50;
console.log(result);
expect(result).to.equal(expected);
});
});
@@ -0,0 +1,57 @@
import { expect } from "chai";
import sinon from "sinon";
import sharp from "sharp";
import { GenerateAvatarImage } from "../../utils/imageProcessing.js";
describe("imageProcessing - GenerateAvatarImage", () => {
it("should resize the image to 64x64 and return a base64 string", async () => {
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 () => {
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();
});
});
+29
View File
@@ -0,0 +1,29 @@
import { errorMessages, successMessages } from "../../utils/messages.js";
describe("Messages", () => {
describe("messages - errorMessages", () => {
it("should have a DB_FIND_MONITOR_BY_ID 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", () => {
const monitorId = "12345";
expect(errorMessages.DB_DELETE_CHECKS(monitorId)).to.equal(
`No checks found for monitor with id ${monitorId}`
);
});
});
describe("messages - successMessages", () => {
it("should have a MONITOR_GET_BY_USER_ID 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
});
});
+50
View File
@@ -0,0 +1,50 @@
import { ParseBoolean, getTokenFromHeaders } from "../../utils/utils.js";
describe("utils - ParseBoolean", () => {
it("should return true", () => {
const result = ParseBoolean("true");
expect(result).to.be.true;
});
it("should return false", () => {
const result = ParseBoolean("false");
expect(result).to.be.false;
});
it("should return false", () => {
const result = ParseBoolean(null);
expect(result).to.be.false;
});
it("should return false", () => {
const result = ParseBoolean(undefined);
expect(result).to.be.false;
});
});
describe("utils - getTokenFromHeaders", () => {
it("should throw an error if authorization header is missing", () => {
const headers = {};
expect(() => getTokenFromHeaders(headers)).to.throw("No auth headers");
});
it("should throw an error if authorization header does not start with Bearer", () => {
const headers = { authorization: "Basic abcdef" };
expect(() => getTokenFromHeaders(headers)).to.throw("Invalid auth headers");
});
it("should return the token if authorization header is correctly formatted", () => {
const headers = { authorization: "Bearer abcdef" };
expect(getTokenFromHeaders(headers)).to.equal("abcdef");
});
it("should throw an error if authorization header has more than two parts", () => {
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", () => {
const headers = { authorization: "Bearer" };
expect(() => getTokenFromHeaders(headers)).to.throw("Invalid auth headers");
});
});
+35 -39
View File
@@ -1,48 +1,44 @@
const calculatePercentile = (arr, percentile) => {
const sorted = arr.slice().sort((a, b) => a.responseTime - b.responseTime);
const index = (percentile / 100) * (sorted.length - 1);
const lower = Math.floor(index);
const upper = lower + 1;
const weight = index % 1;
if (upper >= sorted.length) return sorted[lower].responseTime;
return (
sorted[lower].responseTime * (1 - weight) +
sorted[upper].responseTime * weight
);
const sorted = arr.slice().sort((a, b) => a.responseTime - b.responseTime);
const index = (percentile / 100) * (sorted.length - 1);
const lower = Math.floor(index);
const upper = lower + 1;
const weight = index % 1;
if (upper >= sorted.length) return sorted[lower].responseTime;
return sorted[lower].responseTime * (1 - weight) + sorted[upper].responseTime * weight;
};
const NormalizeData = (checks, rangeMin, rangeMax) => {
if (checks.length > 1) {
// Get the 5th and 95th percentile
const min = calculatePercentile(checks, 0);
const max = calculatePercentile(checks, 95);
if (checks.length > 1) {
// Get the 5th and 95th percentile
const min = calculatePercentile(checks, 0);
const max = calculatePercentile(checks, 95);
const normalizedChecks = checks.map((check) => {
const originalResponseTime = check.responseTime;
// Normalize the response time between 1 and 100
let normalizedResponseTime =
rangeMin +
((check.responseTime - min) * (rangeMax - rangeMin)) / (max - min);
const normalizedChecks = checks.map((check) => {
const originalResponseTime = check.responseTime;
// Normalize the response time between 1 and 100
let normalizedResponseTime =
rangeMin + ((check.responseTime - min) * (rangeMax - rangeMin)) / (max - min);
// Put a floor on the response times so we don't have extreme outliers
// Better visuals
normalizedResponseTime = Math.max(
rangeMin,
Math.min(rangeMax, normalizedResponseTime)
);
return {
...check._doc,
responseTime: normalizedResponseTime,
originalResponseTime: originalResponseTime,
};
});
// Put a floor on the response times so we don't have extreme outliers
// Better visuals
normalizedResponseTime = Math.max(
rangeMin,
Math.min(rangeMax, normalizedResponseTime)
);
return {
...check._doc,
responseTime: normalizedResponseTime,
originalResponseTime: originalResponseTime,
};
});
return normalizedChecks;
} else {
return checks.map((check) => {
return { ...check._doc, originalResponseTime: check.responseTime };
});
}
return normalizedChecks;
} else {
return checks.map((check) => {
return { ...check._doc, originalResponseTime: check.responseTime };
});
}
};
export { NormalizeData };
export { calculatePercentile, NormalizeData };