cache-service-redis.e2e-spec.ts 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. import { CacheService, mergeConfig, RedisCachePlugin } from '@vendure/core';
  2. import { createTestEnvironment } from '@vendure/testing';
  3. import path from 'path';
  4. import { afterAll, beforeAll, describe, expect, it } from 'vitest';
  5. import { initialData } from '../../../e2e-common/e2e-initial-data';
  6. import { TEST_SETUP_TIMEOUT_MS, testConfig } from '../../../e2e-common/test-config';
  7. import {
  8. deletesAKey,
  9. getReturnsUndefinedForNonExistentKey,
  10. invalidatesALargeNumberOfKeysByTag,
  11. invalidatesByMultipleTags,
  12. invalidatesBySingleTag,
  13. invalidatesManyByMultipleTags,
  14. invalidTTLsShouldNotSetKey,
  15. setsAKey,
  16. setsArrayOfObjects,
  17. setsArrayValue,
  18. setsObjectValue,
  19. } from './fixtures/cache-service-shared-tests';
  20. /**
  21. * Checks if Redis is available at the specified host and port
  22. */
  23. async function isRedisAvailable(host: string, port: number): Promise<boolean> {
  24. try {
  25. const IORedis = await import('ioredis').then(m => m.default);
  26. const testClient = new IORedis.Redis({
  27. host,
  28. port,
  29. connectTimeout: 2000,
  30. lazyConnect: true,
  31. maxRetriesPerRequest: 1,
  32. });
  33. await testClient.ping();
  34. await testClient.quit();
  35. return true;
  36. } catch (error) {
  37. return false;
  38. }
  39. }
  40. const redisHost = '127.0.0.1';
  41. const redisPort = process.env.CI ? +(process.env.E2E_REDIS_PORT || 6379) : 6379;
  42. describe('CacheService with RedisCachePlugin', async () => {
  43. const redisAvailable = await isRedisAvailable(redisHost, redisPort);
  44. if (!redisAvailable) {
  45. // eslint-disable-next-line no-console
  46. console.warn(`Redis server not available at ${redisHost}:${redisPort}. Skipping Redis cache tests.`);
  47. }
  48. describe.skipIf(!redisAvailable)('Redis Cache Tests', () => {
  49. let cacheService: CacheService;
  50. const { server, adminClient } = createTestEnvironment(
  51. mergeConfig(testConfig(), {
  52. plugins: [
  53. RedisCachePlugin.init({
  54. redisOptions: {
  55. host: redisHost,
  56. port: redisPort,
  57. },
  58. }),
  59. ],
  60. }),
  61. );
  62. beforeAll(async () => {
  63. await server.init({
  64. initialData,
  65. productsCsvPath: path.join(__dirname, 'fixtures/e2e-products-minimal.csv'),
  66. customerCount: 1,
  67. });
  68. await adminClient.asSuperAdmin();
  69. cacheService = server.app.get(CacheService);
  70. }, TEST_SETUP_TIMEOUT_MS);
  71. afterAll(async () => {
  72. await server.destroy();
  73. });
  74. it('get returns undefined for non-existent key', () =>
  75. getReturnsUndefinedForNonExistentKey(cacheService));
  76. it('sets a key', () => setsAKey(cacheService));
  77. it('sets an object value', () => setsObjectValue(cacheService));
  78. it('sets an array value', () => setsArrayValue(cacheService));
  79. it('sets an array of objects', () => setsArrayOfObjects(cacheService));
  80. it('deletes a key', () => deletesAKey(cacheService));
  81. it('sets a key with ttl', async () => {
  82. await cacheService.set('test-key1', 'test-value', { ttl: 1000 });
  83. const result = await cacheService.get('test-key1');
  84. expect(result).toBe('test-value');
  85. await new Promise(resolve => setTimeout(resolve, 1500));
  86. const result2 = await cacheService.get('test-key1');
  87. expect(result2).toBeUndefined();
  88. });
  89. it('sets a key with sub-second ttl', async () => {
  90. await cacheService.set('test-key2', 'test-value', { ttl: 900 });
  91. const result = await cacheService.get('test-key2');
  92. expect(result).toBe('test-value');
  93. await new Promise(resolve => setTimeout(resolve, 1500));
  94. const result2 = await cacheService.get('test-key2');
  95. expect(result2).toBeUndefined();
  96. });
  97. it('invalidates by single tag', () => invalidatesBySingleTag(cacheService));
  98. it('invalidates by multiple tags', () => invalidatesByMultipleTags(cacheService));
  99. it('invalidates many by multiple tags', () => invalidatesManyByMultipleTags(cacheService));
  100. it('invalidates a large number of keys by tag', () =>
  101. invalidatesALargeNumberOfKeysByTag(cacheService));
  102. it('invalid ttls should not set key', () => invalidTTLsShouldNotSetKey(cacheService));
  103. });
  104. });