From 86c390a6f347ec8b46e05f89db8ddff548f94763 Mon Sep 17 00:00:00 2001 From: Roy Razon Date: Mon, 11 Sep 2023 09:02:24 +0300 Subject: [PATCH] refactor index --- tunnel-server/src/tunnel-store/index.test.ts | 171 +++++++++++++++++++ tunnel-server/src/tunnel-store/index.ts | 9 +- 2 files changed, 176 insertions(+), 4 deletions(-) create mode 100644 tunnel-server/src/tunnel-store/index.test.ts diff --git a/tunnel-server/src/tunnel-store/index.test.ts b/tunnel-server/src/tunnel-store/index.test.ts new file mode 100644 index 00000000..77f2d004 --- /dev/null +++ b/tunnel-server/src/tunnel-store/index.test.ts @@ -0,0 +1,171 @@ +import { describe, it, expect, beforeEach } from '@jest/globals' +import pinoPretty from 'pino-pretty' +import { Logger, pino } from 'pino' +import { ActiveTunnel, ActiveTunnelStore, TransactionDescriptor, inMemoryActiveTunnelStore } from '.' + +describe('inMemoryActiveTunnelStore', () => { + let store: ActiveTunnelStore + let log: Logger + + beforeEach(() => { + log = pino({ level: 'debug' }, pinoPretty()) + store = inMemoryActiveTunnelStore({ log }) + }) + + describe('when setting a new key', () => { + let desc: TransactionDescriptor + let val: ActiveTunnel + beforeEach(async () => { + val = { publicKeyThumbprint: 'pk1' } as ActiveTunnel + desc = await store.set('foo', val) + }) + + it('returns a descriptor', async () => { + expect(desc).toBeDefined() + }) + + describe('when getting a non-existant key', () => { + it('returns undefined', async () => { + expect(await store.get('bar')).toBeUndefined() + }) + }) + + describe('when getting a non-existing value by thumbprint', () => { + let gotValAr: readonly ActiveTunnel[] | undefined + beforeEach(async () => { + gotValAr = await store.getByPkThumbprint('pk2') + }) + + it('returns undefined', () => { + expect(gotValAr).toBeUndefined() + }) + }) + + describe('when getting the key', () => { + let gotVal: ActiveTunnel | undefined + beforeEach(async () => { + gotVal = await store.get('foo') + }) + + it('returns the value', () => { + expect(gotVal).toBe(val) + }) + }) + + describe('when getting an existing value by thumbprint', () => { + let gotValAr: readonly ActiveTunnel[] | undefined + beforeEach(async () => { + gotValAr = await store.getByPkThumbprint('pk1') + }) + + it('returns the value', () => { + expect(gotValAr).toHaveLength(1) + expect(gotValAr).toContain(val) + }) + }) + + describe('when deleting a non-existant value', () => { + beforeEach(async () => { + await store.delete('bar') + }) + + describe('when getting a non-existing value by thumbprint', () => { + let gotValAr: readonly ActiveTunnel[] | undefined + beforeEach(async () => { + gotValAr = await store.getByPkThumbprint('pk2') + }) + + it('returns undefined', () => { + expect(gotValAr).toBeUndefined() + }) + }) + + describe('when getting an existing value by thumbprint', () => { + let gotValAr: readonly ActiveTunnel[] | undefined + beforeEach(async () => { + gotValAr = await store.getByPkThumbprint('pk1') + }) + + it('returns the value', () => { + expect(gotValAr).toHaveLength(1) + expect(gotValAr).toContain(val) + }) + }) + }) + + describe('when deleting an existing value without a tx arg', () => { + beforeEach(async () => { + await store.delete('foo') + }) + + describe('when getting the deleted key', () => { + it('returns undefined', async () => { + expect(await store.get('foo')).toBeUndefined() + }) + }) + + describe('when getting a the deleted value by thumbprint', () => { + let gotValAr: readonly ActiveTunnel[] | undefined + beforeEach(async () => { + gotValAr = await store.getByPkThumbprint('pk1') + }) + + it('returns undefined', () => { + expect(gotValAr).toBeUndefined() + }) + }) + }) + + describe('when deleting an existing value with a correct tx arg', () => { + beforeEach(async () => { + await store.delete('foo', desc) + }) + + describe('when getting the deleted key', () => { + it('returns undefined', async () => { + expect(await store.get('foo')).toBeUndefined() + }) + }) + + describe('when getting a the deleted value by thumbprint', () => { + let gotValAr: readonly ActiveTunnel[] | undefined + beforeEach(async () => { + gotValAr = await store.getByPkThumbprint('pk1') + }) + + it('returns undefined', () => { + expect(gotValAr).toBeUndefined() + }) + }) + }) + + describe('when deleting an existing value with an incorrect tx arg', () => { + beforeEach(async () => { + await store.delete('foo', { txId: -1 }) + }) + + describe('when getting the key', () => { + let gotVal: ActiveTunnel | undefined + beforeEach(async () => { + gotVal = await store.get('foo') + }) + + it('returns the value', () => { + expect(gotVal).toBe(val) + }) + }) + + describe('when getting the value by thumbprint', () => { + let gotValAr: readonly ActiveTunnel[] | undefined + beforeEach(async () => { + gotValAr = await store.getByPkThumbprint('pk1') + }) + + it('returns the value', () => { + expect(gotValAr).toHaveLength(1) + expect(gotValAr).toContain(val) + }) + }) + }) + }) +}) diff --git a/tunnel-server/src/tunnel-store/index.ts b/tunnel-server/src/tunnel-store/index.ts index 9a4b11ac..a0c58135 100644 --- a/tunnel-server/src/tunnel-store/index.ts +++ b/tunnel-server/src/tunnel-store/index.ts @@ -52,11 +52,12 @@ const idGenerator = () => { export const inMemoryActiveTunnelStore = ({ log }: { log: Logger }): ActiveTunnelStore => { const keyToTunnel = new Map() - const pkThumbprintToTunnel = arrayMap() + const pkThumbprintToTunnel = arrayMap() const txIdGen = idGenerator() return { get: async key => keyToTunnel.get(key), - getByPkThumbprint: async pkThumbprint => pkThumbprintToTunnel.get(pkThumbprint), + getByPkThumbprint: async pkThumbprint => pkThumbprintToTunnel.get(pkThumbprint) + ?.map(key => keyToTunnel.get(key) as ActiveTunnel), set: async (key, value) => { if (keyToTunnel.has(key)) { throw new KeyAlreadyExistsError(key) @@ -64,13 +65,13 @@ export const inMemoryActiveTunnelStore = ({ log }: { log: Logger }): ActiveTunne const txId = txIdGen.next() log.debug('setting tunnel key %s id %s: %j', key, txId, value) keyToTunnel.set(key, Object.assign(value, { txId })) - pkThumbprintToTunnel.add(value.publicKeyThumbprint, value) + pkThumbprintToTunnel.add(value.publicKeyThumbprint, key) return { txId } }, delete: async (key, tx) => { const tunnel = keyToTunnel.get(key) if (tunnel && (tx === undefined || tunnel.txId === tx.txId)) { - pkThumbprintToTunnel.delete(tunnel.publicKeyThumbprint, ({ hostname }) => hostname === key) + pkThumbprintToTunnel.delete(tunnel.publicKeyThumbprint, k => k === key) keyToTunnel.delete(key) } },