propagation; improve tests
This commit is contained in:
parent
984bb4f562
commit
0485afdec3
|
@ -107,6 +107,12 @@ The app exposes the following [gRPC](https://grpc.io/) services :
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
- **Propagate** : propagate all configuration items using the message broker
|
||||||
|
|
||||||
|
```json
|
||||||
|
{}
|
||||||
|
```
|
||||||
|
|
||||||
## Messages
|
## Messages
|
||||||
|
|
||||||
As mentionned earlier, RabbitMQ messages are sent after these events :
|
As mentionned earlier, RabbitMQ messages are sent after these events :
|
||||||
|
@ -117,6 +123,8 @@ As mentionned earlier, RabbitMQ messages are sent after these events :
|
||||||
|
|
||||||
- **Delete** (message : the uuid of the deleted configuration item)
|
- **Delete** (message : the uuid of the deleted configuration item)
|
||||||
|
|
||||||
|
- **Propagate** (message : all the configuration items)
|
||||||
|
|
||||||
Various messages are also sent for logging purpose.
|
Various messages are also sent for logging purpose.
|
||||||
|
|
||||||
## Tests
|
## Tests
|
||||||
|
|
|
@ -16,6 +16,7 @@ import { UpdateConfigurationRequest } from '../../domain/dtos/update-configurati
|
||||||
import { Configuration } from '../../domain/entities/configuration';
|
import { Configuration } from '../../domain/entities/configuration';
|
||||||
import { FindAllConfigurationsQuery } from '../../queries/find-all-configurations.query';
|
import { FindAllConfigurationsQuery } from '../../queries/find-all-configurations.query';
|
||||||
import { FindConfigurationByUuidQuery } from '../../queries/find-configuration-by-uuid.query';
|
import { FindConfigurationByUuidQuery } from '../../queries/find-configuration-by-uuid.query';
|
||||||
|
import { PropagateConfigurationsQuery } from '../../queries/propagate-configurations.query';
|
||||||
import { ConfigurationPresenter } from './configuration.presenter';
|
import { ConfigurationPresenter } from './configuration.presenter';
|
||||||
|
|
||||||
@UsePipes(
|
@UsePipes(
|
||||||
|
@ -141,4 +142,13 @@ export class ConfigurationController {
|
||||||
throw new RpcException({});
|
throw new RpcException({});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GrpcMethod('ConfigurationService', 'Propagate')
|
||||||
|
async propagate(): Promise<void> {
|
||||||
|
try {
|
||||||
|
await this._queryBus.execute(new PropagateConfigurationsQuery());
|
||||||
|
} catch (e) {
|
||||||
|
throw new RpcException({});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ service ConfigurationService {
|
||||||
rpc Create(Configuration) returns (Configuration);
|
rpc Create(Configuration) returns (Configuration);
|
||||||
rpc Update(Configuration) returns (Configuration);
|
rpc Update(Configuration) returns (Configuration);
|
||||||
rpc Delete(ConfigurationByUuid) returns (Empty);
|
rpc Delete(ConfigurationByUuid) returns (Empty);
|
||||||
|
rpc Propagate(Empty) returns (Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
message ConfigurationByUuid {
|
message ConfigurationByUuid {
|
||||||
|
|
|
@ -11,6 +11,7 @@ import { CreateConfigurationUseCase } from './domain/usecases/create-configurati
|
||||||
import { DeleteConfigurationUseCase } from './domain/usecases/delete-configuration.usecase';
|
import { DeleteConfigurationUseCase } from './domain/usecases/delete-configuration.usecase';
|
||||||
import { FindAllConfigurationsUseCase } from './domain/usecases/find-all-configurations.usecase';
|
import { FindAllConfigurationsUseCase } from './domain/usecases/find-all-configurations.usecase';
|
||||||
import { FindConfigurationByUuidUseCase } from './domain/usecases/find-configuration-by-uuid.usecase';
|
import { FindConfigurationByUuidUseCase } from './domain/usecases/find-configuration-by-uuid.usecase';
|
||||||
|
import { PropagateConfigurationsUseCase } from './domain/usecases/propagate-configurations.usecase';
|
||||||
import { UpdateConfigurationUseCase } from './domain/usecases/update-configuration.usecase';
|
import { UpdateConfigurationUseCase } from './domain/usecases/update-configuration.usecase';
|
||||||
import { ConfigurationProfile } from './mappers/configuration.profile';
|
import { ConfigurationProfile } from './mappers/configuration.profile';
|
||||||
|
|
||||||
|
@ -49,6 +50,7 @@ import { ConfigurationProfile } from './mappers/configuration.profile';
|
||||||
CreateConfigurationUseCase,
|
CreateConfigurationUseCase,
|
||||||
UpdateConfigurationUseCase,
|
UpdateConfigurationUseCase,
|
||||||
DeleteConfigurationUseCase,
|
DeleteConfigurationUseCase,
|
||||||
|
PropagateConfigurationsUseCase,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class ConfigurationModule {}
|
export class ConfigurationModule {}
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
import { Mapper } from '@automapper/core';
|
||||||
|
import { InjectMapper } from '@automapper/nestjs';
|
||||||
|
import { QueryHandler } from '@nestjs/cqrs';
|
||||||
|
import { ConfigurationMessagerPresenter } from '../../adapters/secondaries/configuration-messager.presenter';
|
||||||
|
import { ConfigurationMessager } from '../../adapters/secondaries/configuration.messager';
|
||||||
|
import { ConfigurationRepository } from '../../adapters/secondaries/configuration.repository';
|
||||||
|
import { LoggingMessager } from '../../adapters/secondaries/logging.messager';
|
||||||
|
import { PropagateConfigurationsQuery } from '../../queries/propagate-configurations.query';
|
||||||
|
import { Configuration } from '../entities/configuration';
|
||||||
|
|
||||||
|
@QueryHandler(PropagateConfigurationsQuery)
|
||||||
|
export class PropagateConfigurationsUseCase {
|
||||||
|
constructor(
|
||||||
|
private readonly _repository: ConfigurationRepository,
|
||||||
|
private readonly _configurationMessager: ConfigurationMessager,
|
||||||
|
private readonly _loggingMessager: LoggingMessager,
|
||||||
|
@InjectMapper() private readonly _mapper: Mapper,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
async execute(propagateConfigurationsQuery: PropagateConfigurationsQuery) {
|
||||||
|
try {
|
||||||
|
const configurations = await this._repository.findAll(1, 999999);
|
||||||
|
this._configurationMessager.publish(
|
||||||
|
'propagate',
|
||||||
|
JSON.stringify(
|
||||||
|
configurations.data.map((configuration) =>
|
||||||
|
this._mapper.map(
|
||||||
|
configuration,
|
||||||
|
Configuration,
|
||||||
|
ConfigurationMessagerPresenter,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
this._loggingMessager.publish('configuration.update.info', 'propagation');
|
||||||
|
} catch (error) {
|
||||||
|
this._loggingMessager.publish('configuration.update.crit', 'propagation');
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
export class PropagateConfigurationsQuery {}
|
|
@ -0,0 +1,38 @@
|
||||||
|
import { AmqpConnection } from '@golevelup/nestjs-rabbitmq';
|
||||||
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
|
import { ConfigurationMessager } from '../../adapters/secondaries/configuration.messager';
|
||||||
|
|
||||||
|
const mockAmqpConnection = {
|
||||||
|
publish: jest.fn().mockImplementation(),
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('ConfigurationMessager', () => {
|
||||||
|
let configurationMessager: ConfigurationMessager;
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
|
imports: [],
|
||||||
|
providers: [
|
||||||
|
ConfigurationMessager,
|
||||||
|
{
|
||||||
|
provide: AmqpConnection,
|
||||||
|
useValue: mockAmqpConnection,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}).compile();
|
||||||
|
|
||||||
|
configurationMessager = module.get<ConfigurationMessager>(
|
||||||
|
ConfigurationMessager,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be defined', () => {
|
||||||
|
expect(configurationMessager).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should publish a message', async () => {
|
||||||
|
jest.spyOn(mockAmqpConnection, 'publish');
|
||||||
|
await configurationMessager.publish('configuration.create.info', 'my-test');
|
||||||
|
expect(mockAmqpConnection.publish).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
});
|
|
@ -33,7 +33,11 @@ const mockConfigurationRepository = {
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
const mockMessager = {
|
const mockConfigurationMessager = {
|
||||||
|
publish: jest.fn().mockImplementation(),
|
||||||
|
};
|
||||||
|
|
||||||
|
const mockLoggingMessager = {
|
||||||
publish: jest.fn().mockImplementation(),
|
publish: jest.fn().mockImplementation(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -52,11 +56,11 @@ describe('CreateConfigurationUseCase', () => {
|
||||||
ConfigurationProfile,
|
ConfigurationProfile,
|
||||||
{
|
{
|
||||||
provide: ConfigurationMessager,
|
provide: ConfigurationMessager,
|
||||||
useValue: mockMessager,
|
useValue: mockConfigurationMessager,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
provide: LoggingMessager,
|
provide: LoggingMessager,
|
||||||
useValue: mockMessager,
|
useValue: mockLoggingMessager,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}).compile();
|
}).compile();
|
||||||
|
@ -72,11 +76,13 @@ describe('CreateConfigurationUseCase', () => {
|
||||||
|
|
||||||
describe('execute', () => {
|
describe('execute', () => {
|
||||||
it('should create and return a new configuration', async () => {
|
it('should create and return a new configuration', async () => {
|
||||||
|
jest.spyOn(mockConfigurationMessager, 'publish');
|
||||||
const newConfiguration: Configuration =
|
const newConfiguration: Configuration =
|
||||||
await createConfigurationUseCase.execute(newConfigurationCommand);
|
await createConfigurationUseCase.execute(newConfigurationCommand);
|
||||||
|
|
||||||
expect(newConfiguration.key).toBe(newConfigurationRequest.key);
|
expect(newConfiguration.key).toBe(newConfigurationRequest.key);
|
||||||
expect(newConfiguration.uuid).toBeDefined();
|
expect(newConfiguration.uuid).toBeDefined();
|
||||||
|
expect(mockConfigurationMessager.publish).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw an error if configuration already exists', async () => {
|
it('should throw an error if configuration already exists', async () => {
|
||||||
|
|
|
@ -1,44 +1,49 @@
|
||||||
import { classes } from '@automapper/classes';
|
import { classes } from '@automapper/classes';
|
||||||
import { AutomapperModule } from '@automapper/nestjs';
|
import { AutomapperModule } from '@automapper/nestjs';
|
||||||
import { Test, TestingModule } from '@nestjs/testing';
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
|
import { ICollection } from 'src/modules/database/src/interfaces/collection.interface';
|
||||||
import { ConfigurationMessager } from '../../adapters/secondaries/configuration.messager';
|
import { ConfigurationMessager } from '../../adapters/secondaries/configuration.messager';
|
||||||
import { ConfigurationRepository } from '../../adapters/secondaries/configuration.repository';
|
import { ConfigurationRepository } from '../../adapters/secondaries/configuration.repository';
|
||||||
import { LoggingMessager } from '../../adapters/secondaries/logging.messager';
|
import { LoggingMessager } from '../../adapters/secondaries/logging.messager';
|
||||||
import { DeleteConfigurationCommand } from '../../commands/delete-configuration.command';
|
import { DeleteConfigurationCommand } from '../../commands/delete-configuration.command';
|
||||||
import { Domain } from '../../domain/dtos/domain.enum';
|
import { Domain } from '../../domain/dtos/domain.enum';
|
||||||
|
import { Configuration } from '../../domain/entities/configuration';
|
||||||
import { DeleteConfigurationUseCase } from '../../domain/usecases/delete-configuration.usecase';
|
import { DeleteConfigurationUseCase } from '../../domain/usecases/delete-configuration.usecase';
|
||||||
import { ConfigurationProfile } from '../../mappers/configuration.profile';
|
import { ConfigurationProfile } from '../../mappers/configuration.profile';
|
||||||
|
|
||||||
const mockConfigurations = [
|
const mockConfigurations: ICollection<Configuration> = {
|
||||||
{
|
data: [
|
||||||
uuid: 'bb281075-1b98-4456-89d6-c643d3044a91',
|
{
|
||||||
domain: Domain.USER,
|
uuid: 'bb281075-1b98-4456-89d6-c643d3044a91',
|
||||||
key: 'key1',
|
domain: Domain.USER,
|
||||||
value: 'value1',
|
key: 'key1',
|
||||||
},
|
value: 'value1',
|
||||||
{
|
},
|
||||||
uuid: 'bb281075-1b98-4456-89d6-c643d3044a92',
|
{
|
||||||
domain: Domain.USER,
|
uuid: 'bb281075-1b98-4456-89d6-c643d3044a92',
|
||||||
key: 'key2',
|
domain: Domain.USER,
|
||||||
value: 'value2',
|
key: 'key2',
|
||||||
},
|
value: 'value2',
|
||||||
{
|
},
|
||||||
uuid: 'bb281075-1b98-4456-89d6-c643d3044a93',
|
{
|
||||||
domain: Domain.USER,
|
uuid: 'bb281075-1b98-4456-89d6-c643d3044a93',
|
||||||
key: 'key3',
|
domain: Domain.USER,
|
||||||
value: 'value3',
|
key: 'key3',
|
||||||
},
|
value: 'value3',
|
||||||
];
|
},
|
||||||
|
],
|
||||||
|
total: 3,
|
||||||
|
};
|
||||||
|
|
||||||
const mockConfigurationRepository = {
|
const mockConfigurationRepository = {
|
||||||
delete: jest
|
delete: jest
|
||||||
.fn()
|
.fn()
|
||||||
.mockImplementationOnce((uuid: string) => {
|
.mockImplementationOnce((uuid: string) => {
|
||||||
let savedConfiguration = {};
|
let savedConfiguration = {};
|
||||||
mockConfigurations.forEach((configuration, index) => {
|
mockConfigurations.data.forEach((configuration, index) => {
|
||||||
if (configuration.uuid === uuid) {
|
if (configuration.uuid === uuid) {
|
||||||
savedConfiguration = { ...configuration };
|
savedConfiguration = { ...configuration };
|
||||||
mockConfigurations.splice(index, 1);
|
mockConfigurations.data.splice(index, 1);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return savedConfiguration;
|
return savedConfiguration;
|
||||||
|
@ -48,10 +53,13 @@ const mockConfigurationRepository = {
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
const mockMessager = {
|
const mockConfigurationMessager = {
|
||||||
publish: jest.fn().mockImplementation(),
|
publish: jest.fn().mockImplementation(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const mockLoggingMessager = {
|
||||||
|
publish: jest.fn().mockImplementation(),
|
||||||
|
};
|
||||||
describe('DeleteConfigurationUseCase', () => {
|
describe('DeleteConfigurationUseCase', () => {
|
||||||
let deleteConfigurationUseCase: DeleteConfigurationUseCase;
|
let deleteConfigurationUseCase: DeleteConfigurationUseCase;
|
||||||
|
|
||||||
|
@ -67,11 +75,11 @@ describe('DeleteConfigurationUseCase', () => {
|
||||||
ConfigurationProfile,
|
ConfigurationProfile,
|
||||||
{
|
{
|
||||||
provide: ConfigurationMessager,
|
provide: ConfigurationMessager,
|
||||||
useValue: mockMessager,
|
useValue: mockConfigurationMessager,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
provide: LoggingMessager,
|
provide: LoggingMessager,
|
||||||
useValue: mockMessager,
|
useValue: mockLoggingMessager,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}).compile();
|
}).compile();
|
||||||
|
@ -87,16 +95,18 @@ describe('DeleteConfigurationUseCase', () => {
|
||||||
|
|
||||||
describe('execute', () => {
|
describe('execute', () => {
|
||||||
it('should delete a configuration', async () => {
|
it('should delete a configuration', async () => {
|
||||||
const savedUuid = mockConfigurations[0].uuid;
|
jest.spyOn(mockConfigurationMessager, 'publish');
|
||||||
|
const savedUuid = mockConfigurations.data[0].uuid;
|
||||||
const deleteConfigurationCommand = new DeleteConfigurationCommand(
|
const deleteConfigurationCommand = new DeleteConfigurationCommand(
|
||||||
savedUuid,
|
savedUuid,
|
||||||
);
|
);
|
||||||
await deleteConfigurationUseCase.execute(deleteConfigurationCommand);
|
await deleteConfigurationUseCase.execute(deleteConfigurationCommand);
|
||||||
|
|
||||||
const deletedConfiguration = mockConfigurations.find(
|
const deletedConfiguration = mockConfigurations.data.find(
|
||||||
(configuration) => configuration.uuid === savedUuid,
|
(configuration) => configuration.uuid === savedUuid,
|
||||||
);
|
);
|
||||||
expect(deletedConfiguration).toBeUndefined();
|
expect(deletedConfiguration).toBeUndefined();
|
||||||
|
expect(mockConfigurationMessager.publish).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
it('should throw an error if configuration does not exist', async () => {
|
it('should throw an error if configuration does not exist', async () => {
|
||||||
await expect(
|
await expect(
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
import { Test, TestingModule } from '@nestjs/testing';
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
|
import { ICollection } from 'src/modules/database/src/interfaces/collection.interface';
|
||||||
import { ConfigurationRepository } from '../../adapters/secondaries/configuration.repository';
|
import { ConfigurationRepository } from '../../adapters/secondaries/configuration.repository';
|
||||||
import { Domain } from '../../domain/dtos/domain.enum';
|
import { Domain } from '../../domain/dtos/domain.enum';
|
||||||
import { FindAllConfigurationsRequest } from '../../domain/dtos/find-all-configurations.request';
|
import { FindAllConfigurationsRequest } from '../../domain/dtos/find-all-configurations.request';
|
||||||
|
import { Configuration } from '../../domain/entities/configuration';
|
||||||
import { FindAllConfigurationsUseCase } from '../../domain/usecases/find-all-configurations.usecase';
|
import { FindAllConfigurationsUseCase } from '../../domain/usecases/find-all-configurations.usecase';
|
||||||
import { FindAllConfigurationsQuery } from '../../queries/find-all-configurations.query';
|
import { FindAllConfigurationsQuery } from '../../queries/find-all-configurations.query';
|
||||||
|
|
||||||
|
@ -13,26 +15,29 @@ findAllConfigurationsRequest.perPage = 10;
|
||||||
const findAllConfigurationsQuery: FindAllConfigurationsQuery =
|
const findAllConfigurationsQuery: FindAllConfigurationsQuery =
|
||||||
new FindAllConfigurationsQuery(findAllConfigurationsRequest);
|
new FindAllConfigurationsQuery(findAllConfigurationsRequest);
|
||||||
|
|
||||||
const mockConfigurations = [
|
const mockConfigurations: ICollection<Configuration> = {
|
||||||
{
|
data: [
|
||||||
uuid: 'bb281075-1b98-4456-89d6-c643d3044a91',
|
{
|
||||||
domain: Domain.USER,
|
uuid: 'bb281075-1b98-4456-89d6-c643d3044a91',
|
||||||
key: 'key1',
|
domain: Domain.USER,
|
||||||
value: 'value1',
|
key: 'key1',
|
||||||
},
|
value: 'value1',
|
||||||
{
|
},
|
||||||
uuid: 'bb281075-1b98-4456-89d6-c643d3044a92',
|
{
|
||||||
domain: Domain.USER,
|
uuid: 'bb281075-1b98-4456-89d6-c643d3044a92',
|
||||||
key: 'key2',
|
domain: Domain.USER,
|
||||||
value: 'value2',
|
key: 'key2',
|
||||||
},
|
value: 'value2',
|
||||||
{
|
},
|
||||||
uuid: 'bb281075-1b98-4456-89d6-c643d3044a93',
|
{
|
||||||
domain: Domain.USER,
|
uuid: 'bb281075-1b98-4456-89d6-c643d3044a93',
|
||||||
key: 'key3',
|
domain: Domain.USER,
|
||||||
value: 'value3',
|
key: 'key3',
|
||||||
},
|
value: 'value3',
|
||||||
];
|
},
|
||||||
|
],
|
||||||
|
total: 3,
|
||||||
|
};
|
||||||
|
|
||||||
const mockConfigurationRepository = {
|
const mockConfigurationRepository = {
|
||||||
findAll: jest
|
findAll: jest
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
import { AmqpConnection } from '@golevelup/nestjs-rabbitmq';
|
||||||
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
|
import { LoggingMessager } from '../../adapters/secondaries/logging.messager';
|
||||||
|
|
||||||
|
const mockAmqpConnection = {
|
||||||
|
publish: jest.fn().mockImplementation(),
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('LoggingMessager', () => {
|
||||||
|
let loggingMessager: LoggingMessager;
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
|
imports: [],
|
||||||
|
providers: [
|
||||||
|
LoggingMessager,
|
||||||
|
{
|
||||||
|
provide: AmqpConnection,
|
||||||
|
useValue: mockAmqpConnection,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}).compile();
|
||||||
|
|
||||||
|
loggingMessager = module.get<LoggingMessager>(LoggingMessager);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be defined', () => {
|
||||||
|
expect(LoggingMessager).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should publish a message', async () => {
|
||||||
|
jest.spyOn(mockAmqpConnection, 'publish');
|
||||||
|
await loggingMessager.publish('configuration.create.info', 'my-test');
|
||||||
|
expect(mockAmqpConnection.publish).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,109 @@
|
||||||
|
import { classes } from '@automapper/classes';
|
||||||
|
import { AutomapperModule } from '@automapper/nestjs';
|
||||||
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
|
import { ICollection } from 'src/modules/database/src/interfaces/collection.interface';
|
||||||
|
import { ConfigurationMessager } from '../../adapters/secondaries/configuration.messager';
|
||||||
|
import { ConfigurationRepository } from '../../adapters/secondaries/configuration.repository';
|
||||||
|
import { LoggingMessager } from '../../adapters/secondaries/logging.messager';
|
||||||
|
import { Domain } from '../../domain/dtos/domain.enum';
|
||||||
|
import { Configuration } from '../../domain/entities/configuration';
|
||||||
|
import { PropagateConfigurationsUseCase } from '../../domain/usecases/propagate-configurations.usecase';
|
||||||
|
import { ConfigurationProfile } from '../../mappers/configuration.profile';
|
||||||
|
import { PropagateConfigurationsQuery } from '../../queries/propagate-configurations.query';
|
||||||
|
|
||||||
|
const propagateConfigurationsQuery: PropagateConfigurationsQuery =
|
||||||
|
new PropagateConfigurationsQuery();
|
||||||
|
|
||||||
|
const mockConfigurations: ICollection<Configuration> = {
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
uuid: 'bb281075-1b98-4456-89d6-c643d3044a91',
|
||||||
|
domain: Domain.USER,
|
||||||
|
key: 'key1',
|
||||||
|
value: 'value1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
uuid: 'bb281075-1b98-4456-89d6-c643d3044a92',
|
||||||
|
domain: Domain.USER,
|
||||||
|
key: 'key2',
|
||||||
|
value: 'value2',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
uuid: 'bb281075-1b98-4456-89d6-c643d3044a93',
|
||||||
|
domain: Domain.USER,
|
||||||
|
key: 'key3',
|
||||||
|
value: 'value3',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
total: 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
const mockConfigurationRepository = {
|
||||||
|
findAll: jest
|
||||||
|
.fn()
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
.mockImplementationOnce((query?: PropagateConfigurationsQuery) => {
|
||||||
|
return Promise.resolve(mockConfigurations);
|
||||||
|
})
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
.mockImplementationOnce((query?: PropagateConfigurationsQuery) => {
|
||||||
|
throw new Error();
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
const mockConfigurationMessager = {
|
||||||
|
publish: jest.fn().mockImplementation(),
|
||||||
|
};
|
||||||
|
|
||||||
|
const mockLoggingMessager = {
|
||||||
|
publish: jest.fn().mockImplementation(),
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('PropagateConfigurationsUseCase', () => {
|
||||||
|
let propagateConfigurationsUseCase: PropagateConfigurationsUseCase;
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
|
imports: [AutomapperModule.forRoot({ strategyInitializer: classes() })],
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: ConfigurationRepository,
|
||||||
|
useValue: mockConfigurationRepository,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provide: ConfigurationMessager,
|
||||||
|
useValue: mockConfigurationMessager,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provide: LoggingMessager,
|
||||||
|
useValue: mockLoggingMessager,
|
||||||
|
},
|
||||||
|
PropagateConfigurationsUseCase,
|
||||||
|
ConfigurationProfile,
|
||||||
|
],
|
||||||
|
}).compile();
|
||||||
|
|
||||||
|
propagateConfigurationsUseCase = module.get<PropagateConfigurationsUseCase>(
|
||||||
|
PropagateConfigurationsUseCase,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be defined', () => {
|
||||||
|
expect(propagateConfigurationsUseCase).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('execute', () => {
|
||||||
|
it('should propagate configurations', async () => {
|
||||||
|
jest.spyOn(mockConfigurationMessager, 'publish');
|
||||||
|
await propagateConfigurationsUseCase.execute(
|
||||||
|
propagateConfigurationsQuery,
|
||||||
|
);
|
||||||
|
expect(mockConfigurationMessager.publish).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
it('should throw an error if repository call fails', async () => {
|
||||||
|
await expect(
|
||||||
|
propagateConfigurationsUseCase.execute(propagateConfigurationsQuery),
|
||||||
|
).rejects.toBeInstanceOf(Error);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -38,7 +38,11 @@ const mockConfigurationRepository = {
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
const mockMessager = {
|
const mockConfigurationMessager = {
|
||||||
|
publish: jest.fn().mockImplementation(),
|
||||||
|
};
|
||||||
|
|
||||||
|
const mockLoggingMessager = {
|
||||||
publish: jest.fn().mockImplementation(),
|
publish: jest.fn().mockImplementation(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -57,11 +61,11 @@ describe('UpdateConfigurationUseCase', () => {
|
||||||
ConfigurationProfile,
|
ConfigurationProfile,
|
||||||
{
|
{
|
||||||
provide: ConfigurationMessager,
|
provide: ConfigurationMessager,
|
||||||
useValue: mockMessager,
|
useValue: mockConfigurationMessager,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
provide: LoggingMessager,
|
provide: LoggingMessager,
|
||||||
useValue: mockMessager,
|
useValue: mockLoggingMessager,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}).compile();
|
}).compile();
|
||||||
|
@ -77,10 +81,12 @@ describe('UpdateConfigurationUseCase', () => {
|
||||||
|
|
||||||
describe('execute', () => {
|
describe('execute', () => {
|
||||||
it('should update a configuration value', async () => {
|
it('should update a configuration value', async () => {
|
||||||
|
jest.spyOn(mockConfigurationMessager, 'publish');
|
||||||
const updatedConfiguration: Configuration =
|
const updatedConfiguration: Configuration =
|
||||||
await updateConfigurationUseCase.execute(updateConfigurationCommand);
|
await updateConfigurationUseCase.execute(updateConfigurationCommand);
|
||||||
|
|
||||||
expect(updatedConfiguration.value).toBe(updateConfigurationRequest.value);
|
expect(updatedConfiguration.value).toBe(updateConfigurationRequest.value);
|
||||||
|
expect(mockConfigurationMessager.publish).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
it('should throw an error if configuration does not exist', async () => {
|
it('should throw an error if configuration does not exist', async () => {
|
||||||
await expect(
|
await expect(
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
import { ArgumentMetadata } from '@nestjs/common';
|
||||||
|
import { FindConfigurationByUuidRequest } from '../../../modules/configuration/domain/dtos/find-configuration-by-uuid.request';
|
||||||
|
import { RpcValidationPipe } from '../../pipes/rpc.validation-pipe';
|
||||||
|
|
||||||
|
describe('RpcValidationPipe', () => {
|
||||||
|
it('should not validate request', async () => {
|
||||||
|
const target: RpcValidationPipe = new RpcValidationPipe({
|
||||||
|
whitelist: true,
|
||||||
|
forbidUnknownValues: false,
|
||||||
|
});
|
||||||
|
const metadata: ArgumentMetadata = {
|
||||||
|
type: 'body',
|
||||||
|
metatype: FindConfigurationByUuidRequest,
|
||||||
|
data: '',
|
||||||
|
};
|
||||||
|
await target
|
||||||
|
.transform(<FindConfigurationByUuidRequest>{}, metadata)
|
||||||
|
.catch((err) => {
|
||||||
|
expect(err.message).toEqual('Rpc Exception');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue