mirror of
https://github.com/CommunitySolidServer/CommunitySolidServer.git
synced 2024-10-03 14:55:10 +00:00
feat: add simple response writer
This commit is contained in:
parent
fe8749390c
commit
618005675f
161
package-lock.json
generated
161
package-lock.json
generated
@ -749,18 +749,60 @@
|
||||
"@babel/types": "^7.3.0"
|
||||
}
|
||||
},
|
||||
"@types/body-parser": {
|
||||
"version": "1.19.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz",
|
||||
"integrity": "sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/connect": "*",
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/color-name": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
|
||||
"integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/connect": {
|
||||
"version": "3.4.33",
|
||||
"resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.33.tgz",
|
||||
"integrity": "sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/eslint-visitor-keys": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz",
|
||||
"integrity": "sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/express": {
|
||||
"version": "4.17.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.6.tgz",
|
||||
"integrity": "sha512-n/mr9tZI83kd4azlPG5y997C/M4DNABK9yErhFM6hKdym4kkmd9j0vtsJyjFIwfRBxtrxZtAfGZCNRIBMFLK5w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/body-parser": "*",
|
||||
"@types/express-serve-static-core": "*",
|
||||
"@types/qs": "*",
|
||||
"@types/serve-static": "*"
|
||||
}
|
||||
},
|
||||
"@types/express-serve-static-core": {
|
||||
"version": "4.17.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.7.tgz",
|
||||
"integrity": "sha512-EMgTj/DF9qpgLXyc+Btimg+XoH7A2liE8uKul8qSmMTHCeNYzydDKFdsJskDvw42UsesCnhO63dO0Grbj8J4Dw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "*",
|
||||
"@types/qs": "*",
|
||||
"@types/range-parser": "*"
|
||||
}
|
||||
},
|
||||
"@types/graceful-fs": {
|
||||
"version": "4.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.3.tgz",
|
||||
@ -871,6 +913,12 @@
|
||||
"integrity": "sha512-8+KAKzEvSUdeo+kmqnKrqgeE+LcA0tjYWFY7RPProVYwnqDjukzO+3b6dLD56rYX5TdWejnEOLJYOIeh4CXKuA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/mime": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.2.tgz",
|
||||
"integrity": "sha512-4kPlzbljFcsttWEq6aBW0OZe6BDajAmyvr2xknBG92tejQnvdGtT9+kXSZ580DqpxY9qG2xeQVF9Dq0ymUTo5Q==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/n3": {
|
||||
"version": "1.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/n3/-/n3-1.1.6.tgz",
|
||||
@ -903,6 +951,18 @@
|
||||
"integrity": "sha512-/rM+sWiuOZ5dvuVzV37sUuklsbg+JPOP8d+nNFlo2ZtfpzPiPvh1/gc8liWOLBqe+sR+ZM7guPaIcTt6UZTo7Q==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/qs": {
|
||||
"version": "6.9.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.3.tgz",
|
||||
"integrity": "sha512-7s9EQWupR1fTc2pSMtXRQ9w9gLOcrJn+h7HOXw4evxyvVqMi4f+q7d2tnFe3ng3SNHjtK+0EzGMGFUQX4/AQRA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/range-parser": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz",
|
||||
"integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/rdf-js": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/rdf-js/-/rdf-js-3.0.0.tgz",
|
||||
@ -911,6 +971,16 @@
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/serve-static": {
|
||||
"version": "1.13.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.4.tgz",
|
||||
"integrity": "sha512-jTDt0o/YbpNwZbQmE/+2e+lfjJEJJR0I3OFaKQKPWkASkCoW3i6fsUnqudSMcNAfbtmADGu8f4MV4q+GqULmug==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/express-serve-static-core": "*",
|
||||
"@types/mime": "*"
|
||||
}
|
||||
},
|
||||
"@types/stack-utils": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz",
|
||||
@ -1006,6 +1076,16 @@
|
||||
"integrity": "sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg==",
|
||||
"dev": true
|
||||
},
|
||||
"accepts": {
|
||||
"version": "1.3.7",
|
||||
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
|
||||
"integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"mime-types": "~2.1.24",
|
||||
"negotiator": "0.6.2"
|
||||
}
|
||||
},
|
||||
"acorn": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-7.2.0.tgz",
|
||||
@ -1779,6 +1859,12 @@
|
||||
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
|
||||
"dev": true
|
||||
},
|
||||
"depd": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
|
||||
"integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=",
|
||||
"dev": true
|
||||
},
|
||||
"detect-newline": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz",
|
||||
@ -2676,6 +2762,12 @@
|
||||
"map-cache": "^0.2.2"
|
||||
}
|
||||
},
|
||||
"fresh": {
|
||||
"version": "0.5.2",
|
||||
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
|
||||
"integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=",
|
||||
"dev": true
|
||||
},
|
||||
"fs.realpath": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||
@ -4095,12 +4187,30 @@
|
||||
"object-visit": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"media-typer": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
||||
"integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=",
|
||||
"dev": true
|
||||
},
|
||||
"merge-descriptors": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
|
||||
"integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=",
|
||||
"dev": true
|
||||
},
|
||||
"merge-stream": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
|
||||
"integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
|
||||
"dev": true
|
||||
},
|
||||
"methods": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
|
||||
"integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=",
|
||||
"dev": true
|
||||
},
|
||||
"micromatch": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz",
|
||||
@ -4111,6 +4221,12 @@
|
||||
"picomatch": "^2.0.5"
|
||||
}
|
||||
},
|
||||
"mime": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
|
||||
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
|
||||
"dev": true
|
||||
},
|
||||
"mime-db": {
|
||||
"version": "1.44.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz",
|
||||
@ -4225,6 +4341,12 @@
|
||||
"integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
|
||||
"dev": true
|
||||
},
|
||||
"negotiator": {
|
||||
"version": "0.6.2",
|
||||
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
|
||||
"integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==",
|
||||
"dev": true
|
||||
},
|
||||
"nice-try": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
|
||||
@ -4237,6 +4359,23 @@
|
||||
"integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=",
|
||||
"dev": true
|
||||
},
|
||||
"node-mocks-http": {
|
||||
"version": "1.8.1",
|
||||
"resolved": "https://registry.npmjs.org/node-mocks-http/-/node-mocks-http-1.8.1.tgz",
|
||||
"integrity": "sha512-qtd9YwXzCTdLfqjP7XSOtFei3TggwnjFIppmYEneQBaDIuknwgJTpItLskC5/pWOpU3lsK5aqdo+5CfIKHkXLg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"accepts": "^1.3.7",
|
||||
"depd": "^1.1.0",
|
||||
"fresh": "^0.5.2",
|
||||
"merge-descriptors": "^1.0.1",
|
||||
"methods": "^1.1.2",
|
||||
"mime": "^1.3.4",
|
||||
"parseurl": "^1.3.3",
|
||||
"range-parser": "^1.2.0",
|
||||
"type-is": "^1.6.18"
|
||||
}
|
||||
},
|
||||
"node-modules-regexp": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz",
|
||||
@ -4536,6 +4675,12 @@
|
||||
"integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==",
|
||||
"dev": true
|
||||
},
|
||||
"parseurl": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
|
||||
"integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
|
||||
"dev": true
|
||||
},
|
||||
"pascalcase": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
|
||||
@ -4696,6 +4841,12 @@
|
||||
"integrity": "sha512-pVzZdDpWwWqEVVLshWUHjNwuVP7SfcmPraYuqocJp1yo2U1R7P+5QAfDhdItkuoGqIBnBYrtPp7rEPqDn9HlZA==",
|
||||
"dev": true
|
||||
},
|
||||
"range-parser": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
|
||||
"integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
|
||||
"dev": true
|
||||
},
|
||||
"rdf-isomorphic": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/rdf-isomorphic/-/rdf-isomorphic-1.1.0.tgz",
|
||||
@ -5969,6 +6120,16 @@
|
||||
"integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
|
||||
"dev": true
|
||||
},
|
||||
"type-is": {
|
||||
"version": "1.6.18",
|
||||
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
|
||||
"integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"media-typer": "0.3.0",
|
||||
"mime-types": "~2.1.24"
|
||||
}
|
||||
},
|
||||
"typedarray-to-buffer": {
|
||||
"version": "3.1.5",
|
||||
"resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
|
||||
|
@ -29,6 +29,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/arrayify-stream": "^1.0.0",
|
||||
"@types/express": "^4.17.6",
|
||||
"@types/jest": "^25.2.1",
|
||||
"@types/streamify-array": "^1.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^2.33.0",
|
||||
@ -40,6 +41,7 @@
|
||||
"husky": "^4.2.5",
|
||||
"jest": "^26.0.1",
|
||||
"jest-rdf": "^1.5.0",
|
||||
"node-mocks-http": "^1.8.1",
|
||||
"streamify-array": "^1.0.1",
|
||||
"ts-jest": "^26.0.0",
|
||||
"typescript": "^3.9.2"
|
||||
|
39
src/ldp/http/SimpleResponseWriter.ts
Normal file
39
src/ldp/http/SimpleResponseWriter.ts
Normal file
@ -0,0 +1,39 @@
|
||||
import { HttpError } from '../../util/errors/HttpError';
|
||||
import { HttpResponse } from '../../server/HttpResponse';
|
||||
import { ResponseDescription } from '../operations/ResponseDescription';
|
||||
import { ResponseWriter } from './ResponseWriter';
|
||||
import { UnsupportedHttpError } from '../../util/errors/UnsupportedHttpError';
|
||||
|
||||
export class SimpleResponseWriter extends ResponseWriter {
|
||||
public async canHandle(input: { response: HttpResponse; description?: ResponseDescription; error?: Error }): Promise<void> {
|
||||
if (!input.description && !input.error) {
|
||||
throw new UnsupportedHttpError('Either a description or an error is required for output.');
|
||||
}
|
||||
}
|
||||
|
||||
public async handle(input: { response: HttpResponse; description?: ResponseDescription; error?: Error }): Promise<void> {
|
||||
if (input.description) {
|
||||
input.response.setHeader('location', input.description.identifier.path);
|
||||
if (input.description.body) {
|
||||
if (input.description.body.metadata.contentType) {
|
||||
input.response.setHeader('content-type', input.description.body.metadata.contentType);
|
||||
}
|
||||
input.description.body.data.pipe(input.response);
|
||||
}
|
||||
|
||||
input.response.writeHead(200);
|
||||
|
||||
if (!input.description.body) {
|
||||
// If there is an input body the response will end once the input stream ends
|
||||
input.response.end();
|
||||
}
|
||||
} else {
|
||||
let code = 500;
|
||||
if (input.error instanceof HttpError) {
|
||||
code = input.error.statusCode;
|
||||
}
|
||||
input.response.writeHead(code);
|
||||
input.response.end(`${input.error.name}: ${input.error.message}\n${input.error.stack}`);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
import { OutgoingMessage } from 'http';
|
||||
import { ServerResponse } from 'http';
|
||||
|
||||
/**
|
||||
* An outgoing HTTP response;
|
||||
*/
|
||||
export type HttpResponse = OutgoingMessage;
|
||||
export type HttpResponse = ServerResponse;
|
||||
|
143
test/integration/AuthenticatedLdpHandler.test.ts
Normal file
143
test/integration/AuthenticatedLdpHandler.test.ts
Normal file
@ -0,0 +1,143 @@
|
||||
import { AuthenticatedLdpHandler } from '../../src/ldp/AuthenticatedLdpHandler';
|
||||
import { CompositeAsyncHandler } from '../../src/util/CompositeAsyncHandler';
|
||||
import { EventEmitter } from 'events';
|
||||
import { HttpRequest } from '../../src/server/HttpRequest';
|
||||
import { Operation } from '../../src/ldp/operations/Operation';
|
||||
import { ResponseDescription } from '../../src/ldp/operations/ResponseDescription';
|
||||
import { SimpleAuthorizer } from '../../src/authorization/SimpleAuthorizer';
|
||||
import { SimpleBodyParser } from '../../src/ldp/http/SimpleBodyParser';
|
||||
import { SimpleCredentialsExtractor } from '../../src/authentication/SimpleCredentialsExtractor';
|
||||
import { SimpleDeleteOperationHandler } from '../../src/ldp/operations/SimpleDeleteOperationHandler';
|
||||
import { SimpleGetOperationHandler } from '../../src/ldp/operations/SimpleGetOperationHandler';
|
||||
import { SimplePermissionsExtractor } from '../../src/ldp/permissions/SimplePermissionsExtractor';
|
||||
import { SimplePostOperationHandler } from '../../src/ldp/operations/SimplePostOperationHandler';
|
||||
import { SimplePreferenceParser } from '../../src/ldp/http/SimplePreferenceParser';
|
||||
import { SimpleRequestParser } from '../../src/ldp/http/SimpleRequestParser';
|
||||
import { SimpleResourceStore } from '../../src/storage/SimpleResourceStore';
|
||||
import { SimpleResponseWriter } from '../../src/ldp/http/SimpleResponseWriter';
|
||||
import { SimpleTargetExtractor } from '../../src/ldp/http/SimpleTargetExtractor';
|
||||
import streamifyArray from 'streamify-array';
|
||||
import { createResponse, MockResponse } from 'node-mocks-http';
|
||||
|
||||
describe('An AuthenticatedLdpHandler with instantiated handlers', (): void => {
|
||||
let handler: AuthenticatedLdpHandler;
|
||||
|
||||
beforeEach(async(): Promise<void> => {
|
||||
const requestParser = new SimpleRequestParser({
|
||||
targetExtractor: new SimpleTargetExtractor(),
|
||||
preferenceParser: new SimplePreferenceParser(),
|
||||
bodyParser: new SimpleBodyParser(),
|
||||
});
|
||||
|
||||
const credentialsExtractor = new SimpleCredentialsExtractor();
|
||||
const permissionsExtractor = new SimplePermissionsExtractor();
|
||||
const authorizer = new SimpleAuthorizer();
|
||||
|
||||
const store = new SimpleResourceStore('http://test.com/');
|
||||
const operationHandler = new CompositeAsyncHandler<Operation, ResponseDescription>([
|
||||
new SimpleGetOperationHandler(store),
|
||||
new SimplePostOperationHandler(store),
|
||||
new SimpleDeleteOperationHandler(store),
|
||||
]);
|
||||
|
||||
const responseWriter = new SimpleResponseWriter();
|
||||
|
||||
handler = new AuthenticatedLdpHandler({
|
||||
requestParser,
|
||||
credentialsExtractor,
|
||||
permissionsExtractor,
|
||||
authorizer,
|
||||
operationHandler,
|
||||
responseWriter,
|
||||
});
|
||||
});
|
||||
|
||||
it('can add, read and delete data based on incoming requests.', async(): Promise<void> => {
|
||||
// POST
|
||||
let request = streamifyArray([ '<http://test.com/s> <http://test.com/p> <http://test.com/o>.' ]) as HttpRequest;
|
||||
request.url = 'http://test.com/';
|
||||
request.method = 'POST';
|
||||
request.headers = {
|
||||
'content-type': 'text/turtle',
|
||||
};
|
||||
let response: MockResponse<any> = createResponse({ eventEmitter: EventEmitter });
|
||||
|
||||
let id;
|
||||
let endPromise = new Promise((resolve): void => {
|
||||
response.on('end', (): void => {
|
||||
expect(response._isEndCalled()).toBeTruthy();
|
||||
expect(response.statusCode).toBe(200);
|
||||
expect(response._getData()).toHaveLength(0);
|
||||
id = response._getHeaders().location;
|
||||
expect(id).toContain(request.url);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
await handler.handleSafe({ request, response });
|
||||
await endPromise;
|
||||
|
||||
// GET
|
||||
request = {} as HttpRequest;
|
||||
request.url = id;
|
||||
request.method = 'GET';
|
||||
request.headers = {
|
||||
accept: 'text/turtle',
|
||||
};
|
||||
response = createResponse({ eventEmitter: EventEmitter });
|
||||
|
||||
endPromise = new Promise((resolve): void => {
|
||||
response.on('end', (): void => {
|
||||
expect(response._isEndCalled()).toBeTruthy();
|
||||
expect(response.statusCode).toBe(200);
|
||||
expect(response._getData()).toContain('<http://test.com/s> <http://test.com/p> <http://test.com/o>.');
|
||||
expect(response._getHeaders().location).toBe(request.url);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
await handler.handleSafe({ request, response });
|
||||
await endPromise;
|
||||
|
||||
// DELETE
|
||||
request = {} as HttpRequest;
|
||||
request.url = id;
|
||||
request.method = 'DELETE';
|
||||
request.headers = {};
|
||||
response = createResponse({ eventEmitter: EventEmitter });
|
||||
|
||||
endPromise = new Promise((resolve): void => {
|
||||
response.on('end', (): void => {
|
||||
expect(response._isEndCalled()).toBeTruthy();
|
||||
expect(response.statusCode).toBe(200);
|
||||
expect(response._getData()).toHaveLength(0);
|
||||
expect(response._getHeaders().location).toBe(request.url);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
await handler.handleSafe({ request, response });
|
||||
await endPromise;
|
||||
|
||||
// GET
|
||||
request = {} as HttpRequest;
|
||||
request.url = id;
|
||||
request.method = 'GET';
|
||||
request.headers = {
|
||||
accept: 'text/turtle',
|
||||
};
|
||||
response = createResponse({ eventEmitter: EventEmitter });
|
||||
|
||||
endPromise = new Promise((resolve): void => {
|
||||
response.on('end', (): void => {
|
||||
expect(response._isEndCalled()).toBeTruthy();
|
||||
expect(response.statusCode).toBe(404);
|
||||
expect(response._getData()).toContain('NotFoundHttpError');
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
await handler.handleSafe({ request, response });
|
||||
await endPromise;
|
||||
});
|
||||
});
|
87
test/unit/ldp/http/SimpleResponseWriter.test.ts
Normal file
87
test/unit/ldp/http/SimpleResponseWriter.test.ts
Normal file
@ -0,0 +1,87 @@
|
||||
import { EventEmitter } from 'events';
|
||||
import { Quad } from 'rdf-js';
|
||||
import { ResponseDescription } from '../../../../src/ldp/operations/ResponseDescription';
|
||||
import { SimpleResponseWriter } from '../../../../src/ldp/http/SimpleResponseWriter';
|
||||
import streamifyArray from 'streamify-array';
|
||||
import { UnsupportedHttpError } from '../../../../src/util/errors/UnsupportedHttpError';
|
||||
import { createResponse, MockResponse } from 'node-mocks-http';
|
||||
|
||||
describe('A SimpleResponseWriter', (): void => {
|
||||
const writer = new SimpleResponseWriter();
|
||||
let response: MockResponse<any>;
|
||||
|
||||
beforeEach(async(): Promise<void> => {
|
||||
response = createResponse({ eventEmitter: EventEmitter });
|
||||
});
|
||||
|
||||
it('can handle input that has at least a description or an error.', async(): Promise<void> => {
|
||||
await expect(writer.canHandle({ response, description: {} as ResponseDescription })).resolves.toBeUndefined();
|
||||
await expect(writer.canHandle({ response, error: {} as Error })).resolves.toBeUndefined();
|
||||
await expect(writer.canHandle({ response })).rejects.toThrow(UnsupportedHttpError);
|
||||
});
|
||||
|
||||
it('responds with status code 200 and a location header if there is a description.', async(): Promise<void> => {
|
||||
await writer.handle({ response, description: { identifier: { path: 'path' }}});
|
||||
expect(response._isEndCalled()).toBeTruthy();
|
||||
expect(response._getStatusCode()).toBe(200);
|
||||
expect(response._getHeaders()).toMatchObject({ location: 'path' });
|
||||
});
|
||||
|
||||
it('responds with a body if the description has a body.', async(done): Promise<void> => {
|
||||
const body = {
|
||||
data: streamifyArray([ '<http://test.com/s> <http://test.com/p> <http://test.com/o>.' ]),
|
||||
dataType: 'binary',
|
||||
metadata: {
|
||||
raw: [] as Quad[],
|
||||
profiles: [] as string[],
|
||||
},
|
||||
};
|
||||
|
||||
response.on('end', (): void => {
|
||||
expect(response._isEndCalled()).toBeTruthy();
|
||||
expect(response._getStatusCode()).toBe(200);
|
||||
expect(response._getHeaders()).toMatchObject({ location: 'path' });
|
||||
expect(response._getData()).toEqual('<http://test.com/s> <http://test.com/p> <http://test.com/o>.');
|
||||
done();
|
||||
});
|
||||
|
||||
await writer.handle({ response, description: { identifier: { path: 'path' }, body }});
|
||||
});
|
||||
|
||||
it('responds with a content-type if the metadata has it.', async(done): Promise<void> => {
|
||||
const body = {
|
||||
data: streamifyArray([ '<http://test.com/s> <http://test.com/p> <http://test.com/o>.' ]),
|
||||
dataType: 'binary',
|
||||
metadata: {
|
||||
raw: [] as Quad[],
|
||||
profiles: [] as string[],
|
||||
contentType: 'text/turtle',
|
||||
},
|
||||
};
|
||||
|
||||
response.on('end', (): void => {
|
||||
expect(response._isEndCalled()).toBeTruthy();
|
||||
expect(response._getStatusCode()).toBe(200);
|
||||
expect(response._getHeaders()).toMatchObject({ location: 'path', 'content-type': 'text/turtle' });
|
||||
expect(response._getData()).toEqual('<http://test.com/s> <http://test.com/p> <http://test.com/o>.');
|
||||
done();
|
||||
});
|
||||
|
||||
await writer.handle({ response, description: { identifier: { path: 'path' }, body }});
|
||||
});
|
||||
|
||||
it('responds with 500 if an error if there is an error.', async(): Promise<void> => {
|
||||
await writer.handle({ response, error: new Error('error') });
|
||||
expect(response._isEndCalled()).toBeTruthy();
|
||||
expect(response._getStatusCode()).toBe(500);
|
||||
expect(response._getData()).toMatch('Error: error');
|
||||
});
|
||||
|
||||
it('responds with the given statuscode if there is an HttpError.', async(): Promise<void> => {
|
||||
const error = new UnsupportedHttpError('error');
|
||||
await writer.handle({ response, error });
|
||||
expect(response._isEndCalled()).toBeTruthy();
|
||||
expect(response._getStatusCode()).toBe(error.statusCode);
|
||||
expect(response._getData()).toMatch('UnsupportedHttpError: error');
|
||||
});
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user