CommunitySolidServer/test/unit/storage/LockingResourceStore.test.ts
2020-07-17 15:26:32 +02:00

98 lines
4.5 KiB
TypeScript

import { Lock } from '../../../src/storage/Lock';
import { LockingResourceStore } from '../../../src/storage/LockingResourceStore';
import { ResourceLocker } from '../../../src/storage/ResourceLocker';
import { ResourceStore } from '../../../src/storage/ResourceStore';
describe('A LockingResourceStore', (): void => {
let store: LockingResourceStore;
let locker: ResourceLocker;
let lock: Lock;
let release: () => Promise<void>;
let source: ResourceStore;
let order: string[];
beforeEach(async(): Promise<void> => {
order = [];
const delayedResolve = (resolve: () => void, name: string): void => {
// `setImmediate` is introduced to make sure the promise doesn't execute immediately
setImmediate((): void => {
order.push(name);
resolve();
});
};
source = {
getRepresentation: jest.fn(async(): Promise<any> => new Promise((resolve): any => delayedResolve(resolve, 'getRepresentation'))),
addResource: jest.fn(async(): Promise<any> => new Promise((resolve): any => delayedResolve(resolve, 'addResource'))),
setRepresentation: jest.fn(async(): Promise<any> => new Promise((resolve): any => delayedResolve(resolve, 'setRepresentation'))),
deleteResource: jest.fn(async(): Promise<any> => new Promise((resolve): any => delayedResolve(resolve, 'deleteResource'))),
modifyResource: jest.fn(async(): Promise<any> => new Promise((resolve): any => delayedResolve(resolve, 'modifyResource'))),
};
release = jest.fn(async(): Promise<any> => order.push('release'));
locker = {
acquire: jest.fn(async(): Promise<any> => {
order.push('acquire');
lock = { release };
return lock;
}),
};
store = new LockingResourceStore(source, locker);
});
it('acquires a lock on the resource when getting it.', async(): Promise<void> => {
await store.getRepresentation({ path: 'path' }, null);
expect(locker.acquire).toHaveBeenCalledTimes(1);
expect(locker.acquire).toHaveBeenLastCalledWith({ path: 'path' });
expect(source.getRepresentation).toHaveBeenCalledTimes(1);
expect(lock.release).toHaveBeenCalledTimes(1);
expect(order).toEqual([ 'acquire', 'getRepresentation', 'release' ]);
});
it('acquires a lock on the container when adding a representation.', async(): Promise<void> => {
await store.addResource({ path: 'path' }, null);
expect(locker.acquire).toHaveBeenCalledTimes(1);
expect(locker.acquire).toHaveBeenLastCalledWith({ path: 'path' });
expect(source.addResource).toHaveBeenCalledTimes(1);
expect(lock.release).toHaveBeenCalledTimes(1);
expect(order).toEqual([ 'acquire', 'addResource', 'release' ]);
});
it('acquires a lock on the resource when setting its representation.', async(): Promise<void> => {
await store.setRepresentation({ path: 'path' }, null);
expect(locker.acquire).toHaveBeenCalledTimes(1);
expect(locker.acquire).toHaveBeenLastCalledWith({ path: 'path' });
expect(source.setRepresentation).toHaveBeenCalledTimes(1);
expect(lock.release).toHaveBeenCalledTimes(1);
expect(order).toEqual([ 'acquire', 'setRepresentation', 'release' ]);
});
it('acquires a lock on the resource when deleting it.', async(): Promise<void> => {
await store.deleteResource({ path: 'path' });
expect(locker.acquire).toHaveBeenCalledTimes(1);
expect(locker.acquire).toHaveBeenLastCalledWith({ path: 'path' });
expect(source.deleteResource).toHaveBeenCalledTimes(1);
expect(lock.release).toHaveBeenCalledTimes(1);
expect(order).toEqual([ 'acquire', 'deleteResource', 'release' ]);
});
it('acquires a lock on the resource when modifying its representation.', async(): Promise<void> => {
await store.modifyResource({ path: 'path' }, null);
expect(locker.acquire).toHaveBeenCalledTimes(1);
expect(locker.acquire).toHaveBeenLastCalledWith({ path: 'path' });
expect(source.modifyResource).toHaveBeenCalledTimes(1);
expect(lock.release).toHaveBeenCalledTimes(1);
expect(order).toEqual([ 'acquire', 'modifyResource', 'release' ]);
});
it('releases the lock if an error was thrown.', async(): Promise<void> => {
source.getRepresentation = async(): Promise<any> => {
throw new Error('dummy');
};
await expect(store.getRepresentation({ path: 'path' }, null)).rejects.toThrow('dummy');
expect(locker.acquire).toHaveBeenCalledTimes(1);
expect(locker.acquire).toHaveBeenLastCalledWith({ path: 'path' });
expect(lock.release).toHaveBeenCalledTimes(1);
expect(order).toEqual([ 'acquire', 'release' ]);
});
});