@itwin/core-backend
Version:
iTwin.js backend components
112 lines • 4.6 kB
JavaScript
import { expect } from "chai";
import { stub } from "sinon";
import { Readable, Writable } from "stream";
import { RpcRequestStatus } from "@itwin/core-common";
import { sendResponse } from "../../rpc/web/response";
import { brotliDecompressSync, unzipSync } from "node:zlib";
/* eslint-disable @typescript-eslint/no-deprecated */
class StubResponse extends Writable {
chunks = [];
get buffer() { return Buffer.concat(this.chunks); }
// eslint-disable-next-line @typescript-eslint/naming-convention
_write(chunk, _encoding, callback) {
this.chunks.push(chunk);
callback();
}
send = stub().returns(this);
status = stub();
set = stub();
}
describe("sendResponse", () => {
let protocol;
let request;
let fulfillment;
let req;
let res;
beforeEach(() => {
protocol = { getStatus: () => RpcRequestStatus.Resolved };
request = { operation: { operationName: "fake-RPC-operation" } };
fulfillment = {
allowCompression: true,
status: 200,
result: {
data: [],
},
};
req = { header: () => "gzip, deflate, br" };
res = new StubResponse();
});
it("should compress response using Brotli", async () => {
// Arrange
const originalData = generateJson();
const originalDataSize = Buffer.byteLength(originalData);
fulfillment.result.objects = originalData;
// Act
await sendResponse(protocol, request, fulfillment, req, res);
// Assert
expect(res.set.calledWithExactly("Content-Encoding", "br")).to.be.true;
const compressedData = res.send.getCall(0).args[0];
expect(compressedData).to.not.be.undefined;
expect(compressedData.length).to.be.lessThan(originalDataSize);
expect(brotliDecompressSync(compressedData).toString()).to.be.equal(originalData);
});
it("should compress response using Gzip if Brotli is not supported", async () => {
// Arrange
const originalData = generateJson();
const originalDataSize = Buffer.byteLength(originalData);
fulfillment.result.objects = originalData;
req.header = () => "gzip, deflate";
// Act
await sendResponse(protocol, request, fulfillment, req, res);
// Assert
expect(res.set.calledWithExactly("Content-Encoding", "gzip")).to.be.true;
const compressedData = res.send.getCall(0).args[0];
expect(compressedData).to.not.be.undefined;
expect(compressedData.length).to.be.lessThan(originalDataSize);
expect(unzipSync(compressedData).toString()).to.be.equal(originalData);
});
it("should not compress if Brotli and Gzip is not supported", async () => {
// Arrange
const originalData = generateJson();
fulfillment.result.objects = originalData;
req.header = () => undefined;
// Act
await sendResponse(protocol, request, fulfillment, req, res);
// Assert
expect(res.set.calledWithMatch("Content-Encoding")).to.be.false;
expect(res.send.getCall(0).args[0]).to.be.equal(originalData);
});
it("should compress stream", async () => {
// Arrange
const originalData = generateJson();
const originalDataSize = Buffer.byteLength(originalData);
fulfillment.result.stream = Readable.from(originalData);
// Act
await sendResponse(protocol, request, fulfillment, req, res);
await new Promise((resolve) => res.on("finish", resolve));
// Assert
const compressedData = res.buffer;
expect(compressedData).to.not.be.undefined;
expect(compressedData.length).to.be.lessThan(originalDataSize);
expect(brotliDecompressSync(compressedData).toString()).to.be.equal(originalData);
});
it("should support Accept-Encoding header value format without spaces between values", async () => {
// Arrange
fulfillment.result.objects = generateJson();
req.header = () => "gzip,deflate,br,zstd";
// Act
await sendResponse(protocol, request, fulfillment, req, res);
// Assert
expect(res.set.calledWithExactly("Content-Encoding", "br")).to.be.true;
});
});
function generateJson(minimumSize = 2000) {
let propertyIdx = 0;
const obj = {};
while (JSON.stringify(obj).length < minimumSize) {
obj[`property-${propertyIdx}`] = `value-${propertyIdx}`;
propertyIdx++;
}
return JSON.stringify(obj);
}
//# sourceMappingURL=response.test.js.map