Skip to content

Commit

Permalink
Merge pull request #226 from samagra-comms/develop
Browse files Browse the repository at this point in the history
Develop merge
  • Loading branch information
chinmoy12c authored Sep 15, 2023
2 parents 5c577eb + a490eaf commit 11b78c1
Show file tree
Hide file tree
Showing 7 changed files with 377 additions and 22 deletions.
Empty file removed .node-xmlhttprequest-sync-3980100
Empty file.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
"reflect-metadata": "^0.1.13",
"rimraf": "^3.0.2",
"rxjs": "^7.2.0",
"socket.io-client": "^4.7.2",
"swagger-ui-express": "^4.3.0",
"undici": "^5.0.0",
"uuid": "^8.3.2",
Expand Down
102 changes: 102 additions & 0 deletions src/health/health.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
} from '@nestjs/terminus';
import { PrismaService } from '../global-services/prisma.service';
import { FormService } from '../modules/form/form.service';
import { io } from 'socket.io-client';

@Injectable()
export class HealthService extends HealthIndicator{
Expand All @@ -28,6 +29,7 @@ export class HealthService extends HealthIndicator{
() => this.checkUciCoreHealth(),
() => this.checkDatabaseHealth(),
() => this.checkFormServiceHealth(),
() => this.checkTransportSocketHealth(),
]);
}

Expand All @@ -53,4 +55,104 @@ export class HealthService extends HealthIndicator{
throw new HealthCheckError("FormService failed to connect!", this.getStatus('FormService', false, {message: e.message}));
});
}

async checkTransportSocketHealth(): Promise<any> {
const baseUrl = this.configService.get('SOCKET_URL');
const connOptions = {
transportOptions: {
polling: {
extraHeaders: {
Authorization: `Bearer ${this.configService.get(
'SOCKET_AUTH_TOKEN',
)}`,
channel: this.configService.get('SOCKET_CONNECTION_CHANNEL'),
},
},
},
query: {
deviceId: this.configService.get('SOCKET_TO'),
},
autoConnect: false,
};

const payload: any = {
content: {
text: '*',
appId: this.configService.get('SOCKET_APP_ID'),
channel: this.configService.get('SOCKET_CHANNEL'),
context: null,
accessToken: null,
},
to: this.configService.get('SOCKET_TO'),
};
try {
const socket = await this.connectSocket(baseUrl, connOptions);
if (!socket) {
return new HealthCheckError(
'Socket connection timed out',
this.getStatus('TransportSocketService', false, {
message: 'Socket connection timed out',
}),
);
}

const responseReceived = await this.sendBotRequest(socket, payload);

if (responseReceived) {
socket.disconnect();
return this.getStatus('TransportSocketService', true);
} else {
return new HealthCheckError(
'Bot response timed out',
this.getStatus('TransportSocketService', false, {
message: 'Bot response timed out',
}),
);
}
} catch (error) {
return new HealthCheckError(
'An error occurred',
this.getStatus('TransportSocketService', false, {
message: 'An error occurred',
}),
);
}
}

private async connectSocket(baseUrl: string, connOptions: any): Promise<any> {
return new Promise(async (resolve) => {
const socket = await io(baseUrl, connOptions);

socket.connect();
socket.on('connect', function () {
resolve(socket);
});
socket.on('connect_error', () => {
resolve(false);
});
setTimeout(async () => {
resolve(false);
}, this.configService.get('SOCKET_TIMEOUT_TIME') || 20000);
});
}

