diff --git a/api/src/identity-access-management/domain/models/RevokedUserAccess.js b/api/src/identity-access-management/domain/models/RevokedUserAccess.js index 1c1b79f938c..d91a9ae83e3 100644 --- a/api/src/identity-access-management/domain/models/RevokedUserAccess.js +++ b/api/src/identity-access-management/domain/models/RevokedUserAccess.js @@ -2,12 +2,12 @@ export class RevokedUserAccess { /** * @param {{ * revokedAllTimeStamp?: number - * revokedSessionTimeStamps?: Record + * revokedSessionIds?: string[] * }} param */ - constructor({ revokedAllTimeStamp, revokedSessionTimeStamps }) { + constructor({ revokedAllTimeStamp, revokedSessionIds }) { this.revokedAllTimeStamp = revokedAllTimeStamp; - this.revokedSessionTimeStamps = revokedSessionTimeStamps; + this.revokedSessionIds = revokedSessionIds; } isAccessTokenRevoked(decodedToken) { @@ -17,7 +17,7 @@ export class RevokedUserAccess { } const sessionId = decodedToken.sid; - if (this.revokedSessionTimeStamps?.[sessionId] && issuedAt < this.revokedSessionTimeStamps[sessionId]) { + if (this.revokedSessionIds?.includes(sessionId)) { return true; } diff --git a/api/src/identity-access-management/infrastructure/repositories/revoked-user-access.repository.js b/api/src/identity-access-management/infrastructure/repositories/revoked-user-access.repository.js index e0cb7e464c2..9fa9ba2df83 100644 --- a/api/src/identity-access-management/infrastructure/repositories/revoked-user-access.repository.js +++ b/api/src/identity-access-management/infrastructure/repositories/revoked-user-access.repository.js @@ -6,49 +6,47 @@ import { featureToggles } from '../../../shared/infrastructure/feature-toggles/i import { RevokedUserAccess } from '../../domain/models/RevokedUserAccess.js'; const revokedUserAccessTemporaryStorage = temporaryStorage.withPrefix('revoked-user-access:'); -const revokedUserAccessLifespanMs = config.authentication.revokedUserAccessLifespanMs; +const { revokedUserAccessLifespanMs } = config.authentication; const isSessionLogoutEnabled = featureToggles.use('isSessionLogoutEnabled'); /** - * Saves the revoke date for all the accesses of a user. + * Saves the revoke date for a user session. * * @param {Object} params - The params object. * @param {string} params.userId - The ID of the user to revoke access for. - * @param {Date} params.revokeUntil - The date until the user's access should be revoked. + * @param {string} params.sessionId - The ID of the user’s session to revoke. */ -async function revokeAll({ userId, revokeUntil }) { +async function revokeSession({ userId, sessionId }) { Joi.assert(userId, Joi.required()); - Joi.assert(revokeUntil, Joi.date().required()); - - await revokedUserAccessTemporaryStorage.save({ - key: userId, - value: Math.floor(revokeUntil.getTime() / 1000), - expirationDelaySeconds: revokedUserAccessLifespanMs / 1000, - }); + Joi.assert(sessionId, Joi.required()); await revokedUserAccessTemporaryStorage.save({ - key: `${userId}:all`, - value: Math.floor(revokeUntil.getTime() / 1000), + key: `${userId}:${sessionId}`, + value: '', expirationDelaySeconds: revokedUserAccessLifespanMs / 1000, }); } /** - * Saves the revoke date for a user session. + * Saves the revoke date for all the accesses of a user. * * @param {Object} params - The params object. * @param {string} params.userId - The ID of the user to revoke access for. - * @param {string} params.sessionId - The ID of the user’s session to revoke. * @param {Date} params.revokeUntil - The date until the user's access should be revoked. */ -async function revokeSession({ userId, sessionId, revokeUntil }) { +async function revokeAll({ userId, revokeUntil }) { Joi.assert(userId, Joi.required()); - Joi.assert(sessionId, Joi.required()); Joi.assert(revokeUntil, Joi.date().required()); await revokedUserAccessTemporaryStorage.save({ - key: `${userId}:${sessionId}`, + key: userId, + value: Math.floor(revokeUntil.getTime() / 1000), + expirationDelaySeconds: revokedUserAccessLifespanMs / 1000, + }); + + await revokedUserAccessTemporaryStorage.save({ + key: `${userId}:all`, value: Math.floor(revokeUntil.getTime() / 1000), expirationDelaySeconds: revokedUserAccessLifespanMs / 1000, }); @@ -66,17 +64,17 @@ async function findByUserId(userId) { return new RevokedUserAccess({ revokedAllTimeStamp }); } - const revokeKeys = await revokedUserAccessTemporaryStorage.keys(`${userId}:*`); + const revokedKeys = await revokedUserAccessTemporaryStorage.keys(`${userId}:*`); + + const revokedAllKey = `${userId}:all`; - const revokedTimeStamps = Object.fromEntries( - await Promise.all( - revokeKeys.map(async (key) => [key.split(':')[1], await revokedUserAccessTemporaryStorage.get(key)]), - ), - ); + const revokedAllTimeStamp = revokedKeys.includes(revokedAllKey) + ? await revokedUserAccessTemporaryStorage.get(`${userId}:all`) + : undefined; - const { all: revokedAllTimeStamp, ...revokedSessionTimeStamps } = revokedTimeStamps; + const revokedSessionIds = revokedKeys.filter((key) => key !== revokedAllKey).map((key) => key.split(':')[1]); - return new RevokedUserAccess({ revokedAllTimeStamp, revokedSessionTimeStamps }); + return new RevokedUserAccess({ revokedAllTimeStamp, revokedSessionIds }); } export const revokedUserAccessRepository = { revokeAll, revokeSession, findByUserId }; diff --git a/api/src/shared/infrastructure/feature-toggles/feature-toggles-client.js b/api/src/shared/infrastructure/feature-toggles/feature-toggles-client.js index e1f88b5ed63..634e3c6aeee 100644 --- a/api/src/shared/infrastructure/feature-toggles/feature-toggles-client.js +++ b/api/src/shared/infrastructure/feature-toggles/feature-toggles-client.js @@ -218,9 +218,13 @@ export class FeatureTogglesClient { this.#currentValues[key] = newValue; this.#eventTarget.dispatchEvent(new FeatureTogglesEvent('set', key, newValue, oldValue)); - - break; } + + break; + } + + default: { + logger.warn({ type: message.type }, 'unknown message type'); } } } diff --git a/api/src/shared/infrastructure/key-value-storages/InMemoryKeyValueStorage.js b/api/src/shared/infrastructure/key-value-storages/InMemoryKeyValueStorage.js index 21a7b066b14..90d1e5a244c 100644 --- a/api/src/shared/infrastructure/key-value-storages/InMemoryKeyValueStorage.js +++ b/api/src/shared/infrastructure/key-value-storages/InMemoryKeyValueStorage.js @@ -1,27 +1,21 @@ -import lodash from 'lodash'; - -const { trim, noop } = lodash; - import { KeyValueStorage } from './KeyValueStorage.js'; class InMemoryKeyValueStorage extends KeyValueStorage { - #store = new Map(); + #store; - constructor() { + constructor({ store = new Map() } = {}) { super(); + this.#store = store; } - async save({ key, value, expirationDelaySeconds }) { - const storageKey = trim(key) || InMemoryKeyValueStorage.generateKey(); - if (expirationDelaySeconds) { - setTimeout(() => this.#store.delete(storageKey), expirationDelaySeconds * 1000); - } + async save({ key, value }) { + const storageKey = key?.trim() ?? InMemoryKeyValueStorage.generateKey(); this.#store.set(storageKey, value); return storageKey; } async update(key, value) { - const storageKey = trim(key); + const storageKey = key.trim(); this.#store.set(storageKey, value); } @@ -50,11 +44,11 @@ class InMemoryKeyValueStorage extends KeyValueStorage { } quit() { - noop; + // noop } async expire() { - noop; + // noop } async ttl() { diff --git a/api/src/shared/infrastructure/key-value-storages/KeyValueStorage.js b/api/src/shared/infrastructure/key-value-storages/KeyValueStorage.js index da8823b61f9..afd8c8f5de2 100644 --- a/api/src/shared/infrastructure/key-value-storages/KeyValueStorage.js +++ b/api/src/shared/infrastructure/key-value-storages/KeyValueStorage.js @@ -95,7 +95,7 @@ class KeyValueStorage { }, ttl(key) { - return storage.ttl(key); + return storage.ttl(prefix + key); }, lpush({ key, value }) { diff --git a/api/tests/identity-access-management/acceptance/application/token.route.test.js b/api/tests/identity-access-management/acceptance/application/token.route.test.js index 227981ab8ed..1f085ef4250 100644 --- a/api/tests/identity-access-management/acceptance/application/token.route.test.js +++ b/api/tests/identity-access-management/acceptance/application/token.route.test.js @@ -669,8 +669,8 @@ describe('Acceptance | Identity Access Management | Route | Token', function () // then expect(response.statusCode).to.equal(204); - const revokeSessionTimestamp = await revokedUserAccessTemporaryStorage.get(`${userId}:${sessionId}`); - expect(revokeSessionTimestamp).to.be.a('number'); + const revokedKeys = await revokedUserAccessTemporaryStorage.keys(`${userId}:*`); + expect(revokedKeys).to.deep.equal([`${userId}:${sessionId}`]); }); }); }); diff --git a/api/tests/identity-access-management/integration/domain/usecases/revoke-session.usecase.test.js b/api/tests/identity-access-management/integration/domain/usecases/revoke-session.usecase.test.js index b8b99af5b43..d2e57cdf493 100644 --- a/api/tests/identity-access-management/integration/domain/usecases/revoke-session.usecase.test.js +++ b/api/tests/identity-access-management/integration/domain/usecases/revoke-session.usecase.test.js @@ -15,7 +15,7 @@ describe('Integration | Identity Access Management | Domain | UseCase | revoke-s await usecases.revokeSession({ userId, sessionId }); // then - const revokeTimeStamp = await revokedUserAccessTemporaryStorage.get(`${userId}:${sessionId}`); - expect(revokeTimeStamp).to.be.a('number'); + const revokedKeys = await revokedUserAccessTemporaryStorage.keys(`${userId}:*`); + expect(revokedKeys).to.deep.equal([`${userId}:${sessionId}`]); }); }); diff --git a/api/tests/identity-access-management/integration/infrastructure/repositories/revoked-user-access.repository.test.js b/api/tests/identity-access-management/integration/infrastructure/repositories/revoked-user-access.repository.test.js index 0c373e34fd9..3df97ca42bb 100644 --- a/api/tests/identity-access-management/integration/infrastructure/repositories/revoked-user-access.repository.test.js +++ b/api/tests/identity-access-management/integration/infrastructure/repositories/revoked-user-access.repository.test.js @@ -2,6 +2,7 @@ import { setImmediate } from 'node:timers/promises'; import { expect } from 'chai'; +import { config } from '../../../../../config/config.js'; import { RevokedUserAccess } from '../../../../../src/identity-access-management/domain/models/RevokedUserAccess.js'; import { revokedUserAccessRepository } from '../../../../../src/identity-access-management/infrastructure/repositories/revoked-user-access.repository.js'; import { featureToggles } from '../../../../../src/shared/infrastructure/feature-toggles/index.js'; @@ -35,15 +36,16 @@ describe('Integration | Identity Access Management | Infrastructure | Repository describe('#revokeSession', function () { it('saves revoked access for user session in TemporaryStorage', async function () { // given - const revokeUntil = new Date(); - const revokedTimeStamp = Math.floor(revokeUntil.getTime() / 1000); + const sessionId = crypto.randomUUID(); // when - await revokedUserAccessRepository.revokeSession({ userId: 12345, sessionId: 67890, revokeUntil }); + await revokedUserAccessRepository.revokeSession({ userId: 12345, sessionId }); // then - const result = await revokedUserAccessTemporaryStorage.get('12345:67890'); - expect(result).to.equal(revokedTimeStamp); + const result = await revokedUserAccessTemporaryStorage.get(`12345:${sessionId}`); + expect(result).to.equal(''); + const ttl = await revokedUserAccessTemporaryStorage.ttl(`12345:${sessionId}`); + expect(ttl).to.equal(config.authentication.revokedUserAccessLifespanMs / 1000); }); }); @@ -59,7 +61,7 @@ describe('Integration | Identity Access Management | Infrastructure | Repository // then expect(result).to.deep.equal({ revokedAllTimeStamp, - revokedSessionTimeStamps: undefined, + revokedSessionIds: undefined, }); expect(result).to.be.instanceOf(RevokedUserAccess); }); @@ -75,22 +77,17 @@ describe('Integration | Identity Access Management | Infrastructure | Repository const revokedAllTimeStamp = Math.floor(new Date('2026-08-27T15:00:50Z').getTime() / 1000); await revokedUserAccessTemporaryStorage.save({ key: '12345:all', value: revokedAllTimeStamp }); - const session1RevokedTimestamp = Math.floor(new Date().getTime('2026-08-27T16:00:50Z') / 1000); - await revokedUserAccessTemporaryStorage.save({ key: '12345:session1', value: session1RevokedTimestamp }); - - const session2RevokedTimestamp = Math.floor(new Date().getTime('2026-08-27T17:00:50Z') / 1000); - await revokedUserAccessTemporaryStorage.save({ key: '12345:session2', value: session2RevokedTimestamp }); + await revokedUserAccessTemporaryStorage.save({ key: '12345:session1', value: '' }); + await revokedUserAccessTemporaryStorage.save({ key: '12345:session2', value: '' }); // when const result = await revokedUserAccessRepository.findByUserId(12345); // then + result.revokedSessionIds.sort(); expect(result).to.deep.equal({ revokedAllTimeStamp, - revokedSessionTimeStamps: { - session1: session1RevokedTimestamp, - session2: session2RevokedTimestamp, - }, + revokedSessionIds: ['session1', 'session2'], }); expect(result).to.be.instanceOf(RevokedUserAccess); }); diff --git a/api/tests/identity-access-management/unit/domain/models/RevokedUserAccess.test.js b/api/tests/identity-access-management/unit/domain/models/RevokedUserAccess.test.js index 358800748d6..498daaf740d 100644 --- a/api/tests/identity-access-management/unit/domain/models/RevokedUserAccess.test.js +++ b/api/tests/identity-access-management/unit/domain/models/RevokedUserAccess.test.js @@ -7,12 +7,12 @@ describe('Unit | Identity Access Management | Domain | Model | RevokedUserAccess it('builds a revoke user access model', function () { //when const revokedAllTimeStamp = Math.floor(new Date().getTime() / 1000); - const revokedSessionTimeStamps = { 12345: Math.floor(new Date().getTime() / 1000) }; - const revokedUserAccess = new RevokedUserAccess({ revokedAllTimeStamp, revokedSessionTimeStamps }); + const revokedSessionIds = [crypto.randomUUID()]; + const revokedUserAccess = new RevokedUserAccess({ revokedAllTimeStamp, revokedSessionIds }); //then expect(revokedUserAccess.revokedAllTimeStamp).to.equal(revokedAllTimeStamp); - expect(revokedUserAccess.revokedSessionTimeStamps).to.equal(revokedSessionTimeStamps); + expect(revokedUserAccess.revokedSessionIds).to.equal(revokedSessionIds); }); }); @@ -52,11 +52,9 @@ describe('Unit | Identity Access Management | Domain | Model | RevokedUserAccess context("when access token's session is revoked", function () { it('returns true', function () { //given - const revokedAllTimeStamp = Math.floor(new Date('2024-12-01').getTime() / 1000); - const iat = Math.floor(new Date('2024-11-01').getTime() / 1000); const sid = crypto.randomUUID(); - const decodedToken = { iat, sid }; - const revokedUserAccess = new RevokedUserAccess({ revokedSessionTimeStamps: { [sid]: revokedAllTimeStamp } }); + const decodedToken = { sid }; + const revokedUserAccess = new RevokedUserAccess({ revokedSessionIds: [sid] }); //when const result = revokedUserAccess.isAccessTokenRevoked(decodedToken); @@ -69,11 +67,9 @@ describe('Unit | Identity Access Management | Domain | Model | RevokedUserAccess context("when access token's session is not revoked", function () { it('returns false', function () { //given - const revokedAllTimeStamp = Math.floor(new Date('2024-10-01').getTime() / 1000); - const iat = Math.floor(new Date('2024-12-01').getTime() / 1000); const sid = crypto.randomUUID(); - const decodedToken = { iat, sid }; - const revokedUserAccess = new RevokedUserAccess({ revokedSessionTimeStamps: { [sid]: revokedAllTimeStamp } }); + const decodedToken = { sid }; + const revokedUserAccess = new RevokedUserAccess({ revokedSessionIds: [crypto.randomUUID()] }); //when const result = revokedUserAccess.isAccessTokenRevoked(decodedToken); diff --git a/api/tests/shared/unit/infrastructure/key-value-storages/InMemoryKeyValueStorage_test.js b/api/tests/shared/unit/infrastructure/key-value-storages/InMemoryKeyValueStorage_test.js index 81f95e955d5..24482c81a40 100644 --- a/api/tests/shared/unit/infrastructure/key-value-storages/InMemoryKeyValueStorage_test.js +++ b/api/tests/shared/unit/infrastructure/key-value-storages/InMemoryKeyValueStorage_test.js @@ -1,26 +1,25 @@ import { expect } from 'chai'; -import sinon from 'sinon'; import { InMemoryKeyValueStorage } from '../../../../../src/shared/infrastructure/key-value-storages/InMemoryKeyValueStorage.js'; describe('Unit | Infrastructure | key-value-storage | InMemoryKeyValueStorage', function () { - let inMemoryKeyValueStorage; + let store, inMemoryKeyValueStorage; beforeEach(function () { - inMemoryKeyValueStorage = new InMemoryKeyValueStorage(); + store = new Map(); + inMemoryKeyValueStorage = new InMemoryKeyValueStorage({ store }); }); describe('#increment', function () { it('should call client incr to increment value', async function () { // given const key = 'valueKey'; - const inMemoryKeyValueStorage = new InMemoryKeyValueStorage(); // when await inMemoryKeyValueStorage.increment(key); // then - expect(await inMemoryKeyValueStorage.get(key)).to.equal('1'); + expect(store.get(key)).to.equal('1'); }); }); @@ -28,24 +27,16 @@ describe('Unit | Infrastructure | key-value-storage | InMemoryKeyValueStorage', it('should call client incr to decrement value', async function () { // given const key = 'valueKey'; - const inMemoryKeyValueStorage = new InMemoryKeyValueStorage(); // when await inMemoryKeyValueStorage.decrement(key); // then - expect(await inMemoryKeyValueStorage.get(key)).to.equal('-1'); + expect(store.get(key)).to.equal('-1'); }); }); describe('#save', function () { - let clock; - - beforeEach(function () { - // InMemoryKeyValueStorage expires its keys with setTimeout - clock = sinon.useFakeTimers({ toFake: ['Date', 'setTimeout'] }); - }); - it('should resolve with the generated key', async function () { // when const key = await inMemoryKeyValueStorage.save({ value: {}, expirationDelaySeconds: 1000 }); @@ -83,31 +74,14 @@ describe('Unit | Infrastructure | key-value-storage | InMemoryKeyValueStorage', // then expect(returnedKey).not.be.equal(keyParameter); }); - - it('should save key value with a defined ttl in seconds', async function () { - // given - const TWO_MINUTES_IN_SECONDS = 2 * 60; - - // when - const key = await inMemoryKeyValueStorage.save({ - value: 'foobar', - expirationDelaySeconds: TWO_MINUTES_IN_SECONDS, - }); - - // then - expect(await inMemoryKeyValueStorage.get(key)).to.equal('foobar'); - await clock.tickAsync(TWO_MINUTES_IN_SECONDS * 1000); - expect(await inMemoryKeyValueStorage.get(key)).to.be.undefined; - }); }); describe('#get', function () { it('should retrieve the value if it exists', async function () { // given + const key = 'testkey'; const value = { name: 'name' }; - const expirationDelaySeconds = 1000; - - const key = await inMemoryKeyValueStorage.save({ value, expirationDelaySeconds }); + store.set(key, value); // when const result = await inMemoryKeyValueStorage.get(key); @@ -120,134 +94,90 @@ describe('Unit | Infrastructure | key-value-storage | InMemoryKeyValueStorage', describe('#update', function () { it('should set a new value', async function () { // given - const key = await inMemoryKeyValueStorage.save({ - value: { name: 'name' }, - }); + const key = 'testkey'; + const value = { name: 'name' }; + store.set(key, value); // when await inMemoryKeyValueStorage.update(key, { url: 'url' }); // then - const result = await inMemoryKeyValueStorage.get(key); - expect(result).to.deep.equal({ url: 'url' }); - }); - - it('should not change the time to live', async function () { - // given - // InMemoryKeyValueStorage expires its keys with setTimeout - const clock = sinon.useFakeTimers({ toFake: ['Date', 'setTimeout'] }); - const keyWithTtl = await inMemoryKeyValueStorage.save({ - value: {}, - expirationDelaySeconds: 1, - }); - const keyWithoutTtl = await inMemoryKeyValueStorage.save({ value: {} }); - - // when - await clock.tickAsync(500); - await inMemoryKeyValueStorage.update(keyWithTtl, {}); - await inMemoryKeyValueStorage.update(keyWithoutTtl, {}); - await clock.tickAsync(600); - - // then - expect(await inMemoryKeyValueStorage.get(keyWithTtl)).to.be.undefined; - expect(await inMemoryKeyValueStorage.get(keyWithoutTtl)).not.to.be.undefined; + expect(store.get(key)).to.deep.equal({ url: 'url' }); }); }); describe('#delete', function () { it('should delete the value if it exists', async function () { // given + const key = 'testkey'; const value = { name: 'name' }; - const expirationDelaySeconds = 1000; - - const key = await inMemoryKeyValueStorage.save({ value, expirationDelaySeconds }); + store.set(key, value); // when await inMemoryKeyValueStorage.delete(key); // then - const savedKey = await inMemoryKeyValueStorage.get(key); - expect(savedKey).to.be.undefined; + expect(store.has(key)).to.be.false; }); }); describe('#expire', function () { - it('should add an expiration time to the list', async function () { - // given - // InMemoryKeyValueStorage expires its keys with setTimeout - const clock = sinon.useFakeTimers({ toFake: ['Date', 'setTimeout'] }); - const inMemoryKeyValueStorage = new InMemoryKeyValueStorage(); - - // when - const key = 'key:lpush'; - await inMemoryKeyValueStorage.lpush(key, 'value'); - await inMemoryKeyValueStorage.expire({ key, expirationDelaySeconds: 1 }); - await clock.tickAsync(1200); - const list = inMemoryKeyValueStorage.lrange(key); - - // then - expect(list).to.be.empty; + it('resolves', async function () { + await inMemoryKeyValueStorage.expire('key'); }); }); describe('#lpush', function () { it('should add value into key list', async function () { // given - const inMemoryKeyValueStorage = new InMemoryKeyValueStorage(); + const key = 'key:lpush'; + const value = 'value'; // when const length = await inMemoryKeyValueStorage.lpush('key:lpush', 'value'); // then expect(length).to.equal(1); + expect(store.get(key)).to.deep.equal([value]); }); }); describe('#lrem', function () { it('should remove values into key list', async function () { // given - const inMemoryKeyValueStorage = new InMemoryKeyValueStorage(); - - // when const key = 'key:lrem'; - await inMemoryKeyValueStorage.lpush(key, 'value1'); - await inMemoryKeyValueStorage.lpush(key, 'value2'); - await inMemoryKeyValueStorage.lpush(key, 'value1'); + store.set(key, ['value1', 'value2', 'value1']); + // when const length = await inMemoryKeyValueStorage.lrem(key, 'value1'); // then expect(length).to.equal(2); + expect(store.get(key)).to.deep.equal(['value2']); }); }); describe('#lrange', function () { it('should return key values list', async function () { // given - const inMemoryKeyValueStorage = new InMemoryKeyValueStorage(); - - // when const key = 'key:lrange'; - await inMemoryKeyValueStorage.lpush(key, 'value1'); - await inMemoryKeyValueStorage.lpush(key, 'value2'); - await inMemoryKeyValueStorage.lpush(key, 'value3'); + store.set(key, ['value1', 'value2', 'value3']); + // when const values = await inMemoryKeyValueStorage.lrange(key); // then - expect(values).to.have.lengthOf(3); - expect(values).to.deep.equal(['value3', 'value2', 'value1']); + expect(values).to.deep.equal(['value1', 'value2', 'value3']); }); }); describe('#keys', function () { it('should return matching keys', async function () { // given - const inMemoryKeyValueStorage = new InMemoryKeyValueStorage(); - inMemoryKeyValueStorage.save({ key: 'prefix:key1', value: true }); - inMemoryKeyValueStorage.save({ key: 'prefix:key2', value: true }); - inMemoryKeyValueStorage.save({ key: 'prefix:key3', value: true }); - inMemoryKeyValueStorage.save({ key: 'otherprefix:key4', value: true }); + store.set('prefix:key1', true); + store.set('prefix:key2', true); + store.set('prefix:key3', true); + store.set('otherprefix:key4', true); // when const values = inMemoryKeyValueStorage.keys('prefix:*'); @@ -258,14 +188,13 @@ describe('Unit | Infrastructure | key-value-storage | InMemoryKeyValueStorage', it('should return matching keys for all keys', async function () { // given - const inMemoryKeyValueStorage = new InMemoryKeyValueStorage(); - inMemoryKeyValueStorage.save({ key: 'prefix:key1', value: true }); - inMemoryKeyValueStorage.save({ key: 'prefix:key2', value: true }); - inMemoryKeyValueStorage.save({ key: 'prefix:key3', value: true }); - inMemoryKeyValueStorage.save({ key: 'otherprefix:key4', value: true }); + store.set('prefix:key1', true); + store.set('prefix:key2', true); + store.set('prefix:key3', true); + store.set('otherprefix:key4', true); // when - const values = inMemoryKeyValueStorage.keys('*'); + const values = await inMemoryKeyValueStorage.keys('*'); // then expect(values).to.deep.equal(['prefix:key1', 'prefix:key2', 'prefix:key3', 'otherprefix:key4']);