mm_cachebase 1.9.7 → 2.0.0

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.
Files changed (4) hide show
  1. package/README.md +269 -559
  2. package/index.js +2075 -1324
  3. package/package.json +3 -3
  4. package/test.js +728 -536
package/test.js CHANGED
@@ -1,536 +1,728 @@
1
- const assert = require('assert');
2
- const { CacheBase, cachebaseAdmin } = require('./index.js');
3
-
4
- class TestRunner {
5
- constructor() {
6
- this.totalTests = 0;
7
- this.passedTests = 0;
8
- this.results = [];
9
- }
10
-
11
- async runTest(name, testFunction) {
12
- this.totalTests++;
13
- try {
14
- await testFunction();
15
- this.passedTests++;
16
- this.results.push({ name, passed: true });
17
- $.log.debug(`✅ ${name}`);
18
- } catch (error) {
19
- this.results.push({ name, passed: false, error: error.message });
20
- $.log.debug(`❌ ${name} - ${error.message}`);
21
- }
22
- }
23
-
24
- displayResults() {
25
- $.log.debug('\n========== 测试结果 ==========');
26
- const passRate = (this.passedTests / this.totalTests * 100).toFixed(2);
27
- $.log.debug(`通过: ${this.passedTests}/${this.totalTests} (${passRate}%)`);
28
-
29
- // 显示失败的测试
30
- const failedTests = this.results.filter(r => !r.passed);
31
- if (failedTests.length > 0) {
32
- $.log.debug('\n失败的测试:');
33
- failedTests.forEach(test => {
34
- $.log.debug(` - ${test.name}: ${test.error}`);
35
- });
36
- }
37
-
38
- return passRate;
39
- }
40
- }
41
-
42
- async function test() {
43
- $.log.debug('[CacheBase] ==============================');
44
- $.log.debug('[CacheBase] 开始兼容性测试');
45
- $.log.debug('[CacheBase] ==============================');
46
-
47
- try {
48
- const runner = new TestRunner();
49
-
50
- // 测试基础方法
51
- $.log.debug('[CacheBase] \n========== 测试基础方法 ==========');
52
-
53
- await runner.runTest('set和get方法', async () => {
54
- const cache = new CacheBase({ scope: 'test_set_get' });
55
- await cache.init();
56
-
57
- await cache.set('test_key', 'test_value');
58
- const value = await cache.get('test_key');
59
-
60
- assert.equal(value, 'test_value', 'set和get方法测试失败');
61
-
62
- await cache.del('test_key');
63
- const deleted_value = await cache.get('test_key');
64
-
65
- assert.equal(deleted_value, null, 'del方法测试失败');
66
-
67
- await cache.close();
68
- });
69
-
70
- await runner.runTest('del方法', async () => {
71
- const cache = new CacheBase({ scope: 'test_del' });
72
- await cache.set('key2', 'value2');
73
- const deleted = await cache.del('key2');
74
- if (deleted !== true) {
75
- throw new Error(`删除失败,预期: true, 实际: ${deleted}`);
76
- }
77
- const value = await cache.get('key2');
78
- if (value !== null) {
79
- throw new Error(`键未被删除,值: ${value}`);
80
- }
81
- });
82
-
83
- await runner.runTest('exists/has方法', async () => {
84
- const cache = new CacheBase({ scope: 'test_exists_has' });
85
- await cache.set('key3', 'value3');
86
- const exists = await cache.exists('key3');
87
- if (exists !== true) {
88
- throw new Error(`exists失败,预期: true, 实际: ${exists}`);
89
- }
90
- const has = await cache.has('key3');
91
- if (!has) {
92
- throw new Error(`has失败,预期: true, 实际: ${has}`);
93
- }
94
- });
95
-
96
- await runner.runTest('keys方法', async () => {
97
- const cache = new CacheBase({
98
- persist: true,
99
- scope: 'test_keys'
100
- });
101
- await cache.set('key4', 'value4');
102
- await cache.set('key5', 'value5');
103
- const keys = await cache.keys();
104
- if (keys.length !== 2 || !keys.includes('key4') || !keys.includes('key5')) {
105
- throw new Error(`keys失败,预期包含key4和key5, 实际: ${JSON.stringify(keys)}`);
106
- }
107
- const filteredKeys = await cache.keys('key4*');
108
- if (filteredKeys.length !== 1 || filteredKeys[0] !== 'key4') {
109
- throw new Error(`keys过滤失败,预期: ["key4"], 实际: ${JSON.stringify(filteredKeys)}`);
110
- }
111
- });
112
-
113
- await runner.runTest('dbsize方法', async () => {
114
- const cache = new CacheBase({
115
- persist: true,
116
- scope: 'test_dbsize'
117
- });
118
- await cache.set('key4', 'value4');
119
- await cache.set('key5', 'value5');
120
- const size = await cache.dbsize();
121
- if (size !== 2) {
122
- throw new Error(`dbsize失败,预期: 2, 实际: ${size}`);
123
- }
124
- });
125
-
126
- await runner.runTest('getset方法', async () => {
127
- const cache = new CacheBase({ scope: 'test_getset' });
128
- await cache.set('key4', 'value4');
129
- const oldValue = await cache.getset('key4', 'newvalue4');
130
- if (oldValue !== 'value4') {
131
- throw new Error(`getset失败,预期旧值: value4, 实际: ${oldValue}`);
132
- }
133
- const newValue = await cache.get('key4');
134
- if (newValue !== 'newvalue4') {
135
- throw new Error(`getset失败,预期新值: newvalue4, 实际: ${newValue}`);
136
- }
137
- });
138
-
139
- await runner.runTest('flushdb/clear方法', async () => {
140
- const cache = new CacheBase({
141
- persist: true,
142
- scope: 'test_flushdb'
143
- });
144
- await cache.set('key6', 'value6');
145
- let result = await cache.clear();
146
- if (result !== true) {
147
- throw new Error(`flushdb失败,预期: true, 实际: ${result}`);
148
- }
149
- const size = await cache.dbsize();
150
- if (size !== 0) {
151
- throw new Error(`flushdb后大小不为0: ${size}`);
152
- }
153
-
154
- // 测试clear方法(兼容)
155
- await cache.set('key7', 'value7');
156
- result = await cache.clear();
157
- if (result !== true) {
158
- throw new Error(`clear失败,预期: true, 实际: ${result}`);
159
- }
160
- const sizeAfterClear = await cache.dbsize();
161
- if (sizeAfterClear !== 0) {
162
- throw new Error(`clear后大小不为0: ${sizeAfterClear}`);
163
- }
164
- });
165
-
166
- // 测试哈希表方法
167
- $.log.debug('[CacheBase] \n========== 测试哈希表方法 ==========');
168
- const hashCache = new CacheBase({ scope: 'test_hash' });
169
-
170
- await runner.runTest('hset和hget方法', async () => {
171
- const result1 = await hashCache.hset('hash1', 'field1', 'value1');
172
- if (result1 !== 1) {
173
- throw new Error(`hset新建失败,预期: 1, 实际: ${result1}`);
174
- }
175
-
176
- const result2 = await hashCache.hset('hash1', 'field1', 'value1_updated');
177
- if (result2 !== 0) {
178
- throw new Error(`hset更新失败,预期: 0, 实际: ${result2}`);
179
- }
180
-
181
- const value = await hashCache.hget('hash1', 'field1');
182
- if (value !== 'value1_updated') {
183
- throw new Error(`hget失败,预期: value1_updated, 实际: ${value}`);
184
- }
185
- });
186
-
187
- await runner.runTest('hgetall方法', async () => {
188
- await hashCache.hset('hash1', 'field2', 'value2');
189
- const hash = await hashCache.hgetall('hash1');
190
- if (JSON.stringify(hash) !== JSON.stringify({ field1: 'value1_updated', field2: 'value2' })) {
191
- throw new Error(`hgetall失败,预期: {"field1":"value1_updated","field2":"value2"}, 实际: ${JSON.stringify(hash)}`);
192
- }
193
- });
194
-
195
- await runner.runTest('hdel方法', async () => {
196
- const result = await hashCache.hdel('hash1', 'field1');
197
- if (result !== true) {
198
- throw new Error(`hdel失败,预期: true, 实际: ${result}`);
199
- }
200
- const value = await hashCache.hget('hash1', 'field1');
201
- if (value !== undefined) {
202
- throw new Error(`hdel后字段未被删除,值: ${value}`);
203
- }
204
-
205
- // 删除不存在的字段
206
- const result2 = await hashCache.hdel('hash1', 'non_existent');
207
- if (result2 !== false) {
208
- throw new Error(`hdel不存在字段失败,预期: false, 实际: ${result2}`);
209
- }
210
- });
211
-
212
- // 测试批量操作
213
- $.log.debug('[CacheBase] \n========== 测试批量操作 ==========');
214
- const batchCache = new CacheBase({ scope: 'test_batch' });
215
-
216
- await runner.runTest('mset方法', async () => {
217
- const result = await batchCache.mset('key7', 'value7', 'key8', 'value8');
218
- if (result !== true) {
219
- throw new Error(`mset失败,预期: true, 实际: ${result}`);
220
- }
221
- const value7 = await batchCache.get('key7');
222
- const value8 = await batchCache.get('key8');
223
- if (value7 !== 'value7' || value8 !== 'value8') {
224
- throw new Error(`mset设置失败,value7: ${value7}, value8: ${value8}`);
225
- }
226
- });
227
-
228
- await runner.runTest('mget方法', async () => {
229
- const values = await batchCache.mget(['key7', 'key8', 'nonExistentKey']);
230
- if (JSON.stringify(values) !== JSON.stringify(['value7', 'value8', null])) {
231
- throw new Error(`mget失败,预期: ["value7","value8",null], 实际: ${JSON.stringify(values)}`);
232
- }
233
- });
234
-
235
- // 测试过期时间
236
- $.log.debug('[CacheBase] \n========== 测试过期时间 ==========');
237
- const expireCache = new CacheBase({ scope: 'test_expire' });
238
-
239
- await runner.runTest('set带过期时间', async () => {
240
- await expireCache.set('expire1', 'value1', 1); // 1秒过期
241
- let ttl = await expireCache.ttl('expire1');
242
- if (ttl <= 0) {
243
- throw new Error(`ttl初始值错误: ${ttl}`);
244
- }
245
-
246
- // 等待过期
247
- await new Promise(resolve => setTimeout(resolve, 1100));
248
-
249
- ttl = await expireCache.ttl('expire1');
250
- if (ttl !== -2) {
251
- throw new Error(`过期后ttl错误,预期: -2, 实际: ${ttl}`);
252
- }
253
-
254
- const value = await expireCache.get('expire1');
255
- if (value !== null) {
256
- throw new Error(`过期后键仍存在: ${value}`);
257
- }
258
- });
259
-
260
- await runner.runTest('expire方法', async () => {
261
- await expireCache.set('expire2', 'value2');
262
- const result = await expireCache.expire('expire2', 1);
263
- if (result !== true) {
264
- throw new Error(`expire设置失败,预期: true, 实际: ${result}`);
265
- }
266
- let ttl = await expireCache.ttl('expire2');
267
- if (ttl <= 0) {
268
- throw new Error(`expire后ttl错误: ${ttl}`);
269
- }
270
- });
271
-
272
- await runner.runTest('persist方法', async () => {
273
- await expireCache.set('expire3', 'value3', 30);
274
- const result = await expireCache.persist('expire3');
275
- if (result !== true) {
276
- throw new Error(`persist设置失败,预期: true, 实际: ${result}`);
277
- }
278
- const ttl = await expireCache.ttl('expire3');
279
- if (ttl !== -1) {
280
- throw new Error(`persist后ttl错误,预期: -1, 实际: ${ttl}`);
281
- }
282
- });
283
-
284
- // 测试数值操作
285
- $.log.debug('[CacheBase] \n========== 测试数值操作 ==========');
286
- const numCache = new CacheBase({ scope: 'test_num' });
287
-
288
- await runner.runTest('incr方法', async () => {
289
- const result1 = await numCache.incr('counter');
290
- if (result1 !== 1) {
291
- throw new Error(`incr初始值失败,预期: 1, 实际: ${result1}`);
292
- }
293
- const value1 = await numCache.get('counter');
294
- if (value1 !== 1) {
295
- throw new Error(`incr值错误,预期: 1, 实际: ${value1}`);
296
- }
297
-
298
- const result2 = await numCache.incr('counter');
299
- if (result2 !== 2) {
300
- throw new Error(`incr递增失败,预期: 2, 实际: ${result2}`);
301
- }
302
- const value2 = await numCache.get('counter');
303
- if (value2 !== 2) {
304
- throw new Error(`incr递增后值错误,预期: 2, 实际: ${value2}`);
305
- }
306
- });
307
-
308
- await runner.runTest('decr方法', async () => {
309
- const result = await numCache.decr('counter');
310
- if (result !== 1) {
311
- throw new Error(`decr递减失败,预期: 1, 实际: ${result}`);
312
- }
313
- const value = await numCache.get('counter');
314
- if (value !== 1) {
315
- throw new Error(`decr递减后值错误,预期: 1, 实际: ${value}`);
316
- }
317
- });
318
-
319
- await runner.runTest('incrby方法', async () => {
320
- const result = await numCache.incrby('counter', 5);
321
- if (result !== 6) {
322
- throw new Error(`incrby增加失败,预期: 6, 实际: ${result}`);
323
- }
324
- const value = await numCache.get('counter');
325
- if (value !== 6) {
326
- throw new Error(`incrby增加后值错误,预期: 6, 实际: ${value}`);
327
- }
328
- });
329
-
330
- await runner.runTest('decrby方法', async () => {
331
- const result = await numCache.decrby('counter', 2);
332
- if (result !== 4) {
333
- throw new Error(`decrby减少失败,预期: 4, 实际: ${result}`);
334
- }
335
- const value = await numCache.get('counter');
336
- if (value !== 4) {
337
- throw new Error(`decrby减少后值错误,预期: 4, 实际: ${value}`);
338
- }
339
- });
340
-
341
- await runner.runTest('incrbyfloat方法', async () => {
342
- const result = await numCache.incrbyfloat('counter', 0.5);
343
- if (result !== 4.5) {
344
- throw new Error(`incrbyfloat增加失败,预期: 4.5, 实际: ${result}`);
345
- }
346
- const value = await numCache.get('counter');
347
- if (value !== 4.5) {
348
- throw new Error(`incrbyfloat增加后值错误,预期: 4.5, 实际: ${value}`);
349
- }
350
- });
351
-
352
- await runner.runTest('add方法(兼容)', async () => {
353
- // 先删除键,确保它不存在
354
- await numCache.del('counter');
355
- const result = await numCache.add('counter', 10);
356
- if (result !== true) {
357
- throw new Error(`add增加失败,预期: true, 实际: ${result}`);
358
- }
359
- const value = await numCache.get('counter');
360
- if (value !== 10) {
361
- throw new Error(`add增加后值错误,预期: 10, 实际: ${value}`);
362
- }
363
-
364
- // 测试键已存在时的行为(不应修改值)
365
- const result2 = await numCache.add('counter', 20);
366
- if (result2 !== false) {
367
- throw new Error(`add键已存在时失败,预期: false, 实际: ${result2}`);
368
- }
369
- const value2 = await numCache.get('counter');
370
- if (value2 !== 10) {
371
- throw new Error(`add键已存在时值不应改变,预期: 10, 实际: ${value2}`);
372
- }
373
- });
374
-
375
- await runner.runTest('addFloat方法(兼容)', async () => {
376
- const result = await numCache.addFloat('counter', 0.5);
377
- if (result !== 10.5) {
378
- throw new Error(`addFloat增加失败,预期: 10.5, 实际: ${result}`);
379
- }
380
- const value = await numCache.get('counter');
381
- if (value !== 10.5) {
382
- throw new Error(`addFloat增加后值错误,预期: 10.5, 实际: ${value}`);
383
- }
384
- });
385
-
386
- // 测试字符串操作
387
- $.log.debug('[CacheBase] \n========== 测试字符串操作 ==========');
388
- const strCache = new CacheBase({ scope: 'test_str' });
389
-
390
- await runner.runTest('append方法', async () => {
391
- await strCache.set('str', 'hello');
392
- const result = await strCache.append('str', ' world');
393
- if (result !== 11) {
394
- throw new Error(`append长度错误,预期: 11, 实际: ${result}`);
395
- }
396
- const value = await strCache.get('str');
397
- if (value !== 'hello world') {
398
- throw new Error(`append值错误,预期: hello world, 实际: ${value}`);
399
- }
400
- });
401
-
402
- await runner.runTest('strlen方法', async () => {
403
- const result = await strCache.strlen('str');
404
- if (result !== 11) {
405
- throw new Error(`strlen长度错误,预期: 11, 实际: ${result}`);
406
- }
407
-
408
- // 不存在的键
409
- const result2 = await strCache.strlen('non_existent');
410
- if (result2 !== 0) {
411
- throw new Error(`strlen不存在键错误,预期: 0, 实际: ${result2}`);
412
- }
413
- });
414
-
415
- await runner.runTest('addStr方法(兼容)', async () => {
416
- const result = await strCache.addStr('str', '!');
417
- if (result !== 12) {
418
- throw new Error(`addStr长度错误,预期: 12, 实际: ${result}`);
419
- }
420
- const value = await strCache.get('str');
421
- if (value !== 'hello world!') {
422
- throw new Error(`addStr值错误,预期: hello world!, 实际: ${value}`);
423
- }
424
- });
425
-
426
- // 测试事件触发
427
- $.log.debug('[CacheBase] \n========== 测试事件触发 ==========');
428
- const eventCache = new CacheBase({ scope: 'test_event' });
429
-
430
- await runner.runTest('set事件触发', async () => {
431
- return new Promise(async (resolve, reject) => {
432
- let beforeTriggered = false;
433
- let afterTriggered = false;
434
-
435
- eventCache.once('set_before', (data) => {
436
- if (data.key === 'event_key' && data.value === 'event_value') {
437
- beforeTriggered = true;
438
- }
439
- });
440
-
441
- eventCache.once('set_after', (data) => {
442
- if (data.key === 'event_key' && data.value === 'event_value' && data.result === 'OK') {
443
- afterTriggered = true;
444
- setTimeout(() => {
445
- if (beforeTriggered && afterTriggered) {
446
- resolve();
447
- } else {
448
- reject(new Error('set事件未全部触发'));
449
- }
450
- }, 10);
451
- }
452
- });
453
-
454
- await eventCache.set('event_key', 'event_value');
455
- });
456
- });
457
-
458
- await runner.runTest('error事件触发', async () => {
459
- return new Promise(async (resolve, reject) => {
460
- eventCache.once('mset_error', (data) => {
461
- if (data.error && data.error.message.includes('参数数量必须为偶数')) {
462
- resolve();
463
- } else {
464
- reject(new Error('mset_error事件触发但消息不正确'));
465
- }
466
- });
467
-
468
- try {
469
- await eventCache.mset(null);
470
- reject(new Error('mset应抛出错误但没有'));
471
- } catch (error) {
472
- // 预期的错误,等待事件触发
473
- setTimeout(() => {
474
- reject(new Error('mset_error事件未触发'));
475
- }, 100);
476
- }
477
- });
478
- });
479
-
480
- // 测试管理功能
481
- $.log.debug('[CacheBase] \n========== 测试管理功能 ==========');
482
-
483
- await runner.runTest('cachebaseAdmin创建实例', async () => {
484
- const cache1 = cachebaseAdmin('test_scope');
485
- const cache2 = cachebaseAdmin('test_scope');
486
- if (cache1 !== cache2) {
487
- throw new Error('cachebaseAdmin应返回相同实例但没有');
488
- }
489
-
490
- const cache3 = cachebaseAdmin('another_scope');
491
- if (cache1 === cache3) {
492
- throw new Error('cachebaseAdmin应返回不同作用域的不同实例但没有');
493
- }
494
- });
495
-
496
- await runner.runTest('dispose方法', async () => {
497
- const disposeCache = new CacheBase({
498
- persist: true,
499
- scope: 'test_dispose'
500
- });
501
- await disposeCache.set('key_to_dispose', 'value');
502
- disposeCache.dispose();
503
-
504
- const size = await disposeCache.dbsize();
505
- if (size !== 0) {
506
- throw new Error(`dispose后大小不为0: ${size}`);
507
- }
508
- });
509
-
510
- // 显示测试结果
511
- const passRate = runner.displayResults();
512
- $.log.debug(`[CacheBase] \n测试完成!通过率: ${passRate}%`);
513
-
514
- $.log.debug('[CacheBase] \n==============================');
515
- $.log.debug('[CacheBase] 所有兼容性测试完成!');
516
- $.log.debug('[CacheBase] ==============================');
517
-
518
- } catch (error) {
519
- $.log.error('[CacheBase] 测试过程中出现错误:', error);
520
- }
521
- }
522
-
523
- test().then(() => {
524
- // 测试成功完成
525
- $.log.debug('[CacheBase] 测试脚本正常退出');
526
- process.exit(0);
527
- }).catch(err => {
528
- $.log.error('[CacheBase] 未捕获的错误:', err);
529
- process.exit(1);
530
- });
531
-
532
- // 添加超时保护,但让Promise处理正常结束
533
- setTimeout(() => {
534
- $.log.warn('[CacheBase] 测试脚本超时');
535
- process.exit(1);
536
- }, 10000); // 10秒超时
1
+ const assert = require('assert');
2
+ const { CacheBase, cachebaseAdmin } = require('./index.js');
3
+
4
+ class TestRunner {
5
+ constructor() {
6
+ this.totalTests = 0;
7
+ this.passedTests = 0;
8
+ this.results = [];
9
+ }
10
+
11
+ async runTest(name, testFunction) {
12
+ this.totalTests++;
13
+ try {
14
+ await testFunction();
15
+ this.passedTests++;
16
+ this.results.push({ name, passed: true });
17
+ $.log.debug(`✅ ${name}`);
18
+ } catch (error) {
19
+ this.results.push({ name, passed: false, error: error.message });
20
+ $.log.debug(`❌ ${name} - ${error.message}`);
21
+ }
22
+ }
23
+
24
+ displayResults() {
25
+ $.log.debug('\n========== 测试结果 ==========');
26
+ const passRate = (this.passedTests / this.totalTests * 100).toFixed(2);
27
+ $.log.debug(`通过: ${this.passedTests}/${this.totalTests} (${passRate}%)`);
28
+
29
+ // 显示失败的测试
30
+ const failedTests = this.results.filter(r => !r.passed);
31
+ if (failedTests.length > 0) {
32
+ $.log.debug('\n失败的测试:');
33
+ failedTests.forEach(test => {
34
+ $.log.debug(` - ${test.name}: ${test.error}`);
35
+ });
36
+ }
37
+
38
+ return passRate;
39
+ }
40
+ }
41
+
42
+ async function test() {
43
+ $.log.debug('[CacheBase] ==============================');
44
+ $.log.debug('[CacheBase] 开始兼容性测试(对齐 mm_redis 接口)');
45
+ $.log.debug('[CacheBase] ==============================');
46
+
47
+ try {
48
+ const runner = new TestRunner();
49
+
50
+ // 测试基础方法
51
+ $.log.debug('[CacheBase] \n========== 测试基础方法 ==========');
52
+
53
+ await runner.runTest('set和get方法', async () => {
54
+ const cache = new CacheBase({ scope: 'test_set_get' });
55
+ await cache.init();
56
+
57
+ await cache.set('test_key', 'test_value');
58
+ const value = await cache.get('test_key');
59
+
60
+ assert.equal(value, 'test_value', 'set和get方法测试失败');
61
+
62
+ await cache.del('test_key');
63
+ const deleted_value = await cache.get('test_key');
64
+
65
+ assert.equal(deleted_value, null, 'del方法测试失败');
66
+
67
+ await cache.close();
68
+ });
69
+
70
+ await runner.runTest('del方法(返回删除数量)', async () => {
71
+ const cache = new CacheBase({ scope: 'test_del' });
72
+ await cache.set('key2', 'value2');
73
+ const deleted = await cache.del('key2');
74
+ // del 返回删除的数量,对齐 mm_redis
75
+ if (deleted !== 1) {
76
+ throw new Error(`删除失败,预期: 1, 实际: ${deleted}`);
77
+ }
78
+ const value = await cache.get('key2');
79
+ if (value !== null) {
80
+ throw new Error(`键未被删除,值: ${value}`);
81
+ }
82
+ // 删除不存在的键返回 0
83
+ const deleted2 = await cache.del('not_exist');
84
+ if (deleted2 !== 0) {
85
+ throw new Error(`删除不存在键预期: 0, 实际: ${deleted2}`);
86
+ }
87
+ });
88
+
89
+ await runner.runTest('exists/has方法(返回数字)', async () => {
90
+ const cache = new CacheBase({ scope: 'test_exists_has' });
91
+ await cache.set('key3', 'value3');
92
+ const exists = await cache.exists('key3');
93
+ // exists 返回 0/1,对齐 mm_redis
94
+ if (exists !== 1) {
95
+ throw new Error(`exists失败,预期: 1, 实际: ${exists}`);
96
+ }
97
+ const has = await cache.has('key3');
98
+ if (!has) {
99
+ throw new Error(`has失败,预期: true, 实际: ${has}`);
100
+ }
101
+ // 不存在的键返回 0
102
+ const exists2 = await cache.exists('not_exist');
103
+ if (exists2 !== 0) {
104
+ throw new Error(`exists不存在键预期: 0, 实际: ${exists2}`);
105
+ }
106
+ });
107
+
108
+ await runner.runTest('keys方法', async () => {
109
+ const cache = new CacheBase({
110
+ persist: false,
111
+ scope: 'test_keys'
112
+ });
113
+ await cache.set('key4', 'value4');
114
+ await cache.set('key5', 'value5');
115
+ const keys = await cache.keys();
116
+ if (keys.length !== 2 || !keys.includes('key4') || !keys.includes('key5')) {
117
+ throw new Error(`keys失败,预期包含key4和key5, 实际: ${JSON.stringify(keys)}`);
118
+ }
119
+ const filteredKeys = await cache.keys('key4*');
120
+ if (filteredKeys.length !== 1 || filteredKeys[0] !== 'key4') {
121
+ throw new Error(`keys过滤失败,预期: ["key4"], 实际: ${JSON.stringify(filteredKeys)}`);
122
+ }
123
+ });
124
+
125
+ await runner.runTest('dbsize方法', async () => {
126
+ const cache = new CacheBase({
127
+ persist: false,
128
+ scope: 'test_dbsize'
129
+ });
130
+ await cache.set('key4', 'value4');
131
+ await cache.set('key5', 'value5');
132
+ const size = await cache.dbsize();
133
+ if (size !== 2) {
134
+ throw new Error(`dbsize失败,预期: 2, 实际: ${size}`);
135
+ }
136
+ });
137
+
138
+ await runner.runTest('getset方法', async () => {
139
+ const cache = new CacheBase({ scope: 'test_getset' });
140
+ await cache.set('key4', 'value4');
141
+ const oldValue = await cache.getset('key4', 'newvalue4');
142
+ if (oldValue !== 'value4') {
143
+ throw new Error(`getset失败,预期旧值: value4, 实际: ${oldValue}`);
144
+ }
145
+ const newValue = await cache.get('key4');
146
+ if (newValue !== 'newvalue4') {
147
+ throw new Error(`getset失败,预期新值: newvalue4, 实际: ${newValue}`);
148
+ }
149
+ });
150
+
151
+ await runner.runTest('flushdb/clear方法', async () => {
152
+ const cache = new CacheBase({
153
+ persist: false,
154
+ scope: 'test_flushdb'
155
+ });
156
+ await cache.set('key6', 'value6');
157
+ let result = await cache.clear();
158
+ if (result !== true) {
159
+ throw new Error(`flushdb失败,预期: true, 实际: ${result}`);
160
+ }
161
+ const size = await cache.dbsize();
162
+ if (size !== 0) {
163
+ throw new Error(`flushdb后大小不为0: ${size}`);
164
+ }
165
+
166
+ await cache.set('key7', 'value7');
167
+ result = await cache.clear();
168
+ if (result !== true) {
169
+ throw new Error(`clear失败,预期: true, 实际: ${result}`);
170
+ }
171
+ const sizeAfterClear = await cache.dbsize();
172
+ if (sizeAfterClear !== 0) {
173
+ throw new Error(`clear后大小不为0: ${sizeAfterClear}`);
174
+ }
175
+ });
176
+
177
+ await runner.runTest('open/close/isConnected方法', async () => {
178
+ const cache = new CacheBase({ scope: 'test_open_close' });
179
+ // 等待构造函数中异步 init 完成
180
+ await cache.init();
181
+ const connected1 = cache.isConnected();
182
+ if (!connected1) {
183
+ throw new Error(`init后应已连接,实际: ${connected1}`);
184
+ }
185
+ const openResult = await cache.open();
186
+ if (!openResult) {
187
+ throw new Error(`open 失败,实际: ${openResult}`);
188
+ }
189
+ const closeResult = await cache.close();
190
+ if (!closeResult) {
191
+ throw new Error(`close 失败,实际: ${closeResult}`);
192
+ }
193
+ const connected2 = cache.isConnected();
194
+ if (connected2) {
195
+ throw new Error(`close后应未连接,实际: ${connected2}`);
196
+ }
197
+ });
198
+
199
+ // 测试哈希表方法
200
+ $.log.debug('[CacheBase] \n========== 测试哈希表方法 ==========');
201
+ const hashCache = new CacheBase({ scope: 'test_hash' });
202
+
203
+ await runner.runTest('hset和hget方法(返回Boolean)', async () => {
204
+ // hset 返回 true/false,对齐 mm_redis
205
+ const result1 = await hashCache.hset('hash1', 'field1', 'value1');
206
+ if (result1 !== true) {
207
+ throw new Error(`hset新建失败,预期: true, 实际: ${result1}`);
208
+ }
209
+
210
+ const result2 = await hashCache.hset('hash1', 'field1', 'value1_updated');
211
+ if (result2 !== true) {
212
+ throw new Error(`hset更新失败,预期: true, 实际: ${result2}`);
213
+ }
214
+
215
+ const value = await hashCache.hget('hash1', 'field1');
216
+ if (value !== 'value1_updated') {
217
+ throw new Error(`hget失败,预期: value1_updated, 实际: ${value}`);
218
+ }
219
+ // 不存在字段返回 null,对齐 mm_redis
220
+ const value2 = await hashCache.hget('hash1', 'non_existent');
221
+ if (value2 !== null) {
222
+ throw new Error(`hget不存在字段预期: null, 实际: ${value2}`);
223
+ }
224
+ });
225
+
226
+ await runner.runTest('hgetall方法', async () => {
227
+ await hashCache.hset('hash1', 'field2', 'value2');
228
+ const hash = await hashCache.hgetall('hash1');
229
+ if (JSON.stringify(hash) !== JSON.stringify({ field1: 'value1_updated', field2: 'value2' })) {
230
+ throw new Error(`hgetall失败,预期: {"field1":"value1_updated","field2":"value2"}, 实际: ${JSON.stringify(hash)}`);
231
+ }
232
+ });
233
+
234
+ await runner.runTest('hdel方法(返回删除数量)', async () => {
235
+ // hdel 返回删除的字段数量,对齐 mm_redis
236
+ const result = await hashCache.hdel('hash1', 'field1');
237
+ if (result !== 1) {
238
+ throw new Error(`hdel失败,预期: 1, 实际: ${result}`);
239
+ }
240
+ const value = await hashCache.hget('hash1', 'field1');
241
+ if (value !== null) {
242
+ throw new Error(`hdel后字段未被删除,值: ${value}`);
243
+ }
244
+
245
+ // 删除不存在的字段返回 0
246
+ const result2 = await hashCache.hdel('hash1', 'non_existent');
247
+ if (result2 !== 0) {
248
+ throw new Error(`hdel不存在字段失败,预期: 0, 实际: ${result2}`);
249
+ }
250
+ });
251
+
252
+ // 测试批量操作
253
+ $.log.debug('[CacheBase] \n========== 测试批量操作 ==========');
254
+ const batchCache = new CacheBase({ scope: 'test_batch' });
255
+
256
+ await runner.runTest('mset方法(对象参数)', async () => {
257
+ // mset 接受对象参数,对齐 mm_redis
258
+ const result = await batchCache.mset({ key7: 'value7', key8: 'value8' });
259
+ if (result !== true) {
260
+ throw new Error(`mset失败,预期: true, 实际: ${result}`);
261
+ }
262
+ const value7 = await batchCache.get('key7');
263
+ const value8 = await batchCache.get('key8');
264
+ if (value7 !== 'value7' || value8 !== 'value8') {
265
+ throw new Error(`mset设置失败,value7: ${value7}, value8: ${value8}`);
266
+ }
267
+ });
268
+
269
+ await runner.runTest('mget方法', async () => {
270
+ const values = await batchCache.mget(['key7', 'key8', 'nonExistentKey']);
271
+ if (JSON.stringify(values) !== JSON.stringify(['value7', 'value8', null])) {
272
+ throw new Error(`mget失败,预期: ["value7","value8",null], 实际: ${JSON.stringify(values)}`);
273
+ }
274
+ });
275
+
276
+ // 测试过期时间
277
+ $.log.debug('[CacheBase] \n========== 测试过期时间 ==========');
278
+ const expireCache = new CacheBase({ scope: 'test_expire' });
279
+
280
+ await runner.runTest('set带过期时间', async () => {
281
+ await expireCache.set('expire1', 'value1', 1); // 1秒过期
282
+ let ttl = await expireCache.ttl('expire1');
283
+ if (ttl <= 0) {
284
+ throw new Error(`ttl初始值错误: ${ttl}`);
285
+ }
286
+
287
+ // 等待过期
288
+ await new Promise(resolve => setTimeout(resolve, 1100));
289
+
290
+ ttl = await expireCache.ttl('expire1');
291
+ if (ttl !== -2) {
292
+ throw new Error(`过期后ttl错误,预期: -2, 实际: ${ttl}`);
293
+ }
294
+
295
+ const value = await expireCache.get('expire1');
296
+ if (value !== null) {
297
+ throw new Error(`过期后键仍存在: ${value}`);
298
+ }
299
+ });
300
+
301
+ await runner.runTest('expire方法', async () => {
302
+ await expireCache.set('expire2', 'value2');
303
+ const result = await expireCache.expire('expire2', 1);
304
+ if (result !== true) {
305
+ throw new Error(`expire设置失败,预期: true, 实际: ${result}`);
306
+ }
307
+ let ttl = await expireCache.ttl('expire2');
308
+ if (ttl <= 0) {
309
+ throw new Error(`expire后ttl错误: ${ttl}`);
310
+ }
311
+ });
312
+
313
+ await runner.runTest('persist方法', async () => {
314
+ await expireCache.set('expire3', 'value3', 30);
315
+ const result = await expireCache.persist('expire3');
316
+ if (result !== true) {
317
+ throw new Error(`persist设置失败,预期: true, 实际: ${result}`);
318
+ }
319
+ const ttl = await expireCache.ttl('expire3');
320
+ if (ttl !== -1) {
321
+ throw new Error(`persist后ttl错误,预期: -1, 实际: ${ttl}`);
322
+ }
323
+ });
324
+
325
+ await runner.runTest('pexpire方法(毫秒过期)', async () => {
326
+ await expireCache.set('expire4', 'value4');
327
+ const result = await expireCache.pexpire('expire4', 500); // 500毫秒过期
328
+ if (result !== true) {
329
+ throw new Error(`pexpire设置失败,预期: true, 实际: ${result}`);
330
+ }
331
+ // 等待过期
332
+ await new Promise(resolve => setTimeout(resolve, 600));
333
+ const value = await expireCache.get('expire4');
334
+ if (value !== null) {
335
+ throw new Error(`pexpire过期后键仍存在: ${value}`);
336
+ }
337
+ });
338
+
339
+ // 测试数值操作
340
+ $.log.debug('[CacheBase] \n========== 测试数值操作 ==========');
341
+ const numCache = new CacheBase({ scope: 'test_num' });
342
+
343
+ await runner.runTest('incr方法', async () => {
344
+ const result1 = await numCache.incr('counter');
345
+ if (result1 !== 1) {
346
+ throw new Error(`incr初始值失败,预期: 1, 实际: ${result1}`);
347
+ }
348
+ const value1 = await numCache.get('counter');
349
+ if (value1 !== 1) {
350
+ throw new Error(`incr值错误,预期: 1, 实际: ${value1}`);
351
+ }
352
+
353
+ const result2 = await numCache.incr('counter');
354
+ if (result2 !== 2) {
355
+ throw new Error(`incr递增失败,预期: 2, 实际: ${result2}`);
356
+ }
357
+ });
358
+
359
+ await runner.runTest('decr方法', async () => {
360
+ const result = await numCache.decr('counter');
361
+ if (result !== 1) {
362
+ throw new Error(`decr递减失败,预期: 1, 实际: ${result}`);
363
+ }
364
+ });
365
+
366
+ await runner.runTest('incrby方法(带seconds)', async () => {
367
+ // incrby 带 seconds 参数,对齐 mm_redis
368
+ const result = await numCache.incrby('counter', 5);
369
+ if (result !== 6) {
370
+ throw new Error(`incrby增加失败,预期: 6, 实际: ${result}`);
371
+ }
372
+ // 测试带 TTL 的 incrby
373
+ const result2 = await numCache.incrby('counter_ttl', 10, 100);
374
+ if (result2 !== 10) {
375
+ throw new Error(`incrby带TTL失败,预期: 10, 实际: ${result2}`);
376
+ }
377
+ const ttl = await numCache.ttl('counter_ttl');
378
+ if (ttl <= 0 || ttl > 100) {
379
+ throw new Error(`incrby带TTL的ttl错误: ${ttl}`);
380
+ }
381
+ });
382
+
383
+ await runner.runTest('decrby方法(带seconds)', async () => {
384
+ const result = await numCache.decrby('counter', 2);
385
+ if (result !== 4) {
386
+ throw new Error(`decrby减少失败,预期: 4, 实际: ${result}`);
387
+ }
388
+ });
389
+
390
+ await runner.runTest('incrbyfloat方法', async () => {
391
+ const result = await numCache.incrbyfloat('counter', 0.5);
392
+ if (result !== 4.5) {
393
+ throw new Error(`incrbyfloat增加失败,预期: 4.5, 实际: ${result}`);
394
+ }
395
+ });
396
+
397
+ await runner.runTest('add方法(兼容)', async () => {
398
+ await numCache.del('counter');
399
+ const result = await numCache.add('counter', 10);
400
+ if (result !== true) {
401
+ throw new Error(`add增加失败,预期: true, 实际: ${result}`);
402
+ }
403
+ const value = await numCache.get('counter');
404
+ if (value !== 10) {
405
+ throw new Error(`add增加后值错误,预期: 10, 实际: ${value}`);
406
+ }
407
+
408
+ const result2 = await numCache.add('counter', 20);
409
+ if (result2 !== false) {
410
+ throw new Error(`add键已存在时失败,预期: false, 实际: ${result2}`);
411
+ }
412
+ });
413
+
414
+ await runner.runTest('addFloat方法(兼容)', async () => {
415
+ const result = await numCache.addFloat('counter', 0.5);
416
+ if (result !== 10.5) {
417
+ throw new Error(`addFloat增加失败,预期: 10.5, 实际: ${result}`);
418
+ }
419
+ });
420
+
421
+ // 测试字符串操作
422
+ $.log.debug('[CacheBase] \n========== 测试字符串操作 ==========');
423
+ const strCache = new CacheBase({ scope: 'test_str' });
424
+
425
+ await runner.runTest('append方法', async () => {
426
+ await strCache.set('str', 'hello');
427
+ const result = await strCache.append('str', ' world');
428
+ if (result !== 11) {
429
+ throw new Error(`append长度错误,预期: 11, 实际: ${result}`);
430
+ }
431
+ const value = await strCache.get('str');
432
+ if (value !== 'hello world') {
433
+ throw new Error(`append值错误,预期: hello world, 实际: ${value}`);
434
+ }
435
+ });
436
+
437
+ await runner.runTest('strlen方法', async () => {
438
+ const result = await strCache.strlen('str');
439
+ if (result !== 11) {
440
+ throw new Error(`strlen长度错误,预期: 11, 实际: ${result}`);
441
+ }
442
+ const result2 = await strCache.strlen('non_existent');
443
+ if (result2 !== 0) {
444
+ throw new Error(`strlen不存在键错误,预期: 0, 实际: ${result2}`);
445
+ }
446
+ });
447
+
448
+ await runner.runTest('setrange方法(原addStr)', async () => {
449
+ // addStr 已重命名为 setrange,对齐 mm_redis
450
+ const result = await strCache.setrange('str', '!');
451
+ if (result !== 12) {
452
+ throw new Error(`setrange长度错误,预期: 12, 实际: ${result}`);
453
+ }
454
+ const value = await strCache.get('str');
455
+ if (value !== 'hello world!') {
456
+ throw new Error(`setrange值错误,预期: hello world!, 实际: ${value}`);
457
+ }
458
+ });
459
+
460
+ // 测试集合操作
461
+ $.log.debug('[CacheBase] \n========== 测试集合操作 ==========');
462
+ const setCache = new CacheBase({ scope: 'test_set' });
463
+
464
+ await runner.runTest('sadd/smembers/scard方法', async () => {
465
+ const added = await setCache.sadd('set1', ['a', 'b', 'c']);
466
+ if (added !== 3) {
467
+ throw new Error(`sadd失败,预期: 3, 实际: ${added}`);
468
+ }
469
+ // 重复添加返回 0
470
+ const added2 = await setCache.sadd('set1', ['a', 'd']);
471
+ if (added2 !== 1) {
472
+ throw new Error(`sadd重复失败,预期: 1, 实际: ${added2}`);
473
+ }
474
+ const members = await setCache.smembers('set1');
475
+ if (members.length !== 4 || !members.includes('a') || !members.includes('d')) {
476
+ throw new Error(`smembers失败,实际: ${JSON.stringify(members)}`);
477
+ }
478
+ const card = await setCache.scard('set1');
479
+ if (card !== 4) {
480
+ throw new Error(`scard失败,预期: 4, 实际: ${card}`);
481
+ }
482
+ });
483
+
484
+ await runner.runTest('sismember方法', async () => {
485
+ const result1 = await setCache.sismember('set1', 'a');
486
+ if (result1 !== true) {
487
+ throw new Error(`sismember失败,预期: true, 实际: ${result1}`);
488
+ }
489
+ const result2 = await setCache.sismember('set1', 'z');
490
+ if (result2 !== false) {
491
+ throw new Error(`sismember不存在预期: false, 实际: ${result2}`);
492
+ }
493
+ });
494
+
495
+ await runner.runTest('srem方法', async () => {
496
+ const removed = await setCache.srem('set1', ['a', 'b']);
497
+ if (removed !== 2) {
498
+ throw new Error(`srem失败,预期: 2, 实际: ${removed}`);
499
+ }
500
+ const card = await setCache.scard('set1');
501
+ if (card !== 2) {
502
+ throw new Error(`srem后scard失败,预期: 2, 实际: ${card}`);
503
+ }
504
+ });
505
+
506
+ await runner.runTest('sinter/sunion/sdiff方法', async () => {
507
+ await setCache.sadd('setA', ['1', '2', '3']);
508
+ await setCache.sadd('setB', ['2', '3', '4']);
509
+
510
+ const inter = await setCache.sinter('setA', 'setB');
511
+ if (inter.length !== 2 || !inter.includes('2') || !inter.includes('3')) {
512
+ throw new Error(`sinter失败,实际: ${JSON.stringify(inter)}`);
513
+ }
514
+
515
+ const union = await setCache.sunion('setA', 'setB');
516
+ if (union.length !== 4) {
517
+ throw new Error(`sunion失败,预期长度4, 实际: ${JSON.stringify(union)}`);
518
+ }
519
+
520
+ const diff = await setCache.sdiff('setA', 'setB');
521
+ if (diff.length !== 1 || diff[0] !== '1') {
522
+ throw new Error(`sdiff失败,实际: ${JSON.stringify(diff)}`);
523
+ }
524
+ });
525
+
526
+ // 测试有序集合操作
527
+ $.log.debug('[CacheBase] \n========== 测试有序集合操作 ==========');
528
+ const zsetCache = new CacheBase({ scope: 'test_zset' });
529
+
530
+ await runner.runTest('zadd/zcard/zscore方法', async () => {
531
+ const added1 = await zsetCache.zadd('zset1', 10, 'member1');
532
+ if (added1 !== true) {
533
+ throw new Error(`zadd新成员失败,预期: true, 实际: ${added1}`);
534
+ }
535
+ const added2 = await zsetCache.zadd('zset1', 20, 'member2');
536
+ if (added2 !== true) {
537
+ throw new Error(`zadd新成员2失败,预期: true, 实际: ${added2}`);
538
+ }
539
+ // 更新已有成员返回 false
540
+ const added3 = await zsetCache.zadd('zset1', 15, 'member1');
541
+ if (added3 !== false) {
542
+ throw new Error(`zadd更新成员失败,预期: false, 实际: ${added3}`);
543
+ }
544
+ const card = await zsetCache.zcard('zset1');
545
+ if (card !== 2) {
546
+ throw new Error(`zcard失败,预期: 2, 实际: ${card}`);
547
+ }
548
+ const score = await zsetCache.zscore('zset1', 'member1');
549
+ if (score !== 15) {
550
+ throw new Error(`zscore失败,预期: 15, 实际: ${score}`);
551
+ }
552
+ });
553
+
554
+ await runner.runTest('zrank/zrange方法', async () => {
555
+ const rank1 = await zsetCache.zrank('zset1', 'member1');
556
+ if (rank1 !== 0) {
557
+ throw new Error(`zrank失败,预期: 0, 实际: ${rank1}`);
558
+ }
559
+ const range = await zsetCache.zrange('zset1', 0, -1);
560
+ if (range.length !== 2 || range[0] !== 'member1' || range[1] !== 'member2') {
561
+ throw new Error(`zrange失败,实际: ${JSON.stringify(range)}`);
562
+ }
563
+ const rangeWithScores = await zsetCache.zrange('zset1', 0, -1, true);
564
+ if (rangeWithScores.length !== 2 || rangeWithScores[0].member !== 'member1' || rangeWithScores[0].score !== 15) {
565
+ throw new Error(`zrange带分数失败,实际: ${JSON.stringify(rangeWithScores)}`);
566
+ }
567
+ });
568
+
569
+ await runner.runTest('zincrby/zrem方法', async () => {
570
+ const newScore = await zsetCache.zincrby('zset1', 5, 'member1');
571
+ if (newScore !== 20) {
572
+ throw new Error(`zincrby失败,预期: 20, 实际: ${newScore}`);
573
+ }
574
+ const removed = await zsetCache.zrem('zset1', 'member1');
575
+ if (removed !== 1) {
576
+ throw new Error(`zrem失败,预期: 1, 实际: ${removed}`);
577
+ }
578
+ const card = await zsetCache.zcard('zset1');
579
+ if (card !== 1) {
580
+ throw new Error(`zrem后zcard失败,预期: 1, 实际: ${card}`);
581
+ }
582
+ });
583
+
584
+ // 测试发布订阅
585
+ $.log.debug('[CacheBase] \n========== 测试发布订阅 ==========');
586
+
587
+ await runner.runTest('subscribe/publish方法', async () => {
588
+ const pubsubCache = new CacheBase({ scope: 'test_pubsub' });
589
+ let receivedMessage = null;
590
+ await pubsubCache.subscribe('channel1', (msg) => {
591
+ receivedMessage = msg;
592
+ });
593
+ const count = await pubsubCache.publish('channel1', 'hello');
594
+ if (count !== 1) {
595
+ throw new Error(`publish接收者数量失败,预期: 1, 实际: ${count}`);
596
+ }
597
+ if (receivedMessage !== 'hello') {
598
+ throw new Error(`订阅未收到消息,预期: hello, 实际: ${receivedMessage}`);
599
+ }
600
+ });
601
+
602
+ await runner.runTest('unsubscribe方法', async () => {
603
+ const pubsubCache = new CacheBase({ scope: 'test_unsub' });
604
+ let received = false;
605
+ await pubsubCache.subscribe('channel2', () => { received = true; });
606
+ await pubsubCache.unsubscribe('channel2');
607
+ const count = await pubsubCache.publish('channel2', 'hello');
608
+ if (count !== 0) {
609
+ throw new Error(`unsubscribe后publish预期: 0, 实际: ${count}`);
610
+ }
611
+ if (received) {
612
+ throw new Error(`unsubscribe后仍收到消息`);
613
+ }
614
+ });
615
+
616
+ // 测试事件触发(冒号风格)
617
+ $.log.debug('[CacheBase] \n========== 测试事件触发(冒号风格) ==========');
618
+ const eventCache = new CacheBase({ scope: 'test_event' });
619
+
620
+ await runner.runTest('set事件触发(冒号风格)', async () => {
621
+ return new Promise(async (resolve, reject) => {
622
+ let beforeTriggered = false;
623
+ let afterTriggered = false;
624
+
625
+ // 事件名改为冒号风格,对齐 mm_redis
626
+ eventCache.once('set:before', (data) => {
627
+ if (data.key === 'event_key' && data.value === 'event_value') {
628
+ beforeTriggered = true;
629
+ }
630
+ });
631
+
632
+ eventCache.once('set:after', (data) => {
633
+ if (data.key === 'event_key' && data.value === 'event_value' && data.success === true) {
634
+ afterTriggered = true;
635
+ setTimeout(() => {
636
+ if (beforeTriggered && afterTriggered) {
637
+ resolve();
638
+ } else {
639
+ reject(new Error('set事件未全部触发'));
640
+ }
641
+ }, 10);
642
+ }
643
+ });
644
+
645
+ await eventCache.set('event_key', 'event_value');
646
+ });
647
+ });
648
+
649
+ await runner.runTest('error事件触发(冒号风格)', async () => {
650
+ return new Promise(async (resolve, reject) => {
651
+ // 事件名改为冒号风格
652
+ eventCache.once('mset:error', (data) => {
653
+ if (data.error) {
654
+ resolve();
655
+ } else {
656
+ reject(new Error('mset:error事件触发但数据不正确'));
657
+ }
658
+ });
659
+
660
+ // 传入非法参数触发错误,mset 内部 catch 后返回 false 并触发 mset:error 事件
661
+ const result = await eventCache.mset(null);
662
+ if (result !== false) {
663
+ reject(new Error(`mset应返回false但返回: ${result}`));
664
+ }
665
+ // 超时保护,若事件未触发则失败
666
+ setTimeout(() => {
667
+ reject(new Error('mset:error事件未触发'));
668
+ }, 100);
669
+ });
670
+ });
671
+
672
+ // 测试管理功能
673
+ $.log.debug('[CacheBase] \n========== 测试管理功能 ==========');
674
+
675
+ await runner.runTest('cachebaseAdmin创建实例', async () => {
676
+ const cache1 = cachebaseAdmin('test_scope');
677
+ const cache2 = cachebaseAdmin('test_scope');
678
+ if (cache1 !== cache2) {
679
+ throw new Error('cachebaseAdmin应返回相同实例但没有');
680
+ }
681
+
682
+ const cache3 = cachebaseAdmin('another_scope');
683
+ if (cache1 === cache3) {
684
+ throw new Error('cachebaseAdmin应返回不同作用域的不同实例但没有');
685
+ }
686
+ });
687
+
688
+ await runner.runTest('dispose方法', async () => {
689
+ const disposeCache = new CacheBase({
690
+ persist: false,
691
+ scope: 'test_dispose'
692
+ });
693
+ await disposeCache.set('key_to_dispose', 'value');
694
+ disposeCache.dispose();
695
+
696
+ const size = await disposeCache.dbsize();
697
+ if (size !== 0) {
698
+ throw new Error(`dispose后大小不为0: ${size}`);
699
+ }
700
+ });
701
+
702
+ // 显示测试结果
703
+ const passRate = runner.displayResults();
704
+ $.log.debug(`[CacheBase] \n测试完成!通过率: ${passRate}%`);
705
+
706
+ $.log.debug('[CacheBase] \n==============================');
707
+ $.log.debug('[CacheBase] 所有兼容性测试完成!');
708
+ $.log.debug('[CacheBase] ==============================');
709
+
710
+ } catch (error) {
711
+ $.log.error('[CacheBase] 测试过程中出现错误:', error);
712
+ }
713
+ }
714
+
715
+ test().then(() => {
716
+ // 测试成功完成
717
+ $.log.debug('[CacheBase] 测试脚本正常退出');
718
+ process.exit(0);
719
+ }).catch(err => {
720
+ $.log.error('[CacheBase] 未捕获的错误:', err);
721
+ process.exit(1);
722
+ });
723
+
724
+ // 添加超时保护
725
+ setTimeout(() => {
726
+ $.log.warn('[CacheBase] 测试脚本超时');
727
+ process.exit(1);
728
+ }, 15000); // 15秒超时