Merge branch 'castValue' into 'main'

Cast value

See merge request v3/service/configuration!27
This commit is contained in:
Sylvain Briat 2023-10-27 09:22:48 +00:00
commit 832fa865b8
23 changed files with 405 additions and 125 deletions

View File

@ -10,10 +10,7 @@ Each item consists in :
## Available domains
- **CARPOOL** : carpool related configuration items (eg. default number of seats proposed as a driver)
- **PAGINATION** : pagination related configuration items (eg. default number of results per page)
New domains will be added in the future depending on the needs !
Domains are set in the [configuration package](https://gitlab.mobicoop.io/v3/packages/configuration).
## Requirements

38
package-lock.json generated
View File

@ -1,17 +1,17 @@
{
"name": "@mobicoop/configuration",
"version": "2.1.0",
"version": "2.2.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@mobicoop/configuration",
"version": "2.1.0",
"version": "2.2.0",
"license": "AGPL",
"dependencies": {
"@grpc/grpc-js": "^1.9.6",
"@grpc/grpc-js": "^1.9.7",
"@grpc/proto-loader": "^0.7.10",
"@mobicoop/configuration-module": "^4.0.0",
"@mobicoop/configuration-module": "^4.1.0",
"@mobicoop/ddd-library": "^2.1.1",
"@mobicoop/health-module": "^2.3.1",
"@mobicoop/message-broker-module": "^2.1.1",
@ -29,17 +29,17 @@
"rimraf": "^5.0.5"
},
"devDependencies": {
"@nestjs/cli": "^10.1.18",
"@nestjs/cli": "^10.2.0",
"@nestjs/schematics": "^10.0.2",
"@nestjs/testing": "^10.2.7",
"@types/express": "^4.17.20",
"@types/jest": "29.5.6",
"@types/node": "^20.8.7",
"@types/node": "^20.8.9",
"@types/supertest": "^2.0.15",
"@typescript-eslint/eslint-plugin": "^6.8.0",
"@typescript-eslint/parser": "^6.8.0",
"@typescript-eslint/eslint-plugin": "^6.9.0",
"@typescript-eslint/parser": "^6.9.0",
"dotenv-cli": "^7.3.0",
"eslint": "^8.51.0",
"eslint": "^8.52.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-prettier": "^5.0.1",
"jest": "29.7.0",
@ -1668,9 +1668,9 @@
}
},
"node_modules/@mobicoop/configuration-module": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@mobicoop/configuration-module/-/configuration-module-4.0.0.tgz",
"integrity": "sha512-Yd5ONDLwvEcolGYpg6EYLUNWQf8ClWT2UaYISBVWSOn37duFi0F3iuSq4W68JY2Y7ZkF3CalSht2fJVjU8rw0Q==",
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/@mobicoop/configuration-module/-/configuration-module-4.1.0.tgz",
"integrity": "sha512-j1C6S1S/v5nid9KeWVa97ZCVxwEbSWBP2oHzzRHazmgtO6lbybugnjQKtRHHKlnTMc1zGdD/4Xii/7JlGckflQ==",
"dependencies": {
"@songkeys/nestjs-redis": "^10.0.0",
"ioredis": "^5.3.2"
@ -2663,11 +2663,11 @@
"dev": true
},
"node_modules/@types/node": {
"version": "20.8.8",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.8.tgz",
"integrity": "sha512-YRsdVxq6OaLfmR9Hy816IMp33xOBjfyOgUd77ehqg96CFywxAPbDbXvAsuN2KVg2HOT8Eh6uAfU+l4WffwPVrQ==",
"version": "20.8.9",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.9.tgz",
"integrity": "sha512-UzykFsT3FhHb1h7yD4CA4YhBHq545JC0YnEz41xkipN88eKQtL6rSgocL5tbAP6Ola9Izm/Aw4Ora8He4x0BHg==",
"dependencies": {
"undici-types": "~5.25.1"
"undici-types": "~5.26.4"
}
},
"node_modules/@types/parse-json": {
@ -9383,9 +9383,9 @@
}
},
"node_modules/undici-types": {
"version": "5.25.3",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.25.3.tgz",
"integrity": "sha512-Ga1jfYwRn7+cP9v8auvEXN1rX3sWqlayd4HP7OKk4mZWylEmu3KzXDUGrQUN6Ol7qo1gPvB2e5gX6udnyEPgdA=="
"version": "5.26.5",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="
},
"node_modules/universalify": {
"version": "2.0.0",

View File

@ -1,6 +1,6 @@
{
"name": "@mobicoop/configuration",
"version": "2.1.0",
"version": "2.2.0",
"description": "Mobicoop V3 Configuration Service",
"author": "sbriat",
"private": true,
@ -24,9 +24,9 @@
"test:e2e": "jest --config ./test/jest-e2e.json"
},
"dependencies": {
"@grpc/grpc-js": "^1.9.6",
"@grpc/grpc-js": "^1.9.7",
"@grpc/proto-loader": "^0.7.10",
"@mobicoop/configuration-module": "^4.0.0",
"@mobicoop/configuration-module": "^4.1.0",
"@mobicoop/ddd-library": "^2.1.1",
"@mobicoop/health-module": "^2.3.1",
"@mobicoop/message-broker-module": "^2.1.1",
@ -44,17 +44,17 @@
"rimraf": "^5.0.5"
},
"devDependencies": {
"@nestjs/cli": "^10.1.18",
"@nestjs/cli": "^10.2.0",
"@nestjs/schematics": "^10.0.2",
"@nestjs/testing": "^10.2.7",
"@types/express": "^4.17.20",
"@types/jest": "29.5.6",
"@types/node": "^20.8.7",
"@types/node": "^20.8.9",
"@types/supertest": "^2.0.15",
"@typescript-eslint/eslint-plugin": "^6.8.0",
"@typescript-eslint/parser": "^6.8.0",
"@typescript-eslint/eslint-plugin": "^6.9.0",
"@typescript-eslint/parser": "^6.9.0",
"dotenv-cli": "^7.3.0",
"eslint": "^8.51.0",
"eslint": "^8.52.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-prettier": "^5.0.1",
"jest": "29.7.0",

View File

@ -1,6 +1,7 @@
import { registerAs } from '@nestjs/config';
import { Config } from './config';
export interface CarpoolConfig {
export interface CarpoolConfig extends Config {
departureTimeMargin: number;
role: string;
seatsProposed: number;

5
src/config/config.ts Normal file
View File

@ -0,0 +1,5 @@
import { ConfigurationDomain } from '@mobicoop/configuration-module';
export interface Config {
domain: ConfigurationDomain;
}

View File

@ -1,6 +1,7 @@
import { registerAs } from '@nestjs/config';
import { Config } from './config';
export interface PaginationConfig {
export interface PaginationConfig extends Config {
perPage: number;
}

View File

@ -4,9 +4,14 @@ import {
ConfigurationIdentifier,
ConfigurationValue,
} from '@mobicoop/configuration-module';
import { ConfigurationsManagerService } from './core/application/services/configurations-manager.service';
@Injectable()
export class ConfigurationMapper {
constructor(
private readonly configurationsManager: ConfigurationsManagerService,
) {}
toResponse = (
configurationIdentifier: ConfigurationIdentifier,
configurationValue: ConfigurationValue,
@ -15,6 +20,8 @@ export class ConfigurationMapper {
response.domain = configurationIdentifier.domain;
response.key = configurationIdentifier.key;
response.value = configurationValue;
response.type =
this.configurationsManager.configurationType(configurationValue);
return response;
};
}

View File

@ -8,6 +8,7 @@ import { ConfigurationMapper } from './configuration.mapper';
import { CONFIGURATION_REPOSITORY } from './configuration.di-tokens';
import { PopulateService } from './core/application/services/populate.service';
import { ConfigurationRepository } from '@mobicoop/configuration-module';
import { ConfigurationsManagerService } from './core/application/services/configurations-manager.service';
const grpcControllers = [
GetConfigurationGrpcController,
@ -20,7 +21,7 @@ const queryHandlers: Provider[] = [GetConfigurationQueryHandler];
const mappers: Provider[] = [ConfigurationMapper];
const providers: Provider[] = [PopulateService];
const providers: Provider[] = [PopulateService, ConfigurationsManagerService];
const repositories: Provider[] = [
{

View File

@ -1,14 +1,13 @@
import { ConfigurationIdentifier } from '@mobicoop/configuration-module';
import { Command, CommandProps } from '@mobicoop/ddd-library';
export class SetConfigurationCommand extends Command {
readonly domain: string;
readonly key: string;
readonly value: string;
readonly configurationIdentifier: ConfigurationIdentifier;
readonly value: string | boolean | number;
constructor(props: CommandProps<SetConfigurationCommand>) {
super(props);
this.domain = props.domain;
this.key = props.key;
this.configurationIdentifier = props.configurationIdentifier;
this.value = props.value;
}
}

View File

@ -3,27 +3,36 @@ import { Inject } from '@nestjs/common';
import { SetConfigurationCommand } from './set-configuration.command';
import { CONFIGURATION_REPOSITORY } from '@modules/configuration/configuration.di-tokens';
import {
ConfigurationDomain,
ConfigurationIdentifier,
ConfigurationType,
SetConfigurationRepositoryPort,
} from '@mobicoop/configuration-module';
import { ConfigurationsManagerService } from '../../services/configurations-manager.service';
import { ArgumentInvalidException } from '@mobicoop/ddd-library';
@CommandHandler(SetConfigurationCommand)
export class SetConfigurationService implements ICommandHandler {
constructor(
@Inject(CONFIGURATION_REPOSITORY)
private readonly configurationRepository: SetConfigurationRepositoryPort,
private readonly configurationsManager: ConfigurationsManagerService,
) {}
async execute(
command: SetConfigurationCommand,
): Promise<ConfigurationIdentifier> {
const configurationType: ConfigurationType =
this.configurationsManager.identifierType(
command.configurationIdentifier,
);
const value: any = this.configurationsManager.cast(
`${command.value}`,
configurationType,
);
if (isNaN(value)) throw new ArgumentInvalidException('Bad value');
return await this.configurationRepository.set(
{
domain: command.domain as ConfigurationDomain,
key: command.key,
},
command.value,
command.configurationIdentifier,
value,
);
}
}

View File

@ -3,21 +3,22 @@ import { GetConfigurationQuery } from './get-configuration.query';
import { Inject } from '@nestjs/common';
import { CONFIGURATION_REPOSITORY } from '@modules/configuration/configuration.di-tokens';
import {
ConfigurationDomain,
ConfigurationValue,
GetConfigurationRepositoryPort,
} from '@mobicoop/configuration-module';
import { ConfigurationsManagerService } from '../../services/configurations-manager.service';
@QueryHandler(GetConfigurationQuery)
export class GetConfigurationQueryHandler implements IQueryHandler {
constructor(
@Inject(CONFIGURATION_REPOSITORY)
private readonly configurationRepository: GetConfigurationRepositoryPort,
private readonly configurationsManager: ConfigurationsManagerService,
) {}
async execute(query: GetConfigurationQuery): Promise<ConfigurationValue> {
return await this.configurationRepository.get({
domain: query.domain as ConfigurationDomain,
key: query.key,
});
return await this.configurationRepository.get(
query.configurationIdentifier,
this.configurationsManager.identifierType(query.configurationIdentifier),
);
}
}

View File

@ -1,12 +1,17 @@
import {
ConfigurationDomain,
ConfigurationIdentifier,
} from '@mobicoop/configuration-module';
import { QueryBase } from '@mobicoop/ddd-library';
export class GetConfigurationQuery extends QueryBase {
readonly domain: string;
readonly key: string;
readonly configurationIdentifier: ConfigurationIdentifier;
constructor(domain: string, key: string) {
constructor(domain: ConfigurationDomain, key: string) {
super();
this.domain = domain;
this.key = key;
this.configurationIdentifier = {
domain,
key,
};
}
}

View File

@ -0,0 +1,93 @@
import {
ConfigurationDomain,
ConfigurationIdentifier,
ConfigurationType,
ConfigurationValue,
} from '@mobicoop/configuration-module';
import { NotFoundException } from '@mobicoop/ddd-library';
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { CarpoolConfig } from '@src/config/carpool.config';
import { Config } from '@src/config/config';
import { PaginationConfig } from '@src/config/pagination.config';
@Injectable()
export class ConfigurationsManagerService {
constructor(private readonly configService: ConfigService) {}
list = (): Config[] => {
return [
{
...(this.configService.get<CarpoolConfig>('carpool') as CarpoolConfig),
domain: ConfigurationDomain.CARPOOL,
},
{
...(this.configService.get<PaginationConfig>(
'pagination',
) as PaginationConfig),
domain: ConfigurationDomain.PAGINATION,
},
];
};
identifierType = (
configurationIdentifier: ConfigurationIdentifier,
): ConfigurationType => {
const configs: Config[] = this.list();
const configuration: Config | undefined = configs.find(
(config: Config) =>
config.domain === configurationIdentifier.domain &&
this._hasProperty(configurationIdentifier.key, config),
);
if (!configuration)
throw new NotFoundException('Configuration item not found');
return this.configurationType(
this._getValue(configurationIdentifier.key, configuration),
);
};
configurationType = (value: any): ConfigurationType => {
switch (typeof value) {
case 'number':
if (this._isInt(value)) return ConfigurationType.INT;
return ConfigurationType.FLOAT;
case 'boolean':
return ConfigurationType.BOOLEAN;
default:
return ConfigurationType.STRING;
}
};
cast = (
value: string,
configurationType: ConfigurationType,
): ConfigurationValue => {
switch (configurationType) {
case ConfigurationType.BOOLEAN:
return value === 'true';
case ConfigurationType.INT:
return parseInt(value);
case ConfigurationType.FLOAT:
return parseFloat(value);
default:
return value;
}
};
private _hasProperty = <T>(property: string, configuration: T): boolean => {
let key: keyof typeof configuration;
for (key in configuration) {
if (key !== 'domain' && key === property) return true;
}
return false;
};
private _getValue = <T>(property: string, configuration: T): any => {
let key: keyof typeof configuration;
for (key in configuration) {
if (key !== 'domain' && key === property) return configuration[key];
}
};
private _isInt = (number: number): boolean => number % 1 === 0;
}

View File

@ -1,15 +1,12 @@
import {
ConfigurationDomain,
GetConfigurationRepositoryPort,
NotFoundException,
SetConfigurationRepositoryPort,
} from '@mobicoop/configuration-module';
import { CONFIGURATION_REPOSITORY } from '@modules/configuration/configuration.di-tokens';
import { Inject, Injectable, OnApplicationBootstrap } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { CarpoolConfig } from '@src/config/carpool.config';
import { PaginationConfig } from '@src/config/pagination.config';
import { ConfigurationsManagerService } from './configurations-manager.service';
import { Config } from '@src/config/config';
@Injectable()
export class PopulateService implements OnApplicationBootstrap {
@ -18,46 +15,41 @@ export class PopulateService implements OnApplicationBootstrap {
private readonly getConfigurationRepository: GetConfigurationRepositoryPort,
@Inject(CONFIGURATION_REPOSITORY)
private readonly setConfigurationRepository: SetConfigurationRepositoryPort,
private readonly configService: ConfigService,
private readonly configurationsManager: ConfigurationsManagerService,
) {}
onApplicationBootstrap() {
this._populate();
async onApplicationBootstrap() {
await this._populate();
}
private _populate = async (): Promise<void> => {
const carpoolConfig: CarpoolConfig = this.configService.get<CarpoolConfig>(
'carpool',
) as CarpoolConfig;
const paginationConfig: PaginationConfig =
this.configService.get<PaginationConfig>(
'pagination',
) as PaginationConfig;
await Promise.all([
this._populateConfig(ConfigurationDomain.CARPOOL, carpoolConfig),
this._populateConfig(ConfigurationDomain.PAGINATION, paginationConfig),
]);
const configs: Config[] = this.configurationsManager.list();
await Promise.all(
configs.map((config: Config) => this._populateConfig(config)),
);
};
private _populateConfig = async <T>(
domain: ConfigurationDomain,
config: T,
): Promise<void> => {
let key: keyof typeof config;
for (key in config) {
private _populateConfig = async <T>(configuration: T): Promise<void> => {
let key: keyof typeof configuration;
const config: Config = configuration as Config;
for (key in configuration) {
try {
await this.getConfigurationRepository.get({
domain,
key,
});
if (key !== 'domain')
await this.getConfigurationRepository.get(
{
domain: config.domain,
key,
},
this.configurationsManager.configurationType(configuration[key]),
);
} catch (error: any) {
if (error instanceof NotFoundException) {
this.setConfigurationRepository.set(
{
domain,
domain: config.domain,
key,
},
`${config[key]}`,
`${configuration[key]}`,
);
}
}

View File

@ -1,5 +1,8 @@
import { ConfigurationType } from '@mobicoop/configuration-module';
export class ConfigurationResponseDto {
domain: string;
key: string;
value: string;
value: string | boolean | number;
type: ConfigurationType;
}

View File

@ -16,6 +16,7 @@ message Configuration {
string domain = 1;
string key = 2;
string value = 3;
string type = 4;
}
message Empty {}

View File

@ -10,7 +10,6 @@ export class SetConfigurationRequestDto {
@IsNotEmpty()
key: string;
@IsString()
@IsNotEmpty()
value: string;
value: string | boolean | number;
}

View File

@ -24,7 +24,13 @@ export class SetConfigurationGrpcController {
try {
const configurationIdentifier: ConfigurationIdentifier =
await this.commandBus.execute(
new SetConfigurationCommand(setConfigurationRequestDto),
new SetConfigurationCommand({
configurationIdentifier: {
domain: setConfigurationRequestDto.domain,
key: setConfigurationRequestDto.key,
},
value: setConfigurationRequestDto.value,
}),
);
return configurationIdentifier;
} catch (error: any) {

View File

@ -1,14 +1,28 @@
import { ConfigurationDomain } from '@mobicoop/configuration-module';
import {
ConfigurationDomain,
ConfigurationType,
} from '@mobicoop/configuration-module';
import { ConfigurationMapper } from '@modules/configuration/configuration.mapper';
import { ConfigurationsManagerService } from '@modules/configuration/core/application/services/configurations-manager.service';
import { ConfigurationResponseDto } from '@modules/configuration/interface/dtos/configuration.response.dto';
import { Test } from '@nestjs/testing';
const mockConfigurationsManagerService = {
configurationType: jest.fn().mockImplementation(() => ConfigurationType.INT),
};
describe('Configuration Mapper', () => {
let configurationMapper: ConfigurationMapper;
beforeAll(async () => {
const module = await Test.createTestingModule({
providers: [ConfigurationMapper],
providers: [
ConfigurationMapper,
{
provide: ConfigurationsManagerService,
useValue: mockConfigurationsManagerService,
},
],
}).compile();
configurationMapper = module.get<ConfigurationMapper>(ConfigurationMapper);
});

View File

@ -0,0 +1,125 @@
import {
ConfigurationDomain,
ConfigurationIdentifier,
ConfigurationType,
} from '@mobicoop/configuration-module';
import { NotFoundException } from '@mobicoop/ddd-library';
import { ConfigurationsManagerService } from '@modules/configuration/core/application/services/configurations-manager.service';
import { ConfigService } from '@nestjs/config';
import { Test, TestingModule } from '@nestjs/testing';
import { Config } from '@src/config/config';
const mockConfigService = {
get: jest.fn().mockImplementation((domain: string) => {
switch (domain) {
case 'carpool':
return {
departureTimeMargin: 900,
role: 'passenger',
seatsProposed: 3,
seatsRequested: 1,
strictFrequency: false,
};
case 'pagination':
return {
perPage: 10,
};
}
}),
};
describe('Configurations Manager Service', () => {
let configurationsManagerService: ConfigurationsManagerService;
beforeAll(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
{
provide: ConfigService,
useValue: mockConfigService,
},
ConfigurationsManagerService,
],
}).compile();
configurationsManagerService = module.get<ConfigurationsManagerService>(
ConfigurationsManagerService,
);
});
it('should be defined', () => {
expect(configurationsManagerService).toBeDefined();
});
it('should return the list of configuration elements', () => {
const list: Config[] = configurationsManagerService.list();
expect(list).toHaveLength(2);
});
describe('identifierType', () => {
it('should return the type of a configuration item for a given identifier', () => {
const configurationIdentifier: ConfigurationIdentifier = {
domain: ConfigurationDomain.CARPOOL,
key: 'seatsProposed',
};
const configurationType: ConfigurationType =
configurationsManagerService.identifierType(configurationIdentifier);
expect(configurationType).toBe(ConfigurationType.INT);
});
it('should throw if configuration item is not found', () => {
const configurationIdentifier: ConfigurationIdentifier = {
domain: ConfigurationDomain.CARPOOL,
key: 'minAge',
};
expect(() => {
configurationsManagerService.identifierType(configurationIdentifier);
}).toThrow(NotFoundException);
});
});
describe('configurationType', () => {
it('should return the configuration type of an int', () => {
expect(configurationsManagerService.configurationType(3)).toBe(
ConfigurationType.INT,
);
});
it('should return the configuration type of a float', () => {
expect(configurationsManagerService.configurationType(3.5)).toBe(
ConfigurationType.FLOAT,
);
});
it('should return the configuration type of a boolean', () => {
expect(configurationsManagerService.configurationType(true)).toBe(
ConfigurationType.BOOLEAN,
);
});
it('should return the configuration type of a string', () => {
expect(configurationsManagerService.configurationType('role')).toBe(
ConfigurationType.STRING,
);
});
});
describe('cast', () => {
it('should cast a string to int', () => {
expect(
configurationsManagerService.cast('1', ConfigurationType.INT),
).toBe(1);
});
it('should cast a string to float', () => {
expect(
configurationsManagerService.cast('1.5', ConfigurationType.FLOAT),
).toBe(1.5);
});
it('should cast a string to boolean', () => {
expect(
configurationsManagerService.cast('true', ConfigurationType.BOOLEAN),
).toBeTruthy();
});
it('should not cast a string and return it as is', () => {
expect(
configurationsManagerService.cast('role', ConfigurationType.STRING),
).toBe('role');
});
});
});

View File

@ -4,8 +4,10 @@ import { CONFIGURATION_REPOSITORY } from '@modules/configuration/configuration.d
import { GetConfigurationQuery } from '@modules/configuration/core/application/queries/get-configuration/get-configuration.query';
import {
ConfigurationDomain,
ConfigurationType,
ConfigurationValue,
} from '@mobicoop/configuration-module';
import { ConfigurationsManagerService } from '@modules/configuration/core/application/services/configurations-manager.service';
const configurationValue: ConfigurationValue = '3';
@ -13,6 +15,10 @@ const mockConfigurationRepository = {
get: jest.fn().mockImplementation(() => configurationValue),
};
const mockConfigurationsManagerService = {
identifierType: jest.fn().mockImplementation(() => ConfigurationType.INT),
};
describe('Get Configuration Query Handler', () => {
let getConfigurationQueryHandler: GetConfigurationQueryHandler;
@ -23,6 +29,10 @@ describe('Get Configuration Query Handler', () => {
provide: CONFIGURATION_REPOSITORY,
useValue: mockConfigurationRepository,
},
{
provide: ConfigurationsManagerService,
useValue: mockConfigurationsManagerService,
},
GetConfigurationQueryHandler,
],
}).compile();

View File

@ -1,7 +1,10 @@
import { NotFoundException } from '@mobicoop/configuration-module';
import {
ConfigurationDomain,
NotFoundException,
} from '@mobicoop/configuration-module';
import { CONFIGURATION_REPOSITORY } from '@modules/configuration/configuration.di-tokens';
import { ConfigurationsManagerService } from '@modules/configuration/core/application/services/configurations-manager.service';
import { PopulateService } from '@modules/configuration/core/application/services/populate.service';
import { ConfigService } from '@nestjs/config';
import { Test, TestingModule } from '@nestjs/testing';
const mockConfigurationRepository = {
@ -14,23 +17,21 @@ const mockConfigurationRepository = {
set: jest.fn(),
};
const mockConfigService = {
get: jest.fn().mockImplementation((domain: string) => {
switch (domain) {
case 'carpool':
return {
departureTimeMargin: 900,
role: 'passenger',
seatsProposed: 3,
seatsRequested: 1,
strictFrequency: false,
};
case 'pagination':
return {
perPage: 10,
};
}
}),
const mockConfigurationsManagerService = {
list: jest.fn().mockImplementation(() => [
{
domain: ConfigurationDomain.CARPOOL,
departureTimeMargin: 900,
role: 'passenger',
seatsProposed: 3,
seatsRequested: 1,
strictFrequency: false,
},
{
domain: ConfigurationDomain.PAGINATION,
perPage: 10,
},
]),
};
describe('Populate Service', () => {
@ -44,25 +45,18 @@ describe('Populate Service', () => {
useValue: mockConfigurationRepository,
},
{
provide: ConfigService,
useValue: mockConfigService,
provide: ConfigurationsManagerService,
useValue: mockConfigurationsManagerService,
},
PopulateService,
],
}).compile();
populateService = module.get<PopulateService>(PopulateService);
populateService.onApplicationBootstrap();
});
it('should be defined', () => {
expect(populateService).toBeDefined();
});
it('should populate database with default values', () => {
jest.spyOn(mockConfigurationRepository, 'get');
jest.spyOn(mockConfigurationRepository, 'set');
populateService.onApplicationBootstrap();
expect(mockConfigurationRepository.get).toHaveBeenCalled();
expect(mockConfigurationRepository.set).toHaveBeenCalled();
});
});

View File

@ -3,7 +3,11 @@ import { SetConfigurationRequestDto } from '@modules/configuration/interface/grp
import { SetConfigurationService } from '@modules/configuration/core/application/commands/set-configuration/set-configuration.service';
import { CONFIGURATION_REPOSITORY } from '@modules/configuration/configuration.di-tokens';
import { SetConfigurationCommand } from '@modules/configuration/core/application/commands/set-configuration/set-configuration.command';
import { ConfigurationDomain } from '@mobicoop/configuration-module';
import {
ConfigurationDomain,
ConfigurationType,
} from '@mobicoop/configuration-module';
import { ConfigurationsManagerService } from '@modules/configuration/core/application/services/configurations-manager.service';
const setConfigurationRequest: SetConfigurationRequestDto = {
domain: ConfigurationDomain.CARPOOL,
@ -20,6 +24,11 @@ const mockConfigurationRepository = {
}),
};
const mockConfigurationsManagerService = {
identifierType: jest.fn().mockImplementation(() => ConfigurationType.INT),
cast: jest.fn().mockImplementation(() => 3),
};
describe('Set Configuration Service', () => {
let setConfigurationService: SetConfigurationService;
@ -30,6 +39,10 @@ describe('Set Configuration Service', () => {
provide: CONFIGURATION_REPOSITORY,
useValue: mockConfigurationRepository,
},
{
provide: ConfigurationsManagerService,
useValue: mockConfigurationsManagerService,
},
SetConfigurationService,
],
}).compile();
@ -44,9 +57,13 @@ describe('Set Configuration Service', () => {
});
describe('execution', () => {
const setConfigurationCommand = new SetConfigurationCommand(
setConfigurationRequest,
);
const setConfigurationCommand = new SetConfigurationCommand({
configurationIdentifier: {
domain: setConfigurationRequest.domain,
key: setConfigurationRequest.key,
},
value: setConfigurationRequest.value,
});
it('should set an existing configuration item', async () => {
jest.spyOn(mockConfigurationRepository, 'set');
await setConfigurationService.execute(setConfigurationCommand);