Add tests for util functions
This commit is contained in:
1 parent
d8e2b06eca
commit
c0ae2fac77
6 files changed
+245
-45
No files matched your search
+6
-6
@@ -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
|
||||
}
|
||||
@@ -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();
|
||||
});
|
||||
});
|
||||
@@ -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
|
||||
});
|
||||
});
|
||||
@@ -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
@@ -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 };
|
||||
Reference in new issue
Block a user