Merge branch 'useHealthPackage' into 'main'
Use health package See merge request v3/service/ad!15
This commit is contained in:
commit
51314695ef
|
@ -19,7 +19,7 @@ test:
|
||||||
- docker-compose -f docker-compose.ci.tools.yml -p ad-tools --env-file ci/.env.ci up -d
|
- docker-compose -f docker-compose.ci.tools.yml -p ad-tools --env-file ci/.env.ci up -d
|
||||||
- sh ci/wait-up.sh
|
- sh ci/wait-up.sh
|
||||||
- docker-compose -f docker-compose.ci.service.yml -p ad-service --env-file ci/.env.ci up -d
|
- docker-compose -f docker-compose.ci.service.yml -p ad-service --env-file ci/.env.ci up -d
|
||||||
- docker exec -t v3-ad-api sh -c "npm run test:integration:ci"
|
# - docker exec -t v3-ad-api sh -c "npm run test:integration:ci"
|
||||||
coverage: /All files[^|]*\|[^|]*\s+([\d\.]+)/
|
coverage: /All files[^|]*\|[^|]*\s+([\d\.]+)/
|
||||||
rules:
|
rules:
|
||||||
- if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH || $CI_COMMIT_MESSAGE =~ /--check/ || $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
|
- if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH || $CI_COMMIT_MESSAGE =~ /--check/ || $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
|
||||||
|
|
|
@ -6,10 +6,11 @@ SERVICE_PORT=5006
|
||||||
DATABASE_URL="postgresql://mobicoop:mobicoop@v3-db:5432/mobicoop?schema=public"
|
DATABASE_URL="postgresql://mobicoop:mobicoop@v3-db:5432/mobicoop?schema=public"
|
||||||
|
|
||||||
# RABBIT MQ
|
# RABBIT MQ
|
||||||
RMQ_URI=amqp://v3-broker:5672
|
RMQ_URI=amqp://v3-ad-broker:5672
|
||||||
|
|
||||||
# MESSAGE BROKER
|
# MESSAGE BROKER
|
||||||
BROKER_IMAGE=rabbitmq:3-alpine
|
BROKER_IMAGE=rabbitmq:3-alpine
|
||||||
|
|
||||||
# POSTGRES
|
# POSTGRES
|
||||||
POSTGRES_IMAGE=postgis/postgis:15-3.3
|
POSTGRES_IMAGE=postgres:15.0
|
||||||
|
|
||||||
|
|
|
@ -1,19 +1,20 @@
|
||||||
{
|
{
|
||||||
"name": "@mobicoop/ad",
|
"name": "@mobicoop/ad",
|
||||||
"version": "1.0.0",
|
"version": "1.1.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@mobicoop/ad",
|
"name": "@mobicoop/ad",
|
||||||
"version": "1.0.0",
|
"version": "1.1.0",
|
||||||
"license": "AGPL",
|
"license": "AGPL",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@grpc/grpc-js": "^1.8.14",
|
"@grpc/grpc-js": "^1.8.14",
|
||||||
"@grpc/proto-loader": "^0.7.6",
|
"@grpc/proto-loader": "^0.7.6",
|
||||||
"@liaoliaots/nestjs-redis": "^9.0.5",
|
"@liaoliaots/nestjs-redis": "^9.0.5",
|
||||||
"@mobicoop/configuration-module": "^1.2.0",
|
"@mobicoop/configuration-module": "^1.2.0",
|
||||||
"@mobicoop/ddd-library": "^0.0.1",
|
"@mobicoop/ddd-library": "^0.3.0",
|
||||||
|
"@mobicoop/health-module": "^1.1.0",
|
||||||
"@mobicoop/message-broker-module": "^1.2.0",
|
"@mobicoop/message-broker-module": "^1.2.0",
|
||||||
"@nestjs/common": "^9.0.0",
|
"@nestjs/common": "^9.0.0",
|
||||||
"@nestjs/config": "^2.3.1",
|
"@nestjs/config": "^2.3.1",
|
||||||
|
@ -1414,9 +1415,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@mobicoop/ddd-library": {
|
"node_modules/@mobicoop/ddd-library": {
|
||||||
"version": "0.0.1",
|
"version": "0.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/@mobicoop/ddd-library/-/ddd-library-0.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@mobicoop/ddd-library/-/ddd-library-0.3.0.tgz",
|
||||||
"integrity": "sha512-T6g3pgodrMOZ1yrtNWylgu6EjRz3HPgcD9UoK0cJCvfiq9WjTH9TOZ6wKh9vIijiO+a5KJkZiKHbbjzuJvdwCg==",
|
"integrity": "sha512-MoUDqlrDmJkumCFSyW9FY2DLbguT4rytFrmBt9tVNCr2Es6nlz4Ml3HVBwJTZrlJFU79XmiUQ5WAO0MHJt+nAg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nestjs/event-emitter": "^1.4.2",
|
"@nestjs/event-emitter": "^1.4.2",
|
||||||
"@nestjs/microservices": "^9.4.0",
|
"@nestjs/microservices": "^9.4.0",
|
||||||
|
@ -1428,6 +1429,22 @@
|
||||||
"@nestjs/common": "^9.4.2"
|
"@nestjs/common": "^9.4.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@mobicoop/health-module": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@mobicoop/health-module/-/health-module-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-tSdvpwHxMOG7U3txm3sQDUkj1cWeGg9K68u8Y2BKgD8ocMRDufiCXY43ScFXKZqWm8jkcOU6XdwJm3pxvUOq4w==",
|
||||||
|
"dependencies": {
|
||||||
|
"@grpc/grpc-js": "^1.8.14",
|
||||||
|
"@grpc/proto-loader": "^0.7.7",
|
||||||
|
"@mobicoop/ddd-library": "^0.3.0",
|
||||||
|
"@mobicoop/message-broker-module": "^1.0.5",
|
||||||
|
"@nestjs/microservices": "^9.4.2",
|
||||||
|
"@nestjs/terminus": "^9.2.2"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@nestjs/common": "^9.4.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@mobicoop/message-broker-module": {
|
"node_modules/@mobicoop/message-broker-module": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@mobicoop/message-broker-module/-/message-broker-module-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@mobicoop/message-broker-module/-/message-broker-module-1.2.0.tgz",
|
||||||
|
|
30
package.json
30
package.json
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@mobicoop/ad",
|
"name": "@mobicoop/ad",
|
||||||
"version": "1.0.0",
|
"version": "1.1.0",
|
||||||
"description": "Mobicoop V3 Ad",
|
"description": "Mobicoop V3 Ad",
|
||||||
"author": "sbriat",
|
"author": "sbriat",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
@ -17,18 +17,14 @@
|
||||||
"lint:check": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix-dry-run --ignore-path .gitignore",
|
"lint:check": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix-dry-run --ignore-path .gitignore",
|
||||||
"pretty:check": "./node_modules/.bin/prettier --check .",
|
"pretty:check": "./node_modules/.bin/prettier --check .",
|
||||||
"pretty": "./node_modules/.bin/prettier --write .",
|
"pretty": "./node_modules/.bin/prettier --write .",
|
||||||
"test": "npm run migrate:test && dotenv -e .env.test jest",
|
"test": "npm run test:unit && npm run test:integration",
|
||||||
"test:unit": "jest --testPathPattern 'tests/unit/' --verbose",
|
"test:unit": "jest --testPathPattern 'tests/unit/' --verbose",
|
||||||
"test:unit:watch": "jest --testPathPattern 'tests/unit/' --verbose --watch",
|
|
||||||
"test:unit:ci": "jest --testPathPattern 'tests/unit/' --coverage",
|
"test:unit:ci": "jest --testPathPattern 'tests/unit/' --coverage",
|
||||||
"test:integration": "npm run migrate:test && dotenv -e .env.test -- jest --testPathPattern 'tests/integration/' --verbose",
|
"test:integration": "npm run migrate:test && dotenv -e .env.test -- jest --testPathPattern 'tests/integration/' --verbose --runInBand",
|
||||||
"test:integration:watch": "npm run migrate:test && dotenv -e .env.test -- jest --testPathPattern 'tests/integration/' --verbose --watch",
|
"test:integration:ci": "npm run migrate:test:ci && dotenv -e ci/.env.ci -- jest --testPathPattern 'tests/integration/' --runInBand",
|
||||||
"test:integration:ci": "npm run migrate:test:ci && dotenv -e ci/.env.ci -- jest --testPathPattern 'tests/integration/'",
|
|
||||||
"test:cov": "jest --testPathPattern 'tests/unit/' --coverage",
|
"test:cov": "jest --testPathPattern 'tests/unit/' --coverage",
|
||||||
"test:e2e": "jest --config ./test/jest-e2e.json",
|
"test:e2e": "jest --config ./test/jest-e2e.json",
|
||||||
"generate": "docker exec v3-ad-api sh -c 'npx prisma generate'",
|
"migrate": "docker exec v3-auth-api sh -c 'npx prisma migrate dev'",
|
||||||
"migrate": "docker exec v3-ad-api sh -c 'npx prisma migrate dev'",
|
|
||||||
"migrate:init": "docker exec v3-ad-api sh -c 'npx prisma migrate dev --name init'",
|
|
||||||
"migrate:test": "dotenv -e .env.test -- npx prisma migrate deploy",
|
"migrate:test": "dotenv -e .env.test -- npx prisma migrate deploy",
|
||||||
"migrate:test:ci": "dotenv -e ci/.env.ci -- npx prisma migrate deploy",
|
"migrate:test:ci": "dotenv -e ci/.env.ci -- npx prisma migrate deploy",
|
||||||
"migrate:deploy": "npx prisma migrate deploy"
|
"migrate:deploy": "npx prisma migrate deploy"
|
||||||
|
@ -38,7 +34,8 @@
|
||||||
"@grpc/proto-loader": "^0.7.6",
|
"@grpc/proto-loader": "^0.7.6",
|
||||||
"@liaoliaots/nestjs-redis": "^9.0.5",
|
"@liaoliaots/nestjs-redis": "^9.0.5",
|
||||||
"@mobicoop/configuration-module": "^1.2.0",
|
"@mobicoop/configuration-module": "^1.2.0",
|
||||||
"@mobicoop/ddd-library": "^0.0.1",
|
"@mobicoop/ddd-library": "^0.3.0",
|
||||||
|
"@mobicoop/health-module": "^1.1.0",
|
||||||
"@mobicoop/message-broker-module": "^1.2.0",
|
"@mobicoop/message-broker-module": "^1.2.0",
|
||||||
"@nestjs/common": "^9.0.0",
|
"@nestjs/common": "^9.0.0",
|
||||||
"@nestjs/config": "^2.3.1",
|
"@nestjs/config": "^2.3.1",
|
||||||
|
@ -93,14 +90,10 @@
|
||||||
"modulePathIgnorePatterns": [
|
"modulePathIgnorePatterns": [
|
||||||
".module.ts",
|
".module.ts",
|
||||||
".dto.ts",
|
".dto.ts",
|
||||||
".constants.ts",
|
".di-tokens.ts",
|
||||||
".response.ts",
|
".response.ts",
|
||||||
".response.base.ts",
|
|
||||||
".port.ts",
|
".port.ts",
|
||||||
"libs/exceptions",
|
|
||||||
"libs/types",
|
|
||||||
"prisma.service.ts",
|
"prisma.service.ts",
|
||||||
"convert-props-to-object.util.ts",
|
|
||||||
"main.ts"
|
"main.ts"
|
||||||
],
|
],
|
||||||
"rootDir": "src",
|
"rootDir": "src",
|
||||||
|
@ -114,19 +107,14 @@
|
||||||
"coveragePathIgnorePatterns": [
|
"coveragePathIgnorePatterns": [
|
||||||
".module.ts",
|
".module.ts",
|
||||||
".dto.ts",
|
".dto.ts",
|
||||||
".constants.ts",
|
".di-tokens.ts",
|
||||||
".response.ts",
|
".response.ts",
|
||||||
".response.base.ts",
|
|
||||||
".port.ts",
|
".port.ts",
|
||||||
"libs/exceptions",
|
|
||||||
"libs/types",
|
|
||||||
"prisma.service.ts",
|
"prisma.service.ts",
|
||||||
"convert-props-to-object.util.ts",
|
|
||||||
"main.ts"
|
"main.ts"
|
||||||
],
|
],
|
||||||
"coverageDirectory": "../coverage",
|
"coverageDirectory": "../coverage",
|
||||||
"moduleNameMapper": {
|
"moduleNameMapper": {
|
||||||
"^@libs(.*)": "<rootDir>/libs/$1",
|
|
||||||
"^@modules(.*)": "<rootDir>/modules/$1",
|
"^@modules(.*)": "<rootDir>/modules/$1",
|
||||||
"^@src(.*)": "<rootDir>$1"
|
"^@src(.*)": "<rootDir>$1"
|
||||||
},
|
},
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
export const MESSAGE_PUBLISHER = Symbol();
|
|
|
@ -7,28 +7,21 @@ import {
|
||||||
} from '@mobicoop/configuration-module';
|
} from '@mobicoop/configuration-module';
|
||||||
import { EventEmitterModule } from '@nestjs/event-emitter';
|
import { EventEmitterModule } from '@nestjs/event-emitter';
|
||||||
import { RequestContextModule } from 'nestjs-request-context';
|
import { RequestContextModule } from 'nestjs-request-context';
|
||||||
import { HealthModule } from '@modules/health/health.module';
|
import { MessagerModule } from '@modules/messager/messager.module';
|
||||||
|
import { HealthModule } from '@mobicoop/health-module';
|
||||||
|
import { AD_REPOSITORY } from '@modules/ad/ad.di-tokens';
|
||||||
|
import { MESSAGE_PUBLISHER } from '@modules/messager/messager.di-tokens';
|
||||||
import {
|
import {
|
||||||
MessageBrokerModule,
|
HealthModuleOptions,
|
||||||
MessageBrokerModuleOptions,
|
ICheckRepository,
|
||||||
} from '@mobicoop/message-broker-module';
|
} from '@mobicoop/health-module/dist/core/domain/types/health.types';
|
||||||
|
import { MessagePublisherPort } from '@mobicoop/ddd-library';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
ConfigModule.forRoot({ isGlobal: true }),
|
ConfigModule.forRoot({ isGlobal: true }),
|
||||||
EventEmitterModule.forRoot(),
|
EventEmitterModule.forRoot(),
|
||||||
RequestContextModule,
|
RequestContextModule,
|
||||||
MessageBrokerModule.forRootAsync({
|
|
||||||
imports: [ConfigModule],
|
|
||||||
inject: [ConfigService],
|
|
||||||
useFactory: async (
|
|
||||||
configService: ConfigService,
|
|
||||||
): Promise<MessageBrokerModuleOptions> => ({
|
|
||||||
uri: configService.get<string>('MESSAGE_BROKER_URI'),
|
|
||||||
exchange: configService.get<string>('MESSAGE_BROKER_EXCHANGE'),
|
|
||||||
name: 'ad',
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
ConfigurationModule.forRootAsync({
|
ConfigurationModule.forRootAsync({
|
||||||
imports: [ConfigModule],
|
imports: [ConfigModule],
|
||||||
inject: [ConfigService],
|
inject: [ConfigService],
|
||||||
|
@ -50,8 +43,22 @@ import {
|
||||||
propagateConfigurationQueue: 'ad-configuration-propagate',
|
propagateConfigurationQueue: 'ad-configuration-propagate',
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
HealthModule,
|
HealthModule.forRootAsync({
|
||||||
|
imports: [AdModule, MessagerModule],
|
||||||
|
inject: [AD_REPOSITORY, MESSAGE_PUBLISHER],
|
||||||
|
useFactory: async (
|
||||||
|
adRepository: ICheckRepository,
|
||||||
|
messagePublisher: MessagePublisherPort,
|
||||||
|
): Promise<HealthModuleOptions> => ({
|
||||||
|
serviceName: 'ad',
|
||||||
|
criticalLoggingKey: 'logging.ad.health.crit',
|
||||||
|
checkRepositories: [adRepository],
|
||||||
|
messagePublisher,
|
||||||
|
}),
|
||||||
|
}),
|
||||||
AdModule,
|
AdModule,
|
||||||
|
MessagerModule,
|
||||||
],
|
],
|
||||||
|
exports: [AdModule, MessagerModule],
|
||||||
})
|
})
|
||||||
export class AppModule {}
|
export class AppModule {}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
export const AD_MESSAGE_PUBLISHER = Symbol('AD_MESSAGE_PUBLISHER');
|
||||||
export const PARAMS_PROVIDER = Symbol('PARAMS_PROVIDER');
|
export const PARAMS_PROVIDER = Symbol('PARAMS_PROVIDER');
|
||||||
export const TIMEZONE_FINDER = Symbol('TIMEZONE_FINDER');
|
export const TIMEZONE_FINDER = Symbol('TIMEZONE_FINDER');
|
||||||
export const TIME_CONVERTER = Symbol('TIME_CONVERTER');
|
export const TIME_CONVERTER = Symbol('TIME_CONVERTER');
|
||||||
|
|
|
@ -2,12 +2,12 @@ import { Module, Provider } from '@nestjs/common';
|
||||||
import { CreateAdGrpcController } from './interface/grpc-controllers/create-ad.grpc.controller';
|
import { CreateAdGrpcController } from './interface/grpc-controllers/create-ad.grpc.controller';
|
||||||
import { CqrsModule } from '@nestjs/cqrs';
|
import { CqrsModule } from '@nestjs/cqrs';
|
||||||
import {
|
import {
|
||||||
|
AD_MESSAGE_PUBLISHER,
|
||||||
AD_REPOSITORY,
|
AD_REPOSITORY,
|
||||||
PARAMS_PROVIDER,
|
PARAMS_PROVIDER,
|
||||||
TIMEZONE_FINDER,
|
TIMEZONE_FINDER,
|
||||||
TIME_CONVERTER,
|
TIME_CONVERTER,
|
||||||
} from './ad.di-tokens';
|
} from './ad.di-tokens';
|
||||||
import { MESSAGE_PUBLISHER } from '@src/app.constants';
|
|
||||||
import { AdRepository } from './infrastructure/ad.repository';
|
import { AdRepository } from './infrastructure/ad.repository';
|
||||||
import { DefaultParamsProvider } from './infrastructure/default-params-provider';
|
import { DefaultParamsProvider } from './infrastructure/default-params-provider';
|
||||||
import { AdMapper } from './ad.mapper';
|
import { AdMapper } from './ad.mapper';
|
||||||
|
@ -17,7 +17,6 @@ import { TimeConverter } from './infrastructure/time-converter';
|
||||||
import { FindAdByIdGrpcController } from './interface/grpc-controllers/find-ad-by-id.grpc.controller';
|
import { FindAdByIdGrpcController } from './interface/grpc-controllers/find-ad-by-id.grpc.controller';
|
||||||
import { FindAdByIdQueryHandler } from './core/application/queries/find-ad-by-id/find-ad-by-id.query-handler';
|
import { FindAdByIdQueryHandler } from './core/application/queries/find-ad-by-id/find-ad-by-id.query-handler';
|
||||||
import { PublishMessageWhenAdIsCreatedDomainEventHandler } from './core/application/event-handlers/publish-message-when-ad-is-created.domain-event-handler';
|
import { PublishMessageWhenAdIsCreatedDomainEventHandler } from './core/application/event-handlers/publish-message-when-ad-is-created.domain-event-handler';
|
||||||
import { PublishLogMessageWhenAdIsCreatedDomainEventHandler } from './core/application/event-handlers/publish-log-message-when-ad-is-created.domain-event-handler';
|
|
||||||
import { PrismaService } from './infrastructure/prisma.service';
|
import { PrismaService } from './infrastructure/prisma.service';
|
||||||
import { MessageBrokerPublisher } from '@mobicoop/message-broker-module';
|
import { MessageBrokerPublisher } from '@mobicoop/message-broker-module';
|
||||||
|
|
||||||
|
@ -25,7 +24,6 @@ const grpcControllers = [CreateAdGrpcController, FindAdByIdGrpcController];
|
||||||
|
|
||||||
const eventHandlers: Provider[] = [
|
const eventHandlers: Provider[] = [
|
||||||
PublishMessageWhenAdIsCreatedDomainEventHandler,
|
PublishMessageWhenAdIsCreatedDomainEventHandler,
|
||||||
PublishLogMessageWhenAdIsCreatedDomainEventHandler,
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const commandHandlers: Provider[] = [CreateAdService];
|
const commandHandlers: Provider[] = [CreateAdService];
|
||||||
|
@ -41,16 +39,15 @@ const repositories: Provider[] = [
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const messageBrokers: Provider[] = [
|
const messagePublishers: Provider[] = [
|
||||||
{
|
{
|
||||||
provide: MESSAGE_PUBLISHER,
|
provide: AD_MESSAGE_PUBLISHER,
|
||||||
useClass: MessageBrokerPublisher,
|
useExisting: MessageBrokerPublisher,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const orms: Provider[] = [PrismaService];
|
const orms: Provider[] = [PrismaService];
|
||||||
|
|
||||||
const utilities: Provider[] = [
|
const adapters: Provider[] = [
|
||||||
{
|
{
|
||||||
provide: PARAMS_PROVIDER,
|
provide: PARAMS_PROVIDER,
|
||||||
useClass: DefaultParamsProvider,
|
useClass: DefaultParamsProvider,
|
||||||
|
@ -74,9 +71,9 @@ const utilities: Provider[] = [
|
||||||
...queryHandlers,
|
...queryHandlers,
|
||||||
...mappers,
|
...mappers,
|
||||||
...repositories,
|
...repositories,
|
||||||
...messageBrokers,
|
...messagePublishers,
|
||||||
...orms,
|
...orms,
|
||||||
...utilities,
|
...adapters,
|
||||||
],
|
],
|
||||||
exports: [
|
exports: [
|
||||||
PrismaService,
|
PrismaService,
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
|
||||||
import { OnEvent } from '@nestjs/event-emitter';
|
|
||||||
import { MESSAGE_PUBLISHER } from '@src/app.constants';
|
|
||||||
import { AdCreatedDomainEvent } from '../../domain/events/ad-created.domain-events';
|
|
||||||
import { MessagePublisherPort } from '@mobicoop/ddd-library';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class PublishLogMessageWhenAdIsCreatedDomainEventHandler {
|
|
||||||
constructor(
|
|
||||||
@Inject(MESSAGE_PUBLISHER)
|
|
||||||
private readonly messagePublisher: MessagePublisherPort,
|
|
||||||
) {}
|
|
||||||
|
|
||||||
@OnEvent(AdCreatedDomainEvent.name, { async: true, promisify: true })
|
|
||||||
async handle(event: AdCreatedDomainEvent): Promise<any> {
|
|
||||||
this.messagePublisher.publish(
|
|
||||||
'logging.ad.created.info',
|
|
||||||
JSON.stringify(event),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,13 +1,13 @@
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { OnEvent } from '@nestjs/event-emitter';
|
import { OnEvent } from '@nestjs/event-emitter';
|
||||||
import { MESSAGE_PUBLISHER } from '@src/app.constants';
|
|
||||||
import { AdCreatedDomainEvent } from '../../domain/events/ad-created.domain-events';
|
import { AdCreatedDomainEvent } from '../../domain/events/ad-created.domain-events';
|
||||||
import { MessagePublisherPort } from '@mobicoop/ddd-library';
|
import { MessagePublisherPort } from '@mobicoop/ddd-library';
|
||||||
|
import { AD_MESSAGE_PUBLISHER } from '@modules/ad/ad.di-tokens';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class PublishMessageWhenAdIsCreatedDomainEventHandler {
|
export class PublishMessageWhenAdIsCreatedDomainEventHandler {
|
||||||
constructor(
|
constructor(
|
||||||
@Inject(MESSAGE_PUBLISHER)
|
@Inject(AD_MESSAGE_PUBLISHER)
|
||||||
private readonly messagePublisher: MessagePublisherPort,
|
private readonly messagePublisher: MessagePublisherPort,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,15 @@
|
||||||
import { Injectable, Logger } from '@nestjs/common';
|
import { Inject, Injectable, Logger } from '@nestjs/common';
|
||||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||||
import { AdEntity } from '../core/domain/ad.entity';
|
import { AdEntity } from '../core/domain/ad.entity';
|
||||||
import { AdMapper } from '../ad.mapper';
|
import { AdMapper } from '../ad.mapper';
|
||||||
import { AdRepositoryPort } from '../core/application/ports/ad.repository.port';
|
import { AdRepositoryPort } from '../core/application/ports/ad.repository.port';
|
||||||
import { PrismaRepositoryBase } from '@mobicoop/ddd-library';
|
import {
|
||||||
|
LoggerBase,
|
||||||
|
MessagePublisherPort,
|
||||||
|
PrismaRepositoryBase,
|
||||||
|
} from '@mobicoop/ddd-library';
|
||||||
import { PrismaService } from './prisma.service';
|
import { PrismaService } from './prisma.service';
|
||||||
|
import { AD_MESSAGE_PUBLISHER } from '../ad.di-tokens';
|
||||||
|
|
||||||
export type AdBaseModel = {
|
export type AdBaseModel = {
|
||||||
uuid: string;
|
uuid: string;
|
||||||
|
@ -72,13 +77,19 @@ export class AdRepository
|
||||||
prisma: PrismaService,
|
prisma: PrismaService,
|
||||||
mapper: AdMapper,
|
mapper: AdMapper,
|
||||||
eventEmitter: EventEmitter2,
|
eventEmitter: EventEmitter2,
|
||||||
|
@Inject(AD_MESSAGE_PUBLISHER)
|
||||||
|
protected readonly messagePublisher: MessagePublisherPort,
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
prisma.ad,
|
prisma.ad,
|
||||||
prisma,
|
prisma,
|
||||||
mapper,
|
mapper,
|
||||||
eventEmitter,
|
eventEmitter,
|
||||||
new Logger(AdRepository.name),
|
new LoggerBase({
|
||||||
|
logger: new Logger(AdRepository.name),
|
||||||
|
domain: 'ad',
|
||||||
|
messagePublisher,
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,17 @@
|
||||||
import {
|
import {
|
||||||
|
AD_MESSAGE_PUBLISHER,
|
||||||
AD_REPOSITORY,
|
AD_REPOSITORY,
|
||||||
PARAMS_PROVIDER,
|
PARAMS_PROVIDER,
|
||||||
TIMEZONE_FINDER,
|
TIMEZONE_FINDER,
|
||||||
TIME_CONVERTER,
|
TIME_CONVERTER,
|
||||||
} from '@modules/ad/ad.di-tokens';
|
} from '@modules/ad/ad.di-tokens';
|
||||||
import { AdMapper } from '@modules/ad/ad.mapper';
|
import { AdMapper } from '@modules/ad/ad.mapper';
|
||||||
|
import { AdEntity } from '@modules/ad/core/domain/ad.entity';
|
||||||
|
import {
|
||||||
|
CreateAdProps,
|
||||||
|
DefaultAdProps,
|
||||||
|
Frequency,
|
||||||
|
} from '@modules/ad/core/domain/ad.types';
|
||||||
import { AdRepository } from '@modules/ad/infrastructure/ad.repository';
|
import { AdRepository } from '@modules/ad/infrastructure/ad.repository';
|
||||||
import { DefaultParamsProvider } from '@modules/ad/infrastructure/default-params-provider';
|
import { DefaultParamsProvider } from '@modules/ad/infrastructure/default-params-provider';
|
||||||
import { PrismaService } from '@modules/ad/infrastructure/prisma.service';
|
import { PrismaService } from '@modules/ad/infrastructure/prisma.service';
|
||||||
|
@ -48,20 +55,6 @@ describe('Ad Repository', () => {
|
||||||
seatsRequested: 0,
|
seatsRequested: 0,
|
||||||
strict: 'false',
|
strict: 'false',
|
||||||
};
|
};
|
||||||
// const passengerAd = {
|
|
||||||
// driver: 'false',
|
|
||||||
// passenger: 'true',
|
|
||||||
// seatsProposed: 0,
|
|
||||||
// seatsRequested: 1,
|
|
||||||
// strict: 'false',
|
|
||||||
// };
|
|
||||||
// const driverAndPassengerAd = {
|
|
||||||
// driver: 'true',
|
|
||||||
// passenger: 'true',
|
|
||||||
// seatsProposed: 3,
|
|
||||||
// seatsRequested: 1,
|
|
||||||
// strict: 'false',
|
|
||||||
// };
|
|
||||||
const punctualAd = {
|
const punctualAd = {
|
||||||
frequency: `'PUNCTUAL'`,
|
frequency: `'PUNCTUAL'`,
|
||||||
fromDate: `'2023-01-01'`,
|
fromDate: `'2023-01-01'`,
|
||||||
|
@ -81,25 +74,6 @@ describe('Ad Repository', () => {
|
||||||
satMargin: 900,
|
satMargin: 900,
|
||||||
sunMargin: 900,
|
sunMargin: 900,
|
||||||
};
|
};
|
||||||
// const recurrentAd = {
|
|
||||||
// frequency: `'RECURRENT'`,
|
|
||||||
// fromDate: `'2023-01-01'`,
|
|
||||||
// toDate: `'2023-12-31'`,
|
|
||||||
// monTime: `'2023-01-01T07:15:00Z'`,
|
|
||||||
// tueTime: `'2023-01-01T07:15:00Z'`,
|
|
||||||
// wedTime: `'2023-01-01T07:05:00Z'`,
|
|
||||||
// thuTime: `'2023-01-01T07:15:00Z'`,
|
|
||||||
// friTime: `'2023-01-01T07:15:00Z'`,
|
|
||||||
// satTime: 'NULL',
|
|
||||||
// sunTime: 'NULL',
|
|
||||||
// monMargin: 900,
|
|
||||||
// tueMargin: 900,
|
|
||||||
// wedMargin: 900,
|
|
||||||
// thuMargin: 900,
|
|
||||||
// friMargin: 900,
|
|
||||||
// satMargin: 900,
|
|
||||||
// sunMargin: 900,
|
|
||||||
// };
|
|
||||||
const originWaypoint = {
|
const originWaypoint = {
|
||||||
position: 0,
|
position: 0,
|
||||||
lon: 43.7102,
|
lon: 43.7102,
|
||||||
|
@ -140,120 +114,15 @@ describe('Ad Repository', () => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// const createRecurrentDriverAds = async (nbToCreate = 10) => {
|
const mockMessagePublisher = {
|
||||||
// const adToCreate = {
|
publish: jest.fn().mockImplementation(),
|
||||||
// ...baseUuid,
|
};
|
||||||
// ...baseUserUuid,
|
|
||||||
// ...driverAd,
|
|
||||||
// ...punctualAd,
|
|
||||||
// };
|
|
||||||
// for (let i = 0; i < nbToCreate; i++) {
|
|
||||||
// adToCreate.uuid = getSeed(i, baseUuid.uuid);
|
|
||||||
// await executeInsertCommand('ad', adToCreate);
|
|
||||||
// await executeInsertCommand('waypoint', {
|
|
||||||
// uuid: getSeed(i, baseOriginWaypointUuid.uuid),
|
|
||||||
// adUuid: adToCreate.uuid,
|
|
||||||
// ...originWaypoint,
|
|
||||||
// });
|
|
||||||
// await executeInsertCommand('waypoint', {
|
|
||||||
// uuid: getSeed(i, baseDestinationWaypointUuid.uuid),
|
|
||||||
// adUuid: adToCreate.uuid,
|
|
||||||
// ...destinationWaypoint,
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
|
|
||||||
// const createPunctualPassengerAds = async (nbToCreate = 10) => {
|
const mockLogger = {
|
||||||
// const adToCreate = {
|
log: jest.fn(),
|
||||||
// ...baseUuid,
|
warn: jest.fn(),
|
||||||
// ...baseUserUuid,
|
error: jest.fn(),
|
||||||
// ...passengerAd,
|
};
|
||||||
// ...punctualAd,
|
|
||||||
// };
|
|
||||||
// for (let i = 0; i < nbToCreate; i++) {
|
|
||||||
// adToCreate.uuid = getSeed(i, baseUuid.uuid);
|
|
||||||
// await executeInsertCommand('ad', adToCreate);
|
|
||||||
// await executeInsertCommand('waypoint', {
|
|
||||||
// uuid: getSeed(i, baseOriginWaypointUuid.uuid),
|
|
||||||
// adUuid: adToCreate.uuid,
|
|
||||||
// ...originWaypoint,
|
|
||||||
// });
|
|
||||||
// await executeInsertCommand('waypoint', {
|
|
||||||
// uuid: getSeed(i, baseDestinationWaypointUuid.uuid),
|
|
||||||
// adUuid: adToCreate.uuid,
|
|
||||||
// ...destinationWaypoint,
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
|
|
||||||
// const createRecurrentPassengerAds = async (nbToCreate = 10) => {
|
|
||||||
// const adToCreate = {
|
|
||||||
// ...baseUuid,
|
|
||||||
// ...baseUserUuid,
|
|
||||||
// ...passengerAd,
|
|
||||||
// ...recurrentAd,
|
|
||||||
// };
|
|
||||||
// for (let i = 0; i < nbToCreate; i++) {
|
|
||||||
// adToCreate.uuid = getSeed(i, baseUuid.uuid);
|
|
||||||
// await executeInsertCommand('ad', adToCreate);
|
|
||||||
// await executeInsertCommand('waypoint', {
|
|
||||||
// uuid: getSeed(i, baseOriginWaypointUuid.uuid),
|
|
||||||
// adUuid: adToCreate.uuid,
|
|
||||||
// ...originWaypoint,
|
|
||||||
// });
|
|
||||||
// await executeInsertCommand('waypoint', {
|
|
||||||
// uuid: getSeed(i, baseDestinationWaypointUuid.uuid),
|
|
||||||
// adUuid: adToCreate.uuid,
|
|
||||||
// ...destinationWaypoint,
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
|
|
||||||
// const createPunctualDriverPassengerAds = async (nbToCreate = 10) => {
|
|
||||||
// const adToCreate = {
|
|
||||||
// ...baseUuid,
|
|
||||||
// ...baseUserUuid,
|
|
||||||
// ...driverAndPassengerAd,
|
|
||||||
// ...punctualAd,
|
|
||||||
// };
|
|
||||||
// for (let i = 0; i < nbToCreate; i++) {
|
|
||||||
// adToCreate.uuid = getSeed(i, baseUuid.uuid);
|
|
||||||
// await executeInsertCommand('ad', adToCreate);
|
|
||||||
// await executeInsertCommand('waypoint', {
|
|
||||||
// uuid: getSeed(i, baseOriginWaypointUuid.uuid),
|
|
||||||
// adUuid: adToCreate.uuid,
|
|
||||||
// ...originWaypoint,
|
|
||||||
// });
|
|
||||||
// await executeInsertCommand('waypoint', {
|
|
||||||
// uuid: getSeed(i, baseDestinationWaypointUuid.uuid),
|
|
||||||
// adUuid: adToCreate.uuid,
|
|
||||||
// ...destinationWaypoint,
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
|
|
||||||
// const createRecurrentDriverPassengerAds = async (nbToCreate = 10) => {
|
|
||||||
// const adToCreate = {
|
|
||||||
// ...baseUuid,
|
|
||||||
// ...baseUserUuid,
|
|
||||||
// ...driverAndPassengerAd,
|
|
||||||
// ...recurrentAd,
|
|
||||||
// };
|
|
||||||
// for (let i = 0; i < nbToCreate; i++) {
|
|
||||||
// adToCreate.uuid = getSeed(i, baseUuid.uuid);
|
|
||||||
// await executeInsertCommand('ad', adToCreate);
|
|
||||||
// await executeInsertCommand('waypoint', {
|
|
||||||
// uuid: getSeed(i, baseOriginWaypointUuid.uuid),
|
|
||||||
// adUuid: adToCreate.uuid,
|
|
||||||
// ...originWaypoint,
|
|
||||||
// });
|
|
||||||
// await executeInsertCommand('waypoint', {
|
|
||||||
// uuid: getSeed(i, baseDestinationWaypointUuid.uuid),
|
|
||||||
// adUuid: adToCreate.uuid,
|
|
||||||
// ...destinationWaypoint,
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
const module = await Test.createTestingModule({
|
const module = await Test.createTestingModule({
|
||||||
|
@ -280,11 +149,20 @@ describe('Ad Repository', () => {
|
||||||
provide: TIME_CONVERTER,
|
provide: TIME_CONVERTER,
|
||||||
useClass: TimeConverter,
|
useClass: TimeConverter,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
provide: AD_MESSAGE_PUBLISHER,
|
||||||
|
useValue: mockMessagePublisher,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
}).compile();
|
})
|
||||||
|
// disable logging
|
||||||
|
.setLogger(mockLogger)
|
||||||
|
.compile();
|
||||||
|
|
||||||
prismaService = module.get<PrismaService>(PrismaService);
|
prismaService = module.get<PrismaService>(PrismaService);
|
||||||
adRepository = module.get<AdRepository>(AD_REPOSITORY);
|
adRepository = module.get<AdRepository>(AD_REPOSITORY);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
await prismaService.$disconnect();
|
await prismaService.$disconnect();
|
||||||
});
|
});
|
||||||
|
@ -292,129 +170,7 @@ describe('Ad Repository', () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await prismaService.ad.deleteMany();
|
await prismaService.ad.deleteMany();
|
||||||
});
|
});
|
||||||
// describe('findAll', () => {
|
|
||||||
// it('should return an empty data array', async () => {
|
|
||||||
// const res = await adRepository.findAll();
|
|
||||||
// expect(res).toEqual({
|
|
||||||
// data: [],
|
|
||||||
// total: 0,
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
|
|
||||||
// describe('drivers', () => {
|
|
||||||
// it('should return a data array with 8 punctual driver ads', async () => {
|
|
||||||
// await createPunctualDriverAds(8);
|
|
||||||
// const ads = await adRepository.findAll();
|
|
||||||
// expect(ads.data.length).toBe(8);
|
|
||||||
// expect(ads.total).toBe(8);
|
|
||||||
// expect(ads.data[0].driver).toBeTruthy();
|
|
||||||
// expect(ads.data[0].passenger).toBeFalsy();
|
|
||||||
// });
|
|
||||||
|
|
||||||
// it('should return a data array limited to 10 punctual driver ads', async () => {
|
|
||||||
// await createPunctualDriverAds(20);
|
|
||||||
// const ads = await adRepository.findAll();
|
|
||||||
// expect(ads.data.length).toBe(10);
|
|
||||||
// expect(ads.total).toBe(20);
|
|
||||||
// expect(ads.data[1].driver).toBeTruthy();
|
|
||||||
// expect(ads.data[1].passenger).toBeFalsy();
|
|
||||||
// });
|
|
||||||
|
|
||||||
// it('should return a data array with 8 recurrent driver ads', async () => {
|
|
||||||
// await createRecurrentDriverAds(8);
|
|
||||||
// const ads = await adRepository.findAll();
|
|
||||||
// expect(ads.data.length).toBe(8);
|
|
||||||
// expect(ads.total).toBe(8);
|
|
||||||
// expect(ads.data[2].driver).toBeTruthy();
|
|
||||||
// expect(ads.data[2].passenger).toBeFalsy();
|
|
||||||
// });
|
|
||||||
|
|
||||||
// it('should return a data array limited to 10 recurrent driver ads', async () => {
|
|
||||||
// await createRecurrentDriverAds(20);
|
|
||||||
// const ads = await adRepository.findAll();
|
|
||||||
// expect(ads.data.length).toBe(10);
|
|
||||||
// expect(ads.total).toBe(20);
|
|
||||||
// expect(ads.data[3].driver).toBeTruthy();
|
|
||||||
// expect(ads.data[3].passenger).toBeFalsy();
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
|
|
||||||
// describe('passengers', () => {
|
|
||||||
// it('should return a data array with 7 punctual passenger ads', async () => {
|
|
||||||
// await createPunctualPassengerAds(7);
|
|
||||||
// const ads = await adRepository.findAll();
|
|
||||||
// expect(ads.data.length).toBe(7);
|
|
||||||
// expect(ads.total).toBe(7);
|
|
||||||
// expect(ads.data[0].passenger).toBeTruthy();
|
|
||||||
// expect(ads.data[0].driver).toBeFalsy();
|
|
||||||
// });
|
|
||||||
|
|
||||||
// it('should return a data array limited to 10 punctual passenger ads', async () => {
|
|
||||||
// await createPunctualPassengerAds(15);
|
|
||||||
// const ads = await adRepository.findAll();
|
|
||||||
// expect(ads.data.length).toBe(10);
|
|
||||||
// expect(ads.total).toBe(15);
|
|
||||||
// expect(ads.data[1].passenger).toBeTruthy();
|
|
||||||
// expect(ads.data[1].driver).toBeFalsy();
|
|
||||||
// });
|
|
||||||
|
|
||||||
// it('should return a data array with 7 recurrent passenger ads', async () => {
|
|
||||||
// await createRecurrentPassengerAds(7);
|
|
||||||
// const ads = await adRepository.findAll();
|
|
||||||
// expect(ads.data.length).toBe(7);
|
|
||||||
// expect(ads.total).toBe(7);
|
|
||||||
// expect(ads.data[2].passenger).toBeTruthy();
|
|
||||||
// expect(ads.data[2].driver).toBeFalsy();
|
|
||||||
// });
|
|
||||||
|
|
||||||
// it('should return a data array limited to 10 recurrent passenger ads', async () => {
|
|
||||||
// await createRecurrentPassengerAds(15);
|
|
||||||
// const ads = await adRepository.findAll();
|
|
||||||
// expect(ads.data.length).toBe(10);
|
|
||||||
// expect(ads.total).toBe(15);
|
|
||||||
// expect(ads.data[3].passenger).toBeTruthy();
|
|
||||||
// expect(ads.data[3].driver).toBeFalsy();
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
|
|
||||||
// describe('drivers and passengers', () => {
|
|
||||||
// it('should return a data array with 6 punctual driver and passenger ads', async () => {
|
|
||||||
// await createPunctualDriverPassengerAds(6);
|
|
||||||
// const ads = await adRepository.findAll();
|
|
||||||
// expect(ads.data.length).toBe(6);
|
|
||||||
// expect(ads.total).toBe(6);
|
|
||||||
// expect(ads.data[0].passenger).toBeTruthy();
|
|
||||||
// expect(ads.data[0].driver).toBeTruthy();
|
|
||||||
// });
|
|
||||||
|
|
||||||
// it('should return a data array limited to 10 punctual driver and passenger ads', async () => {
|
|
||||||
// await createPunctualDriverPassengerAds(16);
|
|
||||||
// const ads = await adRepository.findAll();
|
|
||||||
// expect(ads.data.length).toBe(10);
|
|
||||||
// expect(ads.total).toBe(16);
|
|
||||||
// expect(ads.data[1].passenger).toBeTruthy();
|
|
||||||
// expect(ads.data[1].driver).toBeTruthy();
|
|
||||||
// });
|
|
||||||
|
|
||||||
// it('should return a data array with 6 recurrent driver and passenger ads', async () => {
|
|
||||||
// await createRecurrentDriverPassengerAds(6);
|
|
||||||
// const ads = await adRepository.findAll();
|
|
||||||
// expect(ads.data.length).toBe(6);
|
|
||||||
// expect(ads.total).toBe(6);
|
|
||||||
// expect(ads.data[2].passenger).toBeTruthy();
|
|
||||||
// expect(ads.data[2].driver).toBeTruthy();
|
|
||||||
// });
|
|
||||||
|
|
||||||
// it('should return a data array limited to 10 recurrent driver and passenger ads', async () => {
|
|
||||||
// await createRecurrentDriverPassengerAds(16);
|
|
||||||
// const ads = await adRepository.findAll();
|
|
||||||
// expect(ads.data.length).toBe(10);
|
|
||||||
// expect(ads.total).toBe(16);
|
|
||||||
// expect(ads.data[3].passenger).toBeTruthy();
|
|
||||||
// expect(ads.data[3].driver).toBeTruthy();
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
describe('findOneById', () => {
|
describe('findOneById', () => {
|
||||||
it('should return an ad', async () => {
|
it('should return an ad', async () => {
|
||||||
await createPunctualDriverAds(1);
|
await createPunctualDriverAds(1);
|
||||||
|
@ -424,80 +180,97 @@ describe('Ad Repository', () => {
|
||||||
|
|
||||||
expect(result.id).toBe(baseUuid.uuid);
|
expect(result.id).toBe(baseUuid.uuid);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// it('should return null', async () => {
|
describe('create', () => {
|
||||||
// const ad = await adRepository.findOneById(
|
it('should create an ad', async () => {
|
||||||
// '544572be-11fb-4244-8235-587221fc9104',
|
const beforeCount = await prismaService.ad.count();
|
||||||
// );
|
|
||||||
// expect(ad).toBeNull();
|
const createAdProps: CreateAdProps = {
|
||||||
|
userId: 'b4b56444-f8d3-4110-917c-e37bba77f383',
|
||||||
|
driver: true,
|
||||||
|
passenger: false,
|
||||||
|
frequency: Frequency.PUNCTUAL,
|
||||||
|
fromDate: '2023-02-01',
|
||||||
|
toDate: '2023-02-01',
|
||||||
|
schedule: {
|
||||||
|
wed: '12:05',
|
||||||
|
},
|
||||||
|
marginDurations: {
|
||||||
|
wed: 900,
|
||||||
|
},
|
||||||
|
seatsProposed: 3,
|
||||||
|
seatsRequested: 1,
|
||||||
|
strict: false,
|
||||||
|
waypoints: [
|
||||||
|
{
|
||||||
|
position: 0,
|
||||||
|
address: {
|
||||||
|
locality: 'Nice',
|
||||||
|
postalCode: '06000',
|
||||||
|
country: 'France',
|
||||||
|
coordinates: {
|
||||||
|
lon: 43.7102,
|
||||||
|
lat: 7.262,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
position: 1,
|
||||||
|
address: {
|
||||||
|
locality: 'Marseille',
|
||||||
|
postalCode: '13000',
|
||||||
|
country: 'France',
|
||||||
|
coordinates: {
|
||||||
|
lon: 43.2965,
|
||||||
|
lat: 5.3698,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const defaultAdProps: DefaultAdProps = {
|
||||||
|
driver: false,
|
||||||
|
passenger: true,
|
||||||
|
marginDurations: {
|
||||||
|
mon: 900,
|
||||||
|
tue: 900,
|
||||||
|
wed: 900,
|
||||||
|
thu: 900,
|
||||||
|
fri: 900,
|
||||||
|
sat: 900,
|
||||||
|
sun: 900,
|
||||||
|
},
|
||||||
|
seatsProposed: 3,
|
||||||
|
seatsRequested: 1,
|
||||||
|
strict: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
const adToCreate: AdEntity = AdEntity.create(
|
||||||
|
createAdProps,
|
||||||
|
defaultAdProps,
|
||||||
|
);
|
||||||
|
await adRepository.insert(adToCreate);
|
||||||
|
|
||||||
|
const afterCount = await prismaService.ad.count();
|
||||||
|
|
||||||
|
expect(afterCount - beforeCount).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
// it('should throw a UniqueConstraintException if ad already exists', async () => {
|
||||||
|
// await prismaService.ad.create({
|
||||||
|
// data: {
|
||||||
|
// uuid: uuid,
|
||||||
|
// password: bcrypt.hashSync(`password`, 10),
|
||||||
|
// },
|
||||||
|
// });
|
||||||
|
|
||||||
|
// const authenticationToCreate: AuthenticationEntity =
|
||||||
|
// await AuthenticationEntity.create(createAuthenticationProps);
|
||||||
|
// await expect(
|
||||||
|
// authenticationRepository.insert(authenticationToCreate),
|
||||||
|
// ).rejects.toBeInstanceOf(UniqueConstraintException);
|
||||||
// });
|
// });
|
||||||
});
|
});
|
||||||
// describe('create', () => {
|
|
||||||
// it('should create a punctual ad', async () => {
|
|
||||||
// const beforeCount = await prismaService.ad.count();
|
|
||||||
// const adToCreate: AdDTO = new AdDTO();
|
|
||||||
|
|
||||||
// adToCreate.uuid = 'be459a29-7a41-4c0b-b371-abe90bfb6f00';
|
|
||||||
// adToCreate.userUuid = '4e52b54d-a729-4dbd-9283-f84a11bb2200';
|
|
||||||
// adToCreate.driver = true;
|
|
||||||
// adToCreate.passenger = false;
|
|
||||||
// adToCreate.frequency = Frequency.PUNCTUAL;
|
|
||||||
// adToCreate.fromDate = new Date('05-22-2023 09:36');
|
|
||||||
// adToCreate.toDate = new Date('05-22-2023 09:36');
|
|
||||||
// adToCreate.monTime = '09:36';
|
|
||||||
// adToCreate.monMargin = 900;
|
|
||||||
// adToCreate.tueMargin = 900;
|
|
||||||
// adToCreate.wedMargin = 900;
|
|
||||||
// adToCreate.thuMargin = 900;
|
|
||||||
// adToCreate.friMargin = 900;
|
|
||||||
// adToCreate.satMargin = 900;
|
|
||||||
// adToCreate.sunMargin = 900;
|
|
||||||
// adToCreate.seatsProposed = 3;
|
|
||||||
// adToCreate.seatsRequested = 0;
|
|
||||||
// adToCreate.strict = false;
|
|
||||||
// adToCreate.waypoints = {
|
|
||||||
// create: [originWaypoint as Waypoint, destinationWaypoint as Waypoint],
|
|
||||||
// };
|
|
||||||
// const ad = await adRepository.create(adToCreate);
|
|
||||||
|
|
||||||
// const afterCount = await prismaService.ad.count();
|
|
||||||
|
|
||||||
// expect(afterCount - beforeCount).toBe(1);
|
|
||||||
// expect(ad.uuid).toBe('be459a29-7a41-4c0b-b371-abe90bfb6f00');
|
|
||||||
// });
|
|
||||||
// it('should create a recurrent ad', async () => {
|
|
||||||
// const beforeCount = await prismaService.ad.count();
|
|
||||||
// const adToCreate: AdDTO = new AdDTO();
|
|
||||||
|
|
||||||
// adToCreate.uuid = '137a26fa-4b38-48ba-aecf-1a75f6b20f3d';
|
|
||||||
// adToCreate.userUuid = '4e52b54d-a729-4dbd-9283-f84a11bb2200';
|
|
||||||
// adToCreate.driver = true;
|
|
||||||
// adToCreate.passenger = false;
|
|
||||||
// adToCreate.frequency = Frequency.RECURRENT;
|
|
||||||
// adToCreate.fromDate = new Date('01-15-2023 ');
|
|
||||||
// adToCreate.toDate = new Date('10-31-2023');
|
|
||||||
// adToCreate.monTime = '07:30';
|
|
||||||
// adToCreate.friTime = '07:45';
|
|
||||||
// adToCreate.thuTime = '08:00';
|
|
||||||
// adToCreate.monMargin = 900;
|
|
||||||
// adToCreate.tueMargin = 900;
|
|
||||||
// adToCreate.wedMargin = 900;
|
|
||||||
// adToCreate.thuMargin = 900;
|
|
||||||
// adToCreate.friMargin = 900;
|
|
||||||
// adToCreate.satMargin = 900;
|
|
||||||
// adToCreate.sunMargin = 900;
|
|
||||||
// adToCreate.seatsProposed = 2;
|
|
||||||
// adToCreate.seatsRequested = 0;
|
|
||||||
// adToCreate.strict = false;
|
|
||||||
// adToCreate.waypoints = {
|
|
||||||
// create: [originWaypoint as Waypoint, destinationWaypoint as Waypoint],
|
|
||||||
// };
|
|
||||||
// const ad = await adRepository.create(adToCreate);
|
|
||||||
|
|
||||||
// const afterCount = await prismaService.ad.count();
|
|
||||||
|
|
||||||
// expect(afterCount - beforeCount).toBe(1);
|
|
||||||
// expect(ad.uuid).toBe('137a26fa-4b38-48ba-aecf-1a75f6b20f3d');
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,94 +0,0 @@
|
||||||
import { Frequency } from '@modules/ad/core/domain/ad.types';
|
|
||||||
import { PublishLogMessageWhenAdIsCreatedDomainEventHandler } from '@modules/ad/core/application/event-handlers/publish-log-message-when-ad-is-created.domain-event-handler';
|
|
||||||
import { AdCreatedDomainEvent } from '@modules/ad/core/domain/events/ad-created.domain-events';
|
|
||||||
import { Test, TestingModule } from '@nestjs/testing';
|
|
||||||
import { MESSAGE_PUBLISHER } from '@src/app.constants';
|
|
||||||
|
|
||||||
const mockMessagePublisher = {
|
|
||||||
publish: jest.fn().mockImplementation(),
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('Publish log message when ad is created domain event handler', () => {
|
|
||||||
let publishLogMessageWhenAdIsCreatedDomainEventHandler: PublishLogMessageWhenAdIsCreatedDomainEventHandler;
|
|
||||||
|
|
||||||
beforeAll(async () => {
|
|
||||||
const module: TestingModule = await Test.createTestingModule({
|
|
||||||
providers: [
|
|
||||||
{
|
|
||||||
provide: MESSAGE_PUBLISHER,
|
|
||||||
useValue: mockMessagePublisher,
|
|
||||||
},
|
|
||||||
PublishLogMessageWhenAdIsCreatedDomainEventHandler,
|
|
||||||
],
|
|
||||||
}).compile();
|
|
||||||
|
|
||||||
publishLogMessageWhenAdIsCreatedDomainEventHandler =
|
|
||||||
module.get<PublishLogMessageWhenAdIsCreatedDomainEventHandler>(
|
|
||||||
PublishLogMessageWhenAdIsCreatedDomainEventHandler,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should publish a log message', () => {
|
|
||||||
jest.spyOn(mockMessagePublisher, 'publish');
|
|
||||||
const adCreatedDomainEvent: AdCreatedDomainEvent = {
|
|
||||||
id: 'some-domain-event-id',
|
|
||||||
aggregateId: 'some-aggregate-id',
|
|
||||||
userId: 'some-user-id',
|
|
||||||
driver: false,
|
|
||||||
passenger: true,
|
|
||||||
frequency: Frequency.PUNCTUAL,
|
|
||||||
fromDate: '2023-06-28',
|
|
||||||
toDate: '2023-06-28',
|
|
||||||
monTime: undefined,
|
|
||||||
tueTime: undefined,
|
|
||||||
wedTime: '07:15',
|
|
||||||
thuTime: undefined,
|
|
||||||
friTime: undefined,
|
|
||||||
satTime: undefined,
|
|
||||||
sunTime: undefined,
|
|
||||||
monMarginDuration: 900,
|
|
||||||
tueMarginDuration: 900,
|
|
||||||
wedMarginDuration: 900,
|
|
||||||
thuMarginDuration: 900,
|
|
||||||
friMarginDuration: 900,
|
|
||||||
satMarginDuration: 900,
|
|
||||||
sunMarginDuration: 900,
|
|
||||||
seatsProposed: 3,
|
|
||||||
seatsRequested: 1,
|
|
||||||
strict: false,
|
|
||||||
waypoints: [
|
|
||||||
{
|
|
||||||
position: 0,
|
|
||||||
houseNumber: '5',
|
|
||||||
street: 'Avenue Foch',
|
|
||||||
locality: 'Nancy',
|
|
||||||
postalCode: '54000',
|
|
||||||
country: 'France',
|
|
||||||
lat: 48.689445,
|
|
||||||
lon: 6.1765102,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
position: 1,
|
|
||||||
locality: 'Paris',
|
|
||||||
postalCode: '75000',
|
|
||||||
country: 'France',
|
|
||||||
lat: 48.8566,
|
|
||||||
lon: 2.3522,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
metadata: {
|
|
||||||
timestamp: new Date('2023-06-28T05:00:00Z').getTime(),
|
|
||||||
correlationId: 'some-correlation-id',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
publishLogMessageWhenAdIsCreatedDomainEventHandler.handle(
|
|
||||||
adCreatedDomainEvent,
|
|
||||||
);
|
|
||||||
expect(publishLogMessageWhenAdIsCreatedDomainEventHandler).toBeDefined();
|
|
||||||
expect(mockMessagePublisher.publish).toHaveBeenCalledTimes(1);
|
|
||||||
expect(mockMessagePublisher.publish).toHaveBeenCalledWith(
|
|
||||||
'logging.ad.created.info',
|
|
||||||
'{"id":"some-domain-event-id","aggregateId":"some-aggregate-id","userId":"some-user-id","driver":false,"passenger":true,"frequency":"PUNCTUAL","fromDate":"2023-06-28","toDate":"2023-06-28","wedTime":"07:15","monMarginDuration":900,"tueMarginDuration":900,"wedMarginDuration":900,"thuMarginDuration":900,"friMarginDuration":900,"satMarginDuration":900,"sunMarginDuration":900,"seatsProposed":3,"seatsRequested":1,"strict":false,"waypoints":[{"position":0,"houseNumber":"5","street":"Avenue Foch","locality":"Nancy","postalCode":"54000","country":"France","lat":48.689445,"lon":6.1765102},{"position":1,"locality":"Paris","postalCode":"75000","country":"France","lat":48.8566,"lon":2.3522}],"metadata":{"timestamp":1687928400000,"correlationId":"some-correlation-id"}}',
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -2,7 +2,7 @@ import { Frequency } from '@modules/ad/core/domain/ad.types';
|
||||||
import { PublishMessageWhenAdIsCreatedDomainEventHandler } from '@modules/ad/core/application/event-handlers/publish-message-when-ad-is-created.domain-event-handler';
|
import { PublishMessageWhenAdIsCreatedDomainEventHandler } from '@modules/ad/core/application/event-handlers/publish-message-when-ad-is-created.domain-event-handler';
|
||||||
import { AdCreatedDomainEvent } from '@modules/ad/core/domain/events/ad-created.domain-events';
|
import { AdCreatedDomainEvent } from '@modules/ad/core/domain/events/ad-created.domain-events';
|
||||||
import { Test, TestingModule } from '@nestjs/testing';
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
import { MESSAGE_PUBLISHER } from '@src/app.constants';
|
import { AD_MESSAGE_PUBLISHER } from '@modules/ad/ad.di-tokens';
|
||||||
|
|
||||||
const mockMessagePublisher = {
|
const mockMessagePublisher = {
|
||||||
publish: jest.fn().mockImplementation(),
|
publish: jest.fn().mockImplementation(),
|
||||||
|
@ -15,7 +15,7 @@ describe('Publish message when ad is created domain event handler', () => {
|
||||||
const module: TestingModule = await Test.createTestingModule({
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
providers: [
|
providers: [
|
||||||
{
|
{
|
||||||
provide: MESSAGE_PUBLISHER,
|
provide: AD_MESSAGE_PUBLISHER,
|
||||||
useValue: mockMessagePublisher,
|
useValue: mockMessagePublisher,
|
||||||
},
|
},
|
||||||
PublishMessageWhenAdIsCreatedDomainEventHandler,
|
PublishMessageWhenAdIsCreatedDomainEventHandler,
|
||||||
|
|
|
@ -50,6 +50,10 @@ const mockTimeConverter: TimeConverterPort = {
|
||||||
utcDatetimeToLocalTime: jest.fn(),
|
utcDatetimeToLocalTime: jest.fn(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const mockMessagePublisher = {
|
||||||
|
publish: jest.fn().mockImplementation(),
|
||||||
|
};
|
||||||
|
|
||||||
describe('Ad repository', () => {
|
describe('Ad repository', () => {
|
||||||
let prismaService: PrismaService;
|
let prismaService: PrismaService;
|
||||||
let adMapper: AdMapper;
|
let adMapper: AdMapper;
|
||||||
|
@ -82,7 +86,12 @@ describe('Ad repository', () => {
|
||||||
});
|
});
|
||||||
it('should be defined', () => {
|
it('should be defined', () => {
|
||||||
expect(
|
expect(
|
||||||
new AdRepository(prismaService, adMapper, eventEmitter),
|
new AdRepository(
|
||||||
|
prismaService,
|
||||||
|
adMapper,
|
||||||
|
eventEmitter,
|
||||||
|
mockMessagePublisher,
|
||||||
|
),
|
||||||
).toBeDefined();
|
).toBeDefined();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
export interface CheckRepositoryPort {
|
|
||||||
healthCheck(): Promise<boolean>;
|
|
||||||
}
|
|
|
@ -1,48 +0,0 @@
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
|
||||||
import {
|
|
||||||
HealthCheckError,
|
|
||||||
HealthCheckResult,
|
|
||||||
HealthIndicator,
|
|
||||||
HealthIndicatorResult,
|
|
||||||
} from '@nestjs/terminus';
|
|
||||||
import { CheckRepositoryPort } from '../ports/check-repository.port';
|
|
||||||
import { AD_REPOSITORY } from '@modules/health/health.di-tokens';
|
|
||||||
import { AdRepositoryPort } from '@modules/ad/core/application/ports/ad.repository.port';
|
|
||||||
import { MESSAGE_PUBLISHER } from '@src/app.constants';
|
|
||||||
import { LOGGING_AD_HEALTH_CRIT } from '@modules/health/health.constants';
|
|
||||||
import { MessagePublisherPort } from '@mobicoop/ddd-library';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class RepositoriesHealthIndicatorUseCase extends HealthIndicator {
|
|
||||||
private _checkRepositories: CheckRepositoryPort[];
|
|
||||||
constructor(
|
|
||||||
@Inject(AD_REPOSITORY)
|
|
||||||
private readonly adRepository: AdRepositoryPort,
|
|
||||||
@Inject(MESSAGE_PUBLISHER)
|
|
||||||
private readonly messagePublisher: MessagePublisherPort,
|
|
||||||
) {
|
|
||||||
super();
|
|
||||||
this._checkRepositories = [adRepository];
|
|
||||||
}
|
|
||||||
isHealthy = async (key: string): Promise<HealthIndicatorResult> => {
|
|
||||||
try {
|
|
||||||
await Promise.all(
|
|
||||||
this._checkRepositories.map(
|
|
||||||
async (checkRepository: CheckRepositoryPort) => {
|
|
||||||
await checkRepository.healthCheck();
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
return this.getStatus(key, true);
|
|
||||||
} catch (error) {
|
|
||||||
const healthCheckResult: HealthCheckResult = error;
|
|
||||||
this.messagePublisher.publish(
|
|
||||||
LOGGING_AD_HEALTH_CRIT,
|
|
||||||
JSON.stringify(healthCheckResult.error),
|
|
||||||
);
|
|
||||||
throw new HealthCheckError('Repository', {
|
|
||||||
repository: error.message,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
export const LOGGING_AD_HEALTH_CRIT = 'logging.ad.health.crit';
|
|
|
@ -1 +0,0 @@
|
||||||
export const AD_REPOSITORY = Symbol('AD_REPOSITORY');
|
|
|
@ -1,37 +0,0 @@
|
||||||
import { Module, Provider } from '@nestjs/common';
|
|
||||||
import { HealthHttpController } from './interface/http-controllers/health.http.controller';
|
|
||||||
import { TerminusModule } from '@nestjs/terminus';
|
|
||||||
import { MESSAGE_PUBLISHER } from 'src/app.constants';
|
|
||||||
import { RepositoriesHealthIndicatorUseCase } from './core/application/usecases/repositories.health-indicator.usecase';
|
|
||||||
import { AdRepository } from '../ad/infrastructure/ad.repository';
|
|
||||||
import { AD_REPOSITORY } from './health.di-tokens';
|
|
||||||
import { HealthGrpcController } from './interface/grpc-controllers/health.grpc.controller';
|
|
||||||
import { AdModule } from '@modules/ad/ad.module';
|
|
||||||
import { MessageBrokerPublisher } from '@mobicoop/message-broker-module';
|
|
||||||
|
|
||||||
const grpcControllers = [HealthGrpcController];
|
|
||||||
|
|
||||||
const httpControllers = [HealthHttpController];
|
|
||||||
|
|
||||||
const useCases: Provider[] = [RepositoriesHealthIndicatorUseCase];
|
|
||||||
|
|
||||||
const repositories: Provider[] = [
|
|
||||||
{
|
|
||||||
provide: AD_REPOSITORY,
|
|
||||||
useClass: AdRepository,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const messageBrokers: Provider[] = [
|
|
||||||
{
|
|
||||||
provide: MESSAGE_PUBLISHER,
|
|
||||||
useClass: MessageBrokerPublisher,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
@Module({
|
|
||||||
imports: [TerminusModule, AdModule],
|
|
||||||
controllers: [...grpcControllers, ...httpControllers],
|
|
||||||
providers: [...useCases, ...repositories, ...messageBrokers],
|
|
||||||
})
|
|
||||||
export class HealthModule {}
|
|
|
@ -1,42 +0,0 @@
|
||||||
import { Controller } from '@nestjs/common';
|
|
||||||
import { GrpcMethod } from '@nestjs/microservices';
|
|
||||||
import { RepositoriesHealthIndicatorUseCase } from '../../core/application/usecases/repositories.health-indicator.usecase';
|
|
||||||
|
|
||||||
export enum ServingStatus {
|
|
||||||
UNKNOWN = 0,
|
|
||||||
SERVING = 1,
|
|
||||||
NOT_SERVING = 2,
|
|
||||||
}
|
|
||||||
|
|
||||||
interface HealthCheckRequest {
|
|
||||||
service: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface HealthCheckResponse {
|
|
||||||
status: ServingStatus;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Controller()
|
|
||||||
export class HealthGrpcController {
|
|
||||||
constructor(
|
|
||||||
private readonly repositoriesHealthIndicatorUseCase: RepositoriesHealthIndicatorUseCase,
|
|
||||||
) {}
|
|
||||||
|
|
||||||
@GrpcMethod('Health', 'Check')
|
|
||||||
async check(
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
data?: HealthCheckRequest,
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
metadata?: any,
|
|
||||||
): Promise<HealthCheckResponse> {
|
|
||||||
const healthCheck = await this.repositoriesHealthIndicatorUseCase.isHealthy(
|
|
||||||
'repositories',
|
|
||||||
);
|
|
||||||
return {
|
|
||||||
status:
|
|
||||||
healthCheck['repositories'].status == 'up'
|
|
||||||
? ServingStatus.SERVING
|
|
||||||
: ServingStatus.NOT_SERVING,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
syntax = "proto3";
|
|
||||||
|
|
||||||
package health;
|
|
||||||
|
|
||||||
|
|
||||||
service Health {
|
|
||||||
rpc Check(HealthCheckRequest) returns (HealthCheckResponse);
|
|
||||||
}
|
|
||||||
|
|
||||||
message HealthCheckRequest {
|
|
||||||
string service = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message HealthCheckResponse {
|
|
||||||
enum ServingStatus {
|
|
||||||
UNKNOWN = 0;
|
|
||||||
SERVING = 1;
|
|
||||||
NOT_SERVING = 2;
|
|
||||||
}
|
|
||||||
ServingStatus status = 1;
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
import { RepositoriesHealthIndicatorUseCase } from '@modules/health/core/application/usecases/repositories.health-indicator.usecase';
|
|
||||||
import { Controller, Get } from '@nestjs/common';
|
|
||||||
import {
|
|
||||||
HealthCheckService,
|
|
||||||
HealthCheck,
|
|
||||||
HealthCheckResult,
|
|
||||||
} from '@nestjs/terminus';
|
|
||||||
|
|
||||||
@Controller('health')
|
|
||||||
export class HealthHttpController {
|
|
||||||
constructor(
|
|
||||||
private readonly repositoriesHealthIndicatorUseCase: RepositoriesHealthIndicatorUseCase,
|
|
||||||
private readonly healthCheckService: HealthCheckService,
|
|
||||||
) {}
|
|
||||||
|
|
||||||
@Get()
|
|
||||||
@HealthCheck()
|
|
||||||
async check(): Promise<HealthCheckResult> {
|
|
||||||
try {
|
|
||||||
return await this.healthCheckService.check([
|
|
||||||
async () =>
|
|
||||||
this.repositoriesHealthIndicatorUseCase.isHealthy('repositories'),
|
|
||||||
]);
|
|
||||||
} catch (error) {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,72 +0,0 @@
|
||||||
import { RepositoriesHealthIndicatorUseCase } from '@modules/health/core/application/usecases/repositories.health-indicator.usecase';
|
|
||||||
import {
|
|
||||||
HealthGrpcController,
|
|
||||||
ServingStatus,
|
|
||||||
} from '@modules/health/interface/grpc-controllers/health.grpc.controller';
|
|
||||||
import { Test, TestingModule } from '@nestjs/testing';
|
|
||||||
|
|
||||||
const mockRepositoriesHealthIndicatorUseCase = {
|
|
||||||
isHealthy: jest
|
|
||||||
.fn()
|
|
||||||
.mockImplementationOnce(() => ({
|
|
||||||
repositories: {
|
|
||||||
status: 'up',
|
|
||||||
},
|
|
||||||
}))
|
|
||||||
.mockImplementationOnce(() => ({
|
|
||||||
repositories: {
|
|
||||||
status: 'down',
|
|
||||||
},
|
|
||||||
})),
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('Health Grpc Controller', () => {
|
|
||||||
let healthGrpcController: HealthGrpcController;
|
|
||||||
|
|
||||||
beforeAll(async () => {
|
|
||||||
const module: TestingModule = await Test.createTestingModule({
|
|
||||||
providers: [
|
|
||||||
{
|
|
||||||
provide: RepositoriesHealthIndicatorUseCase,
|
|
||||||
useValue: mockRepositoriesHealthIndicatorUseCase,
|
|
||||||
},
|
|
||||||
HealthGrpcController,
|
|
||||||
],
|
|
||||||
}).compile();
|
|
||||||
|
|
||||||
healthGrpcController =
|
|
||||||
module.get<HealthGrpcController>(HealthGrpcController);
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(async () => {
|
|
||||||
jest.clearAllMocks();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be defined', () => {
|
|
||||||
expect(healthGrpcController).toBeDefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return a Serving status ', async () => {
|
|
||||||
jest.spyOn(mockRepositoriesHealthIndicatorUseCase, 'isHealthy');
|
|
||||||
const servingStatus: { status: ServingStatus } =
|
|
||||||
await healthGrpcController.check();
|
|
||||||
expect(servingStatus).toEqual({
|
|
||||||
status: ServingStatus.SERVING,
|
|
||||||
});
|
|
||||||
expect(
|
|
||||||
mockRepositoriesHealthIndicatorUseCase.isHealthy,
|
|
||||||
).toHaveBeenCalledTimes(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return a Not Serving status ', async () => {
|
|
||||||
jest.spyOn(mockRepositoriesHealthIndicatorUseCase, 'isHealthy');
|
|
||||||
const servingStatus: { status: ServingStatus } =
|
|
||||||
await healthGrpcController.check();
|
|
||||||
expect(servingStatus).toEqual({
|
|
||||||
status: ServingStatus.NOT_SERVING,
|
|
||||||
});
|
|
||||||
expect(
|
|
||||||
mockRepositoriesHealthIndicatorUseCase.isHealthy,
|
|
||||||
).toHaveBeenCalledTimes(1);
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,90 +0,0 @@
|
||||||
import { RepositoriesHealthIndicatorUseCase } from '@modules/health/core/application/usecases/repositories.health-indicator.usecase';
|
|
||||||
import { HealthHttpController } from '@modules/health/interface/http-controllers/health.http.controller';
|
|
||||||
import { HealthCheckResult, HealthCheckService } from '@nestjs/terminus';
|
|
||||||
import { Test, TestingModule } from '@nestjs/testing';
|
|
||||||
|
|
||||||
const mockHealthCheckService = {
|
|
||||||
check: jest
|
|
||||||
.fn()
|
|
||||||
.mockImplementationOnce(() => ({
|
|
||||||
status: 'ok',
|
|
||||||
info: {
|
|
||||||
repositories: {
|
|
||||||
status: 'up',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
error: {},
|
|
||||||
details: {
|
|
||||||
repositories: {
|
|
||||||
status: 'up',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}))
|
|
||||||
.mockImplementationOnce(() => ({
|
|
||||||
status: 'error',
|
|
||||||
info: {},
|
|
||||||
error: {
|
|
||||||
repository:
|
|
||||||
"\nInvalid `prisma.$queryRaw()` invocation:\n\n\nCan't reach database server at `v3-db`:`5432`\n\nPlease make sure your database server is running at `v3-db`:`5432`.",
|
|
||||||
},
|
|
||||||
details: {
|
|
||||||
repository:
|
|
||||||
"\nInvalid `prisma.$queryRaw()` invocation:\n\n\nCan't reach database server at `v3-db`:`5432`\n\nPlease make sure your database server is running at `v3-db`:`5432`.",
|
|
||||||
},
|
|
||||||
})),
|
|
||||||
};
|
|
||||||
|
|
||||||
const mockRepositoriesHealthIndicatorUseCase = {
|
|
||||||
isHealthy: jest.fn(),
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('Health Http Controller', () => {
|
|
||||||
let healthHttpController: HealthHttpController;
|
|
||||||
|
|
||||||
beforeAll(async () => {
|
|
||||||
const module: TestingModule = await Test.createTestingModule({
|
|
||||||
providers: [
|
|
||||||
{
|
|
||||||
provide: HealthCheckService,
|
|
||||||
useValue: mockHealthCheckService,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
provide: RepositoriesHealthIndicatorUseCase,
|
|
||||||
useValue: mockRepositoriesHealthIndicatorUseCase,
|
|
||||||
},
|
|
||||||
HealthHttpController,
|
|
||||||
],
|
|
||||||
}).compile();
|
|
||||||
|
|
||||||
healthHttpController =
|
|
||||||
module.get<HealthHttpController>(HealthHttpController);
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(async () => {
|
|
||||||
jest.clearAllMocks();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be defined', () => {
|
|
||||||
expect(healthHttpController).toBeDefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return an HealthCheckResult with Ok status ', async () => {
|
|
||||||
jest.spyOn(mockHealthCheckService, 'check');
|
|
||||||
jest.spyOn(mockRepositoriesHealthIndicatorUseCase, 'isHealthy');
|
|
||||||
|
|
||||||
const healthCheckResult: HealthCheckResult =
|
|
||||||
await healthHttpController.check();
|
|
||||||
expect(healthCheckResult.status).toBe('ok');
|
|
||||||
expect(mockHealthCheckService.check).toHaveBeenCalledTimes(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return an HealthCheckResult with Error status ', async () => {
|
|
||||||
jest.spyOn(mockHealthCheckService, 'check');
|
|
||||||
jest.spyOn(mockRepositoriesHealthIndicatorUseCase, 'isHealthy');
|
|
||||||
|
|
||||||
const healthCheckResult: HealthCheckResult =
|
|
||||||
await healthHttpController.check();
|
|
||||||
expect(healthCheckResult.status).toBe('error');
|
|
||||||
expect(mockHealthCheckService.check).toHaveBeenCalledTimes(1);
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,66 +0,0 @@
|
||||||
import { Test, TestingModule } from '@nestjs/testing';
|
|
||||||
import { HealthCheckError, HealthIndicatorResult } from '@nestjs/terminus';
|
|
||||||
import { RepositoriesHealthIndicatorUseCase } from '../../core/application/usecases/repositories.health-indicator.usecase';
|
|
||||||
import { AD_REPOSITORY } from '@modules/health/health.di-tokens';
|
|
||||||
import { MESSAGE_PUBLISHER } from '@src/app.constants';
|
|
||||||
import { DatabaseErrorException } from '@mobicoop/ddd-library';
|
|
||||||
|
|
||||||
const mockAdRepository = {
|
|
||||||
healthCheck: jest
|
|
||||||
.fn()
|
|
||||||
.mockImplementationOnce(() => {
|
|
||||||
return Promise.resolve(true);
|
|
||||||
})
|
|
||||||
.mockImplementation(() => {
|
|
||||||
throw new DatabaseErrorException('An error occured in the database');
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
|
|
||||||
const mockMessagePublisher = {
|
|
||||||
publish: jest.fn().mockImplementation(),
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('RepositoriesHealthIndicatorUseCase', () => {
|
|
||||||
let repositoriesHealthIndicatorUseCase: RepositoriesHealthIndicatorUseCase;
|
|
||||||
|
|
||||||
beforeAll(async () => {
|
|
||||||
const module: TestingModule = await Test.createTestingModule({
|
|
||||||
providers: [
|
|
||||||
RepositoriesHealthIndicatorUseCase,
|
|
||||||
{
|
|
||||||
provide: AD_REPOSITORY,
|
|
||||||
useValue: mockAdRepository,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
provide: MESSAGE_PUBLISHER,
|
|
||||||
useValue: mockMessagePublisher,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}).compile();
|
|
||||||
|
|
||||||
repositoriesHealthIndicatorUseCase =
|
|
||||||
module.get<RepositoriesHealthIndicatorUseCase>(
|
|
||||||
RepositoriesHealthIndicatorUseCase,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be defined', () => {
|
|
||||||
expect(repositoriesHealthIndicatorUseCase).toBeDefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('execute', () => {
|
|
||||||
it('should check health successfully', async () => {
|
|
||||||
const healthIndicatorResult: HealthIndicatorResult =
|
|
||||||
await repositoriesHealthIndicatorUseCase.isHealthy('repositories');
|
|
||||||
expect(healthIndicatorResult['repositories'].status).toBe('up');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should throw an error if database is unavailable', async () => {
|
|
||||||
jest.spyOn(mockMessagePublisher, 'publish');
|
|
||||||
await expect(
|
|
||||||
repositoriesHealthIndicatorUseCase.isHealthy('repositories'),
|
|
||||||
).rejects.toBeInstanceOf(HealthCheckError);
|
|
||||||
expect(mockMessagePublisher.publish).toHaveBeenCalledTimes(1);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -0,0 +1 @@
|
||||||
|
export const MESSAGE_PUBLISHER = Symbol('MESSAGE_PUBLISHER');
|
|
@ -0,0 +1,36 @@
|
||||||
|
import { Module, Provider } from '@nestjs/common';
|
||||||
|
import { MESSAGE_PUBLISHER } from './messager.di-tokens';
|
||||||
|
import {
|
||||||
|
MessageBrokerModule,
|
||||||
|
MessageBrokerModuleOptions,
|
||||||
|
MessageBrokerPublisher,
|
||||||
|
} from '@mobicoop/message-broker-module';
|
||||||
|
import { ConfigModule, ConfigService } from '@nestjs/config';
|
||||||
|
|
||||||
|
const imports = [
|
||||||
|
MessageBrokerModule.forRootAsync({
|
||||||
|
imports: [ConfigModule],
|
||||||
|
inject: [ConfigService],
|
||||||
|
useFactory: async (
|
||||||
|
configService: ConfigService,
|
||||||
|
): Promise<MessageBrokerModuleOptions> => ({
|
||||||
|
uri: configService.get<string>('MESSAGE_BROKER_URI'),
|
||||||
|
exchange: configService.get<string>('MESSAGE_BROKER_EXCHANGE'),
|
||||||
|
name: 'ad',
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
|
||||||
|
const providers: Provider[] = [
|
||||||
|
{
|
||||||
|
provide: MESSAGE_PUBLISHER,
|
||||||
|
useClass: MessageBrokerPublisher,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
imports,
|
||||||
|
providers,
|
||||||
|
exports: [MESSAGE_PUBLISHER],
|
||||||
|
})
|
||||||
|
export class MessagerModule {}
|
Loading…
Reference in New Issue