mirror of
https://github.com/CommunitySolidServer/CommunitySolidServer.git
synced 2024-10-03 14:55:10 +00:00
feat: Create ConditionalHandler
This handler rejects all inputs once a certain condition is met
This commit is contained in:
parent
fb0b50c997
commit
facf691e86
@ -307,6 +307,7 @@ export * from './util/errors/UnsupportedMediaTypeHttpError';
|
||||
// Util/Handlers
|
||||
export * from './util/handlers/AsyncHandler';
|
||||
export * from './util/handlers/BooleanHandler';
|
||||
export * from './util/handlers/ConditionalHandler';
|
||||
export * from './util/handlers/ParallelHandler';
|
||||
export * from './util/handlers/SequenceHandler';
|
||||
export * from './util/handlers/UnsupportedAsyncHandler';
|
||||
|
57
src/util/handlers/ConditionalHandler.ts
Normal file
57
src/util/handlers/ConditionalHandler.ts
Normal file
@ -0,0 +1,57 @@
|
||||
import type { KeyValueStorage } from '../../storage/keyvalue/KeyValueStorage';
|
||||
import { NotImplementedHttpError } from '../errors/NotImplementedHttpError';
|
||||
import { AsyncHandler } from './AsyncHandler';
|
||||
|
||||
/**
|
||||
* This handler will pass all requests to the wrapped handler,
|
||||
* until a specific value has been set in the given storage.
|
||||
* After that all input will be rejected.
|
||||
* Once the value has been matched this behaviour will be cached,
|
||||
* so changing the value again afterwards will not enable this handler again.
|
||||
*/
|
||||
export class ConditionalHandler<TIn, TOut> extends AsyncHandler<TIn, TOut> {
|
||||
private readonly source: AsyncHandler<TIn, TOut>;
|
||||
private readonly storage: KeyValueStorage<string, unknown>;
|
||||
private readonly storageKey: string;
|
||||
private readonly storageValue: unknown;
|
||||
|
||||
private finished: boolean;
|
||||
|
||||
public constructor(source: AsyncHandler<TIn, TOut>, storage: KeyValueStorage<string, unknown>, storageKey: string,
|
||||
storageValue: unknown) {
|
||||
super();
|
||||
this.source = source;
|
||||
this.storage = storage;
|
||||
this.storageKey = storageKey;
|
||||
this.storageValue = storageValue;
|
||||
|
||||
this.finished = false;
|
||||
}
|
||||
|
||||
public async canHandle(input: TIn): Promise<void> {
|
||||
await this.checkCondition();
|
||||
await this.source.canHandle(input);
|
||||
}
|
||||
|
||||
public async handleSafe(input: TIn): Promise<TOut> {
|
||||
await this.checkCondition();
|
||||
return this.source.handleSafe(input);
|
||||
}
|
||||
|
||||
public async handle(input: TIn): Promise<TOut> {
|
||||
return this.source.handle(input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the condition has already been fulfilled.
|
||||
*/
|
||||
private async checkCondition(): Promise<void> {
|
||||
if (!this.finished) {
|
||||
this.finished = await this.storage.get(this.storageKey) === this.storageValue;
|
||||
}
|
||||
|
||||
if (this.finished) {
|
||||
throw new NotImplementedHttpError('The condition has been fulfilled.');
|
||||
}
|
||||
}
|
||||
}
|
68
test/unit/util/handlers/ConditionalHandler.test.ts
Normal file
68
test/unit/util/handlers/ConditionalHandler.test.ts
Normal file
@ -0,0 +1,68 @@
|
||||
import type { KeyValueStorage } from '../../../../src/storage/keyvalue/KeyValueStorage';
|
||||
import { NotImplementedHttpError } from '../../../../src/util/errors/NotImplementedHttpError';
|
||||
import type { AsyncHandler } from '../../../../src/util/handlers/AsyncHandler';
|
||||
import { ConditionalHandler } from '../../../../src/util/handlers/ConditionalHandler';
|
||||
|
||||
describe('A ConditionalHandler', (): void => {
|
||||
const storageKey = 'completed';
|
||||
const storageValue = true;
|
||||
const input = 'input';
|
||||
let storage: KeyValueStorage<string, unknown>;
|
||||
let source: jest.Mocked<AsyncHandler<string, string>>;
|
||||
let handler: ConditionalHandler<string, string>;
|
||||
|
||||
beforeEach(async(): Promise<void> => {
|
||||
storage = new Map<string, boolean>() as any;
|
||||
source = {
|
||||
canHandle: jest.fn(),
|
||||
handleSafe: jest.fn().mockResolvedValue('handledSafely'),
|
||||
handle: jest.fn().mockResolvedValue('handled'),
|
||||
};
|
||||
|
||||
handler = new ConditionalHandler(source, storage, storageKey, storageValue);
|
||||
});
|
||||
|
||||
it('send canHandle input to the source.', async(): Promise<void> => {
|
||||
await expect(handler.canHandle(input)).resolves.toBeUndefined();
|
||||
expect(source.canHandle).toHaveBeenCalledTimes(1);
|
||||
expect(source.canHandle).toHaveBeenLastCalledWith(input);
|
||||
});
|
||||
|
||||
it('rejects all canHandle requests once the storage value matches.', async(): Promise<void> => {
|
||||
await storage.set(storageKey, storageValue);
|
||||
await expect(handler.canHandle(input)).rejects.toThrow(NotImplementedHttpError);
|
||||
expect(source.canHandle).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
it('caches the value of the storage.', async(): Promise<void> => {
|
||||
await storage.set(storageKey, storageValue);
|
||||
await expect(handler.canHandle(input)).rejects.toThrow(NotImplementedHttpError);
|
||||
await storage.delete(storageKey);
|
||||
await expect(handler.canHandle(input)).rejects.toThrow(NotImplementedHttpError);
|
||||
});
|
||||
|
||||
it('redirects input to the source handleSafe call.', async(): Promise<void> => {
|
||||
await expect(handler.handleSafe(input)).resolves.toBe('handledSafely');
|
||||
expect(source.handleSafe).toHaveBeenCalledTimes(1);
|
||||
expect(source.handleSafe).toHaveBeenLastCalledWith(input);
|
||||
});
|
||||
|
||||
it('rejects all handleSafe requests once the storage value matches.', async(): Promise<void> => {
|
||||
await storage.set(storageKey, storageValue);
|
||||
await expect(handler.handleSafe(input)).rejects.toThrow(NotImplementedHttpError);
|
||||
expect(source.handleSafe).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
it('redirects input to the source handle call.', async(): Promise<void> => {
|
||||
await expect(handler.handle(input)).resolves.toBe('handled');
|
||||
expect(source.handle).toHaveBeenCalledTimes(1);
|
||||
expect(source.handle).toHaveBeenLastCalledWith(input);
|
||||
});
|
||||
|
||||
it('does not reject handle requests once the storage value matches.', async(): Promise<void> => {
|
||||
await storage.set(storageKey, storageValue);
|
||||
await expect(handler.handle(input)).resolves.toBe('handled');
|
||||
expect(source.handle).toHaveBeenCalledTimes(1);
|
||||
expect(source.handle).toHaveBeenLastCalledWith(input);
|
||||
});
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user