Branch data Line data Source code
1 [ + ]: 1 : /**
2 : 1 : * @module redis-leaderboard-test
3 : 1 : * @desc The leaderboard-api redis-leaderboard LeaderBoard class testing module.
4 : 1 : * @version 1.0.0
5 : 1 : * @author Essam A. El-Sherif
6 : 1 : */
7 : 1 :
8 : 1 : /* Import node.js core modules */
9 : 1 : import assert from 'node:assert/strict';
10 : 1 : import runner from 'node:test';
11 : 1 : import { fileURLToPath } from 'node:url';
12 : 1 : import { dirname, join } from 'node:path';
13 : 1 :
14 : 1 : /* Import package dependencies */
15 : 1 : import redis from 'redis';
16 : 1 : import dotenv from 'dotenv';
17 : 1 :
18 : 1 : /* Import local dependencies */
19 : 1 : import { LeaderBoard } from '../lib/redis-leaderboard.js';
20 : 1 :
21 : 1 : /* Emulate commonJS __filename and __dirname constants */
22 : 1 : const __filename = fileURLToPath(import.meta.url);
23 : 1 : const __dirname = dirname(__filename);
24 : 1 :
25 : 1 : /* Configure dotenv path to read the package .env file */
26 : 1 : dotenv.config({path: join(__dirname, '../.env')});
27 : 1 :
28 : 1 : /* Prepare test environment */
29 : 1 : const suites = new Map();
30 : 1 : let lbObj = null;
31 : 1 :
32 : 1 : /**
33 : 1 : * @func Main
34 : 1 : * @async
35 : 1 : * @desc The module entry point function.
36 : 1 : */
37 [ + ]: 1 : (async () => {
38 : 1 :
39 : 1 : let clientRd;
40 : 1 :
41 : 1 : /*
42 : 1 : * https://github.com/redis/node-redis
43 : 1 : *
44 : 1 : * Create a node-redis Client instance, or throws on failure.
45 : 1 : * Connect to Redis.
46 : 1 : * Since v4 of node-redis, the client does not automatically connect to the server.
47 : 1 : * Instead you need to run .connect() after creating the client or you will receive an error.
48 : 1 : */
49 : 1 : try{
50 : 1 : clientRd = redis.createClient({
51 : 1 : url: process.env.lb_connectRd,
52 : 1 : name: 'leaderboard-api-test'
53 : 1 : });
54 : 1 :
55 : 1 : await clientRd.connect();
56 : 1 : await clientRd.sendCommand(['FLUSHALL']);
57 : 1 :
58 : 1 : lbObj = new LeaderBoard(clientRd, 'lb:ts:', 'lb:act:');
59 : 1 : }
60 [ - ]: 1 : catch(err){ /* node:coverage disable */
61 : : console.error(err.message);
62 : : process.exit(1);
63 : : } /* node:coverage enable */
64 : 1 :
65 : 1 : loadTestData();
66 : 1 :
67 [ + ]: 1 : runner.after(async() => {
68 : 1 : await clientRd.sendCommand(['FLUSHALL']);
69 : 1 : await clientRd.quit();
70 : 1 : });
71 : 1 :
72 : 1 : nodeRunner(runner);
73 : 1 :
74 : 1 : })('Main Function');
75 : 1 :
76 : 1 : /**
77 : 1 : * @func loadTestData
78 : 1 : * @desc Load test data.
79 : 1 : */
80 [ + ]: 1 : function loadTestData(){
81 : 1 :
82 : 1 : let testData = null;
83 : 1 : let suiteDesc = '';
84 : 1 : let testObj = null;
85 : 1 :
86 : 1 : // TEST SUITE ### - Test Leaderboard Class
87 : 1 : suiteDesc = 'Test LeaderBoard Class';
88 : 1 : suites.set(suiteDesc, []);
89 : 1 :
90 : 1 : // TEST ### - Test addUserScore(activity, username, score) ... test#1
91 : 1 : testData = {};
92 : 1 :
93 : 1 : testObj = {
94 : 1 : lbMethod: lbObj.addUserScore,
95 : 1 : lbMethodInp: ['activity-1', 'user@1', 110],
96 : 1 : lbMethodOut: {activity: 'activity-1', username: 'user@1', score: '110'},
97 : 1 : lbThrows: false,
98 : 1 : };
99 : 1 :
100 : 1 : testData.method = testMethod.bind(testObj);
101 : 1 : testData.desc = 'Test addUserScore(activity, username, score) ... test#1';
102 : 1 :
103 : 1 : testData.skip = false;
104 : 1 : suites.get(suiteDesc).push(testData);
105 : 1 :
106 : 1 : // TEST ### - Test addUserScore(activity, username, score) ... test#2
107 : 1 : testData = {};
108 : 1 :
109 : 1 : testObj = {
110 : 1 : lbMethod: lbObj.addUserScore,
111 : 1 : lbMethodInp: ['activity-1', 'user@2', 120],
112 : 1 : lbMethodOut: {activity: 'activity-1', username: 'user@2', score: '120'},
113 : 1 : lbThrows: false,
114 : 1 : };
115 : 1 :
116 : 1 : testData.method = testMethod.bind(testObj);
117 : 1 : testData.desc = 'Test addUserScore(activity, username, score) ... test#2';
118 : 1 :
119 : 1 : testData.skip = false;
120 : 1 : suites.get(suiteDesc).push(testData);
121 : 1 :
122 : 1 : // TEST ### - Test addUserScore(activity, username, score) ... test#3
123 : 1 : testData = {};
124 : 1 :
125 : 1 : testObj = {
126 : 1 : lbMethod: lbObj.addUserScore,
127 : 1 : lbMethodInp: ['activity-2', 'user@1', 210],
128 : 1 : lbMethodOut: {activity: 'activity-2', username: 'user@1', score: '210'},
129 : 1 : lbThrows: false,
130 : 1 : };
131 : 1 :
132 : 1 : testData.method = testMethod.bind(testObj);
133 : 1 : testData.desc = 'Test addUserScore(activity, username, score) ... test#3';
134 : 1 :
135 : 1 : testData.skip = false;
136 : 1 : suites.get(suiteDesc).push(testData);
137 : 1 :
138 : 1 : // TEST ### - Test addUserScore(activity, username, score) ... test#4
139 : 1 : testData = {};
140 : 1 :
141 : 1 : testObj = {
142 : 1 : lbMethod: lbObj.addUserScore,
143 : 1 : lbMethodInp: ['activity-2', 'user@2', 220],
144 : 1 : lbMethodOut: {activity: 'activity-2', username: 'user@2', score: '220'},
145 : 1 : lbThrows: false,
146 : 1 : };
147 : 1 :
148 : 1 : testData.method = testMethod.bind(testObj);
149 : 1 : testData.desc = 'Test addUserScore(activity, username, score) ... test#4';
150 : 1 :
151 : 1 : testData.skip = false;
152 : 1 : suites.get(suiteDesc).push(testData);
153 : 1 :
154 : 1 : // TEST ### - Test addUserScore(activity, username, score) ... test#5
155 : 1 : testData = {};
156 : 1 :
157 : 1 : testObj = {
158 : 1 : lbMethod: lbObj.addUserScore,
159 : 1 : lbMethodInp: ['activity-2', 'user@3', 230],
160 : 1 : lbMethodOut: {activity: 'activity-2', username: 'user@3', score: '230'},
161 : 1 : lbThrows: false,
162 : 1 : };
163 : 1 :
164 : 1 : testData.method = testMethod.bind(testObj);
165 : 1 : testData.desc = 'Test addUserScore(activity, username, score) ... test#5';
166 : 1 :
167 : 1 : testData.skip = false;
168 : 1 : suites.get(suiteDesc).push(testData);
169 : 1 :
170 : 1 : // TEST ### - Test removeUserScore(username, activity) ... test#1
171 : 1 : testData = {};
172 : 1 :
173 : 1 : testObj = {
174 : 1 : lbMethod: lbObj.removeUserScore,
175 : 1 : lbMethodInp: ['user@3', 'activity-2'],
176 : 1 : lbMethodOut: [{activity: 'activity-2', username: 'user@3'}],
177 : 1 : lbThrows: false,
178 : 1 : };
179 : 1 :
180 : 1 : testData.method = testMethod.bind(testObj);
181 : 1 : testData.desc = 'Test removeUserScore(username, activity) ... test#1';
182 : 1 :
183 : 1 : testData.skip = false;
184 : 1 : suites.get(suiteDesc).push(testData);
185 : 1 :
186 : 1 : // TEST ### - Test removeUserScore(username, activity) ... test#2
187 : 1 : testData = {};
188 : 1 :
189 : 1 : testObj = {
190 : 1 : lbMethod: lbObj.removeUserScore,
191 : 1 : lbMethodInp: ['user@3', 'activity-2'],
192 : 1 : lbMethodOut: [],
193 : 1 : lbThrows: false,
194 : 1 : };
195 : 1 :
196 : 1 : testData.method = testMethod.bind(testObj);
197 : 1 : testData.desc = 'Test removeUserScore(username, activity) ... test#2';
198 : 1 :
199 : 1 : testData.skip = false;
200 : 1 : suites.get(suiteDesc).push(testData);
201 : 1 :
202 : 1 : // TEST ### - Test getUserScoreAndRank(activity, username) ... test#1
203 : 1 : testData = {};
204 : 1 :
205 : 1 : testObj = {
206 : 1 : lbMethod: lbObj.getUserScoreAndRank,
207 : 1 : lbMethodInp: ['activity-x', 'user@1'],
208 : 1 : lbMethodOut: [],
209 : 1 : lbThrows: `no activity 'activity-x'`,
210 : 1 : };
211 : 1 :
212 : 1 : testData.method = testMethod.bind(testObj);
213 : 1 : testData.desc = 'Test getUserScoreAndRank(activity, username) ... test#1';
214 : 1 :
215 : 1 : testData.skip = false;
216 : 1 : suites.get(suiteDesc).push(testData);
217 : 1 :
218 : 1 : // TEST ### - Test getUserScoreAndRank(activity, username) ... test#2
219 : 1 : testData = {};
220 : 1 :
221 : 1 : testObj = {
222 : 1 : lbMethod: lbObj.getUserScoreAndRank,
223 : 1 : lbMethodInp: ['activity-1', 'user@x'],
224 : 1 : lbMethodOut: {},
225 : 1 : lbThrows: false,
226 : 1 : };
227 : 1 :
228 : 1 : testData.method = testMethod.bind(testObj);
229 : 1 : testData.desc = 'Test getUserScoreAndRank(activity, username) ... test#2';
230 : 1 :
231 : 1 : testData.skip = false;
232 : 1 : suites.get(suiteDesc).push(testData);
233 : 1 :
234 : 1 : // TEST ### - Test getUserScoreAndRank(activity, username) ... test#3
235 : 1 : testData = {};
236 : 1 :
237 : 1 : testObj = {
238 : 1 : lbMethod: lbObj.getUserScoreAndRank,
239 : 1 : lbMethodInp: ['activity-1', 'user@1'],
240 : 1 : lbMethodOut: {activity: 'activity-1', username: 'user@1', score: '110', rank: 2},
241 : 1 : lbThrows: false,
242 : 1 : };
243 : 1 :
244 : 1 : testData.method = testMethod.bind(testObj);
245 : 1 : testData.desc = 'Test getUserScoreAndRank(activity, username) ... test#3';
246 : 1 :
247 : 1 : testData.final = true;
248 : 1 : testData.skip = false;
249 : 1 : suites.get(suiteDesc).push(testData);
250 : 1 :
251 : 1 : // TEST ### - Test getUserScoreAndRank(activity, username) ... test#4
252 : 1 : testData = {};
253 : 1 :
254 : 1 : testObj = {
255 : 1 : lbMethod: lbObj.getUserScoreAndRank,
256 : 1 : lbMethodInp: ['activity-1', 'user@2'],
257 : 1 : lbMethodOut: {activity: 'activity-1', username: 'user@2', score: '120', rank: 1},
258 : 1 : lbThrows: false,
259 : 1 : };
260 : 1 :
261 : 1 : testData.method = testMethod.bind(testObj);
262 : 1 : testData.desc = 'Test getUserScoreAndRank(activity, username) ... test#4';
263 : 1 :
264 : 1 : testData.skip = false;
265 : 1 : suites.get(suiteDesc).push(testData);
266 : 1 :
267 : 1 : // TEST ### - Test getActivity(activity) ... test#1
268 : 1 : testData = {};
269 : 1 :
270 : 1 : testObj = {
271 : 1 : lbMethod: lbObj.getActivity,
272 : 1 : lbMethodInp: ['activity-x'],
273 : 1 : lbMethodOut: [],
274 : 1 : lbThrows: `no activity 'activity-x'`,
275 : 1 : };
276 : 1 :
277 : 1 : testData.method = testMethod.bind(testObj);
278 : 1 : testData.desc = 'Test getActivity(activity) ... test#1';
279 : 1 :
280 : 1 : testData.skip = false;
281 : 1 : suites.get(suiteDesc).push(testData);
282 : 1 :
283 : 1 : // TEST ### - Test getActivity(activity) ... test#2
284 : 1 : testData = {};
285 : 1 :
286 : 1 : testObj = {
287 : 1 : lbMethod: lbObj.getActivity,
288 : 1 : lbMethodInp: ['activity-2'],
289 : 1 : lbMethodOut: [
290 : 1 : {activity: 'activity-2', username: 'user@2', score: '220', rank: 1},
291 : 1 : {activity: 'activity-2', username: 'user@1', score: '210', rank: 2},
292 : 1 : ],
293 : 1 : lbThrows: false,
294 : 1 : };
295 : 1 :
296 : 1 : testData.method = testMethod.bind(testObj);
297 : 1 : testData.desc = 'Test getActivity(activity) ... test#2';
298 : 1 :
299 : 1 : testData.skip = false;
300 : 1 : suites.get(suiteDesc).push(testData);
301 : 1 :
302 : 1 : // TEST ### - Test getActivities() ... test#1
303 : 1 : testData = {};
304 : 1 :
305 : 1 : testObj = {
306 : 1 : lbMethod: lbObj.getActivities,
307 : 1 : lbMethodInp: [],
308 : 1 : lbMethodOut: [
309 : 1 : {activity: 'activity-2', username: 'user@2', score: '220', rank: 1},
310 : 1 : {activity: 'activity-2', username: 'user@1', score: '210', rank: 2},
311 : 1 : {activity: 'activity-1', username: 'user@2', score: '120', rank: 3},
312 : 1 : {activity: 'activity-1', username: 'user@1', score: '110', rank: 4},
313 : 1 : ],
314 : 1 : lbThrows: false,
315 : 1 : };
316 : 1 :
317 : 1 : testData.method = testMethod.bind(testObj);
318 : 1 : testData.desc = 'Test getActivities() ... test#1';
319 : 1 :
320 : 1 : testData.skip = false;
321 : 1 : suites.get(suiteDesc).push(testData);
322 : 1 :
323 : 1 : // TEST ### - Test getUserActivities(username) ... test#1
324 : 1 : testData = {};
325 : 1 :
326 : 1 : testObj = {
327 : 1 : lbMethod: lbObj.getUserActivities,
328 : 1 : lbMethodInp: ['user@2'],
329 : 1 : lbMethodOut: [
330 : 1 : {activity: 'activity-2', username: 'user@2', score: '220', rank: 1},
331 : 1 : {activity: 'activity-1', username: 'user@2', score: '120', rank: 2},
332 : 1 : ],
333 : 1 : lbThrows: false,
334 : 1 : };
335 : 1 :
336 : 1 : testData.method = testMethod.bind(testObj);
337 : 1 : testData.desc = 'Test getUserActivities(username) ... test#1';
338 : 1 :
339 : 1 : testData.skip = false;
340 : 1 : suites.get(suiteDesc).push(testData);
341 : 1 :
342 : 1 : // TEST ### - Test getUserActivities(username) ... test#2
343 : 1 : testData = {};
344 : 1 :
345 : 1 : testObj = {
346 : 1 : lbMethod: lbObj.getUserActivities,
347 : 1 : lbMethodInp: ['user@x'],
348 : 1 : lbMethodOut: [],
349 : 1 : lbThrows: false,
350 : 1 : };
351 : 1 :
352 : 1 : testData.method = testMethod.bind(testObj);
353 : 1 : testData.desc = 'Test getUserActivities(username) ... test#2';
354 : 1 :
355 : 1 : testData.skip = false;
356 : 1 : suites.get(suiteDesc).push(testData);
357 : 1 :
358 : 1 : // TEST ### - Test getActivityTopUsers(activity, n) ... test#1
359 : 1 : testData = {};
360 : 1 :
361 : 1 : testObj = {
362 : 1 : lbMethod: lbObj.getActivityTopUsers,
363 : 1 : lbMethodInp: ['activity-1', 2],
364 : 1 : lbMethodOut: [
365 : 1 : {activity: 'activity-1', username: 'user@2', score: '120', rank: 1},
366 : 1 : {activity: 'activity-1', username: 'user@1', score: '110', rank: 2},
367 : 1 : ],
368 : 1 : lbThrows: false,
369 : 1 : };
370 : 1 :
371 : 1 : testData.method = testMethod.bind(testObj);
372 : 1 : testData.desc = 'Test getActivityTopUsers(activity, n) ... test#1';
373 : 1 :
374 : 1 : testData.skip = false;
375 : 1 : suites.get(suiteDesc).push(testData);
376 : 1 :
377 : 1 : // TEST ### - Test getActivityTopUsers(activity, n) ... test#2
378 : 1 : testData = {};
379 : 1 :
380 : 1 : testObj = {
381 : 1 : lbMethod: lbObj.getActivityTopUsers,
382 : 1 : lbMethodInp: ['activity-2', 2],
383 : 1 : lbMethodOut: [
384 : 1 : {activity: 'activity-2', username: 'user@2', score: '220', rank: 1},
385 : 1 : {activity: 'activity-2', username: 'user@1', score: '210', rank: 2},
386 : 1 : ],
387 : 1 : lbThrows: false,
388 : 1 : };
389 : 1 :
390 : 1 : testData.method = testMethod.bind(testObj);
391 : 1 : testData.desc = 'Test getActivityTopUsers(activity, n) ... test#2';
392 : 1 :
393 : 1 : testData.skip = false;
394 : 1 : suites.get(suiteDesc).push(testData);
395 : 1 :
396 : 1 : // TEST ### - Test getActivityTopUsers(activity, n) ... test#3
397 : 1 : testData = {};
398 : 1 :
399 : 1 : testObj = {
400 : 1 : lbMethod: lbObj.getActivityTopUsers,
401 : 1 : lbMethodInp: ['activity-2', 1],
402 : 1 : lbMethodOut: [
403 : 1 : {activity: 'activity-2', username: 'user@2', score: '220', rank: 1},
404 : 1 : ],
405 : 1 : lbThrows: false,
406 : 1 : };
407 : 1 :
408 : 1 : testData.method = testMethod.bind(testObj);
409 : 1 : testData.desc = 'Test getActivityTopUsers(activity, n) ... test#3';
410 : 1 :
411 : 1 : testData.skip = false;
412 : 1 : suites.get(suiteDesc).push(testData);
413 : 1 :
414 : 1 : // TEST ### - Test getActivityTopUsers(activity, n) ... test#4
415 : 1 : testData = {};
416 : 1 :
417 : 1 : testObj = {
418 : 1 : lbMethod: lbObj.getActivityTopUsers,
419 : 1 : lbMethodInp: ['activity-2', 0],
420 : 1 : lbMethodOut: [
421 : 1 : {activity: 'activity-2', username: 'user@2', score: '220', rank: 1},
422 : 1 : {activity: 'activity-2', username: 'user@1', score: '210', rank: 2},
423 : 1 : ],
424 : 1 : lbThrows: false,
425 : 1 : };
426 : 1 :
427 : 1 : testData.method = testMethod.bind(testObj);
428 : 1 : testData.desc = 'Test getActivityTopUsers(activity, n) ... test#4';
429 : 1 :
430 : 1 : testData.skip = false;
431 : 1 : suites.get(suiteDesc).push(testData);
432 : 1 :
433 : 1 : // TEST ### - Test getActivityTopUsers(activity, n) ... test#5
434 : 1 : testData = {};
435 : 1 :
436 : 1 : testObj = {
437 : 1 : lbMethod: lbObj.getActivityTopUsers,
438 : 1 : lbMethodInp: ['activity-x', 2],
439 : 1 : lbMethodOut: [],
440 : 1 : lbThrows: false,
441 : 1 : };
442 : 1 :
443 : 1 : testData.method = testMethod.bind(testObj);
444 : 1 : testData.desc = 'Test getActivityTopUsers(activity, n) ... test#5';
445 : 1 :
446 : 1 : testData.skip = false;
447 : 1 : suites.get(suiteDesc).push(testData);
448 : 1 :
449 : 1 : }
450 : 1 :
451 : 1 : /**
452 : 1 : * @func nodeRunner
453 : 1 : * @param {object} runner - The node core module 'node:test' object.
454 : 1 : * @desc Carry out the loaded tests using node test runner.
455 : 1 : */
456 [ + ]: 1 : function nodeRunner(runner){
457 : 1 :
458 : 1 : for(let [suiteDesc, suiteTests] of suites){
459 [ + ]: 1 : runner.suite(suiteDesc, () => {
460 [ + ]: 1 : for(let cmdObj of suiteTests){
461 [ + ]: 21 : runner.test(cmdObj.desc, {skip: cmdObj.skip}, async () => {
462 : 21 : await cmdObj.method();
463 : 21 : });
464 : 21 : }
465 : 1 : });
466 : 1 : }
467 : 1 : }
468 : 1 :
469 : 1 : /**
470 : 1 : * @func
471 : 1 : * @async
472 : 1 : * @desc Carries out the assertions tests.
473 : 1 : */
474 [ + ]: 21 : async function testMethod(){
475 : 21 :
476 [ + ]: 21 : if(this.lbThrows){
477 : 2 : try{
478 [ - ]: 2 : await this.lbMethod.apply(lbObj, this.lbMethodInp); /* node:coverage disable */
479 : : assert(false);
480 : : } /* node:coverage enable */
481 : 2 : catch(err){
482 : 2 : if(typeof this.lbThrows === 'string'){
483 : 2 : assert.strictEqual(err.message, this.lbThrows);
484 : 2 : }
485 : 2 : }
486 [ + ]: 2 : }
487 : 19 : else{
488 : 19 : let actOut = await this.lbMethod.apply(lbObj, this.lbMethodInp);
489 : 19 :
490 : 19 : if(typeof actOut === 'object'){
491 [ + ]: 19 : if(Array.isArray(actOut)){
492 [ + ]: 11 : actOut.forEach((obj) => delete obj.timestamp);
493 [ + ]: 11 : }
494 : 8 : else{
495 : 8 : delete actOut.timestamp;
496 : 8 : }
497 : 19 : assert.deepStrictEqual(actOut, this.lbMethodOut);
498 : 19 : }
499 : 19 : }
500 : 21 : }
|