mirror of
https://github.com/CommunitySolidServer/CommunitySolidServer.git
synced 2024-10-03 14:55:10 +00:00
fix: Update resource size in ConstantConverter
This commit is contained in:
parent
4318479154
commit
6c30a2512b
@ -1,8 +1,15 @@
|
|||||||
|
import type { Stats } from 'node:fs';
|
||||||
import { createReadStream } from 'node:fs';
|
import { createReadStream } from 'node:fs';
|
||||||
|
import { stat } from 'fs-extra';
|
||||||
import { BasicRepresentation } from '../../http/representation/BasicRepresentation';
|
import { BasicRepresentation } from '../../http/representation/BasicRepresentation';
|
||||||
import type { Representation } from '../../http/representation/Representation';
|
import type { Representation } from '../../http/representation/Representation';
|
||||||
|
import { getLoggerFor } from '../../logging/LogUtil';
|
||||||
|
import { createErrorMessage } from '../../util/errors/ErrorUtil';
|
||||||
|
import { InternalServerError } from '../../util/errors/InternalServerError';
|
||||||
import { NotImplementedHttpError } from '../../util/errors/NotImplementedHttpError';
|
import { NotImplementedHttpError } from '../../util/errors/NotImplementedHttpError';
|
||||||
import { isContainerIdentifier } from '../../util/PathUtil';
|
import { isContainerIdentifier } from '../../util/PathUtil';
|
||||||
|
import { toLiteral } from '../../util/TermUtil';
|
||||||
|
import { POSIX, XSD } from '../../util/Vocabularies';
|
||||||
import { cleanPreferences, getTypeWeight, matchesMediaType } from './ConversionUtil';
|
import { cleanPreferences, getTypeWeight, matchesMediaType } from './ConversionUtil';
|
||||||
import { RepresentationConverter } from './RepresentationConverter';
|
import { RepresentationConverter } from './RepresentationConverter';
|
||||||
import type { RepresentationConverterArgs } from './RepresentationConverter';
|
import type { RepresentationConverterArgs } from './RepresentationConverter';
|
||||||
@ -46,6 +53,8 @@ export interface ConstantConverterOptions {
|
|||||||
* Options default to the most permissive values when not defined.
|
* Options default to the most permissive values when not defined.
|
||||||
*/
|
*/
|
||||||
export class ConstantConverter extends RepresentationConverter {
|
export class ConstantConverter extends RepresentationConverter {
|
||||||
|
private readonly logger = getLoggerFor(this);
|
||||||
|
|
||||||
private readonly filePath: string;
|
private readonly filePath: string;
|
||||||
private readonly contentType: string;
|
private readonly contentType: string;
|
||||||
private readonly options: Required<ConstantConverterOptions>;
|
private readonly options: Required<ConstantConverterOptions>;
|
||||||
@ -113,8 +122,19 @@ export class ConstantConverter extends RepresentationConverter {
|
|||||||
// Ignore the original representation
|
// Ignore the original representation
|
||||||
representation.data.destroy();
|
representation.data.destroy();
|
||||||
|
|
||||||
|
// Get the stats to have the correct size metadata
|
||||||
|
let stats: Stats;
|
||||||
|
try {
|
||||||
|
stats = await stat(this.filePath);
|
||||||
|
} catch (error: unknown) {
|
||||||
|
this.logger.error(`Unable to access ${this.filePath}: ${createErrorMessage(error)}`);
|
||||||
|
// Not giving out details in error as it contains internal server information
|
||||||
|
throw new InternalServerError(`Unable to access file used for constant conversion.`);
|
||||||
|
}
|
||||||
|
|
||||||
// Create a new representation from the constant file
|
// Create a new representation from the constant file
|
||||||
const data = createReadStream(this.filePath, 'utf8');
|
const data = createReadStream(this.filePath, 'utf8');
|
||||||
|
representation.metadata.set(POSIX.terms.size, toLiteral(stats.size, XSD.terms.integer));
|
||||||
return new BasicRepresentation(data, representation.metadata, this.contentType);
|
return new BasicRepresentation(data, representation.metadata, this.contentType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
import fs from 'node:fs';
|
import fs from 'node:fs';
|
||||||
|
import fsExtra from 'fs-extra';
|
||||||
import arrayifyStream from 'arrayify-stream';
|
import arrayifyStream from 'arrayify-stream';
|
||||||
import { RepresentationMetadata } from '../../../../src/http/representation/RepresentationMetadata';
|
import { RepresentationMetadata } from '../../../../src/http/representation/RepresentationMetadata';
|
||||||
import type { ConstantConverterOptions } from '../../../../src/storage/conversion/ConstantConverter';
|
import type { ConstantConverterOptions } from '../../../../src/storage/conversion/ConstantConverter';
|
||||||
import { ConstantConverter } from '../../../../src/storage/conversion/ConstantConverter';
|
import { ConstantConverter } from '../../../../src/storage/conversion/ConstantConverter';
|
||||||
import { CONTENT_TYPE } from '../../../../src/util/Vocabularies';
|
import { CONTENT_TYPE, POSIX } from '../../../../src/util/Vocabularies';
|
||||||
|
|
||||||
const createReadStream = jest.spyOn(fs, 'createReadStream').mockReturnValue('file contents' as any);
|
const createReadStream = jest.spyOn(fs, 'createReadStream').mockReturnValue('file contents' as any);
|
||||||
|
const stat = jest.spyOn(fsExtra, 'stat').mockReturnValue({ size: 100 } as any);
|
||||||
|
|
||||||
describe('A ConstantConverter', (): void => {
|
describe('A ConstantConverter', (): void => {
|
||||||
const identifier = { path: 'identifier' };
|
const identifier = { path: 'identifier' };
|
||||||
@ -13,6 +15,7 @@ describe('A ConstantConverter', (): void => {
|
|||||||
let converter: ConstantConverter;
|
let converter: ConstantConverter;
|
||||||
|
|
||||||
beforeEach(async(): Promise<void> => {
|
beforeEach(async(): Promise<void> => {
|
||||||
|
jest.clearAllMocks();
|
||||||
options = { container: true, document: true, minQuality: 1, enabledMediaRanges: [ '*/*' ], disabledMediaRanges: []};
|
options = { container: true, document: true, minQuality: 1, enabledMediaRanges: [ '*/*' ], disabledMediaRanges: []};
|
||||||
converter = new ConstantConverter('abc/def/index.html', 'text/html', options);
|
converter = new ConstantConverter('abc/def/index.html', 'text/html', options);
|
||||||
});
|
});
|
||||||
@ -99,7 +102,7 @@ describe('A ConstantConverter', (): void => {
|
|||||||
await expect(converter.canHandle(args)).resolves.toBeUndefined();
|
await expect(converter.canHandle(args)).resolves.toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('replaces the representation of a supported request.', async(): Promise<void> => {
|
it('replaces the representation of a supported request and replaces the size.', async(): Promise<void> => {
|
||||||
const preferences = { type: { 'text/html': 1 }};
|
const preferences = { type: { 'text/html': 1 }};
|
||||||
const metadata = new RepresentationMetadata({ [CONTENT_TYPE]: 'text/turtle' });
|
const metadata = new RepresentationMetadata({ [CONTENT_TYPE]: 'text/turtle' });
|
||||||
const representation = { metadata, data: { destroy: jest.fn() }} as any;
|
const representation = { metadata, data: { destroy: jest.fn() }} as any;
|
||||||
@ -114,9 +117,28 @@ describe('A ConstantConverter', (): void => {
|
|||||||
expect(createReadStream).toHaveBeenCalledWith('abc/def/index.html', 'utf8');
|
expect(createReadStream).toHaveBeenCalledWith('abc/def/index.html', 'utf8');
|
||||||
|
|
||||||
expect(converted.metadata.contentType).toBe('text/html');
|
expect(converted.metadata.contentType).toBe('text/html');
|
||||||
|
expect(converted.metadata.get(POSIX.terms.size)?.value).toBe('100');
|
||||||
await expect(arrayifyStream(converted.data)).resolves.toEqual([ 'file contents' ]);
|
await expect(arrayifyStream(converted.data)).resolves.toEqual([ 'file contents' ]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('throws an internal error if the file cannot be accessed.', async(): Promise<void> => {
|
||||||
|
const preferences = { type: { 'text/html': 1 }};
|
||||||
|
const metadata = new RepresentationMetadata({ [CONTENT_TYPE]: 'text/turtle' });
|
||||||
|
const representation = { metadata, data: { destroy: jest.fn() }} as any;
|
||||||
|
const args = { identifier, representation, preferences };
|
||||||
|
|
||||||
|
await expect(converter.canHandle(args)).resolves.toBeUndefined();
|
||||||
|
|
||||||
|
// eslint-disable-next-line ts/no-misused-promises
|
||||||
|
stat.mockImplementation(async(): Promise<never> => {
|
||||||
|
throw new Error('file not found');
|
||||||
|
});
|
||||||
|
|
||||||
|
await expect(converter.handle(args)).rejects.toThrow('Unable to access file used for constant conversion.');
|
||||||
|
expect(representation.data.destroy).toHaveBeenCalledTimes(1);
|
||||||
|
expect(createReadStream).toHaveBeenCalledTimes(0);
|
||||||
|
});
|
||||||
|
|
||||||
it('defaults to the most permissive options.', async(): Promise<void> => {
|
it('defaults to the most permissive options.', async(): Promise<void> => {
|
||||||
const preferences = { type: { 'text/html': 0.1 }};
|
const preferences = { type: { 'text/html': 0.1 }};
|
||||||
const metadata = new RepresentationMetadata();
|
const metadata = new RepresentationMetadata();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user