Skip to main content
Glama
redis.test.ts4.35 kB
// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors // SPDX-License-Identifier: Apache-2.0 import { randomUUID } from 'crypto'; import { Redis } from 'ioredis'; import { loadTestConfig } from './config/loader'; import type { MedplumServerConfig } from './config/types'; import { closeRedis, getRedis, getRedisSubscriber, getRedisSubscriberCount, initRedis } from './redis'; import { deleteRedisKeys } from './test.setup'; describe('Redis', () => { let config: MedplumServerConfig; beforeAll(async () => { config = await loadTestConfig(); }); test('Get redis', async () => { initRedis(config.redis); expect(getRedis()).toBeDefined(); await closeRedis(); }); test('Not initialized', async () => { expect(() => getRedis()).toThrow(); await expect(closeRedis()).resolves.toBeUndefined(); }); describe('getRedisSubscriber', () => { test('Not initialized', async () => { await closeRedis(); expect(() => getRedisSubscriber()).toThrow(); }); test('Getting a subscriber', async () => { initRedis(config.redis); const subscriber = getRedisSubscriber(); expect(subscriber).toBeInstanceOf(Redis); await closeRedis(); }); test('Hanging subscriber still disconnects on closeRedis', async () => { initRedis(config.redis); const subscriber = getRedisSubscriber(); let reject: (err: Error) => void; const closePromise = new Promise<void>((resolve, _reject) => { subscriber.on('end', () => { resolve(); }); reject = _reject; }); expect(subscriber).toBeDefined(); await closeRedis(); const timer = setTimeout(() => { reject(new Error('Timeout')); }, 3500); await expect(closePromise).resolves.toBeUndefined(); clearTimeout(timer); }); test('Disconnecting a subscriber removes it from the list', async () => { initRedis(config.redis); expect(getRedisSubscriberCount()).toStrictEqual(0); const subscriber = getRedisSubscriber(); expect(getRedisSubscriberCount()).toStrictEqual(1); subscriber.disconnect(); let reject: (err: Error) => void; const closePromise = new Promise<void>((resolve, _reject) => { subscriber.on('end', () => { resolve(); }); reject = _reject; }); expect(subscriber).toBeDefined(); await closeRedis(); const timer = setTimeout(() => { reject(new Error('Timeout')); }, 3500); await expect(closePromise).resolves.toBeUndefined(); expect(getRedisSubscriberCount()).toStrictEqual(0); clearTimeout(timer); await closeRedis(); }); }); // `deleteRedisKeys` is for tests only (i.e. in test.setup.ts), so testing it is a bit meta, // but the function is just complicated enough that testing is merited describe('deleteRedisKeys', () => { let r1: Redis | undefined; let r2: Redis | undefined; afterEach(async () => { if (r1) { await r1.quit(); r1 = undefined; } if (r2) { await r2.quit(); r2 = undefined; } }); test('Deletes keys by prefix', async () => { const config1 = await loadTestConfig(); const config2 = await loadTestConfig(); config1.redis.db = 8; config2.redis.db = 8; const prefix1 = randomUUID() + ':'; const prefix2 = randomUUID() + ':'; r1 = new Redis({ ...config1.redis, keyPrefix: prefix1 }); r2 = new Redis({ ...config2.redis, keyPrefix: prefix2 }); await r1.set('key1', 'r1.val1'); await r1.set('key2', 'r1.val2'); await r1.set('key3', 'r1.val3'); await r1.set('key4', 'r1.val4'); await r1.set('key5', 'r1.val5'); await r2.set('key1', 'r2.val1'); await expect(r1.get('key1')).resolves.toEqual('r1.val1'); await expect(r2.get('key1')).resolves.toEqual('r2.val1'); await expect(deleteRedisKeys(r1, prefix1)).resolves.toEqual(5); await expect(r1.get('key1')).resolves.toBeNull(); await expect(r2.get('key1')).resolves.toEqual('r2.val1'); await expect(deleteRedisKeys(r2, prefix2)).resolves.toEqual(1); await expect(r1.get('key1')).resolves.toBeNull(); await expect(r2.get('key1')).resolves.toBeNull(); }); }); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/medplum/medplum'

If you have feedback or need assistance with the MCP directory API, please join our Discord server