mm_cachebase 1.8.6 → 1.8.8
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/README.md +558 -524
- package/config/cachebase.config.json +11 -0
- package/config/cachebase.const.json +16 -0
- package/index.js +2307 -1668
- package/index_old.js +2521 -0
- package/package.json +2 -2
- package/simple_test.js +21 -70
- package/simple_test_direct.js +27 -0
- package/test.js +449 -424
- package/test_cache/test_file_operations.json +1 -0
- package/test_cache/undefined.cache.json +12 -0
- package/test_new_methods.js +170 -0
- package/compatibility_table.md +0 -101
- package/test_add_direct_save.js +0 -60
- package/test_add_if_not_exists.js +0 -50
- package/test_add_method.js +0 -44
- package/test_cache/scope1.cache.json +0 -5
- package/test_cache/scope2.cache.json +0 -5
- package/test_cache/scope3.cache.json +0 -5
- package/test_cache/test_scope.cache.json +0 -5
- package/test_compatibility.js +0 -109
- package/test_compatibility_fixes.js +0 -272
- package/test_compatibility_improvements.js +0 -147
- package/test_list_and_decr_compatibility.js +0 -99
- package/test_multi_file_persistence.js +0 -160
- package/test_persistence.js +0 -138
- package/test_redis_behavior.js +0 -57
- package/test_undocumented_methods.js +0 -57
package/test.js
CHANGED
|
@@ -13,24 +13,24 @@ class TestRunner {
|
|
|
13
13
|
await testFunction();
|
|
14
14
|
this.passedTests++;
|
|
15
15
|
this.results.push({ name, passed: true });
|
|
16
|
-
|
|
16
|
+
$.log.debug(`✅ ${name}`);
|
|
17
17
|
} catch (error) {
|
|
18
18
|
this.results.push({ name, passed: false, error: error.message });
|
|
19
|
-
|
|
19
|
+
$.log.debug(`❌ ${name} - ${error.message}`);
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
displayResults() {
|
|
24
|
-
|
|
24
|
+
$.log.debug('\n========== 测试结果 ==========');
|
|
25
25
|
const passRate = (this.passedTests / this.totalTests * 100).toFixed(2);
|
|
26
|
-
|
|
26
|
+
$.log.debug(`通过: ${this.passedTests}/${this.totalTests} (${passRate}%)`);
|
|
27
27
|
|
|
28
28
|
// 显示失败的测试
|
|
29
29
|
const failedTests = this.results.filter(r => !r.passed);
|
|
30
30
|
if (failedTests.length > 0) {
|
|
31
|
-
|
|
31
|
+
$.log.debug('\n失败的测试:');
|
|
32
32
|
failedTests.forEach(test => {
|
|
33
|
-
|
|
33
|
+
$.log.debug(` - ${test.name}: ${test.error}`);
|
|
34
34
|
});
|
|
35
35
|
}
|
|
36
36
|
|
|
@@ -38,444 +38,469 @@ class TestRunner {
|
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
async function
|
|
42
|
-
|
|
41
|
+
async function test() {
|
|
42
|
+
$.log.debug('[CacheBase] ==============================');
|
|
43
|
+
$.log.debug('[CacheBase] 开始兼容性测试');
|
|
44
|
+
$.log.debug('[CacheBase] ==============================');
|
|
43
45
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
// 测试哈希表方法
|
|
48
|
-
await testHashMethods(runner);
|
|
49
|
-
|
|
50
|
-
// 测试批量操作
|
|
51
|
-
await testBatchOperations(runner);
|
|
52
|
-
|
|
53
|
-
// 测试过期时间
|
|
54
|
-
await testExpiration(runner);
|
|
55
|
-
|
|
56
|
-
// 测试数值操作
|
|
57
|
-
await testNumericOperations(runner);
|
|
58
|
-
|
|
59
|
-
// 测试字符串操作
|
|
60
|
-
await testStringOperations(runner);
|
|
61
|
-
|
|
62
|
-
// 测试事件触发
|
|
63
|
-
await testEvents(runner);
|
|
64
|
-
|
|
65
|
-
// 测试管理功能
|
|
66
|
-
await testAdminFunctions(runner);
|
|
67
|
-
|
|
68
|
-
// 显示测试结果
|
|
69
|
-
return runner.displayResults();
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// 测试基础方法
|
|
73
|
-
async function testBasicMethods(runner) {
|
|
74
|
-
console.log('\n========== 测试基础方法 ==========');
|
|
75
|
-
const cache = new CacheBase();
|
|
76
|
-
|
|
77
|
-
await runner.runTest('set和get方法', async () => {
|
|
78
|
-
await cache.set('key1', 'value1');
|
|
79
|
-
const value = await cache.get('key1');
|
|
80
|
-
if (value !== 'value1') {
|
|
81
|
-
throw new Error(`预期值: value1, 实际值: ${value}`);
|
|
82
|
-
}
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
await runner.runTest('del方法', async () => {
|
|
86
|
-
await cache.set('key2', 'value2');
|
|
87
|
-
const deleted = await cache.del('key2');
|
|
88
|
-
if (deleted !== 1) {
|
|
89
|
-
throw new Error(`删除失败,预期: 1, 实际: ${deleted}`);
|
|
90
|
-
}
|
|
91
|
-
const value = await cache.get('key2');
|
|
92
|
-
if (value !== undefined) {
|
|
93
|
-
throw new Error(`键未被删除,值: ${value}`);
|
|
94
|
-
}
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
await runner.runTest('exists/has方法', async () => {
|
|
98
|
-
await cache.set('key3', 'value3');
|
|
99
|
-
const exists = await cache.exists('key3');
|
|
100
|
-
if (exists !== 1) {
|
|
101
|
-
throw new Error(`exists失败,预期: 1, 实际: ${exists}`);
|
|
102
|
-
}
|
|
103
|
-
const has = await cache.has('key3');
|
|
104
|
-
if (!has) {
|
|
105
|
-
throw new Error(`has失败,预期: true, 实际: ${has}`);
|
|
106
|
-
}
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
await runner.runTest('keys方法', async () => {
|
|
110
|
-
await cache.clear();
|
|
111
|
-
await cache.set('key4', 'value4');
|
|
112
|
-
await cache.set('key5', 'value5');
|
|
113
|
-
const keys = await cache.keys();
|
|
114
|
-
if (keys.length !== 2 || !keys.includes('key4') || !keys.includes('key5')) {
|
|
115
|
-
throw new Error(`keys失败,预期包含key4和key5, 实际: ${JSON.stringify(keys)}`);
|
|
116
|
-
}
|
|
117
|
-
const filteredKeys = await cache.keys('key4*');
|
|
118
|
-
if (filteredKeys.length !== 1 || filteredKeys[0] !== 'key4') {
|
|
119
|
-
throw new Error(`keys过滤失败,预期: ["key4"], 实际: ${JSON.stringify(filteredKeys)}`);
|
|
120
|
-
}
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
await runner.runTest('dbsize方法', async () => {
|
|
124
|
-
const size = await cache.dbsize();
|
|
125
|
-
if (size !== 2) {
|
|
126
|
-
throw new Error(`dbsize失败,预期: 2, 实际: ${size}`);
|
|
127
|
-
}
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
await runner.runTest('getset方法', async () => {
|
|
131
|
-
const oldValue = await cache.getset('key4', 'newvalue4');
|
|
132
|
-
if (oldValue !== 'value4') {
|
|
133
|
-
throw new Error(`getset失败,预期旧值: value4, 实际: ${oldValue}`);
|
|
134
|
-
}
|
|
135
|
-
const newValue = await cache.get('key4');
|
|
136
|
-
if (newValue !== 'newvalue4') {
|
|
137
|
-
throw new Error(`getset失败,预期新值: newvalue4, 实际: ${newValue}`);
|
|
138
|
-
}
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
await runner.runTest('flushdb/clear方法', async () => {
|
|
142
|
-
let result = await cache.clear();
|
|
143
|
-
if (result !== 'OK') {
|
|
144
|
-
throw new Error(`flushdb失败,预期: OK, 实际: ${result}`);
|
|
145
|
-
}
|
|
146
|
-
const size = await cache.dbsize();
|
|
147
|
-
if (size !== 0) {
|
|
148
|
-
throw new Error(`flushdb后大小不为0: ${size}`);
|
|
149
|
-
}
|
|
46
|
+
try {
|
|
47
|
+
const runner = new TestRunner();
|
|
150
48
|
|
|
151
|
-
//
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
if (result !== 'OK') {
|
|
155
|
-
throw new Error(`clear失败,预期: OK, 实际: ${result}`);
|
|
156
|
-
}
|
|
157
|
-
const sizeAfterClear = await cache.dbsize();
|
|
158
|
-
if (sizeAfterClear !== 0) {
|
|
159
|
-
throw new Error(`clear后大小不为0: ${sizeAfterClear}`);
|
|
160
|
-
}
|
|
161
|
-
});
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// 测试哈希表方法
|
|
165
|
-
async function testHashMethods(runner) {
|
|
166
|
-
console.log('\n========== 测试哈希表方法 ==========');
|
|
167
|
-
const cache = new CacheBase();
|
|
168
|
-
|
|
169
|
-
await runner.runTest('hset和hget方法', async () => {
|
|
170
|
-
const result1 = await cache.hset('hash1', 'field1', 'value1');
|
|
171
|
-
if (result1 !== 1) {
|
|
172
|
-
throw new Error(`hset新建失败,预期: 1, 实际: ${result1}`);
|
|
173
|
-
}
|
|
49
|
+
// 测试基础方法
|
|
50
|
+
$.log.debug('[CacheBase] \n========== 测试基础方法 ==========');
|
|
51
|
+
const cache = new CacheBase();
|
|
174
52
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
53
|
+
await runner.runTest('set和get方法', async () => {
|
|
54
|
+
await cache.set('key1', 'value1');
|
|
55
|
+
const value = await cache.get('key1');
|
|
56
|
+
if (value !== 'value1') {
|
|
57
|
+
throw new Error(`预期值: value1, 实际值: ${value}`);
|
|
58
|
+
}
|
|
59
|
+
});
|
|
179
60
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
}
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
await runner.runTest('hdel方法', async () => {
|
|
195
|
-
const result = await cache.hdel('hash1', 'field1');
|
|
196
|
-
if (result !== 1) {
|
|
197
|
-
throw new Error(`hdel失败,预期: 1, 实际: ${result}`);
|
|
198
|
-
}
|
|
199
|
-
const value = await cache.hget('hash1', 'field1');
|
|
200
|
-
if (value !== undefined) {
|
|
201
|
-
throw new Error(`hdel后字段未被删除,值: ${value}`);
|
|
202
|
-
}
|
|
61
|
+
await runner.runTest('del方法', async () => {
|
|
62
|
+
await cache.set('key2', 'value2');
|
|
63
|
+
const deleted = await cache.del('key2');
|
|
64
|
+
if (deleted !== true) {
|
|
65
|
+
throw new Error(`删除失败,预期: true, 实际: ${deleted}`);
|
|
66
|
+
}
|
|
67
|
+
const value = await cache.get('key2');
|
|
68
|
+
if (value !== null) {
|
|
69
|
+
throw new Error(`键未被删除,值: ${value}`);
|
|
70
|
+
}
|
|
71
|
+
});
|
|
203
72
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
const cache = new CacheBase();
|
|
216
|
-
|
|
217
|
-
await runner.runTest('mset方法', async () => {
|
|
218
|
-
const result = await cache.mset({ key7: 'value7', key8: 'value8' });
|
|
219
|
-
if (result !== 'OK') {
|
|
220
|
-
throw new Error(`mset失败,预期: OK, 实际: ${result}`);
|
|
221
|
-
}
|
|
222
|
-
const value7 = await cache.get('key7');
|
|
223
|
-
const value8 = await cache.get('key8');
|
|
224
|
-
if (value7 !== 'value7' || value8 !== 'value8') {
|
|
225
|
-
throw new Error(`mset后值不匹配: key7=${value7}, key8=${value8}`);
|
|
226
|
-
}
|
|
227
|
-
});
|
|
228
|
-
|
|
229
|
-
await runner.runTest('mget方法', async () => {
|
|
230
|
-
const values = await cache.mget(['key7', 'key8', 'non_existent']);
|
|
231
|
-
if (JSON.stringify(values) !== JSON.stringify(['value7', 'value8', undefined])) {
|
|
232
|
-
throw new Error(`mget失败,预期: ["value7","value8",undefined], 实际: ${JSON.stringify(values)}`);
|
|
233
|
-
}
|
|
234
|
-
});
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
// 测试过期时间
|
|
238
|
-
async function testExpiration(runner) {
|
|
239
|
-
console.log('\n========== 测试过期时间 ==========');
|
|
240
|
-
const cache = new CacheBase();
|
|
241
|
-
|
|
242
|
-
await runner.runTest('set带过期时间', async () => {
|
|
243
|
-
await cache.set('expire1', 'value1', 1); // 1秒过期
|
|
244
|
-
let ttl = await cache.ttl('expire1');
|
|
245
|
-
if (ttl <= 0) {
|
|
246
|
-
throw new Error(`ttl初始值错误: ${ttl}`);
|
|
247
|
-
}
|
|
73
|
+
await runner.runTest('exists/has方法', async () => {
|
|
74
|
+
await cache.set('key3', 'value3');
|
|
75
|
+
const exists = await cache.exists('key3');
|
|
76
|
+
if (exists !== true) {
|
|
77
|
+
throw new Error(`exists失败,预期: true, 实际: ${exists}`);
|
|
78
|
+
}
|
|
79
|
+
const has = await cache.has('key3');
|
|
80
|
+
if (!has) {
|
|
81
|
+
throw new Error(`has失败,预期: true, 实际: ${has}`);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
248
84
|
|
|
249
|
-
|
|
250
|
-
|
|
85
|
+
await runner.runTest('keys方法', async () => {
|
|
86
|
+
await cache.clear();
|
|
87
|
+
await cache.set('key4', 'value4');
|
|
88
|
+
await cache.set('key5', 'value5');
|
|
89
|
+
const keys = await cache.keys();
|
|
90
|
+
if (keys.length !== 2 || !keys.includes('key4') || !keys.includes('key5')) {
|
|
91
|
+
throw new Error(`keys失败,预期包含key4和key5, 实际: ${JSON.stringify(keys)}`);
|
|
92
|
+
}
|
|
93
|
+
const filteredKeys = await cache.keys('key4*');
|
|
94
|
+
if (filteredKeys.length !== 1 || filteredKeys[0] !== 'key4') {
|
|
95
|
+
throw new Error(`keys过滤失败,预期: ["key4"], 实际: ${JSON.stringify(filteredKeys)}`);
|
|
96
|
+
}
|
|
97
|
+
});
|
|
251
98
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
99
|
+
await runner.runTest('dbsize方法', async () => {
|
|
100
|
+
const size = await cache.dbsize();
|
|
101
|
+
if (size !== 2) {
|
|
102
|
+
throw new Error(`dbsize失败,预期: 2, 实际: ${size}`);
|
|
103
|
+
}
|
|
104
|
+
});
|
|
256
105
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
throw new Error(`expire设置失败,预期: 1, 实际: ${result}`);
|
|
268
|
-
}
|
|
269
|
-
let ttl = await cache.ttl('expire2');
|
|
270
|
-
if (ttl <= 0) {
|
|
271
|
-
throw new Error(`expire后ttl错误: ${ttl}`);
|
|
272
|
-
}
|
|
273
|
-
});
|
|
274
|
-
|
|
275
|
-
await runner.runTest('persist方法', async () => {
|
|
276
|
-
await cache.set('expire3', 'value3', 30);
|
|
277
|
-
const result = await cache.persist('expire3');
|
|
278
|
-
if (result !== 1) {
|
|
279
|
-
throw new Error(`persist设置失败,预期: 1, 实际: ${result}`);
|
|
280
|
-
}
|
|
281
|
-
const ttl = await cache.ttl('expire3');
|
|
282
|
-
if (ttl !== -1) {
|
|
283
|
-
throw new Error(`persist后ttl错误,预期: -1, 实际: ${ttl}`);
|
|
284
|
-
}
|
|
285
|
-
});
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
// 测试数值操作
|
|
289
|
-
async function testNumericOperations(runner) {
|
|
290
|
-
console.log('\n========== 测试数值操作 ==========');
|
|
291
|
-
const cache = new CacheBase();
|
|
292
|
-
|
|
293
|
-
await runner.runTest('incr方法', async () => {
|
|
294
|
-
const result1 = await cache.incr('counter');
|
|
295
|
-
if (result1 !== 1) {
|
|
296
|
-
throw new Error(`incr初始值失败,预期: 1, 实际: ${result1}`);
|
|
297
|
-
}
|
|
298
|
-
const result2 = await cache.incr('counter');
|
|
299
|
-
if (result2 !== 2) {
|
|
300
|
-
throw new Error(`incr递增失败,预期: 2, 实际: ${result2}`);
|
|
301
|
-
}
|
|
302
|
-
});
|
|
303
|
-
|
|
304
|
-
await runner.runTest('decr方法', async () => {
|
|
305
|
-
const result = await cache.decr('counter');
|
|
306
|
-
if (result !== 1) {
|
|
307
|
-
throw new Error(`decr递减失败,预期: 1, 实际: ${result}`);
|
|
308
|
-
}
|
|
309
|
-
});
|
|
310
|
-
|
|
311
|
-
await runner.runTest('incrby方法', async () => {
|
|
312
|
-
const result = await cache.incrby('counter', 5);
|
|
313
|
-
if (result !== 6) {
|
|
314
|
-
throw new Error(`incrby增加失败,预期: 6, 实际: ${result}`);
|
|
315
|
-
}
|
|
316
|
-
});
|
|
317
|
-
|
|
318
|
-
await runner.runTest('decrby方法', async () => {
|
|
319
|
-
const result = await cache.decrby('counter', 2);
|
|
320
|
-
if (result !== 4) {
|
|
321
|
-
throw new Error(`decrby减少失败,预期: 4, 实际: ${result}`);
|
|
322
|
-
}
|
|
323
|
-
});
|
|
324
|
-
|
|
325
|
-
await runner.runTest('incrbyfloat方法', async () => {
|
|
326
|
-
const result = await cache.incrbyfloat('counter', 0.5);
|
|
327
|
-
if (result !== 4.5) {
|
|
328
|
-
throw new Error(`incrbyfloat增加失败,预期: 4.5, 实际: ${result}`);
|
|
329
|
-
}
|
|
330
|
-
});
|
|
331
|
-
|
|
332
|
-
await runner.runTest('add方法(兼容)', async () => {
|
|
333
|
-
const result = await cache.add('counter', 10);
|
|
334
|
-
if (result !== 14.5) {
|
|
335
|
-
throw new Error(`add增加失败,预期: 14.5, 实际: ${result}`);
|
|
336
|
-
}
|
|
337
|
-
});
|
|
338
|
-
|
|
339
|
-
await runner.runTest('addFloat方法(兼容)', async () => {
|
|
340
|
-
const result = await cache.addFloat('counter', 0.5);
|
|
341
|
-
if (result !== 15) {
|
|
342
|
-
throw new Error(`addFloat增加失败,预期: 15, 实际: ${result}`);
|
|
343
|
-
}
|
|
344
|
-
});
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
// 测试字符串操作
|
|
348
|
-
async function testStringOperations(runner) {
|
|
349
|
-
console.log('\n========== 测试字符串操作 ==========');
|
|
350
|
-
const cache = new CacheBase();
|
|
351
|
-
|
|
352
|
-
await runner.runTest('append方法', async () => {
|
|
353
|
-
await cache.set('str', 'hello');
|
|
354
|
-
const result = await cache.append('str', ' world');
|
|
355
|
-
if (result !== 11) {
|
|
356
|
-
throw new Error(`append长度错误,预期: 11, 实际: ${result}`);
|
|
357
|
-
}
|
|
358
|
-
const value = await cache.get('str');
|
|
359
|
-
if (value !== 'hello world') {
|
|
360
|
-
throw new Error(`append值错误,预期: hello world, 实际: ${value}`);
|
|
361
|
-
}
|
|
362
|
-
});
|
|
363
|
-
|
|
364
|
-
await runner.runTest('strlen方法', async () => {
|
|
365
|
-
const result = await cache.strlen('str');
|
|
366
|
-
if (result !== 11) {
|
|
367
|
-
throw new Error(`strlen长度错误,预期: 11, 实际: ${result}`);
|
|
368
|
-
}
|
|
106
|
+
await runner.runTest('getset方法', async () => {
|
|
107
|
+
const oldValue = await cache.getset('key4', 'newvalue4');
|
|
108
|
+
if (oldValue !== 'value4') {
|
|
109
|
+
throw new Error(`getset失败,预期旧值: value4, 实际: ${oldValue}`);
|
|
110
|
+
}
|
|
111
|
+
const newValue = await cache.get('key4');
|
|
112
|
+
if (newValue !== 'newvalue4') {
|
|
113
|
+
throw new Error(`getset失败,预期新值: newvalue4, 实际: ${newValue}`);
|
|
114
|
+
}
|
|
115
|
+
});
|
|
369
116
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
if (result !== 12) {
|
|
380
|
-
throw new Error(`addStr长度错误,预期: 12, 实际: ${result}`);
|
|
381
|
-
}
|
|
382
|
-
const value = await cache.get('str');
|
|
383
|
-
if (value !== 'hello world!') {
|
|
384
|
-
throw new Error(`addStr值错误,预期: hello world!, 实际: ${value}`);
|
|
385
|
-
}
|
|
386
|
-
});
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
// 测试事件触发
|
|
390
|
-
async function testEvents(runner) {
|
|
391
|
-
console.log('\n========== 测试事件触发 ==========');
|
|
392
|
-
const cache = new CacheBase();
|
|
393
|
-
|
|
394
|
-
await runner.runTest('set事件触发', async () => {
|
|
395
|
-
return new Promise(async (resolve, reject) => {
|
|
396
|
-
let beforeTriggered = false;
|
|
397
|
-
let afterTriggered = false;
|
|
117
|
+
await runner.runTest('flushdb/clear方法', async () => {
|
|
118
|
+
let result = await cache.clear();
|
|
119
|
+
if (result !== true) {
|
|
120
|
+
throw new Error(`flushdb失败,预期: true, 实际: ${result}`);
|
|
121
|
+
}
|
|
122
|
+
const size = await cache.dbsize();
|
|
123
|
+
if (size !== 0) {
|
|
124
|
+
throw new Error(`flushdb后大小不为0: ${size}`);
|
|
125
|
+
}
|
|
398
126
|
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
127
|
+
// 测试clear方法(兼容)
|
|
128
|
+
await cache.set('key6', 'value6');
|
|
129
|
+
result = await cache.clear();
|
|
130
|
+
if (result !== true) {
|
|
131
|
+
throw new Error(`clear失败,预期: true, 实际: ${result}`);
|
|
132
|
+
}
|
|
133
|
+
const sizeAfterClear = await cache.dbsize();
|
|
134
|
+
if (sizeAfterClear !== 0) {
|
|
135
|
+
throw new Error(`clear后大小不为0: ${sizeAfterClear}`);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
// 测试哈希表方法
|
|
140
|
+
$.log.debug('[CacheBase] \n========== 测试哈希表方法 ==========');
|
|
141
|
+
const hashCache = new CacheBase();
|
|
142
|
+
|
|
143
|
+
await runner.runTest('hset和hget方法', async () => {
|
|
144
|
+
const result1 = await hashCache.hset('hash1', 'field1', 'value1');
|
|
145
|
+
if (result1 !== 1) {
|
|
146
|
+
throw new Error(`hset新建失败,预期: 1, 实际: ${result1}`);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const result2 = await hashCache.hset('hash1', 'field1', 'value1_updated');
|
|
150
|
+
if (result2 !== 0) {
|
|
151
|
+
throw new Error(`hset更新失败,预期: 0, 实际: ${result2}`);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const value = await hashCache.hget('hash1', 'field1');
|
|
155
|
+
if (value !== 'value1_updated') {
|
|
156
|
+
throw new Error(`hget失败,预期: value1_updated, 实际: ${value}`);
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
await runner.runTest('hgetall方法', async () => {
|
|
161
|
+
await hashCache.hset('hash1', 'field2', 'value2');
|
|
162
|
+
const hash = await hashCache.hgetall('hash1');
|
|
163
|
+
if (JSON.stringify(hash) !== JSON.stringify({ field1: 'value1_updated', field2: 'value2' })) {
|
|
164
|
+
throw new Error(`hgetall失败,预期: {"field1":"value1_updated","field2":"value2"}, 实际: ${JSON.stringify(hash)}`);
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
await runner.runTest('hdel方法', async () => {
|
|
169
|
+
const result = await hashCache.hdel('hash1', 'field1');
|
|
170
|
+
if (result !== true) {
|
|
171
|
+
throw new Error(`hdel失败,预期: true, 实际: ${result}`);
|
|
172
|
+
}
|
|
173
|
+
const value = await hashCache.hget('hash1', 'field1');
|
|
174
|
+
if (value !== undefined) {
|
|
175
|
+
throw new Error(`hdel后字段未被删除,值: ${value}`);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// 删除不存在的字段
|
|
179
|
+
const result2 = await hashCache.hdel('hash1', 'non_existent');
|
|
180
|
+
if (result2 !== false) {
|
|
181
|
+
throw new Error(`hdel不存在字段失败,预期: false, 实际: ${result2}`);
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
// 测试批量操作
|
|
186
|
+
$.log.debug('[CacheBase] \n========== 测试批量操作 ==========');
|
|
187
|
+
const batchCache = new CacheBase();
|
|
188
|
+
|
|
189
|
+
await runner.runTest('mset方法', async () => {
|
|
190
|
+
const result = await batchCache.mset('key7', 'value7', 'key8', 'value8');
|
|
191
|
+
if (result !== true) {
|
|
192
|
+
throw new Error(`mset失败,预期: true, 实际: ${result}`);
|
|
193
|
+
}
|
|
194
|
+
const value7 = await batchCache.get('key7');
|
|
195
|
+
const value8 = await batchCache.get('key8');
|
|
196
|
+
if (value7 !== 'value7' || value8 !== 'value8') {
|
|
197
|
+
throw new Error(`mset设置失败,value7: ${value7}, value8: ${value8}`);
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
await runner.runTest('mget方法', async () => {
|
|
202
|
+
const values = await batchCache.mget(['key7', 'key8', 'nonExistentKey']);
|
|
203
|
+
if (JSON.stringify(values) !== JSON.stringify(['value7', 'value8', null])) {
|
|
204
|
+
throw new Error(`mget失败,预期: ["value7","value8",null], 实际: ${JSON.stringify(values)}`);
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
// 测试过期时间
|
|
209
|
+
$.log.debug('[CacheBase] \n========== 测试过期时间 ==========');
|
|
210
|
+
const expireCache = new CacheBase();
|
|
211
|
+
|
|
212
|
+
await runner.runTest('set带过期时间', async () => {
|
|
213
|
+
await expireCache.set('expire1', 'value1', 1); // 1秒过期
|
|
214
|
+
let ttl = await expireCache.ttl('expire1');
|
|
215
|
+
if (ttl <= 0) {
|
|
216
|
+
throw new Error(`ttl初始值错误: ${ttl}`);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// 等待过期
|
|
220
|
+
await new Promise(resolve => setTimeout(resolve, 1100));
|
|
221
|
+
|
|
222
|
+
ttl = await expireCache.ttl('expire1');
|
|
223
|
+
if (ttl !== -2) {
|
|
224
|
+
throw new Error(`过期后ttl错误,预期: -2, 实际: ${ttl}`);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const value = await expireCache.get('expire1');
|
|
228
|
+
if (value !== null) {
|
|
229
|
+
throw new Error(`过期后键仍存在: ${value}`);
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
await runner.runTest('expire方法', async () => {
|
|
234
|
+
await expireCache.set('expire2', 'value2');
|
|
235
|
+
const result = await expireCache.expire('expire2', 1);
|
|
236
|
+
if (result !== true) {
|
|
237
|
+
throw new Error(`expire设置失败,预期: true, 实际: ${result}`);
|
|
238
|
+
}
|
|
239
|
+
let ttl = await expireCache.ttl('expire2');
|
|
240
|
+
if (ttl <= 0) {
|
|
241
|
+
throw new Error(`expire后ttl错误: ${ttl}`);
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
await runner.runTest('persist方法', async () => {
|
|
246
|
+
await expireCache.set('expire3', 'value3', 30);
|
|
247
|
+
const result = await expireCache.persist('expire3');
|
|
248
|
+
if (result !== true) {
|
|
249
|
+
throw new Error(`persist设置失败,预期: true, 实际: ${result}`);
|
|
250
|
+
}
|
|
251
|
+
const ttl = await expireCache.ttl('expire3');
|
|
252
|
+
if (ttl !== -1) {
|
|
253
|
+
throw new Error(`persist后ttl错误,预期: -1, 实际: ${ttl}`);
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
// 测试数值操作
|
|
258
|
+
$.log.debug('[CacheBase] \n========== 测试数值操作 ==========');
|
|
259
|
+
const numCache = new CacheBase();
|
|
260
|
+
|
|
261
|
+
await runner.runTest('incr方法', async () => {
|
|
262
|
+
const result1 = await numCache.incr('counter');
|
|
263
|
+
if (result1 !== 1) {
|
|
264
|
+
throw new Error(`incr初始值失败,预期: 1, 实际: ${result1}`);
|
|
265
|
+
}
|
|
266
|
+
const value1 = await numCache.get('counter');
|
|
267
|
+
if (value1 !== 1) {
|
|
268
|
+
throw new Error(`incr值错误,预期: 1, 实际: ${value1}`);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
const result2 = await numCache.incr('counter');
|
|
272
|
+
if (result2 !== 2) {
|
|
273
|
+
throw new Error(`incr递增失败,预期: 2, 实际: ${result2}`);
|
|
274
|
+
}
|
|
275
|
+
const value2 = await numCache.get('counter');
|
|
276
|
+
if (value2 !== 2) {
|
|
277
|
+
throw new Error(`incr递增后值错误,预期: 2, 实际: ${value2}`);
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
await runner.runTest('decr方法', async () => {
|
|
282
|
+
const result = await numCache.decr('counter');
|
|
283
|
+
if (result !== 1) {
|
|
284
|
+
throw new Error(`decr递减失败,预期: 1, 实际: ${result}`);
|
|
285
|
+
}
|
|
286
|
+
const value = await numCache.get('counter');
|
|
287
|
+
if (value !== 1) {
|
|
288
|
+
throw new Error(`decr递减后值错误,预期: 1, 实际: ${value}`);
|
|
289
|
+
}
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
await runner.runTest('incrby方法', async () => {
|
|
293
|
+
const result = await numCache.incrby('counter', 5);
|
|
294
|
+
if (result !== 6) {
|
|
295
|
+
throw new Error(`incrby增加失败,预期: 6, 实际: ${result}`);
|
|
296
|
+
}
|
|
297
|
+
const value = await numCache.get('counter');
|
|
298
|
+
if (value !== 6) {
|
|
299
|
+
throw new Error(`incrby增加后值错误,预期: 6, 实际: ${value}`);
|
|
300
|
+
}
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
await runner.runTest('decrby方法', async () => {
|
|
304
|
+
const result = await numCache.decrby('counter', 2);
|
|
305
|
+
if (result !== 4) {
|
|
306
|
+
throw new Error(`decrby减少失败,预期: 4, 实际: ${result}`);
|
|
307
|
+
}
|
|
308
|
+
const value = await numCache.get('counter');
|
|
309
|
+
if (value !== 4) {
|
|
310
|
+
throw new Error(`decrby减少后值错误,预期: 4, 实际: ${value}`);
|
|
311
|
+
}
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
await runner.runTest('incrbyfloat方法', async () => {
|
|
315
|
+
const result = await numCache.incrbyfloat('counter', 0.5);
|
|
316
|
+
if (result !== 4.5) {
|
|
317
|
+
throw new Error(`incrbyfloat增加失败,预期: 4.5, 实际: ${result}`);
|
|
318
|
+
}
|
|
319
|
+
const value = await numCache.get('counter');
|
|
320
|
+
if (value !== 4.5) {
|
|
321
|
+
throw new Error(`incrbyfloat增加后值错误,预期: 4.5, 实际: ${value}`);
|
|
322
|
+
}
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
await runner.runTest('add方法(兼容)', async () => {
|
|
326
|
+
// 先删除键,确保它不存在
|
|
327
|
+
await numCache.del('counter');
|
|
328
|
+
const result = await numCache.add('counter', 10);
|
|
329
|
+
if (result !== true) {
|
|
330
|
+
throw new Error(`add增加失败,预期: true, 实际: ${result}`);
|
|
331
|
+
}
|
|
332
|
+
const value = await numCache.get('counter');
|
|
333
|
+
if (value !== 10) {
|
|
334
|
+
throw new Error(`add增加后值错误,预期: 10, 实际: ${value}`);
|
|
335
|
+
}
|
|
404
336
|
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
337
|
+
// 测试键已存在时的行为(不应修改值)
|
|
338
|
+
const result2 = await numCache.add('counter', 20);
|
|
339
|
+
if (result2 !== false) {
|
|
340
|
+
throw new Error(`add键已存在时失败,预期: false, 实际: ${result2}`);
|
|
341
|
+
}
|
|
342
|
+
const value2 = await numCache.get('counter');
|
|
343
|
+
if (value2 !== 10) {
|
|
344
|
+
throw new Error(`add键已存在时值不应改变,预期: 10, 实际: ${value2}`);
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
await runner.runTest('addFloat方法(兼容)', async () => {
|
|
349
|
+
const result = await numCache.addFloat('counter', 0.5);
|
|
350
|
+
if (result !== 10.5) {
|
|
351
|
+
throw new Error(`addFloat增加失败,预期: 10.5, 实际: ${result}`);
|
|
352
|
+
}
|
|
353
|
+
const value = await numCache.get('counter');
|
|
354
|
+
if (value !== 10.5) {
|
|
355
|
+
throw new Error(`addFloat增加后值错误,预期: 10.5, 实际: ${value}`);
|
|
356
|
+
}
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
// 测试字符串操作
|
|
360
|
+
$.log.debug('[CacheBase] \n========== 测试字符串操作 ==========');
|
|
361
|
+
const strCache = new CacheBase();
|
|
362
|
+
|
|
363
|
+
await runner.runTest('append方法', async () => {
|
|
364
|
+
await strCache.set('str', 'hello');
|
|
365
|
+
const result = await strCache.append('str', ' world');
|
|
366
|
+
if (result !== 11) {
|
|
367
|
+
throw new Error(`append长度错误,预期: 11, 实际: ${result}`);
|
|
368
|
+
}
|
|
369
|
+
const value = await strCache.get('str');
|
|
370
|
+
if (value !== 'hello world') {
|
|
371
|
+
throw new Error(`append值错误,预期: hello world, 实际: ${value}`);
|
|
372
|
+
}
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
await runner.runTest('strlen方法', async () => {
|
|
376
|
+
const result = await strCache.strlen('str');
|
|
377
|
+
if (result !== 11) {
|
|
378
|
+
throw new Error(`strlen长度错误,预期: 11, 实际: ${result}`);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// 不存在的键
|
|
382
|
+
const result2 = await strCache.strlen('non_existent');
|
|
383
|
+
if (result2 !== 0) {
|
|
384
|
+
throw new Error(`strlen不存在键错误,预期: 0, 实际: ${result2}`);
|
|
385
|
+
}
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
await runner.runTest('addStr方法(兼容)', async () => {
|
|
389
|
+
const result = await strCache.addStr('str', '!');
|
|
390
|
+
if (result !== 12) {
|
|
391
|
+
throw new Error(`addStr长度错误,预期: 12, 实际: ${result}`);
|
|
392
|
+
}
|
|
393
|
+
const value = await strCache.get('str');
|
|
394
|
+
if (value !== 'hello world!') {
|
|
395
|
+
throw new Error(`addStr值错误,预期: hello world!, 实际: ${value}`);
|
|
396
|
+
}
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
// 测试事件触发
|
|
400
|
+
$.log.debug('[CacheBase] \n========== 测试事件触发 ==========');
|
|
401
|
+
const eventCache = new CacheBase();
|
|
402
|
+
|
|
403
|
+
await runner.runTest('set事件触发', async () => {
|
|
404
|
+
return new Promise(async (resolve, reject) => {
|
|
405
|
+
let beforeTriggered = false;
|
|
406
|
+
let afterTriggered = false;
|
|
407
|
+
|
|
408
|
+
eventCache.once('set_before', (data) => {
|
|
409
|
+
if (data.key === 'event_key' && data.value === 'event_value') {
|
|
410
|
+
beforeTriggered = true;
|
|
411
|
+
}
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
eventCache.once('set_after', (data) => {
|
|
415
|
+
if (data.key === 'event_key' && data.value === 'event_value' && data.result === 'OK') {
|
|
416
|
+
afterTriggered = true;
|
|
417
|
+
setTimeout(() => {
|
|
418
|
+
if (beforeTriggered && afterTriggered) {
|
|
419
|
+
resolve();
|
|
420
|
+
} else {
|
|
421
|
+
reject(new Error('set事件未全部触发'));
|
|
422
|
+
}
|
|
423
|
+
}, 10);
|
|
424
|
+
}
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
await eventCache.set('event_key', 'event_value');
|
|
428
|
+
});
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
await runner.runTest('error事件触发', async () => {
|
|
432
|
+
return new Promise(async (resolve, reject) => {
|
|
433
|
+
eventCache.once('mset_error', (data) => {
|
|
434
|
+
if (data.error && data.error.message.includes('必须是对象')) {
|
|
435
|
+
resolve();
|
|
436
|
+
} else {
|
|
437
|
+
reject(new Error('mset_error事件触发但消息不正确'));
|
|
438
|
+
}
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
try {
|
|
442
|
+
await eventCache.mset(null);
|
|
443
|
+
reject(new Error('mset应抛出错误但没有'));
|
|
444
|
+
} catch (error) {
|
|
445
|
+
// 预期的错误,等待事件触发
|
|
408
446
|
setTimeout(() => {
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
} else {
|
|
412
|
-
reject(new Error('set事件未全部触发'));
|
|
413
|
-
}
|
|
414
|
-
}, 10);
|
|
447
|
+
reject(new Error('mset_error事件未触发'));
|
|
448
|
+
}, 100);
|
|
415
449
|
}
|
|
416
450
|
});
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
// 测试管理功能
|
|
454
|
+
$.log.debug('[CacheBase] \n========== 测试管理功能 ==========');
|
|
455
|
+
|
|
456
|
+
await runner.runTest('cachebase_admin创建实例', async () => {
|
|
457
|
+
const cache1 = cachebase_admin('test_scope');
|
|
458
|
+
const cache2 = cachebase_admin('test_scope');
|
|
459
|
+
if (cache1 !== cache2) {
|
|
460
|
+
throw new Error('cachebase_admin应返回相同实例但没有');
|
|
461
|
+
}
|
|
417
462
|
|
|
418
|
-
|
|
463
|
+
const cache3 = cachebase_admin('another_scope');
|
|
464
|
+
if (cache1 === cache3) {
|
|
465
|
+
throw new Error('cachebase_admin应返回不同作用域的不同实例但没有');
|
|
466
|
+
}
|
|
419
467
|
});
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
return new Promise(async (resolve, reject) => {
|
|
426
|
-
cache.once('mset_error', (data) => {
|
|
427
|
-
if (data.error && data.error.message.includes('必须是对象')) {
|
|
428
|
-
resolve();
|
|
429
|
-
} else {
|
|
430
|
-
reject(new Error('mset_error事件触发但消息不正确'));
|
|
431
|
-
}
|
|
432
|
-
});
|
|
468
|
+
|
|
469
|
+
await runner.runTest('dispose方法', async () => {
|
|
470
|
+
const disposeCache = new CacheBase();
|
|
471
|
+
await disposeCache.set('key_to_dispose', 'value');
|
|
472
|
+
disposeCache.dispose();
|
|
433
473
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
} catch (error) {
|
|
438
|
-
// 预期的错误,等待事件触发
|
|
439
|
-
setTimeout(() => {
|
|
440
|
-
reject(new Error('mset_error事件未触发'));
|
|
441
|
-
}, 100);
|
|
474
|
+
const size = await disposeCache.dbsize();
|
|
475
|
+
if (size !== 0) {
|
|
476
|
+
throw new Error(`dispose后大小不为0: ${size}`);
|
|
442
477
|
}
|
|
443
478
|
});
|
|
444
|
-
});
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
// 测试管理功能
|
|
448
|
-
async function testAdminFunctions(runner) {
|
|
449
|
-
console.log('\n========== 测试管理功能 ==========');
|
|
450
|
-
|
|
451
|
-
await runner.runTest('cachebase_admin创建实例', async () => {
|
|
452
|
-
const cache1 = cachebase_admin('test_scope');
|
|
453
|
-
const cache2 = cachebase_admin('test_scope');
|
|
454
|
-
if (cache1 !== cache2) {
|
|
455
|
-
throw new Error('cachebase_admin应返回相同实例但没有');
|
|
456
|
-
}
|
|
457
479
|
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
}
|
|
462
|
-
});
|
|
463
|
-
|
|
464
|
-
await runner.runTest('dispose方法', async () => {
|
|
465
|
-
const cache = new CacheBase();
|
|
466
|
-
await cache.set('key_to_dispose', 'value');
|
|
467
|
-
cache.dispose();
|
|
480
|
+
// 显示测试结果
|
|
481
|
+
const passRate = runner.displayResults();
|
|
482
|
+
$.log.debug(`[CacheBase] \n测试完成!通过率: ${passRate}%`);
|
|
468
483
|
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
})
|
|
484
|
+
$.log.debug('[CacheBase] \n==============================');
|
|
485
|
+
$.log.debug('[CacheBase] 所有兼容性测试完成!');
|
|
486
|
+
$.log.debug('[CacheBase] ==============================');
|
|
487
|
+
|
|
488
|
+
} catch (error) {
|
|
489
|
+
$.log.error('[CacheBase] 测试过程中出现错误:', error);
|
|
490
|
+
}
|
|
474
491
|
}
|
|
475
492
|
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
493
|
+
test().then(() => {
|
|
494
|
+
// 测试成功完成
|
|
495
|
+
$.log.debug('[CacheBase] 测试脚本正常退出');
|
|
496
|
+
process.exit(0);
|
|
497
|
+
}).catch(err => {
|
|
498
|
+
$.log.error('[CacheBase] 未捕获的错误:', err);
|
|
499
|
+
process.exit(1);
|
|
500
|
+
});
|
|
501
|
+
|
|
502
|
+
// 添加超时保护,但让Promise处理正常结束
|
|
503
|
+
setTimeout(() => {
|
|
504
|
+
$.log.warn('[CacheBase] 测试脚本超时');
|
|
505
|
+
process.exit(1);
|
|
506
|
+
}, 10000); // 10秒超时
|