@@ -2,6 +2,7 @@ import { Test, TestingModule } from '@nestjs/testing';
2
2
import { when } from 'jest-when' ;
3
3
import { IRedisClusterNodeAddress , ReplyError } from 'src/models' ;
4
4
import {
5
+ mockFeatureService ,
5
6
mockIOClusterNode1 ,
6
7
mockIOClusterNode2 ,
7
8
mockIORedisClient ,
@@ -17,14 +18,15 @@ import {
17
18
mockSentinelMasterEndpoint ,
18
19
mockSentinelMasterInDownState ,
19
20
mockSentinelMasterInOkState ,
20
- mockStandaloneRedisInfoReply ,
21
+ mockStandaloneRedisInfoReply , MockType ,
21
22
} from 'src/__mocks__' ;
22
23
import { REDIS_MODULES_COMMANDS , AdditionalRedisModuleName } from 'src/constants' ;
23
24
import { DatabaseInfoProvider } from 'src/modules/database/providers/database-info.provider' ;
24
25
import { RedisDatabaseInfoResponse } from 'src/modules/database/dto/redis-info.dto' ;
25
26
import { BadRequestException , ForbiddenException } from '@nestjs/common' ;
26
27
import { SentinelMasterStatus } from 'src/modules/redis-sentinel/models/sentinel-master' ;
27
28
import ERROR_MESSAGES from 'src/constants/error-messages' ;
29
+ import { FeatureService } from 'src/modules/feature/feature.service' ;
28
30
29
31
const mockClusterNodeAddresses : IRedisClusterNodeAddress [ ] = [
30
32
{
@@ -78,14 +80,22 @@ const mockSentinelConnectionOptions = {
78
80
79
81
describe ( 'DatabaseInfoProvider' , ( ) => {
80
82
let service : DatabaseInfoProvider ;
83
+ let featureService : MockType < FeatureService > ;
81
84
82
85
beforeEach ( async ( ) => {
83
86
jest . clearAllMocks ( ) ;
84
87
const module : TestingModule = await Test . createTestingModule ( {
85
- providers : [ DatabaseInfoProvider ] ,
88
+ providers : [
89
+ DatabaseInfoProvider ,
90
+ {
91
+ provide : FeatureService ,
92
+ useFactory : mockFeatureService ,
93
+ } ,
94
+ ] ,
86
95
} ) . compile ( ) ;
87
96
88
97
service = await module . get ( DatabaseInfoProvider ) ;
98
+ featureService = await module . get ( FeatureService ) ;
89
99
} ) ;
90
100
91
101
describe ( 'isCluster' , ( ) => {
@@ -239,7 +249,7 @@ describe('DatabaseInfoProvider', () => {
239
249
} ) ;
240
250
241
251
describe ( 'determineDatabaseModules' , ( ) => {
242
- it ( 'get modules by using MODULE LIST command' , async ( ) => {
252
+ it ( 'get modules by using MODULE LIST command (without filters) ' , async ( ) => {
243
253
when ( mockIORedisClient . call )
244
254
. calledWith ( 'module' , [ 'list' ] )
245
255
. mockResolvedValue ( mockRedisModuleList ) ;
@@ -258,7 +268,37 @@ describe('DatabaseInfoProvider', () => {
258
268
{ name : 'customModule' , version : 10000 , semanticVersion : undefined } ,
259
269
] ) ;
260
270
} ) ;
261
- it ( 'detect all modules by using COMMAND INFO command' , async ( ) => {
271
+ it ( 'get modules by using MODULE LIST command (with filters applied)' , async ( ) => {
272
+ when ( mockIORedisClient . call )
273
+ . calledWith ( 'module' , [ 'list' ] )
274
+ . mockResolvedValue ( mockRedisModuleList ) ;
275
+ featureService . getByName . mockResolvedValue ( {
276
+ flag : true ,
277
+ data : {
278
+ hideByName : [
279
+ {
280
+ expression : 'rejSoN' ,
281
+ options : 'i' ,
282
+ } ,
283
+ ] ,
284
+ } ,
285
+ } ) ;
286
+
287
+ const result = await service . determineDatabaseModules ( mockIORedisClient ) ;
288
+
289
+ expect ( mockIORedisClient . call ) . not . toHaveBeenCalledWith ( 'command' , expect . anything ( ) ) ;
290
+ expect ( result ) . toEqual ( [
291
+ { name : AdditionalRedisModuleName . RedisAI , version : 10000 , semanticVersion : '1.0.0' } ,
292
+ { name : AdditionalRedisModuleName . RedisGraph , version : 10000 , semanticVersion : '1.0.0' } ,
293
+ { name : AdditionalRedisModuleName . RedisGears , version : 10000 , semanticVersion : '1.0.0' } ,
294
+ { name : AdditionalRedisModuleName . RedisBloom , version : 10000 , semanticVersion : '1.0.0' } ,
295
+ // { name: AdditionalRedisModuleName.RedisJSON, version: 10000, semanticVersion: '1.0.0' }, should be ignored
296
+ { name : AdditionalRedisModuleName . RediSearch , version : 10000 , semanticVersion : '1.0.0' } ,
297
+ { name : AdditionalRedisModuleName . RedisTimeSeries , version : 10000 , semanticVersion : '1.0.0' } ,
298
+ { name : 'customModule' , version : 10000 , semanticVersion : undefined } ,
299
+ ] ) ;
300
+ } ) ;
301
+ it ( 'detect all modules by using COMMAND INFO command (without filter)' , async ( ) => {
262
302
when ( mockIORedisClient . call )
263
303
. calledWith ( 'module' , [ 'list' ] )
264
304
. mockRejectedValue ( mockUnknownCommandModule ) ;
@@ -282,6 +322,41 @@ describe('DatabaseInfoProvider', () => {
282
322
{ name : AdditionalRedisModuleName . RedisTimeSeries } ,
283
323
] ) ;
284
324
} ) ;
325
+ it ( 'detect all modules by using COMMAND INFO command (with filter)' , async ( ) => {
326
+ when ( mockIORedisClient . call )
327
+ . calledWith ( 'module' , [ 'list' ] )
328
+ . mockRejectedValue ( mockUnknownCommandModule ) ;
329
+ when ( mockIORedisClient . call )
330
+ . calledWith ( 'command' , expect . anything ( ) )
331
+ . mockResolvedValue ( [
332
+ null ,
333
+ [ 'somecommand' , - 1 , [ 'readonly' ] , 0 , 0 , - 1 , [ ] ] ,
334
+ ] ) ;
335
+ featureService . getByName . mockResolvedValue ( {
336
+ flag : true ,
337
+ data : {
338
+ hideByName : [
339
+ {
340
+ expression : 'rejSoN' ,
341
+ options : 'i' ,
342
+ } ,
343
+ ] ,
344
+ } ,
345
+ } ) ;
346
+
347
+ const result = await service . determineDatabaseModules ( mockIORedisClient ) ;
348
+
349
+ expect ( mockIORedisClient . call ) . toHaveBeenCalledTimes ( REDIS_MODULES_COMMANDS . size + 1 ) ;
350
+ expect ( result ) . toEqual ( [
351
+ { name : AdditionalRedisModuleName . RedisAI } ,
352
+ { name : AdditionalRedisModuleName . RedisGraph } ,
353
+ { name : AdditionalRedisModuleName . RedisGears } ,
354
+ { name : AdditionalRedisModuleName . RedisBloom } ,
355
+ // { name: AdditionalRedisModuleName.RedisJSON }, should be ignored
356
+ { name : AdditionalRedisModuleName . RediSearch } ,
357
+ { name : AdditionalRedisModuleName . RedisTimeSeries } ,
358
+ ] ) ;
359
+ } ) ;
285
360
it ( 'detect only RediSearch module by using COMMAND INFO command' , async ( ) => {
286
361
when ( mockIORedisClient . call )
287
362
. calledWith ( 'module' , [ 'list' ] )
@@ -372,7 +447,7 @@ describe('DatabaseInfoProvider', () => {
372
447
} ) ;
373
448
it ( 'should throw an error if no permission to run \'info\' command' , async ( ) => {
374
449
mockIORedisClient . info . mockRejectedValue ( {
375
- message : 'NOPERM this user has no permissions to run the \'info\' command'
450
+ message : 'NOPERM this user has no permissions to run the \'info\' command' ,
376
451
} ) ;
377
452
378
453
try {
0 commit comments