mirror of
https://github.com/CommunitySolidServer/CommunitySolidServer.git
synced 2024-10-03 14:55:10 +00:00
137 lines
7.3 KiB
TypeScript
137 lines
7.3 KiB
TypeScript
import { BasicRepresentation } from '../../../src/ldp/representation/BasicRepresentation';
|
|
import type { ResourceIdentifier } from '../../../src/ldp/representation/ResourceIdentifier';
|
|
import { IndexRepresentationStore } from '../../../src/storage/IndexRepresentationStore';
|
|
import type { ResourceStore } from '../../../src/storage/ResourceStore';
|
|
import { ConflictHttpError } from '../../../src/util/errors/ConflictHttpError';
|
|
import { NotFoundHttpError } from '../../../src/util/errors/NotFoundHttpError';
|
|
import { readableToString } from '../../../src/util/StreamUtil';
|
|
|
|
describe('An IndexRepresentationStore', (): void => {
|
|
const baseUrl = 'http://test.com/';
|
|
const emptyContainer = { path: `${baseUrl}/container/` };
|
|
let source: jest.Mocked<ResourceStore>;
|
|
let store: IndexRepresentationStore;
|
|
|
|
beforeEach(async(): Promise<void> => {
|
|
source = {
|
|
getRepresentation: jest.fn((identifier: ResourceIdentifier): any => {
|
|
if (identifier.path === `${baseUrl}index.html`) {
|
|
return new BasicRepresentation('index data', identifier, 'text/html');
|
|
}
|
|
if (identifier.path.endsWith('/')) {
|
|
return new BasicRepresentation('container data', identifier, 'text/turtle');
|
|
}
|
|
throw new NotFoundHttpError();
|
|
}),
|
|
} as any;
|
|
|
|
store = new IndexRepresentationStore(source);
|
|
});
|
|
|
|
it('errors on invalid index names.', async(): Promise<void> => {
|
|
expect((): any => new IndexRepresentationStore(source, '../secretContainer/secret.key'))
|
|
.toThrow('Invalid index name');
|
|
});
|
|
|
|
it('retrieves the index resource if it is explicitly preferred.', async(): Promise<void> => {
|
|
const preferences = { type: { 'text/turtle': 0.5, 'text/html': 0.8 }};
|
|
const result = await store.getRepresentation({ path: baseUrl }, preferences);
|
|
await expect(readableToString(result.data)).resolves.toBe('index data');
|
|
expect(source.getRepresentation).toHaveBeenCalledTimes(2);
|
|
expect(source.getRepresentation).toHaveBeenCalledWith({ path: `${baseUrl}index.html` }, preferences, undefined);
|
|
expect(source.getRepresentation).toHaveBeenLastCalledWith({ path: baseUrl }, {}, undefined);
|
|
|
|
// Use correct metadata
|
|
expect(result.metadata.identifier.value).toBe(baseUrl);
|
|
expect(result.metadata.contentType).toBe('text/html');
|
|
});
|
|
|
|
it('retrieves the index resource if there is a range preference.', async(): Promise<void> => {
|
|
const preferences = { type: { 'text/*': 0.8, 'other/other': 0.7 }};
|
|
const result = await store.getRepresentation({ path: baseUrl }, preferences);
|
|
await expect(readableToString(result.data)).resolves.toBe('index data');
|
|
expect(source.getRepresentation).toHaveBeenCalledTimes(2);
|
|
expect(source.getRepresentation).toHaveBeenCalledWith({ path: `${baseUrl}index.html` }, preferences, undefined);
|
|
expect(source.getRepresentation).toHaveBeenLastCalledWith({ path: baseUrl }, {}, undefined);
|
|
|
|
// Use correct metadata
|
|
expect(result.metadata.identifier.value).toBe(baseUrl);
|
|
expect(result.metadata.contentType).toBe('text/html');
|
|
});
|
|
|
|
it('does not retrieve the index resource if there are no type preferences.', async(): Promise<void> => {
|
|
const preferences = {};
|
|
const result = await store.getRepresentation({ path: baseUrl }, preferences);
|
|
await expect(readableToString(result.data)).resolves.toBe('container data');
|
|
expect(source.getRepresentation).toHaveBeenCalledTimes(1);
|
|
expect(source.getRepresentation).toHaveBeenLastCalledWith({ path: baseUrl }, preferences, undefined);
|
|
|
|
// Use correct metadata
|
|
expect(result.metadata.identifier.value).toBe(baseUrl);
|
|
expect(result.metadata.contentType).toBe('text/turtle');
|
|
});
|
|
|
|
it('does not retrieve the index resource on */*.', async(): Promise<void> => {
|
|
const preferences = { type: { '*/*': 1 }};
|
|
const result = await store.getRepresentation({ path: baseUrl }, preferences);
|
|
await expect(readableToString(result.data)).resolves.toBe('container data');
|
|
});
|
|
|
|
it('errors if a non-404 error was thrown when accessing the index resource.', async(): Promise<void> => {
|
|
const preferences = { type: { 'text/turtle': 0.5, 'text/html': 0.8 }};
|
|
source.getRepresentation.mockRejectedValueOnce(new ConflictHttpError('conflict!'));
|
|
await expect(store.getRepresentation({ path: baseUrl }, preferences)).rejects.toThrow('conflict!');
|
|
expect(source.getRepresentation).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it('requests the usual data if there is no index resource.', async(): Promise<void> => {
|
|
const preferences = { type: { 'text/turtle': 0.5, 'text/html': 0.8 }};
|
|
source.getRepresentation.mockRejectedValueOnce(new NotFoundHttpError());
|
|
const result = await store.getRepresentation(emptyContainer, preferences);
|
|
await expect(readableToString(result.data)).resolves.toBe('container data');
|
|
expect(source.getRepresentation).toHaveBeenCalledTimes(2);
|
|
expect(source.getRepresentation).toHaveBeenCalledWith(
|
|
{ path: `${emptyContainer.path}index.html` }, preferences, undefined,
|
|
);
|
|
expect(source.getRepresentation).toHaveBeenLastCalledWith(emptyContainer, preferences, undefined);
|
|
});
|
|
|
|
it('requests the usual data if the index media range is not the most preferred.', async(): Promise<void> => {
|
|
const preferences = { type: { 'text/turtle': 0.8, 'text/html': 0.5 }};
|
|
const result = await store.getRepresentation({ path: baseUrl }, preferences);
|
|
await expect(readableToString(result.data)).resolves.toBe('container data');
|
|
expect(source.getRepresentation).toHaveBeenCalledTimes(1);
|
|
expect(source.getRepresentation).toHaveBeenLastCalledWith({ path: baseUrl }, preferences, undefined);
|
|
});
|
|
|
|
it('returns the index resource if the media range is set to */*.', async(): Promise<void> => {
|
|
store = new IndexRepresentationStore(source, 'base.html', '*/*');
|
|
// Mocking because we also change the index name
|
|
source.getRepresentation.mockResolvedValueOnce(new BasicRepresentation('index data', 'text/html'));
|
|
|
|
const preferences = { type: { 'text/turtle': 0.8, 'text/html': 0.5 }};
|
|
const result = await store.getRepresentation({ path: baseUrl }, preferences);
|
|
await expect(readableToString(result.data)).resolves.toBe('index data');
|
|
expect(source.getRepresentation).toHaveBeenCalledTimes(2);
|
|
expect(source.getRepresentation).toHaveBeenCalledWith({ path: `${baseUrl}base.html` }, preferences, undefined);
|
|
expect(source.getRepresentation).toHaveBeenLastCalledWith({ path: baseUrl }, {}, undefined);
|
|
|
|
// Use correct metadata
|
|
expect(result.metadata.identifier.value).toBe(baseUrl);
|
|
expect(result.metadata.contentType).toBe('text/html');
|
|
});
|
|
|
|
it('returns the index resource if media range and Accept header are */*.', async(): Promise<void> => {
|
|
store = new IndexRepresentationStore(source, 'base.html', '*/*');
|
|
// Mocking because we also change the index name
|
|
source.getRepresentation.mockResolvedValueOnce(new BasicRepresentation('index data', 'text/html'));
|
|
|
|
const preferences = { type: { '*/*': 1 }};
|
|
const result = await store.getRepresentation({ path: baseUrl }, preferences);
|
|
await expect(readableToString(result.data)).resolves.toBe('index data');
|
|
expect(source.getRepresentation).toHaveBeenCalledTimes(2);
|
|
expect(source.getRepresentation).toHaveBeenCalledWith({ path: `${baseUrl}base.html` }, preferences, undefined);
|
|
expect(source.getRepresentation).toHaveBeenLastCalledWith({ path: baseUrl }, {}, undefined);
|
|
});
|
|
});
|