Skip to content

Commit 3354934

Browse files
author
arthosofteq
authored
Merge pull request #1492 from RedisInsight/feature/RI-3853-database_import_results
Feature/ri 3853 database import results
2 parents 4258ede + 51cd240 commit 3354934

30 files changed

+869
-133
lines changed

redisinsight/api/src/__mocks__/database-import.ts

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import { DatabaseImportResponse } from 'src/modules/database-import/dto/database-import.response';
1+
import { DatabaseImportResponse, DatabaseImportStatus } from 'src/modules/database-import/dto/database-import.response';
22
import { BadRequestException, ForbiddenException } from '@nestjs/common';
33
import { mockDatabase } from 'src/__mocks__/databases';
4-
import { ValidationError } from 'class-validator';
4+
import { ValidationException } from 'src/common/exceptions';
55

66
export const mockDatabasesToImportArray = new Array(10).fill(mockDatabase);
77

@@ -12,23 +12,50 @@ export const mockDatabaseImportFile = {
1212
buffer: Buffer.from(JSON.stringify(mockDatabasesToImportArray)),
1313
};
1414

15+
export const mockDatabaseImportResultSuccess = {
16+
index: 0,
17+
status: DatabaseImportStatus.Success,
18+
host: mockDatabase.host,
19+
port: mockDatabase.port,
20+
};
21+
22+
export const mockDatabaseImportResultFail = {
23+
index: 0,
24+
status: DatabaseImportStatus.Fail,
25+
host: mockDatabase.host,
26+
port: mockDatabase.port,
27+
errors: [new BadRequestException()],
28+
};
29+
1530
export const mockDatabaseImportResponse = Object.assign(new DatabaseImportResponse(), {
1631
total: 10,
17-
success: 7,
18-
errors: [new ValidationError(), new BadRequestException(), new ForbiddenException()],
32+
success: (new Array(7).fill(mockDatabaseImportResultSuccess)).map((v, index) => ({
33+
...v,
34+
index: index + 3,
35+
})),
36+
partial: [],
37+
fail: [
38+
new ValidationException('Bad request'),
39+
new BadRequestException(),
40+
new ForbiddenException(),
41+
].map((error, index) => ({
42+
...mockDatabaseImportResultFail,
43+
index,
44+
errors: [error],
45+
})),
1946
});
2047

2148
export const mockDatabaseImportParseFailedAnalyticsPayload = {
2249

2350
};
2451

2552
export const mockDatabaseImportFailedAnalyticsPayload = {
26-
failed: mockDatabaseImportResponse.errors.length,
27-
errors: ['ValidationError', 'BadRequestException', 'ForbiddenException'],
53+
failed: mockDatabaseImportResponse.fail.length,
54+
errors: ['ValidationException', 'BadRequestException', 'ForbiddenException'],
2855
};
2956

3057
export const mockDatabaseImportSucceededAnalyticsPayload = {
31-
succeed: mockDatabaseImportResponse.success,
58+
succeed: mockDatabaseImportResponse.success.length,
3259
};
3360

