diff --git a/.gitignore b/.gitignore index 98455bb4..e3d4fda9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ node_modules/ */.env +.env .DS_Store mediator/dist mediator/coverage diff --git a/configurator/config/index.js b/configurator/config/index.js index 68dce649..086c95a3 100644 --- a/configurator/config/index.js +++ b/configurator/config/index.js @@ -1,19 +1,38 @@ -require('dotenv/config'); +const dotenv = require('dotenv'); +const path = require('path'); -const OPENHIM_API_HOSTNAME = process.env.OPENHIM_API_HOSTNAME || 'openhim-core'; -const OPENHIM_API_PASSWORD = - process.env.OPENHIM_PASSWORD || 'openhim-password'; -const OPENHIM_API_PORT = process.env.OPENHIM_API_PORT || 8080; -const OPENHIM_API_USERNAME = - process.env.OPENHIM_USERNAME || 'root@openhim.org'; -const OPENHIM_CLIENT_PASSWORD = process.env.OPENHIM_CLIENT_PASSWORD || 'interop-password'; -const OPENHIM_USER_PASSWORD = process.env.OPENHIM_USER_PASSWORD || 'interop-password'; +const isDocker = process.env.DOCKER_ENV === 'true'; +const isTest = process.env.NODE_ENV === 'integration'; + +if (!isDocker && !isTest) { + const envPath = path.resolve(__dirname, '../.env'); + const res = dotenv.config({ path: envPath }); + + if (res.error) { + throw new Error(`Error loading .env file at ${ envPath }: ${ res.error }`); + } +} + +const getEnv = (key) => { + const value = process.env[key]; + if (!value || value.trim() === '') { + throw new Error( + `Missing required environment variable: ${key}` + ); + } + return value.trim(); +}; + +const OPENHIM_API_URL = getEnv('OPENHIM_API_URL'); +const OPENHIM_API_USERNAME = getEnv('OPENHIM_USERNAME'); +const OPENHIM_API_PASSWORD = getEnv('OPENHIM_PASSWORD'); +const OPENHIM_CLIENT_PASSWORD = getEnv('OPENHIM_CLIENT_PASSWORD'); +const OPENHIM_USER_PASSWORD = getEnv('OPENHIM_USER_PASSWORD'); module.exports = { - OPENHIM_API_HOSTNAME, - OPENHIM_API_PASSWORD, - OPENHIM_API_PORT, + OPENHIM_API_URL, OPENHIM_API_USERNAME, + OPENHIM_API_PASSWORD, OPENHIM_CLIENT_PASSWORD, - OPENHIM_USER_PASSWORD + OPENHIM_USER_PASSWORD, }; diff --git a/configurator/env.template b/configurator/env.template index 8c172f48..44445c53 100644 --- a/configurator/env.template +++ b/configurator/env.template @@ -1,6 +1,7 @@ -OPENHIM_API_HOSTNAME = 'localhost'; -OPENHIM_API_PORT = 8080; -OPENHIM_PASSWORD = 'openhim-password'; -OPENHIM_USERNAME = 'root@openhim.org'; -OPENHIM_CLIENT_PASSWORD = 'interop-password'; -OPENHIM_USER_PASSWORD = 'interop-password'; +COUCHDB_USER=admin +COUCHDB_PASSWORD=password +OPENHIM_API_URL=https://openhim-core:8080 +OPENHIM_PASSWORD=openhim-password +OPENHIM_USERNAME=root@openhim.org +OPENHIM_CLIENT_PASSWORD=interop-password +OPENHIM_USER_PASSWORD=interop-password diff --git a/configurator/libs/authentication.js b/configurator/libs/authentication.js index 71c09bda..b2289732 100644 --- a/configurator/libs/authentication.js +++ b/configurator/libs/authentication.js @@ -1,7 +1,8 @@ const crypto = require('crypto'); const { - OPENHIM_API_USERNAME, OPENHIM_API_PASSWORD, - OPENHIM_API_HOSTNAME, OPENHIM_API_PORT + OPENHIM_API_USERNAME, + OPENHIM_API_PASSWORD, + OPENHIM_API_URL, } = require('../config'); const {fetch} = require('../utils'); @@ -44,7 +45,7 @@ const generateAuthHeaders = async (options) => { function generateApiOptions (endpoint) { return { - apiURL: `https://${OPENHIM_API_HOSTNAME}:${OPENHIM_API_PORT}`, + apiURL: OPENHIM_API_URL, apiEndpoint: endpoint, username: OPENHIM_API_USERNAME, password: OPENHIM_API_PASSWORD, diff --git a/docker/docker-compose.mediator.yml b/docker/docker-compose.mediator.yml index 4a001d43..6918fbc0 100644 --- a/docker/docker-compose.mediator.yml +++ b/docker/docker-compose.mediator.yml @@ -1,46 +1,32 @@ services: mediator: - build: + build: context: ../mediator dockerfile: ./Dockerfile container_name: mediator ports: - "6000:6000" + env_file: + - ../mediator/.env environment: - - "OPENHIM_USERNAME=${OPENHIM_USERNAME:-interop@openhim.org}" - - "OPENHIM_PASSWORD=${OPENHIM_PASSWORD:-interop-password}" - - "OPENHIM_API_URL=${OPENHIM_API_URL:-https://openhim-core:8080}" - - "PORT=${PORT:-6000}" - - "FHIR_URL=${FHIR_URL:-http://openhim-core:5001/fhir}" - - "FHIR_USERNAME=${FHIR_USERNAME:-interop-client}" - - "FHIR_PASSWORD=${FHIR_PASSWORD:-interop-password}" - - "CHT_URL=${CHT_URL:-https://nginx}" - - "CHT_USERNAME=${CHT_USERNAME:-admin}" - - "CHT_PASSWORD=${CHT_PASSWORD:-password}" - + - DOCKER_ENV=true depends_on: - configurator restart: 'unless-stopped' networks: - cht-net - + configurator: build: context: ../ dockerfile: ./configurator/Dockerfile + env_file: + - ../configurator/.env environment: - - "COUCHDB_USER=${COUCHDB_USER:-admin}" - - "COUCHDB_PASSWORD=${COUCHDB_PASSWORD:-password}" - - "OPENHIM_API_HOSTNAME=${OPENHIM_API_HOSTNAME:-openhim-core}" - - "OPENHIM_API_PORT=${OPENHIM_API_PORT:-8080}" - - "OPENHIM_PASSWORD=${OPENHIM_PASSWORD:-openhim-password}" - - "OPENHIM_USERNAME=${OPENHIM_USERNAME:-root@openhim.org}" - - "OPENHIM_CLIENT_PASSWORD=${OPENHIM_CLIENT_PASSWORD:-interop-password}" - - "OPENHIM_USER_PASSWORD=${OPENHIM_USER_PASSWORD:-interop-password}" + - DOCKER_ENV=true networks: - cht-net networks: cht-net: name: ${CHT_NETWORK:-cht-net} - diff --git a/mediator/config/index.ts b/mediator/config/index.ts index 7ca72253..74c9a40e 100644 --- a/mediator/config/index.ts +++ b/mediator/config/index.ts @@ -1,32 +1,44 @@ import * as dotenv from 'dotenv'; -dotenv.config(); +import path from 'path'; -export const PORT = process.env.PORT || 6000; +const isDocker = process.env.DOCKER_ENV === 'true'; +const isTest = process.env.NODE_ENV === 'integration'; + +if (!isDocker && !isTest) { + const envPath = path.resolve(__dirname, '../.env'); + const res = dotenv.config({ + path: envPath + }); + if (res.error) { + throw new Error(`Error loading .env file at ${envPath}: ${res.error}`); + } +} + +export const PORT = getEnvironmentVariable('PORT'); export const OPENHIM = { - username: getEnvironmentVariable('OPENHIM_USERNAME', 'interop@openhim.org'), - password: getEnvironmentVariable('OPENHIM_PASSWORD', 'interop-password'), - apiURL: getEnvironmentVariable('OPENHIM_API_URL', 'https://openhim-core:8080'), + username: getEnvironmentVariable('OPENHIM_USERNAME'), + password: getEnvironmentVariable('OPENHIM_PASSWORD'), + apiURL: getEnvironmentVariable('OPENHIM_API_URL'), trustSelfSigned: true, }; export const FHIR = { - url: getEnvironmentVariable('FHIR_URL', 'http://openhim-core:5001/fhir'), - username: getEnvironmentVariable('FHIR_USERNAME', 'interop-client'), - password: getEnvironmentVariable('FHIR_PASSWORD', 'interop-password'), + url: getEnvironmentVariable('FHIR_URL'), + username: getEnvironmentVariable('FHIR_USERNAME'), + password: getEnvironmentVariable('FHIR_PASSWORD'), }; export const CHT = { - url: getEnvironmentVariable('CHT_URL', 'https://nginx'), - username: getEnvironmentVariable('CHT_USERNAME', 'admin'), - password: getEnvironmentVariable('CHT_PASSWORD', 'password'), + url: getEnvironmentVariable('CHT_URL'), + username: getEnvironmentVariable('CHT_USERNAME'), + password: getEnvironmentVariable('CHT_PASSWORD'), }; - -function getEnvironmentVariable(env: string, def: string) { - if (process.env.NODE_ENV === 'test') { - return def; +function getEnvironmentVariable(env: string) { + const value = process.env[env]; + if (typeof value === 'undefined' || value === '') { + throw new Error(`Missing required environment variable: ${env}`); } - - return process.env[env] || def; + return value; } diff --git a/mediator/env.template b/mediator/env.template index 1bd413bc..bb6d1aa1 100644 --- a/mediator/env.template +++ b/mediator/env.template @@ -1,10 +1,10 @@ -OPENHIM_USERNAME = "interop@openhim.org" -OPENHIM_PASSWORD = "password" -OPENHIM_API_URL = "https://openhim-core:8080" -PORT = 6000 -FHIR_URL = http://openhim-core:5001/fhir -FHIR_USERNAME = interop-client -FHIR_PASSWORD = interop-password -CHT_URL = http://nginx -CHT_USERNAME = medic -CHT_PASSWORD = password +OPENHIM_USERNAME=interop@openhim.org +OPENHIM_PASSWORD=interop-password +OPENHIM_API_URL=https://openhim-core:8080 +PORT=6000 +FHIR_URL=http://openhim-core:5001/fhir +FHIR_USERNAME=interop-client +FHIR_PASSWORD=interop-password +CHT_URL=https://nginx +CHT_USERNAME=admin +CHT_PASSWORD=password diff --git a/mediator/jest.config.js b/mediator/jest.base.config.js similarity index 100% rename from mediator/jest.config.js rename to mediator/jest.base.config.js diff --git a/mediator/jest.e2e.config.js b/mediator/jest.e2e.config.js new file mode 100644 index 00000000..7264b12d --- /dev/null +++ b/mediator/jest.e2e.config.js @@ -0,0 +1,10 @@ +const baseConfig = require('./jest.base.config.js'); + +module.exports = { + ...baseConfig, + displayName: 'e2e', + testMatch: [ + '/test/**/*.spec.ts', + ], + // Note: setupFilesAfterEnv is not included here +}; diff --git a/mediator/jest.setup.ts b/mediator/jest.setup.ts new file mode 100644 index 00000000..6a5b1a57 --- /dev/null +++ b/mediator/jest.setup.ts @@ -0,0 +1,21 @@ +jest.mock('dotenv', () => ({ + config: jest.fn(() => { + // Set the environment variables you need for your tests + process.env.DOCKER_ENV = 'false'; + process.env.PORT = '8080'; + process.env.OPENHIM_USERNAME = 'mock_openhim_user'; + process.env.OPENHIM_PASSWORD = 'mock_openhim_password'; + process.env.OPENHIM_API_URL = 'http://mock-openhim.com'; + process.env.FHIR_URL = 'http://mock-fhir.com'; + process.env.FHIR_USERNAME = 'mock_fhir_user'; + process.env.FHIR_PASSWORD = 'mock_fhir_password'; + process.env.CHT_URL = 'http://mock-cht.com'; + process.env.CHT_USERNAME = 'mock_cht_user'; + process.env.CHT_PASSWORD = 'mock_cht_password'; + return { error: null }; + }), +})); + +jest.mock('path', () => ({ + resolve: jest.fn(() => '/mock/path/.env'), +})); diff --git a/mediator/jest.unit.config.js b/mediator/jest.unit.config.js new file mode 100644 index 00000000..1f662383 --- /dev/null +++ b/mediator/jest.unit.config.js @@ -0,0 +1,11 @@ +const baseConfig = require('./jest.base.config.js'); + +module.exports = { + ...baseConfig, + displayName: 'unit', + testMatch: [ + '/src/**/*.spec.ts', + '!/test/**/*', + ], + setupFilesAfterEnv: ['./jest.setup.ts'], +}; diff --git a/mediator/package.json b/mediator/package.json index bd1c1e2b..22cc6e07 100644 --- a/mediator/package.json +++ b/mediator/package.json @@ -11,7 +11,7 @@ "test:watch": "jest --watch", "coverage": "jest --coverage", "clean": "rm -rf ./dist", - "unit-test": "jest src/", + "unit-test": "jest --config ./jest.unit.config.js", "e2e-test": "test/e2e-test.sh" }, "repository": { diff --git a/mediator/src/utils/cht.ts b/mediator/src/utils/cht.ts index e0c96000..7f357b24 100644 --- a/mediator/src/utils/cht.ts +++ b/mediator/src/utils/cht.ts @@ -2,7 +2,6 @@ import axios from 'axios'; import { CHT } from '../../config'; import { generateBasicAuthUrl } from './url'; import https from 'https'; -import path from 'path'; export async function createChtRecord(patientId: string) { const record = { @@ -24,5 +23,6 @@ export async function createChtRecord(patientId: string) { export const generateChtRecordsApiUrl = (chtUrl: string, username: string, password: string) => { const endpoint = generateBasicAuthUrl(chtUrl, username, password); - return path.join(endpoint, '/api/v2/records'); + + return new URL('/api/v2/records', endpoint).toString(); }; diff --git a/mediator/test/e2e-test.sh b/mediator/test/e2e-test.sh index ff3922a5..4b38a7b7 100755 --- a/mediator/test/e2e-test.sh +++ b/mediator/test/e2e-test.sh @@ -1,7 +1,9 @@ #!/bin/bash set -e BASEDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && cd .. && pwd )" -MEDIATORDIR="${BASEDIR}/mediator" +MEDIATOR_DIR="${BASEDIR}/mediator" +MEDIATOR_ENV_FILE="${MEDIATOR_DIR}/.env" +CONFIGURATOR_ENV_FILE="${BASEDIR}/configurator/.env" export NODE_ENV=integration export NODE_TLS_REJECT_UNAUTHORIZED=0 @@ -21,19 +23,70 @@ retry_startup() { fi } +file_check_and_create() { + local filename="$1" + if [ ! -f "$filename" ]; then + touch "$filename" + echo true + else + echo false + fi +} + echo 'Cleanup from last test, in case of interruptions...' cd $BASEDIR +# ensure .env file exists, this won't overwrite an existing file +# .env is required when destroying the containers +MEDIATOR_ENV_FILE_CREATED=$(file_check_and_create "$MEDIATOR_ENV_FILE") +CONFIGURATOR_ENV_FILE_CREATED=$(file_check_and_create "$CONFIGURATOR_ENV_FILE") ./startup.sh destroy echo 'Starting the interoperability containers...' cd $BASEDIR +# Only write to .env file if it doesn't exist +if [ "$MEDIATOR_ENV_FILE_CREATED" = true ]; then + # Write environment variables to .env file for mediator container + cat > "$MEDIATOR_ENV_FILE" << EOF +NODE_ENV=${NODE_ENV} +NODE_TLS_REJECT_UNAUTHORIZED=${NODE_TLS_REJECT_UNAUTHORIZED} +OPENHIM_USERNAME=interop@openhim.org +OPENHIM_PASSWORD=interop-password +OPENHIM_API_URL=https://openhim-core:8080 +PORT=6000 +FHIR_URL=http://openhim-core:5001/fhir +FHIR_USERNAME=interop-client +FHIR_PASSWORD=interop-password +CHT_URL=https://nginx +CHT_USERNAME=admin +CHT_PASSWORD=password +EOF + echo "Created mediator/.env file with test environment variables" +else + echo "Using existing mediator/.env file" +fi + +if [ "$CONFIGURATOR_ENV_FILE_CREATED" = true ]; then + # Write environment variables to .env file for configurator container + cat > "$CONFIGURATOR_ENV_FILE" << EOF +COUCHDB_USER=admin +COUCHDB_PASSWORD=password +OPENHIM_API_URL=https://openhim-core:8080 +OPENHIM_PASSWORD=openhim-password +OPENHIM_USERNAME=root@openhim.org +OPENHIM_CLIENT_PASSWORD=interop-password +OPENHIM_USER_PASSWORD=interop-password +EOF + echo "Created configurator/.env file with test environment variables" +else + echo "Using existing configurator/.env file" +fi retry_startup echo 'Waiting for configurator to finish...' docker container wait chis-interop-configurator-1 echo 'Executing mediator e2e tests...' -cd $MEDIATORDIR +cd $MEDIATOR_DIR export OPENHIM_API_URL='https://localhost:8080' export FHIR_URL='http://localhost:5001' export CHT_URL='http://localhost:5988' @@ -43,7 +96,10 @@ export FHIR_USERNAME='interop-client' export FHIR_PASSWORD='interop-password' export CHT_USERNAME='admin' export CHT_PASSWORD='password' -npm test ltfu-flow.spec.ts +export PORT=6000 +export OPENHIM_CLIENT_PASSWORD='interop-password' +export OPENHIM_USER_PASSWORD='interop-password' +jest --config ./jest.e2e.config.js echo 'Cleanup after test...' unset NODE_ENV @@ -57,6 +113,20 @@ unset FHIR_USERNAME unset FHIR_PASSWORD unset CHT_USERNAME unset CHT_PASSWORD +unset PORT +unset OPENHIM_CLIENT_PASSWORD +unset OPENHIM_USER_PASSWORD cd $BASEDIR ./startup.sh destroy +if [ "$MEDIATOR_ENV_FILE_CREATED" = true ]; then + echo "Deleting the mediator env file we created: $MEDIATOR_ENV_FILE" + rm "$MEDIATOR_ENV_FILE" +fi + +if [ "$CONFIGURATOR_ENV_FILE_CREATED" = true ]; then + echo "Deleting the configurator env file we created: $CONFIGURATOR_ENV_FILE" + rm "$CONFIGURATOR_ENV_FILE" +fi + +echo 'Finish'