private async sendBotRequest(socket: any, payload: any): Promise<boolean> {
const newPayload = { ...payload };
return new Promise(async (resolve) => {
socket.on('session', async (session) => {
const socketID = session.socketID;
const userID = session.userID;
newPayload.content.from = socketID;
newPayload.content.userId = userID;
socket.emit('botRequest', newPayload);
});

socket.on('botResponse', (data) => {
resolve(true);
});
setTimeout(() => {
resolve(false);
}, this.configService.get('SOCKET_TIMEOUT_TIME') || 20000); // Wait for 20 seconds for bot response
});
}
}
18 changes: 15 additions & 3 deletions src/modules/bot/bot.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import { diskStorage } from 'multer';
import { Request } from 'express';
import { extname } from 'path';
import fs from 'fs';
import { DeleteBotsDTO } from './dto/delete-bot-dto';


const editFileName = (req: Request, file: Express.Multer.File, callback) => {
Expand Down Expand Up @@ -335,15 +336,26 @@ export class BotController {
return this.botService.update(id, updateBotDto);
}

@Delete(':id')
@Delete()
@UseInterceptors(
AddResponseObjectInterceptor,
AddAdminHeaderInterceptor,
AddOwnerInfoInterceptor,
AddROToResponseInterceptor,
)
remove(@Param('id') id: string) {
return this.botService.remove(id);
async remove(@Body() body: DeleteBotsDTO) {
return await this.botService.remove(body);
}

@Delete(':botId')
@UseInterceptors(
AddResponseObjectInterceptor,
AddAdminHeaderInterceptor,
AddOwnerInfoInterceptor,
AddROToResponseInterceptor,
)
async removeOne(@Param('botId') botId: string) {
return await this.botService.removeOne(botId);
}

@Get(':botId/broadcastReport')
Expand Down
136 changes: 133 additions & 3 deletions src/modules/bot/bot.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,31 @@ const MockPrismaService = {
}
},
count: () => 10,
update: jest.fn()
}
update: jest.fn(),
deleteMany: (filter) => {
deletedIds.push({'bot': filter.where.id.in});
}
},
service: {
deleteMany: (filter) => {
deletedIds.push({'service': filter.where.id.in});
}
},
userSegment: {
deleteMany: (filter) => {
deletedIds.push({'userSegment': filter.where.id.in});
}
},
transformerConfig: {
deleteMany: (filter) => {
deletedIds.push({'transformerConfig': filter.where.id.in});
}
},
conversationLogic: {
deleteMany: (filter) => {
deletedIds.push({'conversationLogic': filter.where.id.in});
}
},
}