3461
export const mockDatabaseImportAnalytics = jest.fn(() => ({
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './validation.exception';
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { BadRequestException } from '@nestjs/common';
2+
3+
export class ValidationException extends BadRequestException {}

redisinsight/api/src/constants/telemetry-events.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export enum TelemetryEvents {
1818
DatabaseImportParseFailed = 'CONFIG_DATABASES_REDIS_IMPORT_PARSE_FAILED',
1919
DatabaseImportFailed = 'CONFIG_DATABASES_REDIS_IMPORT_FAILED',
2020
DatabaseImportSucceeded = 'CONFIG_DATABASES_REDIS_IMPORT_SUCCEEDED',
21+
DatabaseImportPartiallySucceeded = 'CONFIG_DATABASES_REDIS_IMPORT_PARTIALLY_SUCCEEDED',
2122

2223
// Events for autodiscovery flows
2324
REClusterDiscoverySucceed = 'CONFIG_DATABASES_RE_CLUSTER_AUTODISCOVERY_SUCCEEDED',

redisinsight/api/src/modules/database-import/database-import.analytics.ts

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1+
import { uniq } from 'lodash';
12
import { Injectable } from '@nestjs/common';
23
import { TelemetryBaseService } from 'src/modules/analytics/telemetry.base.service';
34
import { EventEmitter2 } from '@nestjs/event-emitter';
45
import { TelemetryEvents } from 'src/constants';
5-
import { DatabaseImportResponse } from 'src/modules/database-import/dto/database-import.response';
6+
import { DatabaseImportResponse, DatabaseImportResult } from 'src/modules/database-import/dto/database-import.response';
67

78
@Injectable()
89
export class DatabaseImportAnalytics extends TelemetryBaseService {
@@ -11,21 +12,31 @@ export class DatabaseImportAnalytics extends TelemetryBaseService {
1112
}
1213

1314
sendImportResults(importResult: DatabaseImportResponse): void {
14-
if (importResult.success) {
15+
if (importResult.success?.length) {
1516
this.sendEvent(
1617
TelemetryEvents.DatabaseImportSucceeded,
1718
{
18-
succeed: importResult.success,
19+
succeed: importResult.success.length,
1920
},
2021
);
2122
}
2223

23-
if (importResult.errors?.length) {
24+
if (importResult.fail?.length) {
2425
this.sendEvent(
2526
TelemetryEvents.DatabaseImportFailed,
2627
{
27-
failed: importResult.errors.length,
28-
errors: importResult.errors.map((e) => (e?.constructor?.name || 'UncaughtError')),
28+
failed: importResult.fail.length,
29+
errors: DatabaseImportAnalytics.getUniqueErrorNamesFromResults(importResult.fail),
30+
},
31+
);
32+
}
33+
34+
if (importResult.partial?.length) {
35+
this.sendEvent(
36+
TelemetryEvents.DatabaseImportPartiallySucceeded,
37+
{
38+
partially: importResult.partial.length,
39+
errors: DatabaseImportAnalytics.getUniqueErrorNamesFromResults(importResult.partial),
2940
},
3041
);
3142
}
@@ -39,4 +50,16 @@ export class DatabaseImportAnalytics extends TelemetryBaseService {
3950
},
4051
);
4152
}
53+
54+
static getUniqueErrorNamesFromResults(results: DatabaseImportResult[]) {
55+
return uniq(
56+
[].concat(
57+
...results.map(
58+
(res) => (res?.errors || []).map(
59+
(error) => error?.constructor?.name || 'UncaughtError',
60+
),
61+
),
62+
),
63+
);
64+
}
4265
}

redisinsight/api/src/modules/database-import/database-import.controller.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {
2+
ClassSerializerInterceptor,
23
Controller, HttpCode, Post, UploadedFile,
3-
UseInterceptors, UsePipes, ValidationPipe,
4+
UseInterceptors, UsePipes, ValidationPipe
45
} from '@nestjs/common';
56
import {
67
ApiBody, ApiConsumes, ApiResponse, ApiTags,
@@ -10,6 +11,7 @@ import { FileInterceptor } from '@nestjs/platform-express';
1011
import { DatabaseImportResponse } from 'src/modules/database-import/dto/database-import.response';
1112

1213
@UsePipes(new ValidationPipe({ transform: true }))
14+
@UseInterceptors(ClassSerializerInterceptor)
1315
@ApiTags('Database')
1416
@Controller('/databases')
1517
export class DatabaseImportController {

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

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,7 @@ describe('DatabaseImportService', () => {
5959
it('should import databases from json', async () => {
6060
const response = await service.import(mockDatabaseImportFile);
6161

62-
expect(response).toEqual({
63-
...mockDatabaseImportResponse,
64-
errors: undefined, // errors omitted from response
65-
});
62+
expect(response).toEqual(mockDatabaseImportResponse);
6663
expect(analytics.sendImportResults).toHaveBeenCalledWith(mockDatabaseImportResponse);
6764
});
6865

@@ -75,7 +72,6 @@ describe('DatabaseImportService', () => {
7572

7673
expect(response).toEqual({
7774
...mockDatabaseImportResponse,
78-
errors: undefined, // errors omitted from response
7975
});
8076
expect(analytics.sendImportResults).toHaveBeenCalledWith(mockDatabaseImportResponse);
8177
});
@@ -138,7 +134,7 @@ describe('DatabaseImportService', () => {
138134
it('should create standalone database', async () => {
139135
await service['createDatabase']({
140136
...mockDatabase,
141-
});
137+
}, 0);
142138

143139
expect(databaseRepository.create).toHaveBeenCalledWith({
144140
...pick(mockDatabase, ['host', 'port', 'name', 'connectionType']),
@@ -149,7 +145,7 @@ describe('DatabaseImportService', () => {
149145
await service['createDatabase']({
150146
...mockDatabase,
151147
name: undefined,
152-
});
148+
}, 0);
153149

154150
expect(databaseRepository.create).toHaveBeenCalledWith({
155151
...pick(mockDatabase, ['host', 'port', 'name', 'connectionType']),
@@ -161,7 +157,7 @@ describe('DatabaseImportService', () => {
161157
await service['createDatabase']({
162158
...mockDatabase,
163159
cluster: true,
164-
});
160+
}, 0);
165161

166162
expect(databaseRepository.create).toHaveBeenCalledWith({
167163
...pick(mockDatabase, ['host', 'port', 'name']),

0 commit comments

Comments
 (0)