import * as url from 'url'; import { namedNode, quad } from '@rdfjs/data-model'; import { Parser } from 'n3'; import { MockResponse } from 'node-mocks-http'; import { SimpleCredentialsExtractor } from '../../src/authentication/SimpleCredentialsExtractor'; import { SimpleAuthorizer } from '../../src/authorization/SimpleAuthorizer'; import { RuntimeConfig } from '../../src/init/RuntimeConfig'; import { AuthenticatedLdpHandler } from '../../src/ldp/AuthenticatedLdpHandler'; import { AcceptPreferenceParser } from '../../src/ldp/http/AcceptPreferenceParser'; import { BodyParser } from '../../src/ldp/http/BodyParser'; import { SimpleBodyParser } from '../../src/ldp/http/SimpleBodyParser'; import { SimpleRequestParser } from '../../src/ldp/http/SimpleRequestParser'; import { SimpleResponseWriter } from '../../src/ldp/http/SimpleResponseWriter'; import { SimpleSparqlUpdateBodyParser } from '../../src/ldp/http/SimpleSparqlUpdateBodyParser'; import { SimpleTargetExtractor } from '../../src/ldp/http/SimpleTargetExtractor'; import { Operation } from '../../src/ldp/operations/Operation'; import { ResponseDescription } from '../../src/ldp/operations/ResponseDescription'; import { SimpleDeleteOperationHandler } from '../../src/ldp/operations/SimpleDeleteOperationHandler'; import { SimpleGetOperationHandler } from '../../src/ldp/operations/SimpleGetOperationHandler'; import { SimplePatchOperationHandler } from '../../src/ldp/operations/SimplePatchOperationHandler'; import { SimplePostOperationHandler } from '../../src/ldp/operations/SimplePostOperationHandler'; import { BasePermissionsExtractor } from '../../src/ldp/permissions/BasePermissionsExtractor'; import { SparqlPatchPermissionsExtractor } from '../../src/ldp/permissions/SparqlPatchPermissionsExtractor'; import { Representation } from '../../src/ldp/representation/Representation'; import { HttpRequest } from '../../src/server/HttpRequest'; import { QuadToTurtleConverter } from '../../src/storage/conversion/QuadToTurtleConverter'; import { TurtleToQuadConverter } from '../../src/storage/conversion/TurtleToQuadConverter'; import { SimpleSparqlUpdatePatchHandler } from '../../src/storage/patch/SimpleSparqlUpdatePatchHandler'; import { PatchingStore } from '../../src/storage/PatchingStore'; import { RepresentationConvertingStore } from '../../src/storage/RepresentationConvertingStore'; import { SimpleResourceStore } from '../../src/storage/SimpleResourceStore'; import { SingleThreadedResourceLocker } from '../../src/storage/SingleThreadedResourceLocker'; import { CompositeAsyncHandler } from '../../src/util/CompositeAsyncHandler'; import { call } from '../util/Util'; describe('An integrated AuthenticatedLdpHandler', (): void => { describe('with simple handlers', (): void => { const requestParser = new SimpleRequestParser({ targetExtractor: new SimpleTargetExtractor(), preferenceParser: new AcceptPreferenceParser(), bodyParser: new SimpleBodyParser(), }); const credentialsExtractor = new SimpleCredentialsExtractor(); const permissionsExtractor = new BasePermissionsExtractor(); const authorizer = new SimpleAuthorizer(); const store = new SimpleResourceStore(new RuntimeConfig({ base: 'http://test.com/' })); const operationHandler = new CompositeAsyncHandler([ new SimpleGetOperationHandler(store), new SimplePostOperationHandler(store), new SimpleDeleteOperationHandler(store), ]); const responseWriter = new SimpleResponseWriter(); const handler = new AuthenticatedLdpHandler({ requestParser, credentialsExtractor, permissionsExtractor, authorizer, operationHandler, responseWriter, }); it('can add, read and delete data based on incoming requests.', async(): Promise => { // POST let requestUrl = new URL('http://test.com/'); let response: MockResponse = await call( handler, requestUrl, 'POST', { 'content-type': 'text/turtle' }, [ ' .' ], ); expect(response.statusCode).toBe(200); expect(response._getData()).toHaveLength(0); const id = response._getHeaders().location; expect(id).toContain(url.format(requestUrl)); // GET requestUrl = new URL(id); response = await call(handler, requestUrl, 'GET', { accept: 'text/turtle' }, []); expect(response.statusCode).toBe(200); expect(response._getData()).toContain(' .'); expect(response._getHeaders().location).toBe(id); // DELETE response = await call(handler, requestUrl, 'DELETE', {}, []); expect(response.statusCode).toBe(200); expect(response._getData()).toHaveLength(0); expect(response._getHeaders().location).toBe(url.format(requestUrl)); // GET response = await call(handler, requestUrl, 'GET', { accept: 'text/turtle' }, []); expect(response.statusCode).toBe(404); expect(response._getData()).toContain('NotFoundHttpError'); }); }); describe('with simple PATCH handlers', (): void => { const bodyParser: BodyParser = new CompositeAsyncHandler([ new SimpleSparqlUpdateBodyParser(), new SimpleBodyParser(), ]); const requestParser = new SimpleRequestParser({ targetExtractor: new SimpleTargetExtractor(), preferenceParser: new AcceptPreferenceParser(), bodyParser, }); const credentialsExtractor = new SimpleCredentialsExtractor(); const permissionsExtractor = new CompositeAsyncHandler([ new BasePermissionsExtractor(), new SparqlPatchPermissionsExtractor(), ]); const authorizer = new SimpleAuthorizer(); const store = new SimpleResourceStore(new RuntimeConfig({ base: 'http://test.com/' })); const converter = new CompositeAsyncHandler([ new QuadToTurtleConverter(), new TurtleToQuadConverter(), ]); const convertingStore = new RepresentationConvertingStore(store, converter); const locker = new SingleThreadedResourceLocker(); const patcher = new SimpleSparqlUpdatePatchHandler(convertingStore, locker); const patchingStore = new PatchingStore(convertingStore, patcher); const operationHandler = new CompositeAsyncHandler([ new SimpleGetOperationHandler(patchingStore), new SimplePostOperationHandler(patchingStore), new SimpleDeleteOperationHandler(patchingStore), new SimplePatchOperationHandler(patchingStore), ]); const responseWriter = new SimpleResponseWriter(); const handler = new AuthenticatedLdpHandler({ requestParser, credentialsExtractor, permissionsExtractor, authorizer, operationHandler, responseWriter, }); it('can handle simple SPARQL updates.', async(): Promise => { // POST let requestUrl = new URL('http://test.com/'); let response: MockResponse = await call( handler, requestUrl, 'POST', { 'content-type': 'text/turtle' }, [ ' .', ' .' ], ); expect(response.statusCode).toBe(200); expect(response._getData()).toHaveLength(0); const id = response._getHeaders().location; expect(id).toContain(url.format(requestUrl)); // PATCH requestUrl = new URL(id); response = await call( handler, requestUrl, 'PATCH', { 'content-type': 'application/sparql-update' }, [ 'DELETE { }', 'INSERT { }', 'WHERE {}' ], ); expect(response.statusCode).toBe(200); expect(response._getData()).toHaveLength(0); expect(response._getHeaders().location).toBe(id); // GET requestUrl = new URL(id); response = await call(handler, requestUrl, 'GET', { accept: 'text/turtle' }, []); expect(response.statusCode).toBe(200); expect(response._getData()).toContain(' .'); expect(response._getHeaders().location).toBe(id); const parser = new Parser(); const triples = parser.parse(response._getData()); expect(triples).toBeRdfIsomorphic( [ quad(namedNode('http://test.com/s2'), namedNode('http://test.com/p2'), namedNode('http://test.com/o2')), quad(namedNode('http://test.com/s3'), namedNode('http://test.com/p3'), namedNode('http://test.com/o3')), ], ); }); }); });