From 2acb148ba82d276679d1d38f87342282c4229d0b Mon Sep 17 00:00:00 2001 From: Maximiliano Delgado Date: Sat, 15 Apr 2023 20:13:27 -0300 Subject: [PATCH] feat(test-utils): add functions to init and close containers from docker-compose for jest globaSetup --- package.json | 4 +- .../elk/src/elk/constants/elk.constant.ts | 12 ++++ .../src/elk/providers/elk-client.provider.ts | 12 ++-- packages/test-utils/docker-compose.yml | 20 ++++++ packages/test-utils/package.json | 4 +- .../test-utils/src/__mocks__/jest.mocks.ts | 2 +- .../src/__test__/globalTestContainers.spec.ts | 32 +++++++++ .../docker-compose/docker-compose.yml | 69 +++++++++++++++++++ .../testcontainers/globalTestContainersTD.ts | 39 +++++++++++ .../test-utils/src/testcontainers/index.ts | 1 + 10 files changed, 185 insertions(+), 10 deletions(-) create mode 100644 packages/test-utils/docker-compose.yml create mode 100644 packages/test-utils/src/__test__/globalTestContainers.spec.ts create mode 100644 packages/test-utils/src/fixtures/docker-compose/docker-compose.yml create mode 100644 packages/test-utils/src/testcontainers/globalTestContainersTD.ts diff --git a/package.json b/package.json index e9d1bacb..e566d2c4 100644 --- a/package.json +++ b/package.json @@ -73,7 +73,7 @@ "reflect-metadata": "^0.1.13", "rxjs": "^7.5.5", "shx": "^0.3.4", - "testcontainers": "^9.4.0", + "testcontainers": "^9.5.0", "typeorm": "^0.3.13", "uuid": "^9.0.0" }, @@ -127,7 +127,7 @@ "prettier": "^2.8.7", "rimraf": "^4.4.1", "supertest": "^6.2.2", - "testcontainers": "^9.4.0", + "testcontainers": "^9.5.0", "ts-jest": "^29.1.0", "ts-loader": "^9.3.1", "ts-node": "^10.9.0", diff --git a/packages/elk/src/elk/constants/elk.constant.ts b/packages/elk/src/elk/constants/elk.constant.ts index de4c007a..762d31cb 100644 --- a/packages/elk/src/elk/constants/elk.constant.ts +++ b/packages/elk/src/elk/constants/elk.constant.ts @@ -3,3 +3,15 @@ export const ELK_MODULE_OPTIONS = Symbol('ELK_MODULE_OPTIONS'); export const ELK_MSG_SUCCESSFULLY_CONNECTED = 'Connected successfully!:'; export const ELK_MSG_ERROR_CONNECTED = 'Could not establish a connection:'; + +/* +export const OMITS_IN_OPTIONS: string[] = ['indexDate', 'redact']; +export const DEFAULT_OPTIONS_REDACT = { + paths: [], + censor: '****', + remove: false, +}; + +export const DEFAULT_TIMEZONE = 'America/Argentina/Buenos_Aires'; +export const DEFAULT_TIME_FORMAT = 'D tt'; // 4/10/2023 12:55:40 PM +*/ diff --git a/packages/elk/src/elk/providers/elk-client.provider.ts b/packages/elk/src/elk/providers/elk-client.provider.ts index 1b5cbc25..4a6f7e56 100644 --- a/packages/elk/src/elk/providers/elk-client.provider.ts +++ b/packages/elk/src/elk/providers/elk-client.provider.ts @@ -1,17 +1,19 @@ import { Logger, Provider } from '@nestjs/common'; import { Client, ClientOptions } from '@elastic/elasticsearch'; +import { v4 as uuid } from 'uuid'; +import { InfoResponse } from '@elastic/elasticsearch/lib/api/types'; + import { ELK_MODULE_OPTIONS, ELK_CLIENT, ELK_MSG_ERROR_CONNECTED, ELK_MSG_SUCCESSFULLY_CONNECTED, } from '../constants/elk.constant'; -import { v4 as uuid } from 'uuid'; export const createElkClient = (): Provider => ({ provide: ELK_CLIENT, - useFactory: async (options: ClientOptions) => { - const client = new Client({ + useFactory: async (options: ClientOptions): Promise => { + const client: Client = new Client({ ...options, generateRequestId: () => uuid(), }); @@ -19,10 +21,10 @@ export const createElkClient = (): Provider => ({ /* istanbul ignore next */ client .info() - .then((_response) => + .then((_response: InfoResponse) => Logger.log(`${ELK_MSG_SUCCESSFULLY_CONNECTED} ${_response.name}`, 'ElkModule'), ) - .catch((_error) => { + .catch((_error): void => { Logger.error(`${ELK_MSG_ERROR_CONNECTED} ${_error.message}`, 'ElkModule'); }); diff --git a/packages/test-utils/docker-compose.yml b/packages/test-utils/docker-compose.yml new file mode 100644 index 00000000..95eab30c --- /dev/null +++ b/packages/test-utils/docker-compose.yml @@ -0,0 +1,20 @@ +# docker-compose.yml - Only for local debug purposes +# docker-compose up -d elasticsearch kibana jaeger camunda redis mongo mysql postgres pgadmin +version: '3.9' + +services: + mongo: + image: mongo:5.0 + container_name: local-mongo + restart: always + ports: + - '27017:27017' + environment: + TZ: UTC + MONGO_INITDB_ROOT_USERNAME: root + MONGO_INITDB_ROOT_PASSWORD: 123456 + MONGO_INITDB_DATABASE: test_db + #logging: + # driver: none + #volumes: + # - ./.mongo_data:/data/db diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index cf7bdde6..f6efdc43 100644 --- a/packages/test-utils/package.json +++ b/packages/test-utils/package.json @@ -41,10 +41,10 @@ "@nestjs/platform-express": "^9.4.0", "reflect-metadata": "^0.1.13", "rxjs": "^7.5.5", - "testcontainers": "^9.4.0" + "testcontainers": "^9.5.0" }, "dependencies": { - "testcontainers": "^9.4.0" + "testcontainers": "^9.5.0" }, "devDependencies": { "@tresdoce-nestjs-toolkit/config": "^0.2.4", diff --git a/packages/test-utils/src/__mocks__/jest.mocks.ts b/packages/test-utils/src/__mocks__/jest.mocks.ts index bf4b01e8..d763c8ed 100644 --- a/packages/test-utils/src/__mocks__/jest.mocks.ts +++ b/packages/test-utils/src/__mocks__/jest.mocks.ts @@ -1,6 +1,6 @@ import { appConfigBase } from '../fixtures/appConfigBase'; -export const config = jest.fn().mockImplementation(() => appConfigBase); +export const config = () => jest.fn().mockImplementation(() => appConfigBase); export const executionContext: any = () => ({ switchToHttp: jest.fn().mockReturnThis(), diff --git a/packages/test-utils/src/__test__/globalTestContainers.spec.ts b/packages/test-utils/src/__test__/globalTestContainers.spec.ts new file mode 100644 index 00000000..3268aaa5 --- /dev/null +++ b/packages/test-utils/src/__test__/globalTestContainers.spec.ts @@ -0,0 +1,32 @@ +import { closeDockerCompose, initDockerCompose } from '../testcontainers'; +import path from 'path'; +import { StartedDockerComposeEnvironment } from 'testcontainers'; + +describe('globalTestContainers', () => { + const composeFilePath = path.resolve(__dirname, '..', 'fixtures', 'docker-compose'); + const composeFile = 'docker-compose.yml'; + + it('should be initialize service from docker-compose.yml', async () => { + const services = ['mongo']; + await initDockerCompose(services, composeFilePath, composeFile)(); + expect(global.__TESTCONTAINERS__).toBeDefined(); + expect(global.__TESTCONTAINERS__).toBeInstanceOf(StartedDockerComposeEnvironment); + await closeDockerCompose({ removeVolumes: false })(); + }); + + it('should be initialize all services from docker-compose.yml', async () => { + const services = []; + await initDockerCompose(services, composeFilePath, composeFile)(); + expect(global.__TESTCONTAINERS__).toBeDefined(); + expect(global.__TESTCONTAINERS__).toBeInstanceOf(StartedDockerComposeEnvironment); + await closeDockerCompose({ removeVolumes: false })(); + }); + + it('should be initialize services from docker-compose.yml in default path and filename', async () => { + const services = []; + await initDockerCompose(services)(); + expect(global.__TESTCONTAINERS__).toBeDefined(); + expect(global.__TESTCONTAINERS__).toBeInstanceOf(StartedDockerComposeEnvironment); + await closeDockerCompose({ removeVolumes: false })(); + }); +}); diff --git a/packages/test-utils/src/fixtures/docker-compose/docker-compose.yml b/packages/test-utils/src/fixtures/docker-compose/docker-compose.yml new file mode 100644 index 00000000..84c16524 --- /dev/null +++ b/packages/test-utils/src/fixtures/docker-compose/docker-compose.yml @@ -0,0 +1,69 @@ +# docker-compose.yml - Only for local debug purposes +# docker-compose up -d elasticsearch kibana jaeger camunda redis mongo mysql postgres pgadmin +version: '3.9' + +services: + postgres: + image: postgres:13 + container_name: local-postgres + restart: always + ports: + - '5432:5432' + environment: + TZ: UTC + POSTGRES_DB: my_db + POSTGRES_USER: root + POSTGRES_PASSWORD: 123456 + #logging: + # driver: none + #volumes: + # - ./.postgres_data:/var/lib/postgresql/data + + mysql: + image: mysql:5.7 + container_name: local-mysql + restart: always + ports: + - '3306:3306' + environment: + TZ: UTC + MYSQL_ROOT_PASSWORD: 123456 + MYSQL_DATABASE: my_db + MYSQL_PASSWORD: 123456 + #MYSQL_USER: root + #volumes: + # - ./.mysql-data/db:/var/lib/mysql + + mongo: + image: mongo:5.0 + container_name: local-mongo + restart: always + ports: + - '27017:27017' + environment: + TZ: UTC + MONGO_INITDB_ROOT_USERNAME: root + MONGO_INITDB_ROOT_PASSWORD: 123456 + MONGO_INITDB_DATABASE: test_db + #logging: + # driver: none + #volumes: + # - ./.mongo_data:/data/db + + redis: + image: redis:6.2-alpine + container_name: local-redis + restart: always + ports: + - '6379:6379' + environment: + TZ: UTC + REDIS_PORT: 6379 + REDIS_PASSWORD: 123456 + REDIS_HOST: cache + #REDIS_USERNAME: default + command: [ "redis-server", "--appendonly", "yes", "--requirepass","123456" ] + #logging: + # driver: none + #volumes: + # - ./.redis_data:/data diff --git a/packages/test-utils/src/testcontainers/globalTestContainersTD.ts b/packages/test-utils/src/testcontainers/globalTestContainersTD.ts new file mode 100644 index 00000000..f6a0b6bd --- /dev/null +++ b/packages/test-utils/src/testcontainers/globalTestContainersTD.ts @@ -0,0 +1,39 @@ +import { DockerComposeEnvironment } from 'testcontainers'; +import { DockerComposeDownOptions } from 'testcontainers/dist/src/test-container'; +import * as _ from 'lodash'; + +export const initDockerCompose = ( + _services?: Array, + _composeFilePath = '.', + _composeFile = 'docker-compose.yml', +) => { + return async (): Promise => { + console.info(`🐳 Initialize docker-compose...`); + !_.isEmpty(_services) + ? console.log(`• Services from ${_composeFile}: ${_services.join(', ')}`) + : null; + try { + global.__TESTCONTAINERS__ = await new DockerComposeEnvironment( + _composeFilePath, + _composeFile, + ).up(_services); + console.info(`✨ Container(s) initialized.`); + } catch (_error) { + /* istanbul ignore next */ + console.error(`😰 Error initializing container(s): ${_error}`); + } + }; +}; + +export const closeDockerCompose = (_options?: Partial) => { + return async (): Promise => { + console.info('🐳 Terminate docker-compose...'); + try { + await global.__TESTCONTAINERS__.down(_options); + console.info(`👌 Container(s) stopped successfully.`); + } catch (_error) { + /* istanbul ignore next */ + console.error(`😒 Container(s) not initialized.`); + } + }; +}; diff --git a/packages/test-utils/src/testcontainers/index.ts b/packages/test-utils/src/testcontainers/index.ts index d7a64911..a8e85d38 100644 --- a/packages/test-utils/src/testcontainers/index.ts +++ b/packages/test-utils/src/testcontainers/index.ts @@ -1,2 +1,3 @@ export { default as testContainers } from './testContainersTD'; +export * from './globalTestContainersTD'; export * from './types';