Skip to content

Commit 9541182

Browse files
Merge pull request #3460 from RedisInsight/be/feature/RI-5156_rdi_tip
#RI-5156 - add rdi tip check
2 parents 589a084 + fad2b9d commit 9541182

File tree

59 files changed

+916
-497
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+916
-497
lines changed

redisinsight/api/src/constants/recommendations.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,13 @@ export const RECOMMENDATION_NAMES = Object.freeze({
1515
SET_PASSWORD: 'setPassword',
1616
RTS: 'RTS',
1717
REDIS_VERSION: 'redisVersion',
18+
TRY_RDI: 'tryRDI',
1819
SEARCH_INDEXES: 'searchIndexes',
1920
SEARCH_JSON: 'searchJSON',
2021
STRING_TO_JSON: 'stringToJson',
2122
SEARCH_VISUALIZATION: 'searchVisualization',
2223
SEARCH_HASH: 'searchHash',
24+
2325
});
2426

2527
export const ONE_NODE_RECOMMENDATIONS = [

redisinsight/api/src/modules/database-recommendation/scanner/recommendation.provider.spec.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
BigStringStrategy,
1818
CompressionForListStrategy,
1919
BigAmountConnectedClientsStrategy,
20+
TryRdiStrategyStrategy,
2021
} from 'src/modules/database-recommendation/scanner/strategies';
2122

