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,15 +1,18 @@
 | 
				
			||||||
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',
 | 
					      uuid: 'bb281075-1b98-4456-89d6-c643d3044a91',
 | 
				
			||||||
      domain: Domain.USER,
 | 
					      domain: Domain.USER,
 | 
				
			||||||
| 
						 | 
					@ -28,17 +31,19 @@ const mockConfigurations = [
 | 
				
			||||||
      key: 'key3',
 | 
					      key: 'key3',
 | 
				
			||||||
      value: 'value3',
 | 
					      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,7 +15,8 @@ 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',
 | 
					      uuid: 'bb281075-1b98-4456-89d6-c643d3044a91',
 | 
				
			||||||
      domain: Domain.USER,
 | 
					      domain: Domain.USER,
 | 
				
			||||||
| 
						 | 
					@ -32,7 +35,9 @@ const mockConfigurations = [
 | 
				
			||||||
      key: 'key3',
 | 
					      key: 'key3',
 | 
				
			||||||
      value: 'value3',
 | 
					      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