mirror of
https://github.com/TriliumNext/Notes.git
synced 2025-07-27 18:12:29 +08:00

git-subtree-dir: _regroup_monorepo/express-partial-content git-subtree-mainline: 7349176c988df849f7f1cf46f22d48d6b04597e0 git-subtree-split: b80bfb7ca44c16bd5b747362ac2f53ece911b225
183 lines
7.3 KiB
TypeScript
183 lines
7.3 KiB
TypeScript
import * as utils from "../src/utils";
|
|
import * as ParseRangeHeaderExports from "../src/parseRangeHeader";
|
|
import { ContentDoesNotExistError } from "../src/ContentDoesNotExistError";
|
|
import { SinonSandbox, createSandbox, SinonStub, SinonSpy } from "sinon";
|
|
import { createPartialContentHandler } from "../src/createPartialContentHandler";
|
|
import { ContentProvider } from "../src/ContentProvider";
|
|
import { Logger } from "../src/Logger";
|
|
import { expect } from "chai";
|
|
import { Request, Response } from "express";
|
|
import { Content } from "../src/Content";
|
|
import { Stream } from "stream";
|
|
import { Range } from "../src/Range";
|
|
|
|
describe("createPartialContentHandler tests", () => {
|
|
let sandbox: SinonSandbox;
|
|
let logger: Logger;
|
|
beforeEach(() => {
|
|
sandbox = createSandbox();
|
|
logger = {
|
|
debug: sandbox.stub() as (message: string, extra?: any) => void
|
|
};
|
|
});
|
|
afterEach(() => {
|
|
sandbox.restore();
|
|
});
|
|
it("returns a handler", () => {
|
|
const contentProvider = sandbox.stub().resolves({}) as ContentProvider;
|
|
const handler = createPartialContentHandler(contentProvider, logger);
|
|
expect(typeof handler === "function");
|
|
});
|
|
|
|
describe("handler tests", () => {
|
|
let req: Request;
|
|
let res: Response;
|
|
let statusSpy: SinonSpy;
|
|
let sendSpy: SinonSpy;
|
|
let sendStatusSpy: SinonSpy;
|
|
beforeEach(() => {
|
|
req = {} as Request;
|
|
res = {
|
|
status: (code: number) => res,
|
|
send: (message: string) => res,
|
|
sendStatus: (code: number) => res,
|
|
setHeader: sandbox.stub() as (name: string, value: string) => void
|
|
} as Response;
|
|
statusSpy = sandbox.spy(res, "status");
|
|
sendSpy = sandbox.spy(res, "send");
|
|
sendStatusSpy = sandbox.spy(res, "sendStatus");
|
|
});
|
|
it("invokes contentProvider with the specified request", async () => {
|
|
const contentProvider = sandbox.stub().resolves({}) as ContentProvider;
|
|
const handler = createPartialContentHandler(contentProvider, logger);
|
|
try {
|
|
await handler(req, res);
|
|
} catch {}
|
|
expect((contentProvider as SinonStub).calledOnceWith(req));
|
|
});
|
|
it("returns 404 if contentProvider throws ContentDoesNotExistError error", async () => {
|
|
const error = new ContentDoesNotExistError("404-File not found!");
|
|
const contentProvider = sandbox.stub().rejects(error) as ContentProvider;
|
|
const handler = createPartialContentHandler(contentProvider, logger);
|
|
try {
|
|
await handler(req, res);
|
|
expect(statusSpy.calledOnceWith(404));
|
|
expect(sendSpy.calledOnceWith(error.message));
|
|
} catch {
|
|
expect(false);
|
|
}
|
|
});
|
|
it("returns 500 if contentProvider throws any other error", async () => {
|
|
const error = new Error("Something went wrong!");
|
|
const contentProvider = sandbox.stub().rejects(error) as ContentProvider;
|
|
const handler = createPartialContentHandler(contentProvider, logger);
|
|
try {
|
|
await handler(req, res);
|
|
expect(sendStatusSpy.calledOnceWith(500));
|
|
} catch {
|
|
expect(false);
|
|
}
|
|
});
|
|
it("returns 416 if parseRangeHeader throws RangeParserError error", async () => {
|
|
const contentProvider = sandbox.stub().resolves({}) as ContentProvider;
|
|
const handler = createPartialContentHandler(contentProvider, logger);
|
|
req.headers = { range: "bytes=30-10" };
|
|
try {
|
|
await handler(req, res);
|
|
expect(statusSpy.calledOnceWith(416));
|
|
} catch {
|
|
expect(false);
|
|
}
|
|
});
|
|
it("returns 500 if parseRangeHeader throws other errors", async () => {
|
|
const parseRangeHeaderStub = sandbox
|
|
.stub(ParseRangeHeaderExports, "parseRangeHeader")
|
|
.throws(new Error("Something went wrong!"));
|
|
const contentProvider = sandbox.stub().resolves({}) as ContentProvider;
|
|
const handler = createPartialContentHandler(contentProvider, logger);
|
|
try {
|
|
await handler(req, res);
|
|
expect(sendStatusSpy.calledOnceWith(500));
|
|
} catch {
|
|
expect(false);
|
|
}
|
|
});
|
|
it("returns correct response if range is not specified", async () => {
|
|
const result = ({
|
|
pipe() {
|
|
return result;
|
|
}
|
|
} as any) as Stream;
|
|
const content: Content = {
|
|
fileName: "file.txt",
|
|
totalSize: 10,
|
|
mimeType: "text/plain",
|
|
getStream(range?: Range) {
|
|
return result;
|
|
}
|
|
};
|
|
const pipeSpy = sandbox.spy(result, "pipe");
|
|
const getStreamSpy = sandbox.spy(content, "getStream");
|
|
const contentProvider = sandbox.stub().resolves(content) as ContentProvider;
|
|
const handler = createPartialContentHandler(contentProvider, logger);
|
|
const setContentTypeHeaderSpy = sandbox.spy(utils, "setContentTypeHeader");
|
|
const setContentDispositionHeaderSpy = sandbox.spy(utils, "setContentDispositionHeader");
|
|
const setAcceptRangesHeaderSpy = sandbox.spy(utils, "setAcceptRangesHeader");
|
|
const setContentLengthHeaderSpy = sandbox.spy(utils, "setContentLengthHeader");
|
|
const setContentRangeHeaderSpy = sandbox.spy(utils, "setContentRangeHeader");
|
|
try {
|
|
await handler(req, res);
|
|
expect(setContentTypeHeaderSpy.calledOnceWith(content.mimeType, res));
|
|
expect(setContentDispositionHeaderSpy.calledOnceWith(content.fileName, res));
|
|
expect(setAcceptRangesHeaderSpy.calledOnceWith(res));
|
|
expect(setContentLengthHeaderSpy.calledOnceWith(content.totalSize, res));
|
|
expect(getStreamSpy.calledOnceWith());
|
|
expect(pipeSpy.calledOnceWith(res));
|
|
expect(setContentRangeHeaderSpy.notCalled);
|
|
} catch {
|
|
expect(false);
|
|
}
|
|
});
|
|
it("returns correct partial response if range is specified", async () => {
|
|
req.headers = {
|
|
range: "bytes=0-5"
|
|
};
|
|
const result = ({
|
|
pipe() {
|
|
return result;
|
|
}
|
|
} as any) as Stream;
|
|
const content: Content = {
|
|
fileName: "file.txt",
|
|
totalSize: 10,
|
|
mimeType: "text/plain",
|
|
getStream(range?: Range) {
|
|
return result;
|
|
}
|
|
};
|
|
const range = { start: 0, end: 5 };
|
|
const pipeSpy = sandbox.spy(result, "pipe");
|
|
const getStreamSpy = sandbox.spy(content, "getStream");
|
|
const contentProvider = sandbox.stub().resolves(content) as ContentProvider;
|
|
const handler = createPartialContentHandler(contentProvider, logger);
|
|
const setContentTypeHeaderSpy = sandbox.spy(utils, "setContentTypeHeader");
|
|
const setContentDispositionHeaderSpy = sandbox.spy(utils, "setContentDispositionHeader");
|
|
const setAcceptRangesHeaderSpy = sandbox.spy(utils, "setAcceptRangesHeader");
|
|
const setContentLengthHeaderSpy = sandbox.spy(utils, "setContentLengthHeader");
|
|
const setContentRangeHeaderSpy = sandbox.spy(utils, "setContentRangeHeader");
|
|
try {
|
|
await handler(req, res);
|
|
expect(setContentTypeHeaderSpy.calledOnceWith(content.mimeType, res));
|
|
expect(setContentDispositionHeaderSpy.calledOnceWith(content.fileName, res));
|
|
expect(setAcceptRangesHeaderSpy.calledOnceWith(res));
|
|
expect(setContentRangeHeaderSpy.calledOnceWith(range, content.totalSize, res));
|
|
expect(setContentLengthHeaderSpy.calledOnceWith(6, res));
|
|
expect(getStreamSpy.calledOnceWith(range));
|
|
expect(pipeSpy.calledOnceWith(res));
|
|
} catch {
|
|
expect(false);
|
|
}
|
|
});
|
|
});
|
|
});
|