2223
describe('RecommendationProvider', () => {
@@ -51,6 +52,7 @@ describe('RecommendationProvider', () => {
5152
[RECOMMENDATION_NAMES.BIG_STRINGS, new BigStringStrategy()],
5253
[RECOMMENDATION_NAMES.COMPRESSION_FOR_LIST, new CompressionForListStrategy()],
5354
[RECOMMENDATION_NAMES.BIG_AMOUNT_OF_CONNECTED_CLIENTS, new BigAmountConnectedClientsStrategy()],
55+
[RECOMMENDATION_NAMES.TRY_RDI, new TryRdiStrategyStrategy()],
5456
['default', new DefaultRecommendationStrategy()],
5557
['unknown', new DefaultRecommendationStrategy()],
5658
[null, new DefaultRecommendationStrategy()],

redisinsight/api/src/modules/database-recommendation/scanner/recommendation.provider.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
BigStringStrategy,
1919
CompressionForListStrategy,
2020
BigAmountConnectedClientsStrategy,
21+
TryRdiStrategyStrategy,
2122
} from 'src/modules/database-recommendation/scanner/strategies';
2223

2324
@Injectable()
@@ -43,6 +44,7 @@ export class RecommendationProvider {
4344
this.strategies.set(RECOMMENDATION_NAMES.BIG_STRINGS, new BigStringStrategy());
4445
this.strategies.set(RECOMMENDATION_NAMES.COMPRESSION_FOR_LIST, new CompressionForListStrategy());
4546
this.strategies.set(RECOMMENDATION_NAMES.BIG_AMOUNT_OF_CONNECTED_CLIENTS, new BigAmountConnectedClientsStrategy());
47+
this.strategies.set(RECOMMENDATION_NAMES.TRY_RDI, new TryRdiStrategyStrategy());
4648
}
4749

4850
getStrategy(type: string): IRecommendationStrategy {

redisinsight/api/src/modules/database-recommendation/scanner/strategies/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,4 @@ export * from './avoid-lua-scripts.strategy';
1313
export * from './big-string.strategy';
1414
export * from './compression-for-list.strategy';
1515
export * from './big-amount-connected-clients.strategy';
16+
export * from './try-rdi.strategy';
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { TryRdiStrategyStrategy } from 'src/modules/database-recommendation/scanner/strategies';
2+
import { RedisClientConnectionType } from 'src/modules/redis/client';
3+
import { HostingProvider } from 'src/modules/database/entities/database.entity';
4+
5+
const mockClusterConnectionType = RedisClientConnectionType.CLUSTER;
6+
const mockNotClusterConnectionType = RedisClientConnectionType.STANDALONE;
7+
8+
const mockREProvider = HostingProvider.RE_CLUSTER;
9+
const mockNotREProvider = HostingProvider.RE_CLOUD;
10+
11+
describe('TryRdiStrategyStrategy', () => {
12+
let strategy: TryRdiStrategyStrategy;
13+
14+
beforeEach(async () => {
15+
strategy = new TryRdiStrategyStrategy();
16+
});
17+
18+
describe('isRecommendationReached', () => {
19+
it('should return true when connectionType is cluster', async () => {
20+
expect(await strategy.isRecommendationReached({ connectionType: mockClusterConnectionType, provider: mockNotREProvider }))
21+
.toEqual({ isReached: true });
22+
});
23+
24+
it('should return true when provider is Redis Enterprise', async () => {
25+
expect(await strategy.isRecommendationReached({ connectionType: mockNotClusterConnectionType, provider: mockREProvider }))
26+
.toEqual({ isReached: true });
27+
});
28+
29+
it('should return true when provider is Redis Enterprise and connectionType is cluster', async () => {
30+
expect(await strategy.isRecommendationReached({ connectionType: mockClusterConnectionType, provider: mockREProvider }))
31+
.toEqual({ isReached: true });
32+
});
33+
34+
it('should return false when provider is not Redis Enterprise and connectionType is not cluster', async () => {
35+
expect(await strategy.isRecommendationReached({ connectionType: mockNotClusterConnectionType, provider: mockNotREProvider }))
36+
.toEqual({ isReached: false });
37+
});
38+
});
39+
});
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { AbstractRecommendationStrategy }
2+
from 'src/modules/database-recommendation/scanner/strategies/abstract.recommendation.strategy';
3+
import { IDatabaseRecommendationStrategyData }
4+
from 'src/modules/database-recommendation/scanner/recommendation.strategy.interface';
5+
import { HostingProvider } from 'src/modules/database/entities/database.entity';
6+
import { RedisClientConnectionType } from 'src/modules/redis/client';
7+
8+
export class TryRdiStrategyStrategy extends AbstractRecommendationStrategy {
9+
/**
10+
* Check try rdi recommendation
11+
* @param data
12+
*/
13+
14+
async isRecommendationReached(
15+
data: { provider: HostingProvider, connectionType: RedisClientConnectionType },
16+
): Promise<IDatabaseRecommendationStrategyData> {
17+
const isReCLusterOrCluster = data.provider === HostingProvider.RE_CLUSTER
18+
|| data.connectionType === RedisClientConnectionType.CLUSTER;
19+
20+
return { isReached: isReCLusterOrCluster };
21+
}
22+
}

redisinsight/api/src/modules/database/database-connection.service.spec.ts

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
11
import { Test, TestingModule } from '@nestjs/testing';
22
import { get } from 'lodash';
3+
import { when, resetAllWhenMocks } from 'jest-when';
34
import {
45
mockCommonClientMetadata,
56
mockDatabase,
67
mockDatabaseAnalytics,
78
mockDatabaseInfoProvider,
89
mockDatabaseRepository,
910
mockDatabaseService,
10-
mockStandaloneRedisClient,
1111
mockDatabaseRecommendationService,
1212
MockType,
1313
mockRedisGeneralInfo,
1414
mockRedisClientListResult,
1515
mockDatabaseClientFactory,
16+
mockFeatureService,
1617
} from 'src/__mocks__';
1718
import { DatabaseAnalytics } from 'src/modules/database/database.analytics';
1819
import { DatabaseService } from 'src/modules/database/database.service';
@@ -22,15 +23,19 @@ import { DatabaseInfoProvider } from 'src/modules/database/providers/database-in
2223
import { DatabaseConnectionService } from 'src/modules/database/database-connection.service';
2324
import { RECOMMENDATION_NAMES } from 'src/constants';
2425
import { DatabaseClientFactory } from 'src/modules/database/providers/database.client.factory';
26+
import { FeatureService } from 'src/modules/feature/feature.service';
27+
import { KnownFeatures } from 'src/modules/feature/constants';
2528

2629
describe('DatabaseConnectionService', () => {
2730
let service: DatabaseConnectionService;
2831
let analytics: MockType<DatabaseAnalytics>;
2932
let recommendationService: MockType<DatabaseRecommendationService>;
3033
let databaseInfoProvider: MockType<DatabaseInfoProvider>;
34+
let featureService: MockType<FeatureService>;
3135

3236
beforeEach(async () => {
3337
jest.clearAllMocks();
38+
resetAllWhenMocks();
3439

3540
const module: TestingModule = await Test.createTestingModule({
3641
providers: [
@@ -59,13 +64,22 @@ describe('DatabaseConnectionService', () => {
5964
provide: DatabaseRecommendationService,
6065
useFactory: mockDatabaseRecommendationService,
6166
},
67+
{
68+
provide: FeatureService,
69+
useFactory: mockFeatureService,
70+
},
6271
],
6372
}).compile();
6473

6574
service = await module.get(DatabaseConnectionService);
6675
analytics = await module.get(DatabaseAnalytics);
6776
recommendationService = module.get(DatabaseRecommendationService);
6877
databaseInfoProvider = module.get(DatabaseInfoProvider);
78+
featureService = module.get(FeatureService);
79+
80+
featureService.getByName.mockResolvedValue({
81+
flag: false,
82+
});
6983
});
7084

7185
describe('connect', () => {
@@ -95,6 +109,38 @@ describe('DatabaseConnectionService', () => {
95109
);
96110
});
97111

112+
it('should call check try rdi recommendation', async () => {
113+
featureService.getByName.mockResolvedValueOnce({
114+
flag: true,
115+
});
116+
117+
expect(await service.connect(mockCommonClientMetadata)).toEqual(undefined);
118+
119+
expect(recommendationService.check).toHaveBeenCalledTimes(4);
120+
121+
expect(recommendationService.check).toBeCalledWith(
122+
mockCommonClientMetadata,
123+
RECOMMENDATION_NAMES.REDIS_VERSION,
124+
mockRedisGeneralInfo,
125+
);
126+
expect(recommendationService.check).toBeCalledWith(
127+
mockCommonClientMetadata,
128+
RECOMMENDATION_NAMES.LUA_SCRIPT,
129+
mockRedisGeneralInfo,
130+
);
131+
expect(recommendationService.check).toBeCalledWith(
132+
mockCommonClientMetadata,
133+
RECOMMENDATION_NAMES.BIG_AMOUNT_OF_CONNECTED_CLIENTS,
134+
mockRedisGeneralInfo,
135+
);
136+
137+
expect(recommendationService.check).toBeCalledWith(
138+
mockCommonClientMetadata,
139+
RECOMMENDATION_NAMES.TRY_RDI,
140+
{ connectionType: 'STANDALONE', provider: undefined },
141+
);
142+
});
143+
98144
it('should call databaseInfoProvider', async () => {
99145
expect(await service.connect(mockCommonClientMetadata)).toEqual(undefined);
100146

redisinsight/api/src/modules/database/database-connection.service.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import { Database } from 'src/modules/database/models/database';
88
import { ClientMetadata } from 'src/common/models';
99
import { DatabaseClientFactory } from 'src/modules/database/providers/database.client.factory';
1010
import { RedisClient, RedisClientConnectionType } from 'src/modules/redis/client';
11+
import { FeatureService } from 'src/modules/feature/feature.service';
12+
import { KnownFeatures } from 'src/modules/feature/constants';
1113

1214
@Injectable()
1315
export class DatabaseConnectionService {
@@ -18,6 +20,7 @@ export class DatabaseConnectionService {
1820
private readonly databaseInfoProvider: DatabaseInfoProvider,
1921
private readonly repository: DatabaseRepository,
2022
private readonly analytics: DatabaseAnalytics,
23+
private readonly featureService: FeatureService,
2124
private recommendationService: DatabaseRecommendationService,
2225
) {}
2326

@@ -27,7 +30,6 @@ export class DatabaseConnectionService {
2730
*/
2831
async connect(clientMetadata: ClientMetadata): Promise<void> {
2932
const client = await this.databaseClientFactory.getOrCreateClient(clientMetadata);
30-
3133
// refresh modules list and last connected time
3234
// mark database as not a new
3335
// will be refreshed after user navigate to particular database from the databases list
@@ -39,8 +41,9 @@ export class DatabaseConnectionService {
3941
version: await this.databaseInfoProvider.determineDatabaseServer(client),
4042
};
4143

44+
const connectionType = client?.getConnectionType();
4245
// Update cluster nodes db record
43-
if (client?.getConnectionType() === RedisClientConnectionType.CLUSTER) {
46+
if (connectionType === RedisClientConnectionType.CLUSTER) {
4447
toUpdate.nodes = (await client.nodes()).map(({ options }) => ({
4548
host: options.host,
4649
port: options.port,
@@ -67,6 +70,17 @@ export class DatabaseConnectionService {
6770
generalInfo,
6871
);
6972

73+
const rdiFeature = await this.featureService.getByName(KnownFeatures.Rdi);
74+
75+
if (rdiFeature?.flag) {
76+
const database = await this.repository.get(clientMetadata.databaseId);
77+
this.recommendationService.check(
78+
clientMetadata,
79+
RECOMMENDATION_NAMES.TRY_RDI,
80+
{ connectionType, provider: database.provider },
81+
);
82+
}
83+
7084
this.collectClientInfo(clientMetadata, client, generalInfo?.version);
7185

7286
this.logger.log(`Succeed to connect to database ${clientMetadata.databaseId}`);

redisinsight/api/src/modules/recommendation/recommendation.service.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,10 @@ export class RecommendationService {
129129
RECOMMENDATION_NAMES.SEARCH_VISUALIZATION,
130130
() => null,
131131
],
132+
[
133+
RECOMMENDATION_NAMES.TRY_RDI,
134+
() => null,
135+
],
132136
]);
133137

134138
const recommendationsToDetermine = difference(Object.values(RECOMMENDATION_NAMES), exclude);

redisinsight/ui/src/components/index.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,17 @@ import ImportDatabasesDialog from './import-databases-dialog'
2323
import OnboardingTour from './onboarding-tour'
2424
import CodeBlock from './code-block'
2525
import ShowChildByCondition from './show-child-by-condition'
26-
import RecommendationVoting from './recommendation-voting'
27-
import RecommendationCopyComponent from './recommendation-copy-component'
2826
import FeatureFlagComponent from './feature-flag-component'
2927
import AutoRefresh from './auto-refresh'
3028
import { ModuleNotLoaded, FilterNotAvailable } from './messages'
3129
import RdiInstanceHeader from './rdi-instance-header'
30+
import {
31+
RecommendationBody,
32+
RecommendationBadges,
33+
RecommendationBadgesLegend,
34+
RecommendationCopyComponent,
35+
RecommendationVoting,
36+
} from './recommendation'
3237

3338
export { FullScreen } from './full-screen'
3439

@@ -71,4 +76,7 @@ export {
7176
FilterNotAvailable,
7277
AutoRefresh,
7378
RdiInstanceHeader,
79+
RecommendationBody,
80+
RecommendationBadges,
81+
RecommendationBadgesLegend,
7482
}

0 commit comments

Comments
 (0)