mirror of
https://github.com/CommunitySolidServer/CommunitySolidServer.git
synced 2024-10-03 14:55:10 +00:00

Each IDP class using storage now has a different storage. This way those classes don't have to worry about clashing keys anymore. All internal storage is now in the /.internal/ container, thereby making it easier to take the location of the internal data into account: only 1 path needs to be blocked and a regex router handling internal data differently only has to match 1 path as well.
117 lines
5.3 KiB
TypeScript
117 lines
5.3 KiB
TypeScript
import type { AdapterPayload } from 'oidc-provider';
|
|
import type { ExpiringAdapter } from '../../../../src/identity/storage/ExpiringAdapterFactory';
|
|
import { ExpiringAdapterFactory } from '../../../../src/identity/storage/ExpiringAdapterFactory';
|
|
import type { ExpiringStorage } from '../../../../src/storage/keyvalue/ExpiringStorage';
|
|
|
|
// Use fixed dates
|
|
jest.useFakeTimers();
|
|
|
|
describe('An ExpiringAdapterFactory', (): void => {
|
|
const name = 'nnaammee';
|
|
const id = 'http://alice.test.com/card#me';
|
|
const grantId = 'grant123456';
|
|
let payload: AdapterPayload;
|
|
let storage: ExpiringStorage<string, unknown>;
|
|
let adapter: ExpiringAdapter;
|
|
let factory: ExpiringAdapterFactory;
|
|
const expiresIn = 333 * 1000;
|
|
|
|
beforeEach(async(): Promise<void> => {
|
|
payload = { data: 'data!' };
|
|
|
|
const map = new Map<string, any>();
|
|
storage = {
|
|
get: jest.fn().mockImplementation((key: string): any => map.get(key)),
|
|
set: jest.fn().mockImplementation((key: string, value: any): any => map.set(key, value)),
|
|
delete: jest.fn().mockImplementation((key: string): any => map.delete(key)),
|
|
} as any;
|
|
|
|
factory = new ExpiringAdapterFactory(storage);
|
|
adapter = factory.createStorageAdapter(name);
|
|
});
|
|
|
|
it('can find payload by id.', async(): Promise<void> => {
|
|
await expect(adapter.upsert(id, payload, 333)).resolves.toBeUndefined();
|
|
expect(storage.set).toHaveBeenCalledTimes(1);
|
|
expect(storage.set).toHaveBeenCalledWith(expect.anything(), payload, expiresIn);
|
|
await expect(adapter.find(id)).resolves.toBe(payload);
|
|
});
|
|
|
|
it('can store payloads without expiration time.', async(): Promise<void> => {
|
|
await expect(adapter.upsert(id, payload)).resolves.toBeUndefined();
|
|
expect(storage.set).toHaveBeenCalledTimes(1);
|
|
expect(storage.set).toHaveBeenCalledWith(expect.anything(), payload, undefined);
|
|
});
|
|
|
|
it('can find payload by userCode.', async(): Promise<void> => {
|
|
const userCode = 'userCode!';
|
|
payload.userCode = userCode;
|
|
await expect(adapter.upsert(id, payload, 333)).resolves.toBeUndefined();
|
|
expect(storage.set).toHaveBeenCalledTimes(2);
|
|
expect(storage.set).toHaveBeenCalledWith(expect.anything(), payload, expiresIn);
|
|
expect(storage.set).toHaveBeenCalledWith(expect.anything(), id, expiresIn);
|
|
await expect(adapter.findByUserCode(userCode)).resolves.toBe(payload);
|
|
});
|
|
|
|
it('can find payload by uid.', async(): Promise<void> => {
|
|
const uid = 'uid!';
|
|
payload.uid = uid;
|
|
await expect(adapter.upsert(id, payload, 333)).resolves.toBeUndefined();
|
|
expect(storage.set).toHaveBeenCalledTimes(2);
|
|
expect(storage.set).toHaveBeenCalledWith(expect.anything(), payload, expiresIn);
|
|
expect(storage.set).toHaveBeenCalledWith(expect.anything(), id, expiresIn);
|
|
await expect(adapter.findByUid(uid)).resolves.toBe(payload);
|
|
});
|
|
|
|
it('can revoke by grantId.', async(): Promise<void> => {
|
|
payload.grantId = grantId;
|
|
await expect(adapter.upsert(id, payload, 333)).resolves.toBeUndefined();
|
|
expect(storage.set).toHaveBeenCalledTimes(2);
|
|
expect(storage.set).toHaveBeenCalledWith(expect.anything(), payload, expiresIn);
|
|
expect(storage.set).toHaveBeenCalledWith(expect.anything(), [ expect.anything() ], expiresIn);
|
|
await expect(adapter.find(id)).resolves.toBe(payload);
|
|
await expect(adapter.revokeByGrantId(grantId)).resolves.toBeUndefined();
|
|
expect(storage.delete).toHaveBeenCalledTimes(2);
|
|
await expect(adapter.find(id)).resolves.toBeUndefined();
|
|
});
|
|
|
|
it('does not do anything if revokeByGrantId finds no matching grant.', async(): Promise<void> => {
|
|
await expect(adapter.revokeByGrantId(grantId)).resolves.toBeUndefined();
|
|
expect(storage.delete).toHaveBeenCalledTimes(0);
|
|
});
|
|
|
|
it('can store multiple ids for a single grant.', async(): Promise<void> => {
|
|
payload.grantId = grantId;
|
|
const id2 = 'id2!';
|
|
const payload2 = { data: 'data2!', grantId };
|
|
await expect(adapter.upsert(id, payload, 333)).resolves.toBeUndefined();
|
|
await expect(adapter.upsert(id2, payload2, 333)).resolves.toBeUndefined();
|
|
await expect(adapter.find(id)).resolves.toBe(payload);
|
|
await expect(adapter.find(id2)).resolves.toBe(payload2);
|
|
await expect(adapter.revokeByGrantId(grantId)).resolves.toBeUndefined();
|
|
await expect(adapter.find(id)).resolves.toBeUndefined();
|
|
await expect(adapter.find(id2)).resolves.toBeUndefined();
|
|
});
|
|
|
|
it('can destroy the payload.', async(): Promise<void> => {
|
|
await expect(adapter.upsert(id, payload, 333)).resolves.toBeUndefined();
|
|
await expect(adapter.find(id)).resolves.toBe(payload);
|
|
await expect(adapter.destroy(id)).resolves.toBeUndefined();
|
|
await expect(adapter.find(id)).resolves.toBeUndefined();
|
|
});
|
|
|
|
it('can consume the payload.', async(): Promise<void> => {
|
|
// Caching since the object gets modified
|
|
const cachedPayload = { ...payload };
|
|
await expect(adapter.upsert(id, payload, 333)).resolves.toBeUndefined();
|
|
await expect(adapter.find(id)).resolves.toEqual(cachedPayload);
|
|
await expect(adapter.consume(id)).resolves.toBeUndefined();
|
|
await expect(adapter.find(id)).resolves.toEqual({ ...cachedPayload, consumed: Math.floor(Date.now() / 1000) });
|
|
});
|
|
|
|
it('does not do anything if consume finds no payload.', async(): Promise<void> => {
|
|
await expect(adapter.consume(id)).resolves.toBeUndefined();
|
|
await expect(adapter.find(id)).resolves.toBeUndefined();
|
|
});
|
|
});
|