From d213408c8306e437f394900105415489ecfd3ec7 Mon Sep 17 00:00:00 2001 From: Fanch Date: Thu, 16 May 2024 15:40:03 +0200 Subject: [PATCH] feat(pause ad): emit update event after pause ad --- .../commands/pause-ad/pause-ad.service.ts | 13 +++++- ...-when-ad-is-paused.domain-event-handler.ts | 19 --------- src/modules/ad/core/domain/ad.entity.ts | 10 ----- .../domain/events/ad-paused.domain-event.ts | 7 ---- tests/unit/ad/core/pause-ad.service.spec.ts | 42 +++++++++++++++++++ .../pause-ad.grpc.controller.spec.ts | 42 +++++++++++++++++++ 6 files changed, 96 insertions(+), 37 deletions(-) delete mode 100644 src/modules/ad/core/application/event-handlers/publish-message-when-ad-is-paused.domain-event-handler.ts delete mode 100644 src/modules/ad/core/domain/events/ad-paused.domain-event.ts create mode 100644 tests/unit/ad/core/pause-ad.service.spec.ts create mode 100644 tests/unit/ad/interface/pause-ad.grpc.controller.spec.ts diff --git a/src/modules/ad/core/application/commands/pause-ad/pause-ad.service.ts b/src/modules/ad/core/application/commands/pause-ad/pause-ad.service.ts index fecfe01..356f66d 100644 --- a/src/modules/ad/core/application/commands/pause-ad/pause-ad.service.ts +++ b/src/modules/ad/core/application/commands/pause-ad/pause-ad.service.ts @@ -1,19 +1,30 @@ import { AD_REPOSITORY } from '@modules/ad/ad.di-tokens'; import { Inject } from '@nestjs/common'; import { CommandHandler, ICommandHandler } from '@nestjs/cqrs'; +import { EventEmitter2 } from '@nestjs/event-emitter'; import { AdRepositoryPort } from '../../ports/ad.repository.port'; import { PauseAdCommand } from './pause-ad.command'; +import { AdUpdatedDomainEvent } from '@modules/ad/core/domain/events/ad.domain-event'; @CommandHandler(PauseAdCommand) export class PauseAdService implements ICommandHandler { constructor( @Inject(AD_REPOSITORY) private readonly adRepository: AdRepositoryPort, + private readonly eventEmitter: EventEmitter2, ) {} async execute(command: PauseAdCommand): Promise { - const ad = await this.adRepository.findOneById(command.id); + const ad = await this.adRepository.findOneById(command.id, { + // TODO: waypoints and schedule needed for event, should be optional if no modif on them ... + waypoints: true, + schedule: true, + }); ad.pause(); await this.adRepository.update(ad.id, ad); + this.eventEmitter.emitAsync( + AdUpdatedDomainEvent.name, + new AdUpdatedDomainEvent(ad), + ); } } diff --git a/src/modules/ad/core/application/event-handlers/publish-message-when-ad-is-paused.domain-event-handler.ts b/src/modules/ad/core/application/event-handlers/publish-message-when-ad-is-paused.domain-event-handler.ts deleted file mode 100644 index 58193b0..0000000 --- a/src/modules/ad/core/application/event-handlers/publish-message-when-ad-is-paused.domain-event-handler.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { MessagePublisherPort } from '@mobicoop/ddd-library'; -import { AD_MESSAGE_PUBLISHER } from '@modules/ad/ad.di-tokens'; -import { Inject, Injectable } from '@nestjs/common'; -import { OnEvent } from '@nestjs/event-emitter'; -import { AD_PAUSED_ROUTING_KEY } from '@src/app.constants'; -import { AdPausedDomainEvent } from '../../domain/events/ad-paused.domain-event'; - -@Injectable() -export class PublishMessageWhenAdIsPausedDomainEventHandler { - constructor( - @Inject(AD_MESSAGE_PUBLISHER) - private readonly messagePublisher: MessagePublisherPort, - ) {} - - @OnEvent(AdPausedDomainEvent.name, { async: true, promisify: true }) - async handle(event: AdPausedDomainEvent): Promise { - this.messagePublisher.publish(AD_PAUSED_ROUTING_KEY, JSON.stringify(event)); - } -} diff --git a/src/modules/ad/core/domain/ad.entity.ts b/src/modules/ad/core/domain/ad.entity.ts index 60149f5..cb385dd 100644 --- a/src/modules/ad/core/domain/ad.entity.ts +++ b/src/modules/ad/core/domain/ad.entity.ts @@ -3,7 +3,6 @@ import { v4 } from 'uuid'; import { AdProps, CreateAdProps, Status } from './ad.types'; import { AdCreatedDomainEvent } from './events/ad-created.domain-event'; import { AdDeletedDomainEvent } from './events/ad-delete.domain-event'; -import { AdPausedDomainEvent } from './events/ad-paused.domain-event'; import { AdInvalidatedDomainEvent } from './events/ad-invalidated.domain-event'; import { AdSuspendedDomainEvent } from './events/ad-suspended.domain-event'; import { AdValidatedDomainEvent } from './events/ad-validated.domain-event'; @@ -130,15 +129,6 @@ export class AdEntity extends AggregateRoot { pause(): AdEntity { this.props.pause = !this.props.pause; - this.addEvent( - new AdPausedDomainEvent({ - metadata: { - correlationId: this.id, - timestamp: Date.now(), - }, - aggregateId: this.id, - }), - ); return this; } } diff --git a/src/modules/ad/core/domain/events/ad-paused.domain-event.ts b/src/modules/ad/core/domain/events/ad-paused.domain-event.ts deleted file mode 100644 index 7737564..0000000 --- a/src/modules/ad/core/domain/events/ad-paused.domain-event.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { DomainEvent, DomainEventProps } from '@mobicoop/ddd-library'; - -export class AdPausedDomainEvent extends DomainEvent { - constructor(props: DomainEventProps) { - super(props); - } -} diff --git a/tests/unit/ad/core/pause-ad.service.spec.ts b/tests/unit/ad/core/pause-ad.service.spec.ts new file mode 100644 index 0000000..ad74eed --- /dev/null +++ b/tests/unit/ad/core/pause-ad.service.spec.ts @@ -0,0 +1,42 @@ +import { AD_REPOSITORY } from '@modules/ad/ad.di-tokens'; +import { PauseAdCommand } from '@modules/ad/core/application/commands/pause-ad/pause-ad.command'; +import { PauseAdService } from '@modules/ad/core/application/commands/pause-ad/pause-ad.service'; +import { AdEntity } from '@modules/ad/core/domain/ad.entity'; +import { Test, TestingModule } from '@nestjs/testing'; +import { punctualPassengerCreateAdProps } from './ad.fixtures'; + +const ad: AdEntity = AdEntity.create(punctualPassengerCreateAdProps()); +jest.spyOn(ad, 'pause'); + +const mockAdRepository = { + findOneById: jest.fn().mockImplementation(() => ad), + update: jest.fn(), +}; + +describe('pause-ad.service', () => { + let pauseAdService: PauseAdService; + + beforeAll(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [ + { + provide: AD_REPOSITORY, + useValue: mockAdRepository, + }, + PauseAdService, + ], + }).compile(); + + pauseAdService = module.get(PauseAdService); + }); + + it('should be defined', () => { + expect(pauseAdService).toBeDefined(); + }); + + it('should trigger the pause logic and pause the ad from the repository', async () => { + await pauseAdService.execute(new PauseAdCommand({ id: ad.id })); + expect(ad.pause).toHaveBeenCalled(); + expect(mockAdRepository.update).toHaveBeenCalledWith(ad); + }); +}); diff --git a/tests/unit/ad/interface/pause-ad.grpc.controller.spec.ts b/tests/unit/ad/interface/pause-ad.grpc.controller.spec.ts new file mode 100644 index 0000000..cf6288f --- /dev/null +++ b/tests/unit/ad/interface/pause-ad.grpc.controller.spec.ts @@ -0,0 +1,42 @@ +import { PauseAdGrpcController } from '@modules/ad/interface/grpc-controllers/pause-ad.grpc.controller'; +import { CommandBus } from '@nestjs/cqrs'; +import { Test, TestingModule } from '@nestjs/testing'; + +const mockCommandBus = { + execute: jest.fn(), +}; + +describe('Pause Ad Grpc Controller', () => { + let pauseAdGrpcController: PauseAdGrpcController; + + beforeAll(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [ + { + provide: CommandBus, + useValue: mockCommandBus, + }, + PauseAdGrpcController, + ], + }).compile(); + + pauseAdGrpcController = module.get( + PauseAdGrpcController, + ); + }); + + afterEach(async () => { + jest.clearAllMocks(); + }); + + it('should be defined', () => { + expect(pauseAdGrpcController).toBeDefined(); + }); + + it('should execute the pause ad command', async () => { + await pauseAdGrpcController.pause({ + id: '200d61a8-d878-4378-a609-c19ea71633d2', + }); + expect(mockCommandBus.execute).toHaveBeenCalledTimes(1); + }); +});