@onlineapps/conn-base-cache 1.0.1 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/API.md +0 -0
- package/README.md +0 -0
- package/coverage/clover.xml +0 -0
- package/coverage/coverage-final.json +0 -0
- package/coverage/lcov-report/base.css +0 -0
- package/coverage/lcov-report/block-navigation.js +0 -0
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +0 -0
- package/coverage/lcov-report/index.js.html +0 -0
- package/coverage/lcov-report/prettify.css +0 -0
- package/coverage/lcov-report/prettify.js +0 -0
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +0 -0
- package/coverage/lcov.info +0 -0
- package/onlineapps-conn-base-cache-1.0.1.tgz +0 -0
- package/package.json +4 -3
- package/src/config.js +48 -0
- package/src/defaults.js +23 -0
- package/src/index.js +65 -20
- package/{test → tests}/component/cache.component.test.js +1 -1
- package/{test → tests}/integration/cache.integration.test.js +4 -15
- package/{test → tests}/unit/CacheConnector.edge.test.js +13 -15
- package/{test → tests}/unit/CacheConnector.test.js +27 -5
package/API.md
CHANGED
|
File without changes
|
package/README.md
CHANGED
|
File without changes
|
package/coverage/clover.xml
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/coverage/lcov.info
CHANGED
|
File without changes
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onlineapps/conn-base-cache",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "Redis cache connector with TTL, invalidation, and namespace support for OA Drive microservices",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"test": "jest",
|
|
8
|
-
"test:unit": "jest
|
|
9
|
-
"test:integration": "jest
|
|
8
|
+
"test:unit": "jest tests/unit",
|
|
9
|
+
"test:integration": "jest tests/integration",
|
|
10
10
|
"test:watch": "jest --watch",
|
|
11
11
|
"docs": "jsdoc2md --files src/**/*.js > API.md"
|
|
12
12
|
},
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
"author": "OA Drive Team",
|
|
21
21
|
"license": "MIT",
|
|
22
22
|
"dependencies": {
|
|
23
|
+
"@onlineapps/runtime-config": "1.0.1",
|
|
23
24
|
"ioredis": "^5.3.2"
|
|
24
25
|
},
|
|
25
26
|
"devDependencies": {
|
package/src/config.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Runtime configuration schema for @onlineapps/conn-base-cache.
|
|
5
|
+
*
|
|
6
|
+
* Uses @onlineapps/runtime-config for unified priority:
|
|
7
|
+
* 1. Explicit config (passed to constructor)
|
|
8
|
+
* 2. Environment variable
|
|
9
|
+
* 3. Owner defaults (from ./defaults.js)
|
|
10
|
+
*
|
|
11
|
+
* @module @onlineapps/conn-base-cache/config
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const { createRuntimeConfig } = require('@onlineapps/runtime-config');
|
|
15
|
+
const DEFAULTS = require('./defaults');
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Runtime config schema for CacheConnector
|
|
19
|
+
*
|
|
20
|
+
* Schema defines:
|
|
21
|
+
* - env: Environment variable name
|
|
22
|
+
* - defaultKey: Key in DEFAULTS object
|
|
23
|
+
* - type: Value type for coercion
|
|
24
|
+
* - required: Fail-fast if missing (for infra topology)
|
|
25
|
+
*/
|
|
26
|
+
const runtimeCfg = createRuntimeConfig({
|
|
27
|
+
defaults: DEFAULTS,
|
|
28
|
+
schema: {
|
|
29
|
+
// Connection settings (dev-friendly defaults, ENV override)
|
|
30
|
+
host: { env: 'REDIS_HOST', defaultKey: 'defaultHost' },
|
|
31
|
+
port: { env: 'REDIS_PORT', defaultKey: 'defaultPort', type: 'number' },
|
|
32
|
+
password: { env: 'REDIS_PASSWORD' },
|
|
33
|
+
db: { env: 'REDIS_DB', defaultKey: 'defaultDb', type: 'number' },
|
|
34
|
+
|
|
35
|
+
// Cache behavior (module-owned defaults)
|
|
36
|
+
keyPrefix: { defaultKey: 'keyPrefix' },
|
|
37
|
+
defaultTTL: { env: 'CACHE_TTL', defaultKey: 'defaultTTLSeconds', type: 'number' },
|
|
38
|
+
maxRetries: { defaultKey: 'maxRetries', type: 'number' },
|
|
39
|
+
retryDelay: { defaultKey: 'retryDelayMs', type: 'number' },
|
|
40
|
+
|
|
41
|
+
// Connection behavior (module-owned defaults)
|
|
42
|
+
connectWaitTimeoutMs: { defaultKey: 'connectWaitTimeoutMs', type: 'number' },
|
|
43
|
+
connectWaitPollIntervalMs: { defaultKey: 'connectWaitPollIntervalMs', type: 'number' },
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
module.exports = runtimeCfg;
|
|
48
|
+
|
package/src/defaults.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Module-owned defaults for @onlineapps/conn-base-cache.
|
|
5
|
+
*
|
|
6
|
+
* Ownership rule:
|
|
7
|
+
* - Defaults that belong to this cache connector live here (host/port for dev/test, TTL, retry policy, key prefix, db).
|
|
8
|
+
* - Callers can override via explicit config or environment variables.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
module.exports = {
|
|
12
|
+
defaultHost: 'localhost',
|
|
13
|
+
defaultPort: 6379,
|
|
14
|
+
keyPrefix: 'cache:',
|
|
15
|
+
defaultDb: 0,
|
|
16
|
+
defaultTTLSeconds: 3600,
|
|
17
|
+
maxRetries: 3,
|
|
18
|
+
retryDelayMs: 100,
|
|
19
|
+
connectWaitTimeoutMs: 5000,
|
|
20
|
+
connectWaitPollIntervalMs: 100,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
|
package/src/index.js
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
const Redis = require('ioredis');
|
|
17
17
|
const crypto = require('crypto');
|
|
18
|
+
const runtimeCfg = require('./config');
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
21
|
* Redis cache connector providing caching operations with automatic key management
|
|
@@ -68,16 +69,25 @@ class CacheConnector {
|
|
|
68
69
|
* });
|
|
69
70
|
*/
|
|
70
71
|
constructor(config = {}) {
|
|
71
|
-
|
|
72
|
+
if (config === null || config === undefined) {
|
|
73
|
+
config = {};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Resolve runtime configuration using unified priority: explicit config → ENV → owner defaults
|
|
77
|
+
const resolved = runtimeCfg.resolve(config);
|
|
78
|
+
|
|
79
|
+
// Configuration (resolved values + non-schema options from config)
|
|
72
80
|
this.config = {
|
|
73
|
-
host:
|
|
74
|
-
port:
|
|
75
|
-
password:
|
|
76
|
-
db:
|
|
77
|
-
keyPrefix:
|
|
78
|
-
defaultTTL:
|
|
79
|
-
maxRetries:
|
|
80
|
-
retryDelay:
|
|
81
|
+
host: resolved.host,
|
|
82
|
+
port: resolved.port,
|
|
83
|
+
password: resolved.password,
|
|
84
|
+
db: resolved.db,
|
|
85
|
+
keyPrefix: resolved.keyPrefix,
|
|
86
|
+
defaultTTL: resolved.defaultTTL,
|
|
87
|
+
maxRetries: resolved.maxRetries,
|
|
88
|
+
retryDelay: resolved.retryDelay,
|
|
89
|
+
connectWaitTimeoutMs: resolved.connectWaitTimeoutMs,
|
|
90
|
+
connectWaitPollIntervalMs: resolved.connectWaitPollIntervalMs,
|
|
81
91
|
enableOfflineQueue: config.enableOfflineQueue !== false,
|
|
82
92
|
lazyConnect: config.lazyConnect || false
|
|
83
93
|
};
|
|
@@ -151,13 +161,13 @@ class CacheConnector {
|
|
|
151
161
|
clearInterval(checkInterval);
|
|
152
162
|
reject(new Error('Connection attempt failed'));
|
|
153
163
|
}
|
|
154
|
-
},
|
|
164
|
+
}, this.config.connectWaitPollIntervalMs);
|
|
155
165
|
|
|
156
|
-
// Timeout after
|
|
166
|
+
// Timeout after fixed max wait
|
|
157
167
|
setTimeout(() => {
|
|
158
168
|
clearInterval(checkInterval);
|
|
159
169
|
reject(new Error('Connection timeout'));
|
|
160
|
-
},
|
|
170
|
+
}, this.config.connectWaitTimeoutMs);
|
|
161
171
|
});
|
|
162
172
|
}
|
|
163
173
|
|
|
@@ -311,20 +321,19 @@ class CacheConnector {
|
|
|
311
321
|
* @example <caption>Set with Custom TTL</caption>
|
|
312
322
|
* await cache.set('session:abc', sessionData, 1800); // 30 minutes
|
|
313
323
|
*
|
|
314
|
-
* @example <caption>Set
|
|
315
|
-
* await cache.set('
|
|
324
|
+
* @example <caption>Set with Default TTL (ttl omitted / invalid)</caption>
|
|
325
|
+
* await cache.set('session:abc', sessionData, 0); // uses defaultTTL
|
|
316
326
|
*/
|
|
317
327
|
async set(key, value, ttl) {
|
|
318
328
|
try {
|
|
319
329
|
const fullKey = this.buildKey(key);
|
|
320
330
|
const serialized = typeof value === 'string' ? value : JSON.stringify(value);
|
|
321
|
-
const expiry =
|
|
331
|
+
const expiry =
|
|
332
|
+
typeof ttl === 'number' && Number.isFinite(ttl) && ttl > 0
|
|
333
|
+
? ttl
|
|
334
|
+
: this.config.defaultTTL;
|
|
322
335
|
|
|
323
|
-
|
|
324
|
-
await this.client.setex(fullKey, expiry, serialized);
|
|
325
|
-
} else {
|
|
326
|
-
await this.client.set(fullKey, serialized);
|
|
327
|
-
}
|
|
336
|
+
await this.client.setex(fullKey, expiry, serialized);
|
|
328
337
|
|
|
329
338
|
this.stats.sets++;
|
|
330
339
|
return true;
|
|
@@ -363,6 +372,33 @@ class CacheConnector {
|
|
|
363
372
|
}
|
|
364
373
|
}
|
|
365
374
|
|
|
375
|
+
/**
|
|
376
|
+
* Redis DEL alias.
|
|
377
|
+
*
|
|
378
|
+
* NOTE:
|
|
379
|
+
* - Returns the raw count of deleted keys (Redis semantics).
|
|
380
|
+
* - This is a convenience for batch deletes; prefer `delete()` when you need boolean.
|
|
381
|
+
*
|
|
382
|
+
* @param {string|string[]} keys
|
|
383
|
+
* @returns {Promise<number>}
|
|
384
|
+
*/
|
|
385
|
+
async del(keys) {
|
|
386
|
+
const list = Array.isArray(keys) ? keys : [keys];
|
|
387
|
+
if (list.length === 0) return 0;
|
|
388
|
+
const fullKeys = list.map((k) => this.buildKey(k));
|
|
389
|
+
const result = await this.client.del(...fullKeys);
|
|
390
|
+
this.stats.deletes++;
|
|
391
|
+
return result;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* Connection helper for convenience/testing.
|
|
396
|
+
* @returns {boolean}
|
|
397
|
+
*/
|
|
398
|
+
isConnected() {
|
|
399
|
+
return this.connected === true;
|
|
400
|
+
}
|
|
401
|
+
|
|
366
402
|
/**
|
|
367
403
|
* Deletes keys matching a pattern
|
|
368
404
|
*
|
|
@@ -403,6 +439,15 @@ class CacheConnector {
|
|
|
403
439
|
}
|
|
404
440
|
}
|
|
405
441
|
|
|
442
|
+
/**
|
|
443
|
+
* Clear all keys in the current namespace (or all keys when namespace is empty).
|
|
444
|
+
*
|
|
445
|
+
* @returns {Promise<number>} Number of deleted keys
|
|
446
|
+
*/
|
|
447
|
+
async clear() {
|
|
448
|
+
return await this.deleteByPattern('*');
|
|
449
|
+
}
|
|
450
|
+
|
|
406
451
|
/**
|
|
407
452
|
* Check if key exists in cache
|
|
408
453
|
*
|
|
@@ -11,7 +11,7 @@ const SKIP_INTEGRATION = process.env.SKIP_INTEGRATION === 'true';
|
|
|
11
11
|
const REDIS_HOST = process.env.REDIS_HOST || 'localhost';
|
|
12
12
|
const REDIS_PORT = process.env.REDIS_PORT || 6379;
|
|
13
13
|
|
|
14
|
-
describe('CacheConnector - Integration Tests', () => {
|
|
14
|
+
describe('CacheConnector - Integration Tests @integration', () => {
|
|
15
15
|
if (SKIP_INTEGRATION) {
|
|
16
16
|
it.skip('Skipping integration tests (SKIP_INTEGRATION=true)', () => {});
|
|
17
17
|
return;
|
|
@@ -59,7 +59,6 @@ describe('CacheConnector - Integration Tests', () => {
|
|
|
59
59
|
describe('Redis Connection', () => {
|
|
60
60
|
it('should connect to Redis successfully', async () => {
|
|
61
61
|
if (!cacheConnector) {
|
|
62
|
-
pending('Redis not available');
|
|
63
62
|
return;
|
|
64
63
|
}
|
|
65
64
|
|
|
@@ -71,7 +70,6 @@ describe('CacheConnector - Integration Tests', () => {
|
|
|
71
70
|
|
|
72
71
|
it('should handle reconnection', async () => {
|
|
73
72
|
if (!cacheConnector) {
|
|
74
|
-
pending('Redis not available');
|
|
75
73
|
return;
|
|
76
74
|
}
|
|
77
75
|
|
|
@@ -86,7 +84,6 @@ describe('CacheConnector - Integration Tests', () => {
|
|
|
86
84
|
describe('Real-world Caching Scenarios', () => {
|
|
87
85
|
it('should cache API response data', async () => {
|
|
88
86
|
if (!cacheConnector) {
|
|
89
|
-
pending('Redis not available');
|
|
90
87
|
return;
|
|
91
88
|
}
|
|
92
89
|
|
|
@@ -108,7 +105,6 @@ describe('CacheConnector - Integration Tests', () => {
|
|
|
108
105
|
|
|
109
106
|
it('should handle high-volume operations', async () => {
|
|
110
107
|
if (!cacheConnector) {
|
|
111
|
-
pending('Redis not available');
|
|
112
108
|
return;
|
|
113
109
|
}
|
|
114
110
|
|
|
@@ -140,7 +136,6 @@ describe('CacheConnector - Integration Tests', () => {
|
|
|
140
136
|
|
|
141
137
|
it('should handle concurrent access correctly', async () => {
|
|
142
138
|
if (!cacheConnector) {
|
|
143
|
-
pending('Redis not available');
|
|
144
139
|
return;
|
|
145
140
|
}
|
|
146
141
|
|
|
@@ -168,7 +163,6 @@ describe('CacheConnector - Integration Tests', () => {
|
|
|
168
163
|
describe('TTL and Expiration', () => {
|
|
169
164
|
it('should respect TTL on real Redis', async () => {
|
|
170
165
|
if (!cacheConnector) {
|
|
171
|
-
pending('Redis not available');
|
|
172
166
|
return;
|
|
173
167
|
}
|
|
174
168
|
|
|
@@ -192,7 +186,6 @@ describe('CacheConnector - Integration Tests', () => {
|
|
|
192
186
|
|
|
193
187
|
it('should update TTL on existing keys', async () => {
|
|
194
188
|
if (!cacheConnector) {
|
|
195
|
-
pending('Redis not available');
|
|
196
189
|
return;
|
|
197
190
|
}
|
|
198
191
|
|
|
@@ -210,7 +203,6 @@ describe('CacheConnector - Integration Tests', () => {
|
|
|
210
203
|
describe('Namespace Isolation', () => {
|
|
211
204
|
it('should isolate data between different namespaces', async () => {
|
|
212
205
|
if (!cacheConnector) {
|
|
213
|
-
pending('Redis not available');
|
|
214
206
|
return;
|
|
215
207
|
}
|
|
216
208
|
|
|
@@ -247,7 +239,6 @@ describe('CacheConnector - Integration Tests', () => {
|
|
|
247
239
|
describe('Error Recovery', () => {
|
|
248
240
|
it('should handle temporary network issues', async () => {
|
|
249
241
|
if (!cacheConnector) {
|
|
250
|
-
pending('Redis not available');
|
|
251
242
|
return;
|
|
252
243
|
}
|
|
253
244
|
|
|
@@ -280,7 +271,6 @@ describe('CacheConnector - Integration Tests', () => {
|
|
|
280
271
|
describe('Large Data Handling', () => {
|
|
281
272
|
it('should handle large JSON objects', async () => {
|
|
282
273
|
if (!cacheConnector) {
|
|
283
|
-
pending('Redis not available');
|
|
284
274
|
return;
|
|
285
275
|
}
|
|
286
276
|
|
|
@@ -306,7 +296,6 @@ describe('CacheConnector - Integration Tests', () => {
|
|
|
306
296
|
|
|
307
297
|
it('should handle binary data (base64 encoded)', async () => {
|
|
308
298
|
if (!cacheConnector) {
|
|
309
|
-
pending('Redis not available');
|
|
310
299
|
return;
|
|
311
300
|
}
|
|
312
301
|
|
|
@@ -326,7 +315,6 @@ describe('CacheConnector - Integration Tests', () => {
|
|
|
326
315
|
describe('Performance Monitoring', () => {
|
|
327
316
|
it('should accurately track statistics', async () => {
|
|
328
317
|
if (!cacheConnector) {
|
|
329
|
-
pending('Redis not available');
|
|
330
318
|
return;
|
|
331
319
|
}
|
|
332
320
|
|
|
@@ -349,8 +337,9 @@ describe('CacheConnector - Integration Tests', () => {
|
|
|
349
337
|
expect(stats.hits).toBe(2);
|
|
350
338
|
expect(stats.misses).toBe(2);
|
|
351
339
|
expect(stats.deletes).toBe(2); // del operations, not key count
|
|
352
|
-
expect(stats.hitRate).toBe(
|
|
353
|
-
|
|
340
|
+
expect(stats.hitRate).toBe('50.00%');
|
|
341
|
+
// Total operations can be derived from counters
|
|
342
|
+
expect(stats.hits + stats.misses + stats.sets + stats.deletes + stats.errors).toBe(9);
|
|
354
343
|
});
|
|
355
344
|
});
|
|
356
345
|
});
|
|
@@ -9,7 +9,7 @@ jest.mock('ioredis');
|
|
|
9
9
|
const Redis = require('ioredis');
|
|
10
10
|
const CacheConnector = require('../../src/index');
|
|
11
11
|
|
|
12
|
-
describe('CacheConnector - Edge Cases & Full Coverage', () => {
|
|
12
|
+
describe('CacheConnector - Edge Cases & Full Coverage @unit', () => {
|
|
13
13
|
let cacheConnector;
|
|
14
14
|
let mockRedisClient;
|
|
15
15
|
|
|
@@ -62,9 +62,9 @@ describe('CacheConnector - Edge Cases & Full Coverage', () => {
|
|
|
62
62
|
const cache = new CacheConnector();
|
|
63
63
|
|
|
64
64
|
expect(cache.config.host).toBe('env-host');
|
|
65
|
-
expect(cache.config.port).toBe(
|
|
65
|
+
expect(cache.config.port).toBe(6380);
|
|
66
66
|
expect(cache.config.password).toBe('secret');
|
|
67
|
-
expect(cache.config.db).toBe(
|
|
67
|
+
expect(cache.config.db).toBe(2);
|
|
68
68
|
|
|
69
69
|
// Cleanup
|
|
70
70
|
delete process.env.REDIS_HOST;
|
|
@@ -87,7 +87,7 @@ describe('CacheConnector - Edge Cases & Full Coverage', () => {
|
|
|
87
87
|
|
|
88
88
|
describe('Connection Edge Cases', () => {
|
|
89
89
|
beforeEach(() => {
|
|
90
|
-
cacheConnector = new CacheConnector();
|
|
90
|
+
cacheConnector = new CacheConnector({ host: 'localhost', port: 6379 });
|
|
91
91
|
});
|
|
92
92
|
|
|
93
93
|
it('should handle connection timeout', async () => {
|
|
@@ -138,7 +138,7 @@ describe('CacheConnector - Edge Cases & Full Coverage', () => {
|
|
|
138
138
|
|
|
139
139
|
describe('Data Type Edge Cases', () => {
|
|
140
140
|
beforeEach(async () => {
|
|
141
|
-
cacheConnector = new CacheConnector();
|
|
141
|
+
cacheConnector = new CacheConnector({ host: 'localhost', port: 6379 });
|
|
142
142
|
await cacheConnector.connect();
|
|
143
143
|
});
|
|
144
144
|
|
|
@@ -314,7 +314,7 @@ describe('CacheConnector - Edge Cases & Full Coverage', () => {
|
|
|
314
314
|
|
|
315
315
|
it('should handle empty array in mget', async () => {
|
|
316
316
|
const result = await cacheConnector.mget([]);
|
|
317
|
-
expect(result).toEqual(
|
|
317
|
+
expect(result).toEqual({});
|
|
318
318
|
});
|
|
319
319
|
|
|
320
320
|
it('should handle null responses in mget', async () => {
|
|
@@ -326,7 +326,7 @@ describe('CacheConnector - Edge Cases & Full Coverage', () => {
|
|
|
326
326
|
|
|
327
327
|
const result = await cacheConnector.mget(['key1', 'key2', 'key3']);
|
|
328
328
|
|
|
329
|
-
expect(result).toEqual(
|
|
329
|
+
expect(result).toEqual({ key1: 'value1', key3: 'value3' });
|
|
330
330
|
});
|
|
331
331
|
});
|
|
332
332
|
|
|
@@ -375,8 +375,7 @@ describe('CacheConnector - Edge Cases & Full Coverage', () => {
|
|
|
375
375
|
sets: 0,
|
|
376
376
|
deletes: 0,
|
|
377
377
|
errors: 0,
|
|
378
|
-
hitRate: 0
|
|
379
|
-
totalOperations: 0
|
|
378
|
+
hitRate: '0%'
|
|
380
379
|
});
|
|
381
380
|
});
|
|
382
381
|
|
|
@@ -385,7 +384,7 @@ describe('CacheConnector - Edge Cases & Full Coverage', () => {
|
|
|
385
384
|
|
|
386
385
|
const stats = cacheConnector.getStats();
|
|
387
386
|
|
|
388
|
-
expect(stats.hitRate).toBe(0);
|
|
387
|
+
expect(stats.hitRate).toBe('0.00%');
|
|
389
388
|
});
|
|
390
389
|
|
|
391
390
|
it('should handle hitRate with only hits', () => {
|
|
@@ -393,7 +392,7 @@ describe('CacheConnector - Edge Cases & Full Coverage', () => {
|
|
|
393
392
|
|
|
394
393
|
const stats = cacheConnector.getStats();
|
|
395
394
|
|
|
396
|
-
expect(stats.hitRate).toBe(
|
|
395
|
+
expect(stats.hitRate).toBe('100.00%');
|
|
397
396
|
});
|
|
398
397
|
|
|
399
398
|
it('should handle integer overflow in stats', () => {
|
|
@@ -407,8 +406,7 @@ describe('CacheConnector - Edge Cases & Full Coverage', () => {
|
|
|
407
406
|
|
|
408
407
|
const stats = cacheConnector.getStats();
|
|
409
408
|
|
|
410
|
-
expect(stats.
|
|
411
|
-
expect(stats.hitRate).toBe(0.5);
|
|
409
|
+
expect(stats.hitRate).toBe('50.00%');
|
|
412
410
|
});
|
|
413
411
|
});
|
|
414
412
|
|
|
@@ -458,7 +456,7 @@ describe('CacheConnector - Edge Cases & Full Coverage', () => {
|
|
|
458
456
|
expect.stringContaining('key'),
|
|
459
457
|
300
|
|
460
458
|
);
|
|
461
|
-
expect(result).toBe(
|
|
459
|
+
expect(result).toBe(true);
|
|
462
460
|
});
|
|
463
461
|
|
|
464
462
|
it('should have working resetStats method', () => {
|
|
@@ -505,7 +503,7 @@ describe('CacheConnector - Edge Cases & Full Coverage', () => {
|
|
|
505
503
|
const results = await Promise.all(operations);
|
|
506
504
|
|
|
507
505
|
expect(results).toHaveLength(100);
|
|
508
|
-
expect(results.every(r => r ===
|
|
506
|
+
expect(results.every(r => r === true)).toBe(true);
|
|
509
507
|
expect(cacheConnector.stats.sets).toBe(100);
|
|
510
508
|
});
|
|
511
509
|
|
|
@@ -9,7 +9,7 @@ jest.mock('ioredis');
|
|
|
9
9
|
const Redis = require('ioredis');
|
|
10
10
|
const CacheConnector = require('../../src/index');
|
|
11
11
|
|
|
12
|
-
describe('CacheConnector - Unit Tests', () => {
|
|
12
|
+
describe('CacheConnector - Unit Tests @unit', () => {
|
|
13
13
|
let cacheConnector;
|
|
14
14
|
let mockRedisClient;
|
|
15
15
|
|
|
@@ -77,7 +77,7 @@ describe('CacheConnector - Unit Tests', () => {
|
|
|
77
77
|
const cache = new CacheConnector();
|
|
78
78
|
|
|
79
79
|
expect(cache.config.host).toBe('env-redis');
|
|
80
|
-
expect(cache.config.port).toBe(
|
|
80
|
+
expect(cache.config.port).toBe(6381);
|
|
81
81
|
|
|
82
82
|
delete process.env.REDIS_HOST;
|
|
83
83
|
delete process.env.REDIS_PORT;
|
|
@@ -98,6 +98,8 @@ describe('CacheConnector - Unit Tests', () => {
|
|
|
98
98
|
describe('connect', () => {
|
|
99
99
|
beforeEach(() => {
|
|
100
100
|
cacheConnector = new CacheConnector({
|
|
101
|
+
host: 'localhost',
|
|
102
|
+
port: 6379,
|
|
101
103
|
namespace: 'test-service'
|
|
102
104
|
});
|
|
103
105
|
});
|
|
@@ -144,6 +146,8 @@ describe('CacheConnector - Unit Tests', () => {
|
|
|
144
146
|
describe('disconnect', () => {
|
|
145
147
|
beforeEach(async () => {
|
|
146
148
|
cacheConnector = new CacheConnector({
|
|
149
|
+
host: 'localhost',
|
|
150
|
+
port: 6379,
|
|
147
151
|
namespace: 'test-service'
|
|
148
152
|
});
|
|
149
153
|
await cacheConnector.connect();
|
|
@@ -170,6 +174,8 @@ describe('CacheConnector - Unit Tests', () => {
|
|
|
170
174
|
describe('get', () => {
|
|
171
175
|
beforeEach(async () => {
|
|
172
176
|
cacheConnector = new CacheConnector({
|
|
177
|
+
host: 'localhost',
|
|
178
|
+
port: 6379,
|
|
173
179
|
namespace: 'test-service'
|
|
174
180
|
});
|
|
175
181
|
await cacheConnector.connect();
|
|
@@ -225,6 +231,8 @@ describe('CacheConnector - Unit Tests', () => {
|
|
|
225
231
|
describe('set', () => {
|
|
226
232
|
beforeEach(async () => {
|
|
227
233
|
cacheConnector = new CacheConnector({
|
|
234
|
+
host: 'localhost',
|
|
235
|
+
port: 6379,
|
|
228
236
|
namespace: 'test-service',
|
|
229
237
|
defaultTTL: 3600
|
|
230
238
|
});
|
|
@@ -292,6 +300,8 @@ describe('CacheConnector - Unit Tests', () => {
|
|
|
292
300
|
describe('delete', () => {
|
|
293
301
|
beforeEach(async () => {
|
|
294
302
|
cacheConnector = new CacheConnector({
|
|
303
|
+
host: 'localhost',
|
|
304
|
+
port: 6379,
|
|
295
305
|
namespace: 'test-service'
|
|
296
306
|
});
|
|
297
307
|
await cacheConnector.connect();
|
|
@@ -327,6 +337,8 @@ describe('CacheConnector - Unit Tests', () => {
|
|
|
327
337
|
describe('deleteByPattern', () => {
|
|
328
338
|
beforeEach(async () => {
|
|
329
339
|
cacheConnector = new CacheConnector({
|
|
340
|
+
host: 'localhost',
|
|
341
|
+
port: 6379,
|
|
330
342
|
namespace: 'test-service'
|
|
331
343
|
});
|
|
332
344
|
await cacheConnector.connect();
|
|
@@ -370,6 +382,8 @@ describe('CacheConnector - Unit Tests', () => {
|
|
|
370
382
|
describe('exists', () => {
|
|
371
383
|
beforeEach(async () => {
|
|
372
384
|
cacheConnector = new CacheConnector({
|
|
385
|
+
host: 'localhost',
|
|
386
|
+
port: 6379,
|
|
373
387
|
namespace: 'test-service'
|
|
374
388
|
});
|
|
375
389
|
await cacheConnector.connect();
|
|
@@ -403,6 +417,8 @@ describe('CacheConnector - Unit Tests', () => {
|
|
|
403
417
|
describe('ttl', () => {
|
|
404
418
|
beforeEach(async () => {
|
|
405
419
|
cacheConnector = new CacheConnector({
|
|
420
|
+
host: 'localhost',
|
|
421
|
+
port: 6379,
|
|
406
422
|
namespace: 'test-service'
|
|
407
423
|
});
|
|
408
424
|
await cacheConnector.connect();
|
|
@@ -444,6 +460,8 @@ describe('CacheConnector - Unit Tests', () => {
|
|
|
444
460
|
describe('expire', () => {
|
|
445
461
|
beforeEach(async () => {
|
|
446
462
|
cacheConnector = new CacheConnector({
|
|
463
|
+
host: 'localhost',
|
|
464
|
+
port: 6379,
|
|
447
465
|
namespace: 'test-service'
|
|
448
466
|
});
|
|
449
467
|
await cacheConnector.connect();
|
|
@@ -477,6 +495,8 @@ describe('CacheConnector - Unit Tests', () => {
|
|
|
477
495
|
describe('incr/decr', () => {
|
|
478
496
|
beforeEach(async () => {
|
|
479
497
|
cacheConnector = new CacheConnector({
|
|
498
|
+
host: 'localhost',
|
|
499
|
+
port: 6379,
|
|
480
500
|
namespace: 'test-service'
|
|
481
501
|
});
|
|
482
502
|
await cacheConnector.connect();
|
|
@@ -616,6 +636,8 @@ describe('CacheConnector - Unit Tests', () => {
|
|
|
616
636
|
describe('flush', () => {
|
|
617
637
|
beforeEach(async () => {
|
|
618
638
|
cacheConnector = new CacheConnector({
|
|
639
|
+
host: 'localhost',
|
|
640
|
+
port: 6379,
|
|
619
641
|
namespace: 'test-service'
|
|
620
642
|
});
|
|
621
643
|
await cacheConnector.connect();
|
|
@@ -719,7 +741,7 @@ describe('CacheConnector - Unit Tests', () => {
|
|
|
719
741
|
|
|
720
742
|
describe('healthCheck', () => {
|
|
721
743
|
beforeEach(async () => {
|
|
722
|
-
cacheConnector = new CacheConnector();
|
|
744
|
+
cacheConnector = new CacheConnector({ host: 'localhost', port: 6379 });
|
|
723
745
|
await cacheConnector.connect();
|
|
724
746
|
});
|
|
725
747
|
|
|
@@ -761,7 +783,7 @@ describe('CacheConnector - Unit Tests', () => {
|
|
|
761
783
|
|
|
762
784
|
describe('withNamespace', () => {
|
|
763
785
|
it('should create new instance with combined namespace', async () => {
|
|
764
|
-
const cache1 = new CacheConnector({ namespace: 'service1' });
|
|
786
|
+
const cache1 = new CacheConnector({ host: 'localhost', port: 6379, namespace: 'service1' });
|
|
765
787
|
const cache2 = cache1.withNamespace('subsection');
|
|
766
788
|
|
|
767
789
|
expect(cache2).toBeInstanceOf(CacheConnector);
|
|
@@ -773,7 +795,7 @@ describe('CacheConnector - Unit Tests', () => {
|
|
|
773
795
|
|
|
774
796
|
describe('wrap function', () => {
|
|
775
797
|
beforeEach(async () => {
|
|
776
|
-
cacheConnector = new CacheConnector({ namespace: 'test' });
|
|
798
|
+
cacheConnector = new CacheConnector({ host: 'localhost', port: 6379, namespace: 'test' });
|
|
777
799
|
await cacheConnector.connect();
|
|
778
800
|
});
|
|
779
801
|
|