chore: Add SPARQL endpoint logging.

This commit is contained in:
Ruben Verborgh 2020-10-31 22:22:22 +01:00 committed by Joachim Van Herwegen
parent ef6f01a82c
commit 17d774fc18
2 changed files with 59 additions and 7 deletions

View File

@ -17,6 +17,7 @@ import {
import type { Representation } from '../../ldp/representation/Representation'; import type { Representation } from '../../ldp/representation/Representation';
import { RepresentationMetadata } from '../../ldp/representation/RepresentationMetadata'; import { RepresentationMetadata } from '../../ldp/representation/RepresentationMetadata';
import type { ResourceIdentifier } from '../../ldp/representation/ResourceIdentifier'; import type { ResourceIdentifier } from '../../ldp/representation/ResourceIdentifier';
import { getLoggerFor } from '../../logging/LogUtil';
import { INTERNAL_QUADS } from '../../util/ContentTypes'; import { INTERNAL_QUADS } from '../../util/ContentTypes';
import { ConflictHttpError } from '../../util/errors/ConflictHttpError'; import { ConflictHttpError } from '../../util/errors/ConflictHttpError';
import { NotFoundHttpError } from '../../util/errors/NotFoundHttpError'; import { NotFoundHttpError } from '../../util/errors/NotFoundHttpError';
@ -44,6 +45,7 @@ const { defaultGraph, namedNode, quad, variable } = DataFactory;
* so those don't get overwritten. * so those don't get overwritten.
*/ */
export class SparqlDataAccessor implements DataAccessor { export class SparqlDataAccessor implements DataAccessor {
protected readonly logger = getLoggerFor(this);
private readonly endpoint: string; private readonly endpoint: string;
private readonly base: string; private readonly base: string;
private readonly containerManager: ContainerManager; private readonly containerManager: ContainerManager;
@ -298,7 +300,15 @@ export class SparqlDataAccessor implements DataAccessor {
*/ */
private async sendSparqlConstruct(sparqlQuery: ConstructQuery): Promise<Readable> { private async sendSparqlConstruct(sparqlQuery: ConstructQuery): Promise<Readable> {
const query = this.generator.stringify(sparqlQuery); const query = this.generator.stringify(sparqlQuery);
return await this.fetcher.fetchTriples(this.endpoint, query); this.logger.info(`Sending SPARQL CONSTRUCT query to ${this.endpoint}: ${query}`);
try {
return await this.fetcher.fetchTriples(this.endpoint, query);
} catch (error: unknown) {
if (error instanceof Error) {
this.logger.error(`SPARQL endpoint ${this.endpoint} error: ${error.message}`);
}
throw error;
}
} }
/** /**
@ -307,6 +317,14 @@ export class SparqlDataAccessor implements DataAccessor {
*/ */
private async sendSparqlUpdate(sparqlQuery: Update): Promise<void> { private async sendSparqlUpdate(sparqlQuery: Update): Promise<void> {
const query = this.generator.stringify(sparqlQuery); const query = this.generator.stringify(sparqlQuery);
return await this.fetcher.fetchUpdate(this.endpoint, query); this.logger.info(`Sending SPARQL UPDATE query to ${this.endpoint}: ${query}`);
try {
return await this.fetcher.fetchUpdate(this.endpoint, query);
} catch (error: unknown) {
if (error instanceof Error) {
this.logger.error(`SPARQL endpoint ${this.endpoint} error: ${error.message}`);
}
throw error;
}
} }
} }

View File

@ -35,14 +35,25 @@ describe('A SparqlDataAccessor', (): void => {
let fetchTriples: jest.Mock<Promise<Readable>>; let fetchTriples: jest.Mock<Promise<Readable>>;
let fetchUpdate: jest.Mock<Promise<void>>; let fetchUpdate: jest.Mock<Promise<void>>;
let triples: Quad[]; let triples: Quad[];
let fetchError: any;
let updateError: any;
beforeEach(async(): Promise<void> => { beforeEach(async(): Promise<void> => {
metadata = new RepresentationMetadata(); metadata = new RepresentationMetadata();
triples = [ quad(namedNode('this'), namedNode('a'), namedNode('triple')) ]; triples = [ quad(namedNode('this'), namedNode('a'), namedNode('triple')) ];
// Makes it so the `SparqlEndpointFetcher` will always return the contents of the `bindings` array // Makes it so the `SparqlEndpointFetcher` will always return the contents of the `triples` array
fetchTriples = jest.fn(async(): Promise<Readable> => streamifyArray(triples)); fetchTriples = jest.fn(async(): Promise<Readable> => {
fetchUpdate = jest.fn(async(): Promise<void> => undefined); if (fetchError) {
throw fetchError;
}
return streamifyArray(triples);
});
fetchUpdate = jest.fn(async(): Promise<void> => {
if (updateError) {
throw updateError;
}
});
(SparqlEndpointFetcher as any).mockImplementation((): any => ({ (SparqlEndpointFetcher as any).mockImplementation((): any => ({
fetchTriples, fetchTriples,
fetchUpdate, fetchUpdate,
@ -128,8 +139,8 @@ describe('A SparqlDataAccessor', (): void => {
}); });
it('throws 404 if no metadata was found.', async(): Promise<void> => { it('throws 404 if no metadata was found.', async(): Promise<void> => {
// Clear bindings array // Clear triples array
triples.splice(0, triples.length); triples = [];
await expect(accessor.getMetadata({ path: 'http://identifier' })).rejects.toThrow(NotFoundHttpError); await expect(accessor.getMetadata({ path: 'http://identifier' })).rejects.toThrow(NotFoundHttpError);
expect(fetchTriples).toHaveBeenCalledTimes(1); expect(fetchTriples).toHaveBeenCalledTimes(1);
@ -205,4 +216,27 @@ describe('A SparqlDataAccessor', (): void => {
await expect(accessor.writeDocument({ path: 'http://test.com/container/resource' }, data, metadata)) await expect(accessor.writeDocument({ path: 'http://test.com/container/resource' }, data, metadata))
.rejects.toThrow(new UnsupportedHttpError('Only triples in the default graph are supported.')); .rejects.toThrow(new UnsupportedHttpError('Only triples in the default graph are supported.'));
}); });
it('errors when the SPARQL endpoint fails during reading.', async(): Promise<void> => {
fetchError = 'error';
await expect(accessor.getMetadata({ path: 'http://identifier' })).rejects.toBe(fetchError);
fetchError = new Error();
await expect(accessor.getMetadata({ path: 'http://identifier' })).rejects.toThrow(fetchError);
fetchError = undefined;
});
it('errors when the SPARQL endpoint fails during writing.', async(): Promise<void> => {
const path = 'http://test.com/container/';
metadata = new RepresentationMetadata(path);
updateError = 'error';
await expect(accessor.writeContainer({ path }, metadata)).rejects.toBe(updateError);
updateError = new Error();
await expect(accessor.writeContainer({ path }, metadata)).rejects.toThrow(updateError);
updateError = undefined;
});
}); });