Skip to content

Commit 0fd1ce3

Browse files
author
arthosofteq
authored
Merge pull request #570 from RedisInsight/bugfix/RI-2735-file-name
fix few bugs + add edge case tests
2 parents 3307936 + bc0212f commit 0fd1ce3

File tree

7 files changed

+64
-34
lines changed

7 files changed

+64
-34
lines changed

redisinsight/api/src/modules/profiler/models/log-file.spec.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,15 @@ describe('LogFile', () => {
9797
expect(fs.existsSync(logFile['filePath'])).toEqual(false);
9898
const stream = logFile.getWriteStream();
9999
expect(stream['_writableState'].ended).toEqual(false);
100-
stream.write('somedata', () => {
101-
expect(fs.existsSync(logFile['filePath'])).toEqual(true);
100+
await new Promise((res, rej) => {
101+
stream.write('somedata', (err) => {
102+
if (err) {
103+
return rej(err);
104+
}
105+
106+
expect(fs.existsSync(logFile['filePath'])).toEqual(true);
107+
return res(true);
108+
});
102109
});
103110
expect(logFile['writeStream']).toEqual(stream);
104111
await logFile.destroy();

redisinsight/api/src/modules/profiler/models/redis.observer.spec.ts

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ describe('RedisObserver', () => {
4343
describe('init', () => {
4444
it('successfully init', async () => {
4545
await new Promise((resolve) => {
46+
redisObserver['connect'] = jest.fn();
4647
redisObserver.init(getRedisClientFn);
4748
expect(redisObserver['status']).toEqual(RedisObserverStatus.Initializing);
4849
redisObserver.on('connect', () => {
@@ -53,10 +54,14 @@ describe('RedisObserver', () => {
5354
expect(redisObserver['redis']).toEqual(nodeClient);
5455
});
5556
it('init error due to redis connection', async () => {
56-
getRedisClientFn.mockRejectedValueOnce(new Error('error'));
57-
await redisObserver.init(getRedisClientFn);
58-
expect(redisObserver['status']).toEqual(RedisObserverStatus.Error);
59-
expect(redisObserver['redis']).toEqual(undefined);
57+
try {
58+
getRedisClientFn.mockRejectedValueOnce(new Error('error'));
59+
await redisObserver.init(getRedisClientFn);
60+
fail();
61+
} catch (e) {
62+
expect(redisObserver['status']).toEqual(RedisObserverStatus.Error);
63+
expect(redisObserver['redis']).toEqual(undefined);
64+
}
6065
});
6166
});
6267

@@ -96,7 +101,7 @@ describe('RedisObserver', () => {
96101
await redisObserver.subscribe(mockProfilerClient);
97102
redisObserver['status'] = RedisObserverStatus.Ready;
98103
await redisObserver.subscribe(mockProfilerClient);
99-
expect(redisObserver['connect']).toHaveBeenCalledTimes(1);
104+
expect(redisObserver['connect']).toHaveBeenCalledTimes(2);
100105
expect(redisObserver['shardsObservers'].length).toEqual(2);
101106
expect(redisObserver['profilerClientsListeners'].size).toEqual(1);
102107
expect(redisObserver['profilerClientsListeners'].get(mockProfilerClient.id).length).toEqual(4);
@@ -194,10 +199,8 @@ describe('RedisObserver', () => {
194199

195200
it('connect fail due to NOPERM', async () => {
196201
try {
197-
await redisObserver.init(getRedisClientFn);
198202
nodeClient.send_command.mockRejectedValueOnce(NO_PERM_ERROR);
199-
const profilerClient = new ProfilerClient('1', mockSocket);
200-
await redisObserver.subscribe(profilerClient);
203+
await redisObserver.init(getRedisClientFn);
201204
fail();
202205
} catch (e) {
203206
expect(e).toBeInstanceOf(ForbiddenException);
@@ -208,10 +211,8 @@ describe('RedisObserver', () => {
208211

209212
it('connect fail due an error', async () => {
210213
try {
211-
await redisObserver.init(getRedisClientFn);
212214
nodeClient.send_command.mockRejectedValueOnce(new Error('some error'));
213-
const profilerClient = new ProfilerClient('1', mockSocket);
214-
await redisObserver.subscribe(profilerClient);
215+
await redisObserver.init(getRedisClientFn);
215216
fail();
216217
} catch (e) {
217218
expect(e).toBeInstanceOf(ServiceUnavailableException);
@@ -222,14 +223,10 @@ describe('RedisObserver', () => {
222223

223224
it('connect to cluster', async () => {
224225
getRedisClientFn.mockResolvedValue(clusterClient);
226+
clusterClient.nodes = jest.fn().mockReturnValue([mockClusterNode1, mockClusterNode2]);
225227
await redisObserver.init(getRedisClientFn);
226228

227229
redisObserver['redis'] = clusterClient;
228-
clusterClient.nodes = jest.fn().mockReturnValue([mockClusterNode1, mockClusterNode2]);
229-
230-
// RedisObserver.createShardObserver = jest.fn().mockResolvedValue(mockRedisShardObserver);
231-
const profilerClient = new ProfilerClient('1', mockSocket);
232-
await redisObserver.subscribe(profilerClient);
233230
expect(redisObserver['shardsObservers']).toEqual([mockRedisShardObserver, mockRedisShardObserver]);
234231
expect(redisObserver['status']).toEqual(RedisObserverStatus.Ready);
235232
});

redisinsight/api/src/modules/profiler/models/redis.observer.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,16 @@ export class RedisObserver extends EventEmitter2 {
3232
.then((redis) => {
3333
this.redis = redis;
3434
this.status = RedisObserverStatus.Connected;
35+
})
36+
.then(() => this.connect())
37+
.then(() => {
3538
this.emit('connect');
39+
return Promise.resolve();
3640
})
3741
.catch((err) => {
3842
this.status = RedisObserverStatus.Error;
3943
this.emit('connect_error', err);
44+
return Promise.reject(err);
4045
});
4146
}
4247

redisinsight/api/src/modules/profiler/profiler-analytics.service.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,27 +21,27 @@ export class ProfilerAnalyticsService extends TelemetryBaseService {
2121
this.events.set(TelemetryEvents.ProfilerLogDeleted, this.sendLogDeleted.bind(this));
2222
}
2323

24-
sendLogDeleted(databaseId: string, fileSize: number): void {
24+
sendLogDeleted(databaseId: string, fileSizeBytes: number): void {
2525
try {
2626
this.sendEvent(
2727
TelemetryEvents.ProfilerLogDeleted,
2828
{
2929
databaseId,
30-
fileSize,
30+
fileSizeBytes,
3131
},
3232
);
3333
} catch (e) {
3434
// continue regardless of error
3535
}
3636
}
3737

38-
sendLogDownloaded(databaseId: string, fileSize: number): void {
38+
sendLogDownloaded(databaseId: string, fileSizeBytes: number): void {
3939
try {
4040
this.sendEvent(
4141
TelemetryEvents.ProfilerLogDownloaded,
4242
{
4343
databaseId,
44-
fileSize,
44+
fileSizeBytes,
4545
},
4646
);
4747
} catch (e) {

redisinsight/api/src/modules/profiler/providers/redis-observer.provider.spec.ts

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Test, TestingModule } from '@nestjs/testing';
2-
import * as Redis from 'ioredis-mock';
2+
import * as Redis from 'ioredis';
33
import {
4-
mockLogFile,
4+
mockLogFile, mockRedisShardObserver,
55
MockType,
66
} from 'src/__mocks__';
77
import { InstancesBusinessService } from 'src/modules/shared/services/instances-business/instances-business.service';
@@ -10,7 +10,12 @@ import { RedisService } from 'src/modules/core/services/redis/redis.service';
1010
import { mockRedisClientInstance } from 'src/modules/shared/services/base/redis-consumer.abstract.service.spec';
1111
import { RedisObserverStatus } from 'src/modules/profiler/constants';
1212

13-
const mockRedisClient = new Redis();
13+
const nodeClient = Object.create(Redis.prototype);
14+
nodeClient.monitor = jest.fn();
15+
nodeClient.status = 'ready';
16+
nodeClient.disconnect = jest.fn();
17+
nodeClient.duplicate = jest.fn();
18+
nodeClient.send_command = jest.fn();
1419

1520
describe('RedisObserverProvider', () => {
1621
let service: RedisObserverProvider;
@@ -44,17 +49,20 @@ describe('RedisObserverProvider', () => {
4449
redisService = await module.get(RedisService);
4550
databaseService = await module.get(InstancesBusinessService);
4651

47-
redisService.getClientInstance.mockReturnValue(mockRedisClientInstance);
52+
redisService.getClientInstance.mockReturnValue({ ...mockRedisClientInstance, client: nodeClient });
4853
redisService.isClientConnected.mockReturnValue(true);
49-
databaseService.connectToInstance.mockResolvedValue(mockRedisClient);
54+
databaseService.connectToInstance.mockResolvedValue(nodeClient);
55+
nodeClient.send_command.mockResolvedValue('OK');
56+
nodeClient.duplicate.mockReturnValue(nodeClient);
57+
nodeClient.monitor.mockReturnValue(mockRedisShardObserver);
5058
});
5159

5260
it('getOrCreateObserver new observer get existing redis client', async () => {
5361
const redisObserver = await service.getOrCreateObserver(
5462
mockLogFile.instanceId,
5563
);
5664

57-
expect(redisObserver['redis']).toEqual(mockRedisClientInstance.client);
65+
expect(redisObserver['redis']).toEqual(nodeClient);
5866
expect(service['redisObservers'].size).toEqual(1);
5967

6068
expect(await service.getObserver(mockLogFile.instanceId)).toEqual(redisObserver);
@@ -77,9 +85,9 @@ describe('RedisObserverProvider', () => {
7785
mockLogFile.instanceId,
7886
);
7987

80-
redisObserver['init'] = jest.fn();
81-
expect(redisObserver['redis']).toEqual(mockRedisClientInstance.client);
82-
expect(redisObserver['status']).toEqual(RedisObserverStatus.Connected);
88+
redisObserver['init'] = jest.fn().mockResolvedValue(Promise.resolve());
89+
expect(redisObserver['redis']).toEqual(nodeClient);
90+
expect(redisObserver['status']).toEqual(RedisObserverStatus.Ready);
8391

8492
const promise = service.getOrCreateObserver(mockLogFile.instanceId);
8593
redisObserver.emit('connect');

redisinsight/api/src/modules/profiler/providers/redis-observer.provider.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ export class RedisObserverProvider {
3838
this.redisObservers.set(instanceId, redisObserver);
3939

4040
// initialize redis observer
41-
redisObserver.init(this.getRedisClientFn(instanceId));
41+
redisObserver.init(this.getRedisClientFn(instanceId)).catch();
4242
} else {
4343
switch (redisObserver.status) {
4444
case RedisObserverStatus.Ready:
@@ -49,7 +49,7 @@ export class RedisObserverProvider {
4949
case RedisObserverStatus.Error:
5050
this.logger.debug(`Trying to reconnect. Current status: ${redisObserver.status}`);
5151
// try to reconnect
52-
redisObserver.init(this.getRedisClientFn(instanceId));
52+
redisObserver.init(this.getRedisClientFn(instanceId)).catch();
5353
break;
5454
case RedisObserverStatus.Initializing:
5555
case RedisObserverStatus.Wait:

redisinsight/api/test/api/ws/monitor/monitor.test.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,25 @@ const { getSocket, constants, rte } = deps;
1313
const getMonitorClient = async (instanceId): Promise<Socket> => {
1414
return getSocket('monitor', {
1515
query: { instanceId },
16-
})
16+
});
1717
};
1818

1919
describe('monitor', function () {
2020
this.timeout(4000);
2121

22+
describe('Connection edge cases', () => {
23+
it('should not crash on 100 concurrent monitor connections to the same db', async () => {
24+
const client = await getMonitorClient(constants.TEST_INSTANCE_ID);
25+
await Promise.all((new Array(100).fill(1)).map(() => new Promise((res, rej) => {
26+
client.emit('monitor', { logFileId: constants.getRandomString() }, (ack) => {
27+
expect(ack).to.eql({ status: 'ok' });
28+
res(ack);
29+
});
30+
client.on('exception', rej);
31+
})));
32+
});
33+
});
34+
2235
describe('Client creation', () => {
2336
it('Should successfully create a client', async () => {
2437
const client = await getMonitorClient(constants.TEST_INSTANCE_ID);

0 commit comments

Comments
 (0)