class MockConfigService {
Expand Down Expand Up @@ -320,6 +343,9 @@ const mockConfig = {
"totalRecords": 1
};

// Used for delete bot testing
let deletedIds: any[] = []

describe('BotService', () => {
let botService: BotService;
let configService: ConfigService;
Expand Down Expand Up @@ -367,6 +393,17 @@ describe('BotService', () => {
.toThrowError(new ConflictException("Bot already exists with the following name or starting message!"));
});

it('create bot trims bot name properly', async () => {
const mockCreateBotDtoCopy: CreateBotDto & { ownerID: string; ownerOrgID: string } = JSON.parse(JSON.stringify(mockCreateBotDto));
mockCreateBotDtoCopy.name = ' testBotExistingName ';
expect(botService.create(mockCreateBotDtoCopy, mockFile)).rejects
.toThrowError(new ConflictException("Bot already exists with the following name or starting message!"));
const mockCreateBotDtoCopy2: CreateBotDto & { ownerID: string; ownerOrgID: string } = JSON.parse(JSON.stringify(mockCreateBotDto));
mockCreateBotDtoCopy2.startingMessage = ' testBotExistingStartingMessage';
expect(botService.create(mockCreateBotDtoCopy2, mockFile)).rejects
.toThrowError(new ConflictException("Bot already exists with the following name or starting message!"));
});

it('get bot all data test', async () => {
fetchMock.getOnce(`${configService.get<string>('MINIO_GET_SIGNED_FILE_URL')}?fileName=testImageFile`,
'testImageUrl'
Expand Down Expand Up @@ -506,7 +543,7 @@ describe('BotService', () => {
});

it('bot update throws NotFoundException when non existent bot is updated',async () => {
fetchMock.getOnce(`${configService.get<string>('UCI_CORE_BASE_URL')}${configService.get<string>('CAFFINE_INVALIDATE_ENDPOINT')}`,
fetchMock.deleteOnce(`${configService.get<string>('UCI_CORE_BASE_URL')}${configService.get<string>('CAFFINE_INVALIDATE_ENDPOINT')}`,
true
);
expect(botService.update('testBotIdNotExisting', {
Expand Down Expand Up @@ -605,4 +642,97 @@ describe('BotService', () => {
).toBe(true);
fetchMock.restore();
});

it('bot delete with bot id list works as expected', async () => {
fetchMock.delete(`${configService.get<string>('UCI_CORE_BASE_URL')}${configService.get<string>('CAFFINE_INVALIDATE_ENDPOINT')}`,
true
);
mockBotsDb[0].status = BotStatus.DISABLED;
await botService.remove({ids: ['testId'], endDate: null});
expect(deletedIds).toEqual(
[
{'service': ['testId']},
{'userSegment': ['testUserId']},
{'transformerConfig': ['testTransformerId']},
{'conversationLogic': ['testLogicId']},
{'bot': ['testId']},
]
);
deletedIds = [];
await botService.remove({ids: ['nonExisting'], endDate: null});
expect(deletedIds).toEqual(
[
{'service': []},
{'userSegment': []},
{'transformerConfig': []},
{'conversationLogic': []},
{'bot': []},
]
);
deletedIds = [];
expect(fetchMock.called(
`${configService.get<string>('UCI_CORE_BASE_URL')}${configService.get<string>('CAFFINE_INVALIDATE_ENDPOINT')}`
))
.toBe(true);
mockBotsDb[0].status = BotStatus.ENABLED;
fetchMock.restore();
});

it('bot delete with endDate works as expected', async () => {
fetchMock.delete(`${configService.get<string>('UCI_CORE_BASE_URL')}${configService.get<string>('CAFFINE_INVALIDATE_ENDPOINT')}`,
true
);
mockBotsDb[0].status = BotStatus.DISABLED;
await botService.remove({ids: null, endDate: '2025-12-01'});
expect(deletedIds).toEqual(
[
{'service': ['testId']},
{'userSegment': ['testUserId']},
{'transformerConfig': ['testTransformerId']},
{'conversationLogic': ['testLogicId']},
{'bot': ['testId']},
]
);
deletedIds = [];
await botService.remove({ids: null, endDate: '2023-12-01'});
expect(deletedIds).toEqual(
[
{'service': []},
{'userSegment': []},
{'transformerConfig': []},
{'conversationLogic': []},
{'bot': []},
]
);
expect(fetchMock.called(
`${configService.get<string>('UCI_CORE_BASE_URL')}${configService.get<string>('CAFFINE_INVALIDATE_ENDPOINT')}`
))
.toBe(true);
deletedIds = [];
mockBotsDb[0].status = BotStatus.ENABLED;
fetchMock.restore();
});

it('bot delete only deletes disabled bots', async () => {
fetchMock.delete(`${configService.get<string>('UCI_CORE_BASE_URL')}${configService.get<string>('CAFFINE_INVALIDATE_ENDPOINT')}`,
true
);
mockBotsDb[0].status = BotStatus.ENABLED;
await botService.remove({ids: ['testId'], endDate: null});
expect(deletedIds).toEqual(
[
{'service': []},
{'userSegment': []},
{'transformerConfig': []},
{'conversationLogic': []},
{'bot': []},
]
);
expect(fetchMock.called(
`${configService.get<string>('UCI_CORE_BASE_URL')}${configService.get<string>('CAFFINE_INVALIDATE_ENDPOINT')}`
))
.toBe(true);
deletedIds = [];
fetchMock.restore();
});
});
Loading

0 comments on commit 11b78c1

Please sign in to comment.