mirror of
https://gitlab.com/mobicoop/v3/service/ad.git
synced 2026-01-05 13:12:41 +00:00
removed oxide dependecy, added create ad grpc controller test
This commit is contained in:
19
src/libs/exceptions/rpc-exception.codes.enum.ts
Normal file
19
src/libs/exceptions/rpc-exception.codes.enum.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
export enum RpcExceptionCode {
|
||||
OK = 0,
|
||||
CANCELLED = 1,
|
||||
UNKNOWN = 2,
|
||||
INVALID_ARGUMENT = 3,
|
||||
DEADLINE_EXCEEDED = 4,
|
||||
NOT_FOUND = 5,
|
||||
ALREADY_EXISTS = 6,
|
||||
PERMISSION_DENIED = 7,
|
||||
RESOURCE_EXHAUSTED = 8,
|
||||
FAILED_PRECONDITION = 9,
|
||||
ABORTED = 10,
|
||||
OUT_OF_RANGE = 11,
|
||||
UNIMPLEMENTED = 12,
|
||||
INTERNAL = 13,
|
||||
UNAVAILABLE = 14,
|
||||
DATA_LOSS = 15,
|
||||
UNAUTHENTICATED = 16,
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
import { ExceptionBase } from '@libs/exceptions';
|
||||
|
||||
export class AdAlreadyExistsError extends ExceptionBase {
|
||||
export class AdAlreadyExistsException extends ExceptionBase {
|
||||
static readonly message = 'Ad already exists';
|
||||
|
||||
public readonly code = 'AD.ALREADY_EXISTS';
|
||||
|
||||
constructor(cause?: Error, metadata?: unknown) {
|
||||
super(AdAlreadyExistsError.message, cause, metadata);
|
||||
super(AdAlreadyExistsException.message, cause, metadata);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,9 +5,8 @@ import { Inject } from '@nestjs/common';
|
||||
import { AD_REPOSITORY, PARAMS_PROVIDER } from '@modules/ad/ad.di-tokens';
|
||||
import { AdRepositoryPort } from '@modules/ad/core/ports/ad.repository.port';
|
||||
import { DefaultParamsProviderPort } from '@modules/ad/core/ports/default-params-provider.port';
|
||||
import { Err, Ok, Result } from 'oxide.ts';
|
||||
import { AggregateID } from '@libs/ddd';
|
||||
import { AdAlreadyExistsError } from '@modules/ad/core/ad.errors';
|
||||
import { AdAlreadyExistsException } from '@modules/ad/core/ad.errors';
|
||||
import { AdEntity } from '@modules/ad/core/ad.entity';
|
||||
import { ConflictException } from '@libs/exceptions';
|
||||
import { Waypoint } from '../../types/waypoint';
|
||||
@@ -25,9 +24,7 @@ export class CreateAdService implements ICommandHandler {
|
||||
this.defaultParams = defaultParamsProvider.getParams();
|
||||
}
|
||||
|
||||
async execute(
|
||||
command: CreateAdCommand,
|
||||
): Promise<Result<AggregateID, AdAlreadyExistsError>> {
|
||||
async execute(command: CreateAdCommand): Promise<AggregateID> {
|
||||
const ad = AdEntity.create(
|
||||
{
|
||||
userId: command.userId,
|
||||
@@ -77,10 +74,10 @@ export class CreateAdService implements ICommandHandler {
|
||||
|
||||
try {
|
||||
await this.repository.insert(ad);
|
||||
return Ok(ad.id);
|
||||
return ad.id;
|
||||
} catch (error: any) {
|
||||
if (error instanceof ConflictException) {
|
||||
return Err(new AdAlreadyExistsError(error));
|
||||
throw new AdAlreadyExistsException(error);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
|
||||
@@ -4,10 +4,10 @@ import { GrpcMethod, RpcException } from '@nestjs/microservices';
|
||||
import { RpcValidationPipe } from '../../../../utils/pipes/rpc.validation-pipe';
|
||||
import { CreateAdRequestDto } from './dtos/create-ad.request.dto';
|
||||
import { CreateAdCommand } from '../../core/commands/create-ad/create-ad.command';
|
||||
import { Result, match } from 'oxide.ts';
|
||||
import { AggregateID } from '@libs/ddd';
|
||||
import { AdAlreadyExistsError } from '../../core/ad.errors';
|
||||
import { AdAlreadyExistsException } from '../../core/ad.errors';
|
||||
import { IdResponse } from '@libs/api/id.response.dto';
|
||||
import { RpcExceptionCode } from '@libs/exceptions/rpc-exception.codes.enum';
|
||||
|
||||
@UsePipes(
|
||||
new RpcValidationPipe({
|
||||
@@ -21,22 +21,18 @@ export class CreateAdGrpcController {
|
||||
|
||||
@GrpcMethod('AdsService', 'Create')
|
||||
async create(data: CreateAdRequestDto): Promise<IdResponse> {
|
||||
const result: Result<AggregateID, AdAlreadyExistsError> =
|
||||
await this.commandBus.execute(new CreateAdCommand(data));
|
||||
|
||||
// Deciding what to do with a Result (similar to Rust matching)
|
||||
// if Ok we return a response with an id
|
||||
// if Error decide what to do with it depending on its type
|
||||
return match(result, {
|
||||
Ok: (id: string) => new IdResponse(id),
|
||||
Err: (error: Error) => {
|
||||
if (error instanceof AdAlreadyExistsError)
|
||||
throw new RpcException({
|
||||
code: 6,
|
||||
message: 'Ad already exists',
|
||||
});
|
||||
throw new RpcException({});
|
||||
},
|
||||
});
|
||||
try {
|
||||
const aggregateID: AggregateID = await this.commandBus.execute(
|
||||
new CreateAdCommand(data),
|
||||
);
|
||||
return new IdResponse(aggregateID);
|
||||
} catch (error: any) {
|
||||
if (error instanceof AdAlreadyExistsException)
|
||||
throw new RpcException({
|
||||
code: RpcExceptionCode.ALREADY_EXISTS,
|
||||
message: error.message,
|
||||
});
|
||||
throw new RpcException({});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,9 +6,8 @@ import { WaypointDto } from '@modules/ad/interface/grpc-controllers/dtos/waypoin
|
||||
import { CreateAdRequestDto } from '@modules/ad/interface/grpc-controllers/dtos/create-ad.request.dto';
|
||||
import { Frequency } from '@modules/ad/core/ad.types';
|
||||
import { CreateAdCommand } from '@modules/ad/core/commands/create-ad/create-ad.command';
|
||||
import { Result } from 'oxide.ts';
|
||||
import { AggregateID } from '@libs/ddd';
|
||||
import { AdAlreadyExistsError } from '@modules/ad/core/ad.errors';
|
||||
import { AdAlreadyExistsException } from '@modules/ad/core/ad.errors';
|
||||
import { AdEntity } from '@modules/ad/core/ad.entity';
|
||||
import { ConflictException } from '@libs/exceptions';
|
||||
|
||||
@@ -107,9 +106,10 @@ describe('create-ad.service', () => {
|
||||
AdEntity.create = jest.fn().mockReturnValue({
|
||||
id: '047a6ecf-23d4-4d3e-877c-3225d560a8da',
|
||||
});
|
||||
const result: Result<AggregateID, AdAlreadyExistsError> =
|
||||
await createAdService.execute(createAdCommand);
|
||||
expect(result.unwrap()).toBe('047a6ecf-23d4-4d3e-877c-3225d560a8da');
|
||||
const result: AggregateID = await createAdService.execute(
|
||||
createAdCommand,
|
||||
);
|
||||
expect(result).toBe('047a6ecf-23d4-4d3e-877c-3225d560a8da');
|
||||
});
|
||||
it('should throw an error if something bad happens', async () => {
|
||||
AdEntity.create = jest.fn().mockReturnValue({
|
||||
@@ -119,13 +119,13 @@ describe('create-ad.service', () => {
|
||||
createAdService.execute(createAdCommand),
|
||||
).rejects.toBeInstanceOf(Error);
|
||||
});
|
||||
it('should return an Err if Ad already exists', async () => {
|
||||
it('should throw an exception if Ad already exists', async () => {
|
||||
AdEntity.create = jest.fn().mockReturnValue({
|
||||
id: '047a6ecf-23d4-4d3e-877c-3225d560a8da',
|
||||
});
|
||||
const result: Result<AggregateID, AdAlreadyExistsError> =
|
||||
await createAdService.execute(createAdCommand);
|
||||
expect(result.isErr()).toBeTruthy();
|
||||
await expect(
|
||||
createAdService.execute(createAdCommand),
|
||||
).rejects.toBeInstanceOf(AdAlreadyExistsException);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
import { IdResponse } from '@libs/api/id.response.dto';
|
||||
import { RpcExceptionCode } from '@libs/exceptions/rpc-exception.codes.enum';
|
||||
import { AdAlreadyExistsException } from '@modules/ad/core/ad.errors';
|
||||
import { Frequency } from '@modules/ad/core/ad.types';
|
||||
import { CreateAdGrpcController } from '@modules/ad/interface/grpc-controllers/create-ad.grpc.controller';
|
||||
import { CreateAdRequestDto } from '@modules/ad/interface/grpc-controllers/dtos/create-ad.request.dto';
|
||||
import { WaypointDto } from '@modules/ad/interface/grpc-controllers/dtos/waypoint.dto';
|
||||
import { CommandBus } from '@nestjs/cqrs';
|
||||
import { RpcException } from '@nestjs/microservices';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
|
||||
const originWaypoint: WaypointDto = {
|
||||
position: 0,
|
||||
lon: 48.689445,
|
||||
lat: 6.17651,
|
||||
houseNumber: '5',
|
||||
street: 'Avenue Foch',
|
||||
locality: 'Nancy',
|
||||
postalCode: '54000',
|
||||
country: 'France',
|
||||
};
|
||||
const destinationWaypoint: WaypointDto = {
|
||||
position: 1,
|
||||
lon: 48.8566,
|
||||
lat: 2.3522,
|
||||
locality: 'Paris',
|
||||
postalCode: '75000',
|
||||
country: 'France',
|
||||
};
|
||||
const punctualCreateAdRequest: CreateAdRequestDto = {
|
||||
userId: '4eb6a6af-ecfd-41c3-9118-473a507014d4',
|
||||
fromDate: '2023-12-21',
|
||||
toDate: '2023-12-21',
|
||||
schedule: {
|
||||
thu: '08:15',
|
||||
},
|
||||
driver: false,
|
||||
passenger: true,
|
||||
seatsRequested: 1,
|
||||
frequency: Frequency.PUNCTUAL,
|
||||
waypoints: [originWaypoint, destinationWaypoint],
|
||||
};
|
||||
|
||||
const mockCommandBus = {
|
||||
execute: jest
|
||||
.fn()
|
||||
.mockImplementationOnce(() => '200d61a8-d878-4378-a609-c19ea71633d2')
|
||||
.mockImplementationOnce(() => {
|
||||
throw new AdAlreadyExistsException();
|
||||
})
|
||||
.mockImplementationOnce(() => {
|
||||
throw new Error();
|
||||
}),
|
||||
};
|
||||
|
||||
describe('Create Ad Grpc Controller', () => {
|
||||
let createAdGrpcController: CreateAdGrpcController;
|
||||
|
||||
beforeAll(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [
|
||||
{
|
||||
provide: CommandBus,
|
||||
useValue: mockCommandBus,
|
||||
},
|
||||
CreateAdGrpcController,
|
||||
],
|
||||
}).compile();
|
||||
|
||||
createAdGrpcController = module.get<CreateAdGrpcController>(
|
||||
CreateAdGrpcController,
|
||||
);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(createAdGrpcController).toBeDefined();
|
||||
});
|
||||
|
||||
it('should create a new ad', async () => {
|
||||
const result: IdResponse = await createAdGrpcController.create(
|
||||
punctualCreateAdRequest,
|
||||
);
|
||||
expect(result).toBeInstanceOf(IdResponse);
|
||||
expect(result.id).toBe('200d61a8-d878-4378-a609-c19ea71633d2');
|
||||
});
|
||||
|
||||
it('should throw an dedicated RpcException if ad already exists', async () => {
|
||||
expect.assertions(2);
|
||||
try {
|
||||
await createAdGrpcController.create(punctualCreateAdRequest);
|
||||
} catch (e: any) {
|
||||
expect(e).toBeInstanceOf(RpcException);
|
||||
expect(e.error.code).toBe(RpcExceptionCode.ALREADY_EXISTS);
|
||||
}
|
||||
});
|
||||
|
||||
it('should throw a generic RpcException', async () => {
|
||||
expect.assertions(2);
|
||||
try {
|
||||
await createAdGrpcController.create(punctualCreateAdRequest);
|
||||
} catch (e: any) {
|
||||
expect(e).toBeInstanceOf(RpcException);
|
||||
expect(e.error.code).toBeUndefined();
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user