mirror of
https://github.com/CommunitySolidServer/CommunitySolidServer.git
synced 2024-10-03 14:55:10 +00:00
refactor: Restructure source code folder
This way the location of certain classes should make more sense
This commit is contained in:
84
test/unit/http/auxiliary/ComposedAuxiliaryStrategy.test.ts
Normal file
84
test/unit/http/auxiliary/ComposedAuxiliaryStrategy.test.ts
Normal file
@@ -0,0 +1,84 @@
|
||||
import type { AuxiliaryIdentifierStrategy } from '../../../../src/http/auxiliary/AuxiliaryIdentifierStrategy';
|
||||
import { ComposedAuxiliaryStrategy } from '../../../../src/http/auxiliary/ComposedAuxiliaryStrategy';
|
||||
import type { MetadataGenerator } from '../../../../src/http/auxiliary/MetadataGenerator';
|
||||
import type { Validator } from '../../../../src/http/auxiliary/Validator';
|
||||
import { RepresentationMetadata } from '../../../../src/http/representation/RepresentationMetadata';
|
||||
|
||||
describe('A ComposedAuxiliaryStrategy', (): void => {
|
||||
const identifier = { path: 'http://test.com/foo' };
|
||||
let identifierStrategy: AuxiliaryIdentifierStrategy;
|
||||
let metadataGenerator: MetadataGenerator;
|
||||
let validator: Validator;
|
||||
let strategy: ComposedAuxiliaryStrategy;
|
||||
|
||||
beforeEach(async(): Promise<void> => {
|
||||
identifierStrategy = {
|
||||
getAuxiliaryIdentifier: jest.fn(),
|
||||
getAuxiliaryIdentifiers: jest.fn(),
|
||||
getSubjectIdentifier: jest.fn(),
|
||||
isAuxiliaryIdentifier: jest.fn(),
|
||||
};
|
||||
metadataGenerator = {
|
||||
handleSafe: jest.fn(),
|
||||
} as any;
|
||||
validator = {
|
||||
handleSafe: jest.fn(),
|
||||
} as any;
|
||||
strategy = new ComposedAuxiliaryStrategy(identifierStrategy, metadataGenerator, validator, false, true);
|
||||
});
|
||||
|
||||
it('calls the AuxiliaryIdentifierStrategy for related calls.', async(): Promise<void> => {
|
||||
strategy.getAuxiliaryIdentifier(identifier);
|
||||
expect(identifierStrategy.getAuxiliaryIdentifier).toHaveBeenCalledTimes(1);
|
||||
expect(identifierStrategy.getAuxiliaryIdentifier).toHaveBeenLastCalledWith(identifier);
|
||||
|
||||
strategy.getAuxiliaryIdentifiers(identifier);
|
||||
expect(identifierStrategy.getAuxiliaryIdentifiers).toHaveBeenCalledTimes(1);
|
||||
expect(identifierStrategy.getAuxiliaryIdentifiers).toHaveBeenLastCalledWith(identifier);
|
||||
|
||||
strategy.getSubjectIdentifier(identifier);
|
||||
expect(identifierStrategy.getSubjectIdentifier).toHaveBeenCalledTimes(1);
|
||||
expect(identifierStrategy.getSubjectIdentifier).toHaveBeenLastCalledWith(identifier);
|
||||
|
||||
strategy.isAuxiliaryIdentifier(identifier);
|
||||
expect(identifierStrategy.isAuxiliaryIdentifier).toHaveBeenCalledTimes(1);
|
||||
expect(identifierStrategy.isAuxiliaryIdentifier).toHaveBeenLastCalledWith(identifier);
|
||||
});
|
||||
|
||||
it('returns the injected value for usesOwnAuthorization.', async(): Promise<void> => {
|
||||
expect(strategy.usesOwnAuthorization()).toBe(false);
|
||||
});
|
||||
|
||||
it('returns the injected value for isRequiredInRoot.', async(): Promise<void> => {
|
||||
expect(strategy.isRequiredInRoot()).toBe(true);
|
||||
});
|
||||
|
||||
it('adds metadata through the MetadataGenerator.', async(): Promise<void> => {
|
||||
const metadata = new RepresentationMetadata();
|
||||
await expect(strategy.addMetadata(metadata)).resolves.toBeUndefined();
|
||||
expect(metadataGenerator.handleSafe).toHaveBeenCalledTimes(1);
|
||||
expect(metadataGenerator.handleSafe).toHaveBeenLastCalledWith(metadata);
|
||||
});
|
||||
|
||||
it('validates data through the Validator.', async(): Promise<void> => {
|
||||
const representation = { data: 'data!' } as any;
|
||||
await expect(strategy.validate(representation)).resolves.toBeUndefined();
|
||||
expect(validator.handleSafe).toHaveBeenCalledTimes(1);
|
||||
expect(validator.handleSafe).toHaveBeenLastCalledWith(representation);
|
||||
});
|
||||
|
||||
it('defaults isRequiredInRoot to false.', async(): Promise<void> => {
|
||||
strategy = new ComposedAuxiliaryStrategy(identifierStrategy, metadataGenerator, validator);
|
||||
expect(strategy.isRequiredInRoot()).toBe(false);
|
||||
});
|
||||
|
||||
it('does not add metadata or validate if the corresponding classes are not injected.', async(): Promise<void> => {
|
||||
strategy = new ComposedAuxiliaryStrategy(identifierStrategy);
|
||||
|
||||
const metadata = new RepresentationMetadata();
|
||||
await expect(strategy.addMetadata(metadata)).resolves.toBeUndefined();
|
||||
|
||||
const representation = { data: 'data!' } as any;
|
||||
await expect(strategy.validate(representation)).resolves.toBeUndefined();
|
||||
});
|
||||
});
|
||||
41
test/unit/http/auxiliary/LinkMetadataGenerator.test.ts
Normal file
41
test/unit/http/auxiliary/LinkMetadataGenerator.test.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import type { AuxiliaryIdentifierStrategy } from '../../../../src/http/auxiliary/AuxiliaryIdentifierStrategy';
|
||||
import { LinkMetadataGenerator } from '../../../../src/http/auxiliary/LinkMetadataGenerator';
|
||||
import { RepresentationMetadata } from '../../../../src/http/representation/RepresentationMetadata';
|
||||
import type { ResourceIdentifier } from '../../../../src/http/representation/ResourceIdentifier';
|
||||
import { SOLID_META } from '../../../../src/util/Vocabularies';
|
||||
|
||||
describe('A LinkMetadataGenerator', (): void => {
|
||||
const link = 'link';
|
||||
const subjectId: ResourceIdentifier = { path: 'http://test.com/foo' };
|
||||
const auxiliaryId: ResourceIdentifier = { path: 'http://test.com/foo.dummy' };
|
||||
let generator: LinkMetadataGenerator;
|
||||
|
||||
beforeEach(async(): Promise<void> => {
|
||||
const strategy = {
|
||||
getAuxiliaryIdentifier: (identifier: ResourceIdentifier): ResourceIdentifier =>
|
||||
({ path: `${identifier.path}.dummy` }),
|
||||
isAuxiliaryIdentifier: (identifier: ResourceIdentifier): boolean => identifier.path.endsWith('.dummy'),
|
||||
getSubjectIdentifier: (identifier: ResourceIdentifier): ResourceIdentifier =>
|
||||
({ path: identifier.path.slice(0, -'.dummy'.length) }),
|
||||
} as AuxiliaryIdentifierStrategy;
|
||||
generator = new LinkMetadataGenerator(link, strategy);
|
||||
});
|
||||
|
||||
it('can handle all metadata.', async(): Promise<void> => {
|
||||
await expect(generator.canHandle(null as any)).resolves.toBeUndefined();
|
||||
});
|
||||
|
||||
it('stores no metadata if the input is a subject resource.', async(): Promise<void> => {
|
||||
const metadata = new RepresentationMetadata(auxiliaryId);
|
||||
await expect(generator.handle(metadata)).resolves.toBeUndefined();
|
||||
expect(metadata.quads()).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('uses the stored link to add metadata for subject resources.', async(): Promise<void> => {
|
||||
const metadata = new RepresentationMetadata(subjectId);
|
||||
await expect(generator.handle(metadata)).resolves.toBeUndefined();
|
||||
expect(metadata.quads()).toHaveLength(1);
|
||||
expect(metadata.get(link)?.value).toBe(auxiliaryId.path);
|
||||
expect(metadata.getAll(link, SOLID_META.terms.ResponseMetadata)).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
44
test/unit/http/auxiliary/RdfValidator.test.ts
Normal file
44
test/unit/http/auxiliary/RdfValidator.test.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import { RdfValidator } from '../../../../src/http/auxiliary/RdfValidator';
|
||||
import { BasicRepresentation } from '../../../../src/http/representation/BasicRepresentation';
|
||||
import type { RepresentationConverter } from '../../../../src/storage/conversion/RepresentationConverter';
|
||||
import { readableToString } from '../../../../src/util/StreamUtil';
|
||||
import { StaticAsyncHandler } from '../../../util/StaticAsyncHandler';
|
||||
import 'jest-rdf';
|
||||
|
||||
describe('An RdfValidator', (): void => {
|
||||
let converter: RepresentationConverter;
|
||||
let validator: RdfValidator;
|
||||
|
||||
beforeEach(async(): Promise<void> => {
|
||||
converter = new StaticAsyncHandler<any>(true, null);
|
||||
validator = new RdfValidator(converter);
|
||||
});
|
||||
|
||||
it('can handle all representations.', async(): Promise<void> => {
|
||||
await expect(validator.canHandle(null as any)).resolves.toBeUndefined();
|
||||
});
|
||||
|
||||
it('always accepts content-type internal/quads.', async(): Promise<void> => {
|
||||
const representation = new BasicRepresentation('data', 'internal/quads');
|
||||
await expect(validator.handle(representation)).resolves.toBeUndefined();
|
||||
});
|
||||
|
||||
it('validates data by running it through a converter.', async(): Promise<void> => {
|
||||
converter.handleSafe = jest.fn().mockResolvedValue(new BasicRepresentation('transformedData', 'wrongType'));
|
||||
const representation = new BasicRepresentation('data', 'content-type');
|
||||
const quads = representation.metadata.quads();
|
||||
await expect(validator.handle(representation)).resolves.toBeUndefined();
|
||||
// Make sure the data can still be streamed
|
||||
await expect(readableToString(representation.data)).resolves.toBe('data');
|
||||
// Make sure the metadata was not changed
|
||||
expect(quads).toBeRdfIsomorphic(representation.metadata.quads());
|
||||
});
|
||||
|
||||
it('throws an error when validating invalid data.', async(): Promise<void> => {
|
||||
converter.handleSafe = jest.fn().mockRejectedValue(new Error('bad data!'));
|
||||
const representation = new BasicRepresentation('data', 'content-type');
|
||||
await expect(validator.handle(representation)).rejects.toThrow('bad data!');
|
||||
// Make sure the data on the readable has not been reset
|
||||
expect(representation.data.destroyed).toBe(true);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,66 @@
|
||||
import type { AuxiliaryIdentifierStrategy } from '../../../../src/http/auxiliary/AuxiliaryIdentifierStrategy';
|
||||
import { RoutingAuxiliaryIdentifierStrategy } from '../../../../src/http/auxiliary/RoutingAuxiliaryIdentifierStrategy';
|
||||
import type { ResourceIdentifier } from '../../../../src/http/representation/ResourceIdentifier';
|
||||
import { InternalServerError } from '../../../../src/util/errors/InternalServerError';
|
||||
import { NotImplementedHttpError } from '../../../../src/util/errors/NotImplementedHttpError';
|
||||
|
||||
class SimpleSuffixStrategy implements AuxiliaryIdentifierStrategy {
|
||||
private readonly suffix: string;
|
||||
|
||||
public constructor(suffix: string) {
|
||||
this.suffix = suffix;
|
||||
}
|
||||
|
||||
public getAuxiliaryIdentifier(identifier: ResourceIdentifier): ResourceIdentifier {
|
||||
return { path: `${identifier.path}${this.suffix}` };
|
||||
}
|
||||
|
||||
public getAuxiliaryIdentifiers(identifier: ResourceIdentifier): ResourceIdentifier[] {
|
||||
return [ this.getAuxiliaryIdentifier(identifier) ];
|
||||
}
|
||||
|
||||
public isAuxiliaryIdentifier(identifier: ResourceIdentifier): boolean {
|
||||
return identifier.path.endsWith(this.suffix);
|
||||
}
|
||||
|
||||
public getSubjectIdentifier(identifier: ResourceIdentifier): ResourceIdentifier {
|
||||
return { path: identifier.path.slice(0, -this.suffix.length) };
|
||||
}
|
||||
}
|
||||
|
||||
describe('A RoutingAuxiliaryIdentifierStrategy', (): void => {
|
||||
let sources: SimpleSuffixStrategy[];
|
||||
let strategy: RoutingAuxiliaryIdentifierStrategy;
|
||||
const baseId = { path: 'http://test.com/foo' };
|
||||
const dummy1Id = { path: 'http://test.com/foo.dummy1' };
|
||||
const dummy2Id = { path: 'http://test.com/foo.dummy2' };
|
||||
const dummy3Id = { path: 'http://test.com/foo.dummy3' };
|
||||
|
||||
beforeEach(async(): Promise<void> => {
|
||||
sources = [
|
||||
new SimpleSuffixStrategy('.dummy1'),
|
||||
new SimpleSuffixStrategy('.dummy2'),
|
||||
];
|
||||
strategy = new RoutingAuxiliaryIdentifierStrategy(sources);
|
||||
});
|
||||
|
||||
it('#getAuxiliaryIdentifier always errors.', async(): Promise<void> => {
|
||||
expect((): any => strategy.getAuxiliaryIdentifier()).toThrow(InternalServerError);
|
||||
});
|
||||
|
||||
it('#getAuxiliaryIdentifiers returns results of all sources.', async(): Promise<void> => {
|
||||
expect(strategy.getAuxiliaryIdentifiers(baseId)).toEqual([ dummy1Id, dummy2Id ]);
|
||||
});
|
||||
|
||||
it('#isAuxiliaryIdentifier returns true if there is at least 1 match.', async(): Promise<void> => {
|
||||
expect(strategy.isAuxiliaryIdentifier(dummy1Id)).toBe(true);
|
||||
expect(strategy.isAuxiliaryIdentifier(dummy2Id)).toBe(true);
|
||||
expect(strategy.isAuxiliaryIdentifier(dummy3Id)).toBe(false);
|
||||
});
|
||||
|
||||
it('#getSubjectIdentifier returns the base id if a match is found.', async(): Promise<void> => {
|
||||
expect(strategy.getSubjectIdentifier(dummy1Id)).toEqual(baseId);
|
||||
expect(strategy.getSubjectIdentifier(dummy2Id)).toEqual(baseId);
|
||||
expect((): any => strategy.getSubjectIdentifier(dummy3Id)).toThrow(NotImplementedHttpError);
|
||||
});
|
||||
});
|
||||
119
test/unit/http/auxiliary/RoutingAuxiliaryStrategy.test.ts
Normal file
119
test/unit/http/auxiliary/RoutingAuxiliaryStrategy.test.ts
Normal file
@@ -0,0 +1,119 @@
|
||||
import type { AuxiliaryStrategy } from '../../../../src/http/auxiliary/AuxiliaryStrategy';
|
||||
import { RoutingAuxiliaryStrategy } from '../../../../src/http/auxiliary/RoutingAuxiliaryStrategy';
|
||||
import { RepresentationMetadata } from '../../../../src/http/representation/RepresentationMetadata';
|
||||
import type { ResourceIdentifier } from '../../../../src/http/representation/ResourceIdentifier';
|
||||
import { NotImplementedHttpError } from '../../../../src/util/errors/NotImplementedHttpError';
|
||||
|
||||
class SimpleSuffixStrategy implements AuxiliaryStrategy {
|
||||
private readonly suffix: string;
|
||||
|
||||
public constructor(suffix: string) {
|
||||
this.suffix = suffix;
|
||||
}
|
||||
|
||||
public usesOwnAuthorization(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
public getAuxiliaryIdentifier(identifier: ResourceIdentifier): ResourceIdentifier {
|
||||
return { path: `${identifier.path}${this.suffix}` };
|
||||
}
|
||||
|
||||
public getAuxiliaryIdentifiers(identifier: ResourceIdentifier): ResourceIdentifier[] {
|
||||
return [ this.getAuxiliaryIdentifier(identifier) ];
|
||||
}
|
||||
|
||||
public isAuxiliaryIdentifier(identifier: ResourceIdentifier): boolean {
|
||||
return identifier.path.endsWith(this.suffix);
|
||||
}
|
||||
|
||||
public getSubjectIdentifier(identifier: ResourceIdentifier): ResourceIdentifier {
|
||||
return { path: identifier.path.slice(0, -this.suffix.length) };
|
||||
}
|
||||
|
||||
public isRequiredInRoot(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
public async addMetadata(): Promise<void> {
|
||||
// Empty fn
|
||||
}
|
||||
|
||||
public async validate(): Promise<void> {
|
||||
// Always validates
|
||||
}
|
||||
}
|
||||
|
||||
describe('A RoutingAuxiliaryStrategy', (): void => {
|
||||
let sources: SimpleSuffixStrategy[];
|
||||
let strategy: RoutingAuxiliaryStrategy;
|
||||
const baseId = { path: 'http://test.com/foo' };
|
||||
const dummy1Id = { path: 'http://test.com/foo.dummy1' };
|
||||
const dummy2Id = { path: 'http://test.com/foo.dummy2' };
|
||||
const dummy3Id = { path: 'http://test.com/foo.dummy3' };
|
||||
|
||||
beforeEach(async(): Promise<void> => {
|
||||
sources = [
|
||||
new SimpleSuffixStrategy('.dummy1'),
|
||||
new SimpleSuffixStrategy('.dummy2'),
|
||||
];
|
||||
strategy = new RoutingAuxiliaryStrategy(sources);
|
||||
});
|
||||
|
||||
it('#addMetadata adds the metadata of all sources for the base identifier.', async(): Promise<void> => {
|
||||
sources[0].addMetadata = jest.fn();
|
||||
sources[1].addMetadata = jest.fn();
|
||||
const metadata = new RepresentationMetadata(baseId);
|
||||
await expect(strategy.addMetadata(metadata)).resolves.toBeUndefined();
|
||||
expect(sources[0].addMetadata).toHaveBeenCalledTimes(1);
|
||||
expect(sources[0].addMetadata).toHaveBeenLastCalledWith(metadata);
|
||||
expect(sources[1].addMetadata).toHaveBeenCalledTimes(1);
|
||||
expect(sources[1].addMetadata).toHaveBeenLastCalledWith(metadata);
|
||||
});
|
||||
|
||||
it('#addMetadata adds the metadata of the correct source for auxiliary identifiers.', async(): Promise<void> => {
|
||||
sources[0].addMetadata = jest.fn();
|
||||
sources[1].addMetadata = jest.fn();
|
||||
const metadata = new RepresentationMetadata(dummy2Id);
|
||||
await expect(strategy.addMetadata(metadata)).resolves.toBeUndefined();
|
||||
expect(sources[0].addMetadata).toHaveBeenCalledTimes(0);
|
||||
expect(sources[1].addMetadata).toHaveBeenCalledTimes(1);
|
||||
expect(sources[1].addMetadata).toHaveBeenLastCalledWith(metadata);
|
||||
});
|
||||
|
||||
it('#usesOwnAuthorization returns the result of the correct source.', async(): Promise<void> => {
|
||||
sources[0].usesOwnAuthorization = jest.fn();
|
||||
sources[1].usesOwnAuthorization = jest.fn();
|
||||
strategy.usesOwnAuthorization(dummy2Id);
|
||||
expect(sources[0].usesOwnAuthorization).toHaveBeenCalledTimes(0);
|
||||
expect(sources[1].usesOwnAuthorization).toHaveBeenCalledTimes(1);
|
||||
expect(sources[1].usesOwnAuthorization).toHaveBeenLastCalledWith(dummy2Id);
|
||||
});
|
||||
|
||||
it('#isRequiredInRoot returns the result of the correct source.', async(): Promise<void> => {
|
||||
sources[0].isRequiredInRoot = jest.fn();
|
||||
sources[1].isRequiredInRoot = jest.fn();
|
||||
strategy.isRequiredInRoot(dummy2Id);
|
||||
expect(sources[0].isRequiredInRoot).toHaveBeenCalledTimes(0);
|
||||
expect(sources[1].isRequiredInRoot).toHaveBeenCalledTimes(1);
|
||||
expect(sources[1].isRequiredInRoot).toHaveBeenLastCalledWith(dummy2Id);
|
||||
});
|
||||
|
||||
it('#validates using the correct validator.', async(): Promise<void> => {
|
||||
sources[0].validate = jest.fn();
|
||||
sources[1].validate = jest.fn();
|
||||
|
||||
let metadata = new RepresentationMetadata(dummy1Id);
|
||||
await expect(strategy.validate({ metadata } as any)).resolves.toBeUndefined();
|
||||
expect(sources[0].validate).toHaveBeenCalledTimes(1);
|
||||
expect(sources[1].validate).toHaveBeenCalledTimes(0);
|
||||
|
||||
metadata = new RepresentationMetadata(dummy2Id);
|
||||
await expect(strategy.validate({ metadata } as any)).resolves.toBeUndefined();
|
||||
expect(sources[0].validate).toHaveBeenCalledTimes(1);
|
||||
expect(sources[1].validate).toHaveBeenCalledTimes(1);
|
||||
|
||||
metadata = new RepresentationMetadata(dummy3Id);
|
||||
await expect(strategy.validate({ metadata } as any)).rejects.toThrow(NotImplementedHttpError);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,41 @@
|
||||
import { SuffixAuxiliaryIdentifierStrategy } from '../../../../src/http/auxiliary/SuffixAuxiliaryIdentifierStrategy';
|
||||
import type { ResourceIdentifier } from '../../../../src/http/representation/ResourceIdentifier';
|
||||
import { InternalServerError } from '../../../../src/util/errors/InternalServerError';
|
||||
import 'jest-rdf';
|
||||
|
||||
const suffix = '.dummy';
|
||||
|
||||
describe('A SuffixAuxiliaryManager', (): void => {
|
||||
let strategy: SuffixAuxiliaryIdentifierStrategy;
|
||||
const subjectId: ResourceIdentifier = { path: 'http://test.com/foo' };
|
||||
const auxiliaryId: ResourceIdentifier = { path: 'http://test.com/foo.dummy' };
|
||||
|
||||
beforeEach(async(): Promise<void> => {
|
||||
strategy = new SuffixAuxiliaryIdentifierStrategy(suffix);
|
||||
});
|
||||
|
||||
it('errors if the suffix is empty.', async(): Promise<void> => {
|
||||
expect((): any => new SuffixAuxiliaryIdentifierStrategy('')).toThrow('Suffix length should be non-zero.');
|
||||
});
|
||||
|
||||
it('creates new identifiers by appending the suffix.', async(): Promise<void> => {
|
||||
expect(strategy.getAuxiliaryIdentifier(subjectId)).toEqual(auxiliaryId);
|
||||
});
|
||||
|
||||
it('returns the same single identifier when requesting all of them.', async(): Promise<void> => {
|
||||
expect(strategy.getAuxiliaryIdentifiers(subjectId)).toEqual([ auxiliaryId ]);
|
||||
});
|
||||
|
||||
it('checks the suffix to determine if an identifier is auxiliary.', async(): Promise<void> => {
|
||||
expect(strategy.isAuxiliaryIdentifier(subjectId)).toBe(false);
|
||||
expect(strategy.isAuxiliaryIdentifier(auxiliaryId)).toBe(true);
|
||||
});
|
||||
|
||||
it('errors when trying to get the subject id from a non-auxiliary identifier.', async(): Promise<void> => {
|
||||
expect((): any => strategy.getSubjectIdentifier(subjectId)).toThrow(InternalServerError);
|
||||
});
|
||||
|
||||
it('removes the suffix to create the subject identifier.', async(): Promise<void> => {
|
||||
expect(strategy.getSubjectIdentifier(auxiliaryId)).toEqual(subjectId);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user