From 7f7a51d19b9908de7c3b5ed7ddb25634a2c116c1 Mon Sep 17 00:00:00 2001 From: Romain Thouvenin Date: Thu, 28 Mar 2024 11:26:26 +0100 Subject: [PATCH] Let Nest exception filter handle unexpected exceptions --- .../grpc-controllers/match.grpc-controller.ts | 52 ++-- .../interface/match.grpc.controller.spec.ts | 259 ++++++++---------- 2 files changed, 142 insertions(+), 169 deletions(-) diff --git a/src/modules/ad/interface/grpc-controllers/match.grpc-controller.ts b/src/modules/ad/interface/grpc-controllers/match.grpc-controller.ts index 30acfda..35dd9bf 100644 --- a/src/modules/ad/interface/grpc-controllers/match.grpc-controller.ts +++ b/src/modules/ad/interface/grpc-controllers/match.grpc-controller.ts @@ -1,17 +1,16 @@ -import { Controller, Inject, UseInterceptors, UsePipes } from '@nestjs/common'; -import { GrpcMethod, RpcException } from '@nestjs/microservices'; import { RpcValidationPipe } from '@mobicoop/ddd-library'; -import { RpcExceptionCode } from '@mobicoop/ddd-library'; -import { MatchingPaginatedResponseDto } from '../dtos/matching.paginated.response.dto'; -import { QueryBus } from '@nestjs/cqrs'; -import { MatchRequestDto } from './dtos/match.request.dto'; -import { MatchQuery } from '@modules/ad/core/application/queries/match/match.query'; -import { MatchEntity } from '@modules/ad/core/domain/match.entity'; import { AD_ROUTE_PROVIDER } from '@modules/ad/ad.di-tokens'; -import { MatchMapper } from '@modules/ad/match.mapper'; -import { MatchingResult } from '@modules/ad/core/application/queries/match/match.query-handler'; -import { CacheInterceptor, CacheKey } from '@nestjs/cache-manager'; import { GeorouterPort } from '@modules/ad/core/application/ports/georouter.port'; +import { MatchQuery } from '@modules/ad/core/application/queries/match/match.query'; +import { MatchingResult } from '@modules/ad/core/application/queries/match/match.query-handler'; +import { MatchEntity } from '@modules/ad/core/domain/match.entity'; +import { MatchMapper } from '@modules/ad/match.mapper'; +import { CacheInterceptor, CacheKey } from '@nestjs/cache-manager'; +import { Controller, Inject, UseInterceptors, UsePipes } from '@nestjs/common'; +import { QueryBus } from '@nestjs/cqrs'; +import { GrpcMethod } from '@nestjs/microservices'; +import { MatchingPaginatedResponseDto } from '../dtos/matching.paginated.response.dto'; +import { MatchRequestDto } from './dtos/match.request.dto'; @UsePipes( new RpcValidationPipe({ @@ -32,24 +31,17 @@ export class MatchGrpcController { @UseInterceptors(CacheInterceptor) @GrpcMethod('MatcherService', 'Match') async match(data: MatchRequestDto): Promise { - try { - const matchingResult: MatchingResult = await this.queryBus.execute( - new MatchQuery(data, this.routeProvider), - ); - return new MatchingPaginatedResponseDto({ - id: matchingResult.id, - data: matchingResult.matches.map((match: MatchEntity) => - this.matchMapper.toResponse(match), - ), - page: matchingResult.page, - perPage: matchingResult.perPage, - total: matchingResult.total, - }); - } catch (e) { - throw new RpcException({ - code: RpcExceptionCode.UNKNOWN, - message: e.message, - }); - } + const matchingResult: MatchingResult = await this.queryBus.execute( + new MatchQuery(data, this.routeProvider), + ); + return new MatchingPaginatedResponseDto({ + id: matchingResult.id, + data: matchingResult.matches.map((match: MatchEntity) => + this.matchMapper.toResponse(match), + ), + page: matchingResult.page, + perPage: matchingResult.perPage, + total: matchingResult.total, + }); } } diff --git a/src/modules/ad/tests/unit/interface/match.grpc.controller.spec.ts b/src/modules/ad/tests/unit/interface/match.grpc.controller.spec.ts index ecdd72c..f6002ee 100644 --- a/src/modules/ad/tests/unit/interface/match.grpc.controller.spec.ts +++ b/src/modules/ad/tests/unit/interface/match.grpc.controller.spec.ts @@ -1,4 +1,3 @@ -import { RpcExceptionCode } from '@mobicoop/ddd-library'; import { AD_ROUTE_PROVIDER } from '@modules/ad/ad.di-tokens'; import { MatchingResult } from '@modules/ad/core/application/queries/match/match.query-handler'; import { AlgorithmType } from '@modules/ad/core/application/types/algorithm.types'; @@ -14,7 +13,6 @@ import { MatchGrpcController } from '@modules/ad/interface/grpc-controllers/matc import { MatchMapper } from '@modules/ad/match.mapper'; import { CACHE_MANAGER } from '@nestjs/cache-manager'; import { QueryBus } from '@nestjs/cqrs'; -import { RpcException } from '@nestjs/microservices'; import { Test, TestingModule } from '@nestjs/testing'; import { bareMockGeorouter } from '../georouter.mock'; @@ -56,131 +54,126 @@ const recurrentMatchRequestDto: MatchRequestDto = { }; const mockQueryBus = { - execute: jest - .fn() - .mockImplementationOnce( - () => - { - id: '43c83ae2-f4b0-4ac6-b8bf-8071801924d4', - page: 1, - perPage: 10, - matches: [ - MatchEntity.create({ - adId: '53a0bf71-4132-4f7b-a4cc-88c796b6bdf1', - role: Role.DRIVER, - frequency: Frequency.RECURRENT, - distance: 356041, - duration: 12647, - initialDistance: 349251, - initialDuration: 12103, - journeys: [ - { - firstDate: new Date('2023-09-01'), - lastDate: new Date('2024-08-30'), - journeyItems: [ - new JourneyItem({ - lat: 48.689445, - lon: 6.17651, - duration: 0, - distance: 0, - actorTimes: [ - new ActorTime({ - role: Role.DRIVER, - target: Target.START, - firstDatetime: new Date('2023-09-01 07:00'), - firstMinDatetime: new Date('2023-09-01 06:45'), - firstMaxDatetime: new Date('2023-09-01 07:15'), - lastDatetime: new Date('2024-08-30 07:00'), - lastMinDatetime: new Date('2024-08-30 06:45'), - lastMaxDatetime: new Date('2024-08-30 07:15'), - }), - ], - }), - new JourneyItem({ - lat: 48.369445, - lon: 6.67487, - duration: 2100, - distance: 56878, - actorTimes: [ - new ActorTime({ - role: Role.DRIVER, - target: Target.NEUTRAL, - firstDatetime: new Date('2023-09-01 07:35'), - firstMinDatetime: new Date('2023-09-01 07:20'), - firstMaxDatetime: new Date('2023-09-01 07:50'), - lastDatetime: new Date('2024-08-30 07:35'), - lastMinDatetime: new Date('2024-08-30 07:20'), - lastMaxDatetime: new Date('2024-08-30 07:50'), - }), - new ActorTime({ - role: Role.PASSENGER, - target: Target.START, - firstDatetime: new Date('2023-09-01 07:32'), - firstMinDatetime: new Date('2023-09-01 07:17'), - firstMaxDatetime: new Date('2023-09-01 07:47'), - lastDatetime: new Date('2024-08-30 07:32'), - lastMinDatetime: new Date('2024-08-30 07:17'), - lastMaxDatetime: new Date('2024-08-30 07:47'), - }), - ], - }), - new JourneyItem({ - lat: 47.98487, - lon: 6.9427, - duration: 3840, - distance: 76491, - actorTimes: [ - new ActorTime({ - role: Role.DRIVER, - target: Target.NEUTRAL, - firstDatetime: new Date('2023-09-01 08:04'), - firstMinDatetime: new Date('2023-09-01 07:51'), - firstMaxDatetime: new Date('2023-09-01 08:19'), - lastDatetime: new Date('2024-08-30 08:04'), - lastMinDatetime: new Date('2024-08-30 07:51'), - lastMaxDatetime: new Date('2024-08-30 08:19'), - }), - new ActorTime({ - role: Role.PASSENGER, - target: Target.FINISH, - firstDatetime: new Date('2023-09-01 08:01'), - firstMinDatetime: new Date('2023-09-01 07:46'), - firstMaxDatetime: new Date('2023-09-01 08:16'), - lastDatetime: new Date('2024-08-30 08:01'), - lastMinDatetime: new Date('2024-08-30 07:46'), - lastMaxDatetime: new Date('2024-08-30 08:16'), - }), - ], - }), - new JourneyItem({ - lat: 47.365987, - lon: 7.02154, - duration: 4980, - distance: 96475, - actorTimes: [ - new ActorTime({ - role: Role.DRIVER, - target: Target.FINISH, - firstDatetime: new Date('2023-09-01 08:23'), - firstMinDatetime: new Date('2023-09-01 08:08'), - firstMaxDatetime: new Date('2023-09-01 08:38'), - lastDatetime: new Date('2024-08-30 08:23'), - lastMinDatetime: new Date('2024-08-30 08:08'), - lastMaxDatetime: new Date('2024-08-30 08:38'), - }), - ], - }), - ], - }, - ], - }), - ], - total: 1, - }, - ) - .mockImplementationOnce(() => { - throw new Error(); - }), + execute: jest.fn().mockImplementationOnce( + () => + { + id: '43c83ae2-f4b0-4ac6-b8bf-8071801924d4', + page: 1, + perPage: 10, + matches: [ + MatchEntity.create({ + adId: '53a0bf71-4132-4f7b-a4cc-88c796b6bdf1', + role: Role.DRIVER, + frequency: Frequency.RECURRENT, + distance: 356041, + duration: 12647, + initialDistance: 349251, + initialDuration: 12103, + journeys: [ + { + firstDate: new Date('2023-09-01'), + lastDate: new Date('2024-08-30'), + journeyItems: [ + new JourneyItem({ + lat: 48.689445, + lon: 6.17651, + duration: 0, + distance: 0, + actorTimes: [ + new ActorTime({ + role: Role.DRIVER, + target: Target.START, + firstDatetime: new Date('2023-09-01 07:00'), + firstMinDatetime: new Date('2023-09-01 06:45'), + firstMaxDatetime: new Date('2023-09-01 07:15'), + lastDatetime: new Date('2024-08-30 07:00'), + lastMinDatetime: new Date('2024-08-30 06:45'), + lastMaxDatetime: new Date('2024-08-30 07:15'), + }), + ], + }), + new JourneyItem({ + lat: 48.369445, + lon: 6.67487, + duration: 2100, + distance: 56878, + actorTimes: [ + new ActorTime({ + role: Role.DRIVER, + target: Target.NEUTRAL, + firstDatetime: new Date('2023-09-01 07:35'), + firstMinDatetime: new Date('2023-09-01 07:20'), + firstMaxDatetime: new Date('2023-09-01 07:50'), + lastDatetime: new Date('2024-08-30 07:35'), + lastMinDatetime: new Date('2024-08-30 07:20'), + lastMaxDatetime: new Date('2024-08-30 07:50'), + }), + new ActorTime({ + role: Role.PASSENGER, + target: Target.START, + firstDatetime: new Date('2023-09-01 07:32'), + firstMinDatetime: new Date('2023-09-01 07:17'), + firstMaxDatetime: new Date('2023-09-01 07:47'), + lastDatetime: new Date('2024-08-30 07:32'), + lastMinDatetime: new Date('2024-08-30 07:17'), + lastMaxDatetime: new Date('2024-08-30 07:47'), + }), + ], + }), + new JourneyItem({ + lat: 47.98487, + lon: 6.9427, + duration: 3840, + distance: 76491, + actorTimes: [ + new ActorTime({ + role: Role.DRIVER, + target: Target.NEUTRAL, + firstDatetime: new Date('2023-09-01 08:04'), + firstMinDatetime: new Date('2023-09-01 07:51'), + firstMaxDatetime: new Date('2023-09-01 08:19'), + lastDatetime: new Date('2024-08-30 08:04'), + lastMinDatetime: new Date('2024-08-30 07:51'), + lastMaxDatetime: new Date('2024-08-30 08:19'), + }), + new ActorTime({ + role: Role.PASSENGER, + target: Target.FINISH, + firstDatetime: new Date('2023-09-01 08:01'), + firstMinDatetime: new Date('2023-09-01 07:46'), + firstMaxDatetime: new Date('2023-09-01 08:16'), + lastDatetime: new Date('2024-08-30 08:01'), + lastMinDatetime: new Date('2024-08-30 07:46'), + lastMaxDatetime: new Date('2024-08-30 08:16'), + }), + ], + }), + new JourneyItem({ + lat: 47.365987, + lon: 7.02154, + duration: 4980, + distance: 96475, + actorTimes: [ + new ActorTime({ + role: Role.DRIVER, + target: Target.FINISH, + firstDatetime: new Date('2023-09-01 08:23'), + firstMinDatetime: new Date('2023-09-01 08:08'), + firstMaxDatetime: new Date('2023-09-01 08:38'), + lastDatetime: new Date('2024-08-30 08:23'), + lastMinDatetime: new Date('2024-08-30 08:08'), + lastMaxDatetime: new Date('2024-08-30 08:38'), + }), + ], + }), + ], + }, + ], + }), + ], + total: 1, + }, + ), }; const mockMatchMapper = { @@ -317,16 +310,4 @@ describe('Match Grpc Controller', () => { expect(matchingPaginatedResponseDto.perPage).toBe(10); expect(mockQueryBus.execute).toHaveBeenCalledTimes(1); }); - - it('should throw a generic RpcException', async () => { - jest.spyOn(mockQueryBus, 'execute'); - expect.assertions(3); - try { - await matchGrpcController.match(recurrentMatchRequestDto); - } catch (e: any) { - expect(e).toBeInstanceOf(RpcException); - expect(e.error.code).toBe(RpcExceptionCode.UNKNOWN); - } - expect(mockQueryBus.execute).toHaveBeenCalledTimes(1); - }); });