From 385d9ea211eff4f70a478aa1812fb61cb7ceecc5 Mon Sep 17 00:00:00 2001 From: Rajiv Mothilal Date: Sun, 11 Mar 2018 12:13:06 +0200 Subject: [PATCH] Develop (#49) * Incorporate all historical changes to align with mojaloop. * Tested locally with provided scripts - passed Tested with Postman - passed To be fixed: Credentials on tests for SMTP * Fixed Emailing test with a valid user * fixes for unit test issues * re-added sidecar enabled * fixes and updates to tests and package * fixes for functional tests * fixing unit tests, stubbing smtp server * settlement coverage * unit testing for settlements and csv * removed console.logs * code working except for test * fixes for some tests * updates for validation working * fixing reorder * reverting * fix file path * added updated config.yml script * testing * unit test fixes and changes. coverage failing * fixes for coverage tests only setup.js left now * fixes for docker version and updated onboarding doc * removing fs-extra * reverting default json for sidecar * Fix src/setup/setup.js tests * updated code for functional tests and integration tests * files for integration and functional tests * fixes for testing * sodium build issues * issues with sodium * removed global install of sodium and argon which is breaking circleci build. build is currently cached so it may break again because of cache * version upgrade * added local install of tape and tap-xunit to config.yml and test.dockerfile * version change so that cache refreshes * dependency issue for tape and tap-xunit * added tape and tap-xunit for test.docker file back for testing to pass --- .circleci/config.yml | 135 +++---- Dockerfile | 12 +- Onboarding.md | 6 +- admin.Dockerfile | 19 +- api.Dockerfile | 19 +- circle.yml | 2 +- package.json | 64 ++-- security_scan.txt | 35 -- server.sh | 4 + src/admin/accounts/handler.js | 38 +- src/admin/accounts/routes.js | 37 +- src/admin/auth/admin.js | 19 +- src/admin/auth/index.js | 21 +- src/admin/auth/token.js | 26 +- src/admin/charges/handler.js | 41 ++- src/admin/charges/routes.js | 56 +-- src/admin/index.js | 10 +- src/admin/permissions/handler.js | 4 +- src/admin/permissions/routes.js | 2 +- src/admin/positions/handler.js | 15 +- src/admin/positions/routes.js | 10 +- src/admin/roles/handler.js | 25 +- src/admin/roles/routes.js | 40 +- src/admin/root/routes.js | 12 +- src/admin/route-config.js | 12 +- src/admin/routes.js | 14 +- src/admin/token/handler.js | 6 +- src/admin/token/routes.js | 8 +- src/admin/transfers/handler.js | 8 +- src/admin/transfers/routes.js | 2 +- src/admin/users/handler.js | 42 +-- src/admin/users/routes.js | 80 ++-- src/admin/webhooks/handler.js | 23 +- src/admin/webhooks/routes.js | 6 +- src/api/accounts/handler.js | 64 ++-- src/api/accounts/routes.js | 37 +- src/api/auth/account.js | 24 +- src/api/auth/index.js | 17 +- src/api/auth/token.js | 4 +- src/api/charges/handler.js | 12 +- src/api/charges/routes.js | 6 +- src/api/index.js | 18 +- src/api/messages/handler.js | 13 +- src/api/messages/routes.js | 6 +- src/api/metadata/handler.js | 18 +- src/api/metadata/routes.js | 4 +- src/api/positions/handler.js | 14 +- src/api/positions/routes.js | 8 +- src/api/routes.js | 14 +- src/api/sockets/index.js | 19 +- src/api/token/handler.js | 7 +- src/api/token/routes.js | 4 +- src/api/transfers/handler.js | 49 ++- src/api/transfers/routes.js | 24 +- src/api/transfers/validator.js | 3 + src/api/worker/index.js | 20 +- src/domain/account/index.js | 10 +- src/domain/position/index.js | 3 - src/domain/token/auth.js | 53 ++- src/errors/invalid-body.js | 2 +- src/lib/config.js | 2 +- src/lib/request-logger.js | 7 +- src/shared/plugins.js | 48 ++- src/shared/setup.js | 79 ++-- test.Dockerfile | 25 +- test/.env | 1 + test/fixtures/index.js | 2 +- .../functional/admin/accounts/get-all.test.js | 38 +- test/functional/admin/charges/update.test.js | 76 ++-- .../webhooks/post-settle-transfers.test.js | 23 +- test/functional/api/accounts/routes.test.js | 50 +-- test/functional/api/metadata/routes.test.js | 50 ++- .../api/token/get-auth-token.test.js | 22 +- .../api/transfers/get-fulfillment.test.js | 18 +- test/functional/base.js | 27 +- test/integration-runner.env | 14 + test/integration-runner.sh | 134 +++++-- test/unit/admin/accounts/handler.test.js | 163 ++++----- test/unit/admin/auth/admin.test.js | 63 ++-- test/unit/admin/auth/index.test.js | 21 +- test/unit/admin/auth/token.test.js | 39 +- test/unit/admin/charges/handler.test.js | 252 ++++++++----- test/unit/admin/index.test.js | 4 +- test/unit/admin/permissions/handler.test.js | 11 +- test/unit/admin/positions/handler.test.js | 56 +-- test/unit/admin/roles/handler.test.js | 93 +++-- test/unit/admin/root/routes.test.js | 28 +- test/unit/admin/route-config.test.js | 21 +- test/unit/admin/routes.test.js | 3 +- test/unit/admin/token/handler.test.js | 23 +- test/unit/admin/transfers/handler.test.js | 31 +- test/unit/admin/users/handler.test.js | 103 +++--- test/unit/admin/webhooks/handler.test.js | 83 ++--- test/unit/api/accounts/handler.test.js | 345 ++++++++---------- test/unit/api/accounts/routes.test.js | 49 ++- test/unit/api/auth/account.test.js | 67 ++-- test/unit/api/auth/index.test.js | 32 +- test/unit/api/charges/handler.test.js | 40 +- test/unit/api/charges/routes.test.js | 16 +- test/unit/api/index.test.js | 21 +- test/unit/api/messages/handler.test.js | 48 +-- test/unit/api/messages/routes.test.js | 54 ++- test/unit/api/metadata/handler.test.js | 121 +++--- test/unit/api/positions/handler.test.js | 62 ++-- test/unit/api/sockets/index.test.js | 161 ++++---- test/unit/api/token/handler.test.js | 24 +- test/unit/api/transfers/handler.test.js | 270 +++++++------- test/unit/api/transfers/routes.test.js | 151 ++++---- test/unit/api/worker/index.test.js | 86 ++--- test/unit/base.js | 44 ++- test/unit/domain/settlements/index.test.js | 24 +- test/unit/domain/token/auth.test.js | 151 ++++---- test/unit/lib/events.test.js | 39 +- test/unit/models/settlements.test.js | 10 +- test/unit/shared/plugins.test.js | 9 +- test/unit/shared/setup.test.js | 166 ++------- 116 files changed, 2465 insertions(+), 2441 deletions(-) delete mode 100644 security_scan.txt create mode 100644 server.sh create mode 100644 test/integration-runner.env diff --git a/.circleci/config.yml b/.circleci/config.yml index 84453dc19..328645ad1 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -6,7 +6,7 @@ defaults_working_directory: &defaults_working_directory defaults_docker_node: &defaults_docker_node docker: - - image: dwolla/alpine-node-make + - image: mhart/alpine-node:8.9.4 defaults_docker_helm_kube: &defaults_docker_helm_kube docker: @@ -18,13 +18,14 @@ defaults_docker_helm_kube: &defaults_docker_helm_kube # # - TAG_EXP_SNAPSHOT: 'v[0-9]+(\.[0-9]+)*\-SNAPSHOT' # # - TAG: v1.0 -defaults_Dependencies: &defaults_Dependencies | +defaults_Dependencies: &defaults_Dependencies | apk --no-cache add git apk --no-cache add ca-certificates apk --no-cache add curl apk --no-cache add openssh-client + apk add --no-cache -t build-dependencies make gcc g++ python libtool autoconf automake -defaults_awsCliDependencies: &defaults_awsCliDependencies | +defaults_awsCliDependencies: &defaults_awsCliDependencies | apk --no-cache add \ python \ py-pip \ @@ -76,7 +77,7 @@ defaults_deploy_config_kubernetes_credentials: &defaults_deploy_config_kubernete command: | echo "Configure Kubernetes credentails ${K8_USER_NAME}" kubectl config set-credentials $K8_USER_NAME --client-certificate=$CIRCLE_WORKING_DIRECTORY/$AWS_S3_DIR_DEVOPS_DEPLOYMENT_CONFIG_KEYS/$K8_USER_PEM_CERT_FILENAME --client-key=$CIRCLE_WORKING_DIRECTORY/$AWS_S3_DIR_DEVOPS_DEPLOYMENT_CONFIG_KEYS/$K8_USER_PEM_KEY_FILENAME - + defaults_deploy_config_kubernetes_context: &defaults_deploy_config_kubernetes_context name: Confi gure Kubernetes context command: | @@ -100,13 +101,13 @@ defaults_deploy_install_or_upgrade_helm_chart: &defaults_deploy_install_or_upgra echo "Install or Upgrade Chart ${K8_RELEASE_NAME} for Docker Image ${DOCKER_ORG}/${CIRCLE_PROJECT_REPONAME}:${CIRCLE_TAG}" if [ -z "$(helm list -q | grep ${K8_RELEASE_NAME})" ] && [ "$(helm list -q | grep ${K8_RELEASE_NAME})" != "Error: Unauthorized" ]; then - echo "Installing ${K8_RELEASE_NAME} new release" + echo "Installing ${K8_RELEASE_NAME} new release" helm install --namespace=$K8_NAMESPACE --name=$K8_RELEASE_NAME --repo=$K8_HELM_REPO $HELM_VALUE_SET_VALUES -f $CIRCLE_WORKING_DIRECTORY/$AWS_S3_DIR_DEVOPS_DEPLOYMENT_CONFIG_HELM/$HELM_VALUE_FILENAME $K8_HELM_CHART_NAME else - echo "Upgrading ${K8_RELEASE_NAME} release" + echo "Upgrading ${K8_RELEASE_NAME} release" helm upgrade $K8_RELEASE_NAME --repo=$K8_HELM_REPO --reuse-values $HELM_VALUE_SET_VALUES $K8_HELM_CHART_NAME fi - + jobs: setup: <<: *defaults_working_directory @@ -117,17 +118,20 @@ jobs: command: *defaults_Dependencies - checkout - run: - name: Install interledgerjs/five-bells-ledger-api-tests - command: npm install github:interledgerjs/five-bells-ledger-api-tests + name: Access npm folder as root + command: cd $(npm root -g)/npm - run: - name: Link NPM sodium - command: npm link sodium + name: Install node-gyp globally + command: npm install -g node-gyp - run: - name: Link NPM argon2 - command: npm link argon2 + name: Install interledgerjs/five-bells-ledger-api-tests + command: npm install github:interledgerjs/five-bells-ledger-api-tests - run: name: Update NPM install command: npm install + - run: + name: Delete build dependencies + command: apk del build-dependencies # - run: # name: Update NPM install # command: npm link sodium && npm link argon2 && npm install --production @@ -135,7 +139,7 @@ jobs: key: dependency-cache-{{ checksum "package.json" }} paths: - node_modules - + test-unit: <<: *defaults_working_directory <<: *defaults_docker_node @@ -146,10 +150,13 @@ jobs: - checkout - restore_cache: key: dependency-cache-{{ checksum "package.json" }} - - run: + - run: + name: Install tape and tap-xunit + command: npm install -g tape tap-xunit + - run: name: Create dir for test results command: mkdir -p ./test/results - - run: + - run: name: Execute unit tests command: npm -s run test:xunit > ./test/results/tape.xml - store_artifacts: @@ -157,7 +164,7 @@ jobs: prefix: test - store_test_results: path: ./test/results - + test-coverage: <<: *defaults_working_directory <<: *defaults_docker_node @@ -171,7 +178,7 @@ jobs: - checkout - restore_cache: key: dependency-cache-{{ checksum "package.json" }} - - run: + - run: name: Execute code coverage check command: npm -s run test:coverage-check - store_artifacts: @@ -184,12 +191,12 @@ jobs: command: | if [ "${CIRCLE_BRANCH}" == "master" ]; then - echo "Sending lcov.info to SonarQube..." + echo "Sending lcov.info to SonarQube..." aws s3 cp coverage/lcov.info $AWS_S3_DIR_SONARQUBE/central-ledger/lcov.info else - echo "Not a release (env CIRCLE_BRANCH != 'master'), skipping sending lcov.info to SonarQube." - fi - + echo "Not a release (env CIRCLE_BRANCH != 'master'), skipping sending lcov.info to SonarQube." + fi + test-integration: machine: true <<: *defaults_working_directory @@ -197,10 +204,10 @@ jobs: - checkout - restore_cache: key: dependency-cache-{{ checksum "package.json" }} - - run: + - run: name: Create dir for test results command: mkdir -p ./test/results - - run: + - run: name: Execute unit tests command: npm -s run test:integration - store_artifacts: @@ -208,12 +215,12 @@ jobs: prefix: test - store_test_results: path: ./test/results - + test-functional: machine: true <<: *defaults_working_directory steps: - - run: + - run: name: Add the Postgres 9.6 binaries to the path. command: echo ‘/usr/lib/postgresql/9.6/bin/:$PATH’ >> $BASH_ENV - run: @@ -225,10 +232,10 @@ jobs: - checkout - restore_cache: key: dependency-cache-{{ checksum "package.json" }} - - run: + - run: name: Create dir for test results command: mkdir -p ./test/results - - run: + - run: name: Execute unit tests command: npm -s run test:functional - store_artifacts: @@ -240,28 +247,28 @@ jobs: # test-spec: # machine: true -# # <<: *defaults +# # <<: *defaults # steps: -# # - run: -# # name: Install general dependencies -# # command: *defaultDependencies -# # - run: -# # name: Add the Postgres 9.6 binaries to the path. -# # command: apk --no-cache add postgresql-client -# # - setup_remote_docker -# # - run: -# # name: Add docker -# # command: apk --no-cache add docker -# # - run: -# # name: Add docker compose -# # command: | -# # apk --no-cache add py-pip -# # pip install docker-compose -# # - run: -# # name: Install Docker Compose -# # command: | -# # curl -L https://github.com/docker/compose/releases/download/1.8.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose; chmod +x /usr/local/bin/docker-compose -# - run: +# # - run: +# # name: Install general dependencies +# # command: *defaultDependencies +# # - run: +# # name: Add the Postgres 9.6 binaries to the path. +# # command: apk --no-cache add postgresql-client +# # - setup_remote_docker +# # - run: +# # name: Add docker +# # command: apk --no-cache add docker +# # - run: +# # name: Add docker compose +# # command: | +# # apk --no-cache add py-pip +# # pip install docker-compose +# # - run: +# # name: Install Docker Compose +# # command: | +# # curl -L https://github.com/docker/compose/releases/download/1.8.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose; chmod +x /usr/local/bin/docker-compose +# - run: # name: Add the Postgres 9.6 binaries to the path. # command: echo ‘/usr/lib/postgresql/9.6/bin/:$PATH’ >> $BASH_ENV # - run: @@ -273,10 +280,10 @@ jobs: # - checkout # - restore_cache: # key: dependency-cache-{{ checksum "package.json" }} -# - run: +# - run: # name: Create dir for test results # command: mkdir -p ./test/results -# - run: +# - run: # name: Execute unit tests # command: npm -s run test:spec # - store_artifacts: @@ -316,7 +323,7 @@ jobs: <<: *defaults_build_docker_build - run: <<: *defaults_build_docker_publish - + deploy-snapshot: <<: *defaults_working_directory <<: *defaults_docker_helm_kube @@ -385,7 +392,7 @@ workflows: tags: only: /.*/ branches: - ignore: + ignore: - /feature*/ - /bugfix*/ - test-unit: @@ -396,9 +403,9 @@ workflows: tags: only: /.*/ branches: - ignore: + ignore: - /feature*/ - - /bugfix*/ + - /bugfix*/ - test-coverage: context: org-global requires: @@ -407,7 +414,7 @@ workflows: tags: only: /.*/ branches: - ignore: + ignore: - /feature*/ - /bugfix*/ - test-integration: @@ -418,7 +425,7 @@ workflows: tags: only: /.*/ branches: - ignore: + ignore: - /feature*/ - /bugfix*/ - test-functional: @@ -429,7 +436,7 @@ workflows: tags: only: /.*/ branches: - ignore: + ignore: - /feature*/ - /bugfix*/ # - test-spec: @@ -438,9 +445,9 @@ workflows: # - setup # filters: # tags: - # only: /.*/ + # only: /.*/ # branches: - # ignore: + # ignore: # - /feature*/ # - /bugfix*/ - build-snapshot: @@ -456,7 +463,7 @@ workflows: tags: only: /v[0-9]+(\.[0-9]+)*\-snapshot/ branches: - ignore: + ignore: - /.*/ - deploy-snapshot: context: org-global @@ -466,7 +473,7 @@ workflows: tags: only: /v[0-9]+(\.[0-9]+)*\-snapshot/ branches: - ignore: + ignore: - /.*/ - build: context: org-global @@ -481,7 +488,7 @@ workflows: tags: only: /v[0-9]+(\.[0-9]+)*/ branches: - ignore: + ignore: - /.*/ - deploy: context: org-global @@ -491,5 +498,5 @@ workflows: tags: only: /v[0-9]+(\.[0-9]+)*/ branches: - ignore: + ignore: - /.*/ diff --git a/Dockerfile b/Dockerfile index 4b520cf50..047732ddc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,12 +1,16 @@ -FROM dwolla/alpine-node-make +FROM mhart/alpine-node:8.9.4 WORKDIR /opt/central-ledger COPY . /opt/central-ledger -RUN npm link sodium && \ - npm link argon2 && \ - npm install --production && \ +RUN apk add --no-cache -t build-dependencies make gcc g++ python libtool autoconf automake \ + && cd $(npm root -g)/npm \ + && npm install -g node-gyp + +RUN npm install --production && \ npm uninstall -g npm +RUN apk del build-dependencies + EXPOSE 3000 CMD node src/api/index.js diff --git a/Onboarding.md b/Onboarding.md index 26c89f47b..6f5d23bf4 100644 --- a/Onboarding.md +++ b/Onboarding.md @@ -143,12 +143,12 @@ Download the nvm install script via cURL: curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.0/install.sh | bash ``` * Ensure that nvm was installed correctly with `nvm --version`, which should return the version of nvm installed -* Install the version of Node.js you want: +* Install the version (8.9.4 current LTS) of Node.js you want: * Install the latest LTS version with `nvm install --lts` * Use the latest LTS verison with `nvm use --lts` * Install the latest version with `nvm install node` * Use the latest version with `nvm use node` - * If necessary, fallback to `nvm install 6.5.0` and `nvm use 6` + * If necessary, fallback to `nvm install 8.9.4` and `nvm use 0.33.6` ##### Setup nvm Create a *.bash_profile* file with `touch ~/.bash_profile`, then `nano ~/.bash_profile` and *write*: @@ -192,4 +192,4 @@ export CLEDG_DATABASE_URI=postgres://central_ledger:cVq8iFqaLuHy8jjKuA@localhost * `./src/argon2_node.cpp:6:10: fatal error: 'tuple' file not found` - resolved by running `CXX='clang++ -std=c++11 -stdlib=libc++' npm rebuild` * sodium v1.2.3 can't compile during npm install - - resolved by installing v2.0.3 `npm install sodium@2.0.3` \ No newline at end of file + - resolved by installing v2.0.3 `npm install sodium@2.0.3` diff --git a/admin.Dockerfile b/admin.Dockerfile index d51b76fe2..206ffb355 100644 --- a/admin.Dockerfile +++ b/admin.Dockerfile @@ -1,12 +1,21 @@ -FROM dwolla/alpine-node-make +FROM mhart/alpine-node:8.9.4 +USER root WORKDIR /opt/central-ledger -COPY . /opt/central-ledger +COPY src /opt/central-ledger/src +COPY migrations /opt/central-ledger/migrations +COPY config /opt/central-ledger/config +COPY package.json server.sh /opt/central-ledger/ -RUN npm link sodium && \ - npm link argon2 && \ - npm install --production && \ +RUN apk add --no-cache -t build-dependencies make gcc g++ python libtool autoconf automake \ + && cd $(npm root -g)/npm \ + && npm install -g node-gyp \ + && apk --no-cache add git + +RUN npm install --production && \ npm uninstall -g npm +RUN apk del build-dependencies + EXPOSE 3001 CMD node src/admin/index.js diff --git a/api.Dockerfile b/api.Dockerfile index 4b520cf50..d7b0a1ec6 100644 --- a/api.Dockerfile +++ b/api.Dockerfile @@ -1,12 +1,21 @@ -FROM dwolla/alpine-node-make +FROM mhart/alpine-node:8.9.4 +USER root WORKDIR /opt/central-ledger -COPY . /opt/central-ledger +COPY src /opt/central-ledger/src +COPY migrations /opt/central-ledger/migrations +COPY config /opt/central-ledger/config +COPY package.json server.sh /opt/central-ledger/ -RUN npm link sodium && \ - npm link argon2 && \ - npm install --production && \ +RUN apk add --no-cache -t build-dependencies make gcc g++ python libtool autoconf automake \ + && cd $(npm root -g)/npm \ + && npm install -g node-gyp \ + && apk --no-cache add git + +RUN npm install --production && \ npm uninstall -g npm +RUN apk del build-dependencies + EXPOSE 3000 CMD node src/api/index.js diff --git a/circle.yml b/circle.yml index 590a4a5d2..912cb0efe 100644 --- a/circle.yml +++ b/circle.yml @@ -9,7 +9,7 @@ machine: services: - docker node: - version: 6.5.0 + version: 8.9.4 environment: AWS_ACCOUNT_ID: 886403637725 APP_NAME: central-ledger diff --git a/package.json b/package.json index 6473ac897..44a13e764 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@mojaloop/central-ledger", - "version": "1.85.3", + "version": "1.86.2", "description": "Central ledger hosted by a scheme to record and settle transfers.", "license": "Apache-2.0", "private": true, @@ -33,14 +33,13 @@ "test:xunit": "tape 'test/unit/**/*.test.js' | tap-xunit", "test:coverage": "istanbul cover tape -- 'test/unit/**/*.test.js'", "test:coverage-check": "npm run test:coverage && istanbul check-coverage", - "test:integration:test-only": "sh ./test/integration-runner.sh ./test/.env", - "test:integration": "run-s docker:build:test test:integration:test-only", + "test:integration": "sh ./test/integration-runner.sh ./test/integration-runner.env", "test:functional": "run-s docker:build test:functional:test-only", "test:functional:test-only": "sh ./test/functional-runner.sh docker-compose.yml docker-compose.functional.yml ./test/.env", "test:spec:test-only": "sh ./test/spec-runner.sh ./test/.env", "test:spec": "run-s docker:build test:spec:test-only", "db:psql": "docker run -it --net centralledger_back --rm postgres:9.4 sh -c 'exec psql -h postgres -p \"$POSTGRES_PORT_5432_TCP_PORT\" -U central_ledger -d postgres'", - "migrate": "knex migrate:latest $npm_package_config_knex", + "migrate": "knex $npm_package_config_knex migrate:latest", "migrate:create": "knex migrate:make $npm_package_config_knex", "migrate:rollback": "knex migrate:rollback $npm_package_config_knex", "migrate:current": "knex migrate:currentVersion $npm_package_config_knex", @@ -53,48 +52,55 @@ "docker:clean": "docker-compose -f docker-compose.yml -f docker-compose.dev.yml -f docker-compose.functional.yml down --rmi local" }, "dependencies": { - "@mojaloop/central-services-auth": "0.1.3", - "@mojaloop/central-services-database": "0.3.0", - "@mojaloop/central-services-error-handling": "0.2.3", - "@mojaloop/central-services-shared": "0.3.0", - "@mojaloop/forensic-logging-client": "0.4.0", - "argon2": "0.14.0", - "blipp": "2.3.0", + "@mojaloop/central-services-auth": "0.2.0", + "@mojaloop/central-services-database": "0.4.2", + "@mojaloop/central-services-error-handling": "0.5.1", + "@mojaloop/central-services-shared": "0.4.0", + "@mojaloop/forensic-logging-client": "0.5.1", + "@now-ims/hapi-now-auth": "1.0.1", + "argon2": "0.17.1", + "bcrypt": "1.0.3", + "blipp": "3.0.0", "bluebird": "3.5.0", + "boom": "^7.2.0", "continuation-local-storage": "3.2.0", "deasync-promise": "1.0.1", - "decimal.js": "7.2.0", + "decimal.js": "9.0.1", "eventric": "0.26.0", "five-bells-condition": "5.0.1", - "flat": "^4.0.0", + "flat": "4.0.0", "glob": "7.1.1", - "good": "7.1.0", + "good": "8.1.0", + "good-squeeze": "^5.0.2", "good-winston": "4.0.0", - "hapi": "16.1.1", - "hapi-swagger": "7.7.0", - "inert": "4.2.0", - "joi": "10.4.1", - "json2csv": "^3.11.5", - "jsonwebtoken": "7.4.0", + "hapi": "17.2.0", + "hapi-auth-basic": "5.0.0", + "hapi-auth-bearer-token": "^6.0.1", + "hapi-swagger": "9.0.2", + "inert": "5.1.0", + "joi": "13.1.2", + "json2csv": "3.11.5", + "jsonwebtoken": "8.1.1", + "knex": "0.14.2", "lodash": "4.17.4", - "moment": "2.18.1", - "nodemailer": "^4.4.0", - "rc": "1.2.1", - "sodium": "1.2.3", + "moment": "2.21.0", + "nodemailer": "4.4.2", + "rc": "1.2.5", + "sodium": "2.0.3", "urlsafe-base64": "1.0.0", "uuid4": "1.0.0", - "vision": "4.1.1", - "winston": "2.3.1", - "ws": "2.3.1" + "vision": "5.3.1", + "winston": "2.4.0", + "ws": "4.0.0" }, "optionalDependencies": { - "pg": "6.1.0" + "pg": "7.4.1" }, "devDependencies": { "aws-sdk": "2.16.0", "faucet": "0.0.1", "five-bells-ledger-api-tests": "github:interledgerjs/five-bells-ledger-api-tests", - "istanbul": "0.4.5", + "istanbul": "1.1.0-alpha.1", "mag": "0.9.1", "mag-hub": "0.1.1", "npm-run-all": "4.0.1", diff --git a/security_scan.txt b/security_scan.txt deleted file mode 100644 index 25d43cd8d..000000000 --- a/security_scan.txt +++ /dev/null @@ -1,35 +0,0 @@ -┌────────────┬────────────────────────────────────────────────────────────────────┐ -│ │ Regular Expression Denial of Service │ -├────────────┼────────────────────────────────────────────────────────────────────┤ -│ Name │ moment │ -├────────────┼────────────────────────────────────────────────────────────────────┤ -│ CVSS │ 7.5 (High) │ -├────────────┼────────────────────────────────────────────────────────────────────┤ -│ Installed │ 2.18.1 │ -├────────────┼────────────────────────────────────────────────────────────────────┤ -│ Vulnerable │ <2.19.3 │ -├────────────┼────────────────────────────────────────────────────────────────────┤ -│ Patched │ >=2.19.3 │ -├────────────┼────────────────────────────────────────────────────────────────────┤ -│ Path │ @mojaloop/central-ledger@1.85.3 > moment@2.18.1 │ -├────────────┼────────────────────────────────────────────────────────────────────┤ -│ More Info │ https://nodesecurity.io/advisories/532 │ -└────────────┴────────────────────────────────────────────────────────────────────┘ - -┌────────────┬────────────────────────────────────────────────────────────────────┐ -│ │ Denial of Service │ -├────────────┼────────────────────────────────────────────────────────────────────┤ -│ Name │ ws │ -├────────────┼────────────────────────────────────────────────────────────────────┤ -│ CVSS │ 7.5 (High) │ -├────────────┼────────────────────────────────────────────────────────────────────┤ -│ Installed │ 2.3.1 │ -├────────────┼────────────────────────────────────────────────────────────────────┤ -│ Vulnerable │ <1.1.5 || >=2.0.0 <3.3.1 │ -├────────────┼────────────────────────────────────────────────────────────────────┤ -│ Patched │ >= 1.1.5 <2.0.0 || >=3.3.1 │ -├────────────┼────────────────────────────────────────────────────────────────────┤ -│ Path │ @mojaloop/central-ledger@1.85.3 > ws@2.3.1 │ -├────────────┼────────────────────────────────────────────────────────────────────┤ -│ More Info │ https://nodesecurity.io/advisories/550 │ -└────────────┴────────────────────────────────────────────────────────────────────┘ diff --git a/server.sh b/server.sh new file mode 100644 index 000000000..3e5e8fd52 --- /dev/null +++ b/server.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +cd /opt/central-ledger/ +node src/api/index.js diff --git a/src/admin/accounts/handler.js b/src/admin/accounts/handler.js index e560a2ca4..b79d5cb72 100644 --- a/src/admin/accounts/handler.js +++ b/src/admin/accounts/handler.js @@ -5,7 +5,7 @@ const Errors = require('../../errors') const UrlParser = require('../../lib/urlparser') const Sidecar = require('../../lib/sidecar') -const entityItem = ({ name, createdDate, isDisabled }) => { +const entityItem = ({name, createdDate, isDisabled}) => { const link = UrlParser.toAccountUri(name) return { name, @@ -33,35 +33,29 @@ const handleMissingRecord = (entity) => { return entity } -const create = (request, reply) => { +const create = async function (request, h) { Sidecar.logRequest(request) - Account.getByName(request.payload.name) - .then(handleExistingRecord) - .then(() => Account.create(request.payload)) - .then(account => reply(entityItem(account)).code(201)) - .catch(reply) + const entity = await Account.getByName(request.payload.name) + await handleExistingRecord(entity) + const account = await Account.create(request.payload) + return h.response(entityItem(account)).code(201) } -const getAll = (request, reply) => { - Account.getAll() - .then(results => results.map(entityItem)) - .then(reply) - .catch(reply) +const getAll = async function (request, h) { + const results = await Account.getAll() + return results.map(entityItem) } -const getByName = (request, reply) => { - Account.getByName(request.params.name) - .then(handleMissingRecord) - .then(account => entityItem(account)) - .then(reply) - .catch(reply) +const getByName = async function (request, h) { + const entity = await Account.getByName(request.params.name) + handleMissingRecord(entity) + return entityItem(entity) } -const update = (request, reply) => { +const update = async function (request, h) { Sidecar.logRequest(request) - Account.update(request.params.name, request.payload) - .then(result => reply(entityItem(result))) - .catch(reply) + const updatedEntity = await Account.update(request.params.name, request.payload) + return entityItem(updatedEntity) } module.exports = { diff --git a/src/admin/accounts/routes.js b/src/admin/accounts/routes.js index 106198b6b..51a2e2d34 100644 --- a/src/admin/accounts/routes.js +++ b/src/admin/accounts/routes.js @@ -6,21 +6,21 @@ const Permissions = require('../../domain/security/permissions') const RouteConfig = require('../route-config') const tags = ['api', 'accounts'] -const nameValidator = Joi.string().token().max(256).required().description('Name of the account') -const passwordValidator = Joi.string().token().max(256).required().description('Password for the account') +const nameValidator = Joi.string().alphanum().min(3).max(30).required().description('Name of the account') +const passwordValidator = Joi.string().regex(/^[a-zA-Z0-9]{3,30}$/).required().description('Password for the account') module.exports = [ { method: 'GET', path: '/accounts', handler: Handler.getAll, - config: RouteConfig.config(tags, Permissions.ACCOUNTS_LIST) + options: RouteConfig.config(tags, Permissions.ACCOUNTS_LIST) }, { method: 'GET', path: '/accounts/{name}', handler: Handler.getByName, - config: RouteConfig.config(tags, Permissions.ACCOUNTS_VIEW, { + options: RouteConfig.config(tags, Permissions.ACCOUNTS_VIEW, { params: { name: Joi.string().required().description('Account name') } @@ -30,10 +30,17 @@ module.exports = [ method: 'POST', path: '/accounts', handler: Handler.create, - config: RouteConfig.config(tags, Permissions.ACCOUNTS_CREATE, { + options: RouteConfig.config(tags, Permissions.ACCOUNTS_CREATE, { payload: { - name: nameValidator, - password: passwordValidator + allow: ['application/json'], + failAction: 'error' + }, + validate: { + payload: { + name: nameValidator, + password: passwordValidator, + emailAddress: Joi.string().email().required() + } } }) }, @@ -41,12 +48,18 @@ module.exports = [ method: 'PUT', path: '/accounts/{name}', handler: Handler.update, - config: RouteConfig.config(tags, Permissions.ACCOUNTS_UPDATE, { - params: { - name: Joi.string().required().description('Account name') - }, + options: RouteConfig.config(tags, Permissions.ACCOUNTS_UPDATE, { payload: { - is_disabled: Joi.boolean().required().description('Account is_disabled boolean') + allow: ['application/json'], + failAction: 'error' + }, + validate: { + payload: { + is_disabled: Joi.boolean().required().description('Account is_disabled boolean') + }, + params: { + name: Joi.string().required().description('Account name') + } } }) } diff --git a/src/admin/auth/admin.js b/src/admin/auth/admin.js index 05fb25f56..c759d7e85 100644 --- a/src/admin/auth/admin.js +++ b/src/admin/auth/admin.js @@ -1,21 +1,26 @@ 'use strict' +// const Bcrypt = require('bcrypt') for later use const Config = require('../../lib/config') +const Logger = require('@mojaloop/central-services-shared').Logger -const validate = (request, username, password, cb) => { +const validate = async (request, username, password, h) => { if (!(username && password && Config.ADMIN_KEY && Config.ADMIN_SECRET)) { - return cb(null, false) + return {credentials: null, isValid: false} } - - if (username === Config.ADMIN_KEY && password === Config.ADMIN_SECRET) { - return cb(null, true, { is_admin: true }) + const isValid = password === Config.ADMIN_SECRET + // const isValid = await Bcrypt.compare(password, Config.ADMIN_SECRET) to be used in the future to hash passwords + if (username === Config.ADMIN_KEY && isValid) { + const credentials = {id: 'test', name: username, is_admin: true} + Logger.info('is a valid admin') + return {isValid: true, credentials} } else { - return cb(null, false) + return {credentials: null, isValid: false} } } module.exports = { name: 'admin', - scheme: 'basic', + scheme: 'simple', validate } diff --git a/src/admin/auth/index.js b/src/admin/auth/index.js index 618d2880d..94cc08f23 100644 --- a/src/admin/auth/index.js +++ b/src/admin/auth/index.js @@ -4,14 +4,17 @@ const Config = require('../../lib/config') const AdminStrategy = require('./admin') const TokenStrategy = require('./token') -exports.register = (server, options, next) => { - server.auth.strategy(AdminStrategy.name, AdminStrategy.scheme, { validate: AdminStrategy.validate }) - server.auth.strategy(TokenStrategy.name, TokenStrategy.scheme, { validate: TokenStrategy.validate }) - next() -} - -exports.register.attributes = { - name: 'admin auth' +exports.plugin = { + name: 'admin auth', + register: function (server, options) { + server.auth.strategy('simple', 'basic', {validate: AdminStrategy.validate}) + // server.auth.default('simple') + server.auth.strategy('jwt-strategy', 'hapi-now-auth', { + verifyJWT: true, + keychain: [Config.ADMIN_SECRET], + validate: TokenStrategy.validate + }) + } } exports.tokenAuth = (permission) => { @@ -23,5 +26,5 @@ exports.tokenAuth = (permission) => { return TokenStrategy.name } - return { strategy: TokenStrategy.name, scope: permission.key } + return {strategy: TokenStrategy.name, scope: permission.key} } diff --git a/src/admin/auth/token.js b/src/admin/auth/token.js index 30c78764c..c24f36ec3 100644 --- a/src/admin/auth/token.js +++ b/src/admin/auth/token.js @@ -2,6 +2,7 @@ const Util = require('../../lib/util') const JWT = require('../../domain/security/jwt') +const Errors = require('../../errors') const reducePermissions = (roles) => { const flattened = [] @@ -15,19 +16,26 @@ const reducePermissions = (roles) => { return flattened } -const validate = (request, token, cb) => { - JWT.verify(token) - .then(({ user, roles }) => { - const scope = reducePermissions(roles) - const credentials = Util.merge(user, { scope: scope }) - return cb(null, true, credentials) - }) - .catch(e => cb(e, false)) +const validate = async (request, token, h) => { + try { + let isValid = false + const result = await JWT.verify(token) + if (result) { + isValid = true + const scope = reducePermissions(result.roles) + const credentials = Util.merge(result.user, {scope: scope}) + return {isValid, credentials} + } else { + throw new Errors.UnauthorizedError('Invalid token') + } + } catch (e) { + return {e, verified: false} + } } module.exports = { name: 'admin-token', - scheme: 'bearer', + scheme: 'jwt-strategy', validate: validate } diff --git a/src/admin/charges/handler.js b/src/admin/charges/handler.js index 954b506f3..62a398ca7 100644 --- a/src/admin/charges/handler.js +++ b/src/admin/charges/handler.js @@ -3,6 +3,7 @@ const Charges = require('../../domain/charge') const Errors = require('../../errors') const Sidecar = require('../../lib/sidecar') +// const Logger = require('@mojaloop/central-services-shared').Logger const validateRequest = (request) => { return Charges.getByName(request.payload.name).then(charge => { @@ -16,6 +17,18 @@ const validateRequest = (request) => { }) } +const validateExistingRecord = (request) => { + return Charges.getByName(request.payload.name).then(charge => { + if (!charge) { + throw new Errors.RecordExistsError('No record currently exists with the name ' + request.payload.name) + } + if (!(request.params.name && request.payload.name && request.payload.name === request.params.name)) { + throw new Errors.ValidationError('Charge names need to be the values') + } + return request + }) +} + function entityItem (charge) { return { name: charge.name, @@ -33,27 +46,21 @@ function entityItem (charge) { } } -exports.create = (request, reply) => { +exports.create = async function (request, h) { Sidecar.logRequest(request) - return validateRequest(request) - .then(validatedRequest => Charges.create(validatedRequest.payload)) - .then(result => reply(entityItem(result)).code(201)) - .catch(reply) + const validatedRequest = await validateRequest(request) + const result = await Charges.create(validatedRequest.payload) + return h.response(entityItem(result)).code(201) } -exports.update = (request, reply) => { +exports.update = async function (request, h) { Sidecar.logRequest(request) - return validateRequest(request) - .then(validatedRequest => { - return Charges.update(request.params.name, validatedRequest.payload) - }) - .then(result => reply(entityItem(result))) - .catch(reply) + const validatedRequest = await validateExistingRecord(request) + const updatedCharge = await Charges.update(request.params.name, validatedRequest.payload) + return entityItem(updatedCharge) } -exports.getAll = (request, reply) => { - Charges.getAll() - .then(results => results.map(entityItem)) - .then(result => reply(result)) - .catch(e => reply(e)) +exports.getAll = async function (request, h) { + const results = await Charges.getAll() + return await results.map(entityItem) } diff --git a/src/admin/charges/routes.js b/src/admin/charges/routes.js index 91127ab5c..706aa54a0 100644 --- a/src/admin/charges/routes.js +++ b/src/admin/charges/routes.js @@ -9,24 +9,30 @@ module.exports = [ method: 'GET', path: '/charges', handler: Handler.getAll, - config: RouteConfig.config(tags, Permissions.CHARGES_LIST) + options: RouteConfig.config(tags, Permissions.CHARGES_LIST) }, { method: 'POST', path: '/charges', handler: Handler.create, - config: RouteConfig.config(tags, Permissions.CHARGES_CREATE, { + options: RouteConfig.config(tags, Permissions.CHARGES_CREATE, { payload: { - name: Joi.string().token().max(256).required().description('Name of the charge'), - charge_type: Joi.string().required().valid('fee').description('Type of the charge'), - rate_type: Joi.string().required().valid('percent', 'flat').description('Rate type of the charge'), - rate: Joi.number().required().description('Rate for the charge'), - minimum: Joi.number().optional().description('Minimum amount for the charge'), - maximum: Joi.number().optional().description('Maximum amount for the charge'), - code: Joi.string().token().max(256).required().description('Code for the charger'), - is_active: Joi.boolean().required().description('Status for charge'), - payer: Joi.string().required().valid('sender', 'receiver', 'ledger').description('Payer of the charged fee'), - payee: Joi.string().required().valid('sender', 'receiver', 'ledger').description('Payee of the charged fee') + allow: ['application/json'], + failAction: 'error' + }, + validate: { + payload: { + name: Joi.string().token().max(256).required().description('Name of the charge'), + charge_type: Joi.string().required().valid('fee').description('Type of the charge'), + rate_type: Joi.string().required().valid('percent', 'flat').description('Rate type of the charge'), + rate: Joi.number().required().description('Rate for the charge'), + minimum: Joi.number().optional().description('Minimum amount for the charge'), + maximum: Joi.number().optional().description('Maximum amount for the charge'), + code: Joi.string().token().max(256).required().description('Code for the charger'), + is_active: Joi.boolean().required().description('Status for charge'), + payer: Joi.string().required().valid('sender', 'receiver', 'ledger').description('Payer of the charged fee'), + payee: Joi.string().required().valid('sender', 'receiver', 'ledger').description('Payee of the charged fee') + } } }) }, @@ -34,17 +40,23 @@ module.exports = [ method: 'PUT', path: '/charges/{name}', handler: Handler.update, - config: RouteConfig.config(tags, Permissions.CHARGES_UPDATE, { - params: { - name: Joi.string().required().description('Charge name') - }, + options: RouteConfig.config(tags, Permissions.CHARGES_UPDATE, { payload: { - name: Joi.string().token().max(256).optional().description('Name of the charge'), - charge_type: Joi.string().optional().valid('fee').description('Type of the charge'), - minimum: Joi.number().optional().allow(null).description('Minimum amount for the charge'), - maximum: Joi.number().optional().allow(null).description('Maximum amount for the charge'), - code: Joi.string().token().max(256).optional().allow(null).description('Code for the charger'), - is_active: Joi.boolean().optional().description('Status for charge') + allow: ['application/json'], + failAction: 'error' + }, + validate: { + payload: { + name: Joi.string().token().max(256).optional().description('Name of the charge'), + charge_type: Joi.string().optional().valid('fee').description('Type of the charge'), + minimum: Joi.number().optional().allow(null).description('Minimum amount for the charge'), + maximum: Joi.number().optional().allow(null).description('Maximum amount for the charge'), + code: Joi.string().token().max(256).optional().allow(null).description('Code for the charger'), + is_active: Joi.boolean().optional().description('Status for charge') + }, + params: { + name: Joi.string().required().description('Charge name') + } } }) } diff --git a/src/admin/index.js b/src/admin/index.js index 1ed7d68bf..5199ef3fb 100644 --- a/src/admin/index.js +++ b/src/admin/index.js @@ -1,13 +1,13 @@ 'use strict' -const Logger = require('@mojaloop/central-services-shared').Logger const Config = require('../lib/config') const Routes = require('./routes') const Auth = require('./auth') const Setup = require('../shared/setup') -module.exports = Setup.initialize({ service: 'admin', port: Config.ADMIN_PORT, modules: [Auth, Routes] }) - .then(server => server.start().then(() => { - Logger.info('Server running at: %s', server.info.uri) - })) +var moduleList = [] +moduleList[0] = Auth +moduleList[1] = Routes + +module.exports = Setup.initialize({ service: 'admin', port: Config.ADMIN_PORT, modules: moduleList }) diff --git a/src/admin/permissions/handler.js b/src/admin/permissions/handler.js index 8f42d6e00..709ef0b6c 100644 --- a/src/admin/permissions/handler.js +++ b/src/admin/permissions/handler.js @@ -2,14 +2,14 @@ const Permissions = require('../../domain/security/permissions') -const getPermissions = (request, reply) => { +const getPermissions = function (request, h) { const permissions = Object.keys(Permissions).map(k => { /* istanbul ignore else */ if (Permissions.hasOwnProperty(k)) { return Permissions[k] } }) - reply(permissions) + return permissions } module.exports = { diff --git a/src/admin/permissions/routes.js b/src/admin/permissions/routes.js index b4ae5cb5b..693721f78 100644 --- a/src/admin/permissions/routes.js +++ b/src/admin/permissions/routes.js @@ -10,6 +10,6 @@ module.exports = [ method: 'GET', path: '/permissions', handler: Handler.getPermissions, - config: RouteConfig.config(tags, Permissions.PERMISSIONS_LIST) + options: RouteConfig.config(tags, Permissions.PERMISSIONS_LIST) } ] diff --git a/src/admin/positions/handler.js b/src/admin/positions/handler.js index 9ecb5b2c4..5b1deacc6 100644 --- a/src/admin/positions/handler.js +++ b/src/admin/positions/handler.js @@ -3,14 +3,13 @@ const PositionService = require('../../domain/position') const Account = require('../../domain/account') -exports.calculateForAllAccounts = (request, reply) => { - PositionService.calculateForAllAccounts() - .then(positions => reply({ positions: positions })) +exports.calculateForAllAccounts = async function (request, h) { + const positions = await PositionService.calculateForAllAccounts() + return h.response({ positions: positions }) } -exports.calculateForAccount = (request, reply) => { - return Account.getByName(request.params.name).then(account => { - return PositionService.calculateForAccount(account) - .then(position => reply(position)) - }) +exports.calculateForAccount = async function (request, h) { + const account = await Account.getByName(request.params.name) + const positions = await PositionService.calculateForAccount(account) + return h.response(positions) } diff --git a/src/admin/positions/routes.js b/src/admin/positions/routes.js index 148ba2e54..88dcee011 100644 --- a/src/admin/positions/routes.js +++ b/src/admin/positions/routes.js @@ -10,15 +10,17 @@ module.exports = [ method: 'GET', path: '/positions', handler: Handler.calculateForAllAccounts, - config: RouteConfig.config(tags, Permissions.POSITIONS_LIST) + options: RouteConfig.config(tags, Permissions.POSITIONS_LIST) }, { method: 'GET', path: '/positions/{name}', handler: Handler.calculateForAccount, - config: RouteConfig.config(tags, Permissions.POSITIONS_VIEW, { - params: { - name: Joi.string().required().description('Account Name required') + options: RouteConfig.config(tags, Permissions.POSITIONS_VIEW, { + validate: { + params: { + name: Joi.string().required().description('Account Name required') + } } }) } diff --git a/src/admin/roles/handler.js b/src/admin/roles/handler.js index af7cc59e3..f399a87bb 100644 --- a/src/admin/roles/handler.js +++ b/src/admin/roles/handler.js @@ -3,31 +3,24 @@ const SecurityService = require('../../domain/security') const Sidecar = require('../../lib/sidecar') -const getRoles = (request, reply) => { - SecurityService.getAllRoles() - .then(reply) - .catch(reply) +const getRoles = function (request, h) { + return SecurityService.getAllRoles() } -const createRole = (request, reply) => { +const createRole = function (request, h) { Sidecar.logRequest(request) - SecurityService.createRole(request.payload) - .then(reply) - .catch(reply) + return SecurityService.createRole(request.payload) } -const updateRole = (request, reply) => { +const updateRole = function (request, h) { Sidecar.logRequest(request) - SecurityService.updateRole(request.params.id, request.payload) - .then(reply) - .catch(reply) + return SecurityService.updateRole(request.params.id, request.payload) } -const deleteRole = (request, reply) => { +const deleteRole = async function (request, h) { Sidecar.logRequest(request) - SecurityService.deleteRole(request.params.id) - .then(() => reply().code(204)) - .catch(reply) + await SecurityService.deleteRole(request.params.id) + return h.response().code(204) } module.exports = { diff --git a/src/admin/roles/routes.js b/src/admin/roles/routes.js index 58d4147af..4f4ea2b2c 100644 --- a/src/admin/roles/routes.js +++ b/src/admin/roles/routes.js @@ -15,17 +15,19 @@ module.exports = [ method: 'GET', path: '/roles', handler: Handler.getRoles, - config: RouteConfig.config(tags, Permissions.ROLES_LIST) + options: RouteConfig.config(tags, Permissions.ROLES_LIST) }, { method: 'POST', path: '/roles', handler: Handler.createRole, - config: RouteConfig.config(tags, Permissions.ROLES_CREATE, { - payload: { - name: nameValidator.required(), - description: descriptionValidator, - permissions: permissionsValidator.required() + options: RouteConfig.config(tags, Permissions.ROLES_CREATE, { + validate: { + payload: { + name: nameValidator.required(), + description: descriptionValidator, + permissions: permissionsValidator.required() + } } }) }, @@ -34,13 +36,17 @@ module.exports = [ path: '/roles/{id}', handler: Handler.updateRole, config: RouteConfig.config(tags, Permissions.ROLES_UPDATE, { - params: { - id: Joi.string().guid().required().description('Id of role to update') - }, - payload: { - name: nameValidator, - description: descriptionValidator, - permissions: permissionsValidator + options: { + validate: { + params: { + id: Joi.string().guid().required().description('Id of role to update') + }, + payload: { + name: nameValidator, + description: descriptionValidator, + permissions: permissionsValidator + } + } } }) }, @@ -49,8 +55,12 @@ module.exports = [ path: '/roles/{id}', handler: Handler.deleteRole, config: RouteConfig.config(tags, Permissions.ROLES_DELETE, { - params: { - id: Joi.string().guid().required().description('Id of role to delete') + options: { + validate: { + params: { + id: Joi.string().guid().required().description('Id of role to delete') + } + } } }) } diff --git a/src/admin/root/routes.js b/src/admin/root/routes.js index cc3d0e126..7f3986aaa 100644 --- a/src/admin/root/routes.js +++ b/src/admin/root/routes.js @@ -7,13 +7,17 @@ module.exports = [ { method: 'GET', path: '/', - handler: (request, reply) => reply({ status: 'OK' }).code(200), - config: RouteConfig.config(tags, 'Status of ledger admin api') + handler: function (request, h) { + return h.response({ status: 'OK' }).code(200) + }, + options: RouteConfig.config(tags, 'Status of ledger admin api') }, { method: 'GET', path: '/health', - handler: (request, reply) => reply({ status: 'OK' }).code(200), - config: RouteConfig.config(tags, 'Status of ledger admin api') + handler: function (request, h) { + return h.response({ status: 'OK' }).code(200) + }, + options: RouteConfig.config(tags, 'Status of ledger admin api') } ] diff --git a/src/admin/route-config.js b/src/admin/route-config.js index 382cd2a4f..bb7459a9c 100644 --- a/src/admin/route-config.js +++ b/src/admin/route-config.js @@ -7,7 +7,11 @@ const config = (tags, permission, validate) => { if (tags) { conf.tags = tags } - + if (validate) { + if (validate.payload) { + conf.payload = validate.payload + } + } if (permission) { if (permission.key) { conf.auth = Auth.tokenAuth(permission) @@ -16,11 +20,11 @@ const config = (tags, permission, validate) => { conf.description = permission } } - if (validate) { - conf.validate = validate + if (validate.validate) { + conf.validate = validate.validate + } } - return conf } diff --git a/src/admin/routes.js b/src/admin/routes.js index 255090ccc..ca6090116 100644 --- a/src/admin/routes.js +++ b/src/admin/routes.js @@ -2,12 +2,10 @@ const Glob = require('glob') -exports.register = function (server, options, next) { - Glob.sync('**/routes.js', { cwd: __dirname, ignore: 'routes.js' }) - .forEach(x => server.route(require('./' + x))) - next() -} - -exports.register.attributes = { - name: 'admin routes' +exports.plugin = { + name: 'admin routes', + register: function (server, options) { + Glob.sync('**/routes.js', { cwd: __dirname, ignore: 'routes.js' }) + .forEach(x => server.route(require('./' + x))) + } } diff --git a/src/admin/token/handler.js b/src/admin/token/handler.js index 8a672029e..d1f4f4f1f 100644 --- a/src/admin/token/handler.js +++ b/src/admin/token/handler.js @@ -3,11 +3,9 @@ const JWT = require('../../domain/security/jwt') const Sidecar = require('../../lib/sidecar') -const create = (request, reply) => { +const create = async function (request, h) { Sidecar.logRequest(request) - JWT.create(request.payload.key) - .then(token => reply({ token })) - .catch(reply) + return await JWT.create(request.payload.key) } module.exports = { diff --git a/src/admin/token/routes.js b/src/admin/token/routes.js index e5e4dac17..d3f653743 100644 --- a/src/admin/token/routes.js +++ b/src/admin/token/routes.js @@ -10,10 +10,14 @@ module.exports = [ method: 'POST', path: '/auth_token', handler: Handler.create, - config: { + options: { tags, - auth: AdminAuthStrategy.name, + auth: AdminAuthStrategy.scheme, description: 'Get a token for admin authentication', + payload: { + allow: 'application/json', + failAction: 'error' + }, validate: { payload: { key: Joi.string().required().description('Login key') diff --git a/src/admin/transfers/handler.js b/src/admin/transfers/handler.js index 0e47d9de7..873f12276 100644 --- a/src/admin/transfers/handler.js +++ b/src/admin/transfers/handler.js @@ -29,11 +29,9 @@ function entityItem (transfer) { } } -const getAll = (request, reply) => { - Transfer.getAll() - .then(results => results.map(entityItem)) - .then(result => reply(result)) - .catch(e => reply(e)) +const getAll = async function (request, h) { + const transfers = await Transfer.getAll() + return transfers.map(entityItem) } module.exports = { diff --git a/src/admin/transfers/routes.js b/src/admin/transfers/routes.js index ffb6db8e4..0b33d9735 100644 --- a/src/admin/transfers/routes.js +++ b/src/admin/transfers/routes.js @@ -11,6 +11,6 @@ module.exports = [ method: 'GET', path: '/transfers', handler: Handler.getAll, - config: RouteConfig.config(tags, Permissions.TRANSFERS_LIST) + options: RouteConfig.config(tags, Permissions.TRANSFERS_LIST) } ] diff --git a/src/admin/users/handler.js b/src/admin/users/handler.js index e8f6e3bb8..1f038c84b 100644 --- a/src/admin/users/handler.js +++ b/src/admin/users/handler.js @@ -3,50 +3,36 @@ const SecurityService = require('../../domain/security') const Sidecar = require('../../lib/sidecar') -const create = (request, reply) => { +const create = async function (request, h) { Sidecar.logRequest(request) - SecurityService.createUser(request.payload) - .then(reply) - .catch(reply) + return await SecurityService.createUser(request.payload) } -const getAll = (request, reply) => { - SecurityService.getAllUsers() - .then(reply) - .catch(reply) +const getAll = async function (request, h) { + return await SecurityService.getAllUsers() } -const getById = (request, reply) => { - SecurityService.getUserById(request.params.id) - .then(reply) - .catch(reply) +const getById = async function (request, h) { + return await SecurityService.getUserById(request.params.id) } -const remove = (request, reply) => { +const remove = async function (request, h) { Sidecar.logRequest(request) - SecurityService.deleteUser(request.params.id) - .then(() => reply({})) - .catch(reply) + return await SecurityService.deleteUser(request.params.id) } -const update = (request, reply) => { +const update = async function (request, h) { Sidecar.logRequest(request) - SecurityService.updateUser(request.params.id, request.payload) - .then(reply) - .catch(reply) + return await SecurityService.updateUser(request.params.id, request.payload) } -const getRoles = (request, reply) => { - SecurityService.getUserRoles(request.params.id) - .then(reply) - .catch(reply) +const getRoles = async function (request, h) { + return await SecurityService.getUserRoles(request.params.id) } -const updateRoles = (request, reply) => { +const updateRoles = async function (request, h) { Sidecar.logRequest(request) - SecurityService.updateUserRoles(request.params.id, request.payload) - .then(reply) - .catch(reply) + return await SecurityService.updateUserRoles(request.params.id, request.payload) } module.exports = { diff --git a/src/admin/users/routes.js b/src/admin/users/routes.js index 33e1b102b..7a184cc9b 100644 --- a/src/admin/users/routes.js +++ b/src/admin/users/routes.js @@ -12,15 +12,17 @@ module.exports = [ method: 'GET', path: '/users', handler: Handler.getAll, - config: RouteConfig.config(tags, Permissions.USERS_LIST) + options: RouteConfig.config(tags, Permissions.USERS_LIST) }, { method: 'GET', path: '/users/{id}', handler: Handler.getById, - config: RouteConfig.config(tags, Permissions.USERS_VIEW, { - params: { - id: Joi.string().guid().description('User Id') + options: RouteConfig.config(tags, Permissions.USERS_VIEW, { + validate: { + params: { + id: Joi.string().guid().description('User Id') + } } }) }, @@ -28,16 +30,22 @@ module.exports = [ method: 'PUT', path: '/users/{id}', handler: Handler.update, - config: RouteConfig.config(tags, Permissions.USERS_UPDATE, { - params: { - id: Joi.string().guid().description('User Id') - }, + options: RouteConfig.config(tags, Permissions.USERS_UPDATE, { payload: { - firstName: Joi.string().description('First name'), - lastName: Joi.string().description('Last name'), - key: Joi.string().description('Login key'), - email: Joi.string().description('Email address'), - isActive: Joi.bool().description('Active user') + allow: 'application/json', + failAction: 'error' + }, + validate: { + params: { + id: Joi.string().guid().description('User Id') + }, + payload: { + firstName: Joi.string().description('First name'), + lastName: Joi.string().description('Last name'), + key: Joi.string().description('Login key'), + email: Joi.string().description('Email address'), + isActive: Joi.bool().description('Active user') + } } }) }, @@ -45,12 +53,18 @@ module.exports = [ method: 'POST', path: '/users', handler: Handler.create, - config: RouteConfig.config(tags, Permissions.USERS_CREATE, { + options: RouteConfig.config(tags, Permissions.USERS_CREATE, { payload: { - firstName: Joi.string().required().description('First name'), - lastName: Joi.string().required().description('Last name'), - key: Joi.string().required().description('Login key'), - email: Joi.string().required().description('Email address') + allow: 'application/json', + failAction: 'error' + }, + validate: { + payload: { + firstName: Joi.string().required().description('First name'), + lastName: Joi.string().required().description('Last name'), + key: Joi.string().required().description('Login key'), + email: Joi.string().required().description('Email address') + } } }) }, @@ -58,9 +72,11 @@ module.exports = [ method: 'DELETE', path: '/users/{id}', handler: Handler.remove, - config: RouteConfig.config(tags, Permissions.USERS_DELETE, { - params: { - id: Joi.string().guid().description('user id') + options: RouteConfig.config(tags, Permissions.USERS_DELETE, { + validate: { + params: { + id: Joi.string().guid().description('User Id') + } } }) }, @@ -68,9 +84,11 @@ module.exports = [ method: 'GET', path: '/users/{id}/roles', handler: Handler.getRoles, - config: RouteConfig.config(tags, Permissions.USERS_ROLES_LIST, { - params: { - id: Joi.string().guid().description('user id') + options: RouteConfig.config(tags, Permissions.USERS_ROLES_LIST, { + validate: { + params: { + id: Joi.string().guid().description('User Id') + } } }) }, @@ -78,11 +96,17 @@ module.exports = [ method: 'POST', path: '/users/{id}/roles', handler: Handler.updateRoles, - config: RouteConfig.config(tags, Permissions.USERS_ROLES_UPDATE, { - params: { - id: Joi.string().guid().description('user id') + options: RouteConfig.config(tags, Permissions.USERS_ROLES_UPDATE, { + payload: { + allow: 'application/json', + failAction: 'error' }, - payload: Joi.array().items(Joi.string().guid()).required().description('Role ids') + validate: { + params: { + id: Joi.string().guid().description('User Id') + }, + payload: Joi.array().items(Joi.string().guid()).required().description('Role ids') + } }) } ] diff --git a/src/admin/webhooks/handler.js b/src/admin/webhooks/handler.js index 95ad1bd6c..4f4d1797a 100644 --- a/src/admin/webhooks/handler.js +++ b/src/admin/webhooks/handler.js @@ -6,28 +6,19 @@ const TokenService = require('../../domain/token') const SettlementService = require('../../domain/settlements') const Sidecar = require('../../lib/sidecar') -exports.rejectExpired = function (request, reply) { +exports.rejectExpired = async function (request, h) { Sidecar.logRequest(request) - return TransferService.rejectExpired() - .then(response => reply(response)) - .catch(e => reply(e)) + return await TransferService.rejectExpired() } -exports.settle = function (request, reply) { +exports.settle = async function (request, h) { Sidecar.logRequest(request) - return TransferService.settle() - .then(settledTransfers => { - return FeeService.settleFeesForTransfers(settledTransfers) - .then(settledFees => { - return reply(SettlementService.performSettlement(settledTransfers, settledFees)) - }) - }) - .catch(e => reply(e)) + const settledTransfers = await TransferService.settle() + const settledFees = await FeeService.settleFeesForTransfers(settledTransfers) + return SettlementService.performSettlement(settledTransfers, settledFees) } -exports.rejectExpiredTokens = function (request, reply) { +exports.rejectExpiredTokens = async function (request, h) { Sidecar.logRequest(request) return TokenService.removeExpired() - .then(response => reply(response)) - .catch(e => reply(e)) } diff --git a/src/admin/webhooks/routes.js b/src/admin/webhooks/routes.js index b5072ee81..a7ea0d796 100644 --- a/src/admin/webhooks/routes.js +++ b/src/admin/webhooks/routes.js @@ -10,18 +10,18 @@ module.exports = [ method: 'POST', path: '/webhooks/reject-expired-transfers', handler: Handler.rejectExpired, - config: RouteConfig.config(tags, Permissions.TRANSFERS_REJECT_EXPIRED) + options: RouteConfig.config(tags, Permissions.TRANSFERS_REJECT_EXPIRED) }, { method: 'POST', path: '/webhooks/reject-expired-tokens', handler: Handler.rejectExpiredTokens, - config: RouteConfig.config(tags, Permissions.TOKENS_REJECT_EXPIRED) + options: RouteConfig.config(tags, Permissions.TOKENS_REJECT_EXPIRED) }, { method: 'POST', path: '/webhooks/settle-transfers', handler: Handler.settle, - config: RouteConfig.config(tags, Permissions.TRANSFERS_SETTLE) + options: RouteConfig.config(tags, Permissions.TRANSFERS_SETTLE) } ] diff --git a/src/api/accounts/handler.js b/src/api/accounts/handler.js index 9b7b2a8b8..f4ab5595f 100644 --- a/src/api/accounts/handler.js +++ b/src/api/accounts/handler.js @@ -7,6 +7,9 @@ const Util = require('../../lib/util') const PositionService = require('../../domain/position') const Errors = require('../../errors') const Sidecar = require('../../lib/sidecar') +// const Logger = require('@mojaloop/central-services-shared').Logger +const Boom = require('boom') +// const ErrorHandling = require('@mojaloop/central-services-error-handling') const buildAccount = (account) => { return { @@ -16,7 +19,7 @@ const buildAccount = (account) => { } } -const buildResponse = (account, { net = '0' } = {}) => { +const buildResponse = (account, {net = '0'} = {}) => { return Util.mergeAndOmitNil(buildAccount(account), { created: account.createdDate, balance: net, @@ -54,34 +57,34 @@ const getPosition = (account) => { .then(position => buildResponse(account, position)) } -exports.create = (request, reply) => { - Sidecar.logRequest(request) - Account.getByName(request.payload.name) - .then(handleExistingRecord) - .then(() => Account.create(request.payload)) - .then(account => reply(buildResponse(account)).code(201)) - .catch(reply) +exports.create = async function (request, h) { + try { + Sidecar.logRequest(request) + const entity = await Account.getByName(request.payload.name) + handleExistingRecord(entity) + const account = await Account.create(request.payload) + return h.response(buildResponse(account)).code(201) + } catch (err) { + throw Boom.boomify(err, {statusCode: 400, message: 'An error has occurred'}) + } } -exports.updateUserCredentials = (request, reply) => { +exports.updateUserCredentials = async function (request, h) { Sidecar.logRequest(request) const accountName = request.params.name const credentials = request.auth.credentials const authenticated = (credentials && (credentials.is_admin || credentials.name === accountName)) if (!authenticated) { - throw new Errors.UnauthorizedError('Invalid attempt updating the password.') + throw Boom.boomify(new Errors.UnauthorizedError('Invalid attempt updating the password.'), {statusCode: 400}) } - - Account.getByName(request.params.name) - .then(handleMissingRecord) - .then(account => Account.updateUserCredentials(account, request.payload)) - .then(updatedAccount => buildAccount(updatedAccount)) - .then(reply) - .catch(reply) + const account = await Account.getByName(request.params.name) + handleMissingRecord(account) + const updatedAccount = await Account.updateUserCredentials(account, request.payload) + return buildAccount(updatedAccount) } -exports.updateAccountSettlement = (request, reply) => { +exports.updateAccountSettlement = async function (request, h) { Sidecar.logRequest(request) const accountName = request.params.name const credentials = request.auth.credentials @@ -90,23 +93,22 @@ exports.updateAccountSettlement = (request, reply) => { if (!authenticated) { throw new Errors.UnauthorizedError('Invalid attempt updating the settlement.') } - - Account.getByName(request.params.name) - .then(handleMissingRecord) - .then(account => Account.updateAccountSettlement(account, request.payload)) - .then(settlement => settlementResponse(settlement)) - .then(reply) - .catch(reply) + const account = await Account.getByName(request.params.name) + handleMissingRecord(account) + const settlement = await Account.updateAccountSettlement(account, request.payload) + return settlementResponse(settlement) } -exports.getByName = (request, reply) => { +exports.getByName = async function (request, h) { Sidecar.logRequest(request) const accountName = request.params.name const credentials = request.auth.credentials const authenticated = (credentials && (credentials.is_admin || credentials.name === accountName)) - Account.getByName(request.params.name) - .then(handleMissingRecord) - .then(account => (authenticated ? getPosition(account) : buildAccount(account))) - .then(reply) - .catch(reply) + const account = await Account.getByName(request.params.name) + handleMissingRecord(account) + if (authenticated) { + return await getPosition(account) + } else { + return buildAccount(account) + } } diff --git a/src/api/accounts/routes.js b/src/api/accounts/routes.js index 23b8793b6..0d58a7883 100644 --- a/src/api/accounts/routes.js +++ b/src/api/accounts/routes.js @@ -1,26 +1,32 @@ const Handler = require('./handler') const Joi = require('joi') const Auth = require('../auth') +// const Boom = require('boom') const tags = ['api', 'accounts'] -const nameValidator = Joi.string().token().max(256).required().description('Name of the account') -const passwordValidator = Joi.string().token().max(256).required().description('Password for the account') -const emailAddressValidator = Joi.string().email() +const nameValidator = Joi.string().alphanum().min(3).max(30).required().description('Name of the account') +const passwordValidator = Joi.string().regex(/^[a-zA-Z0-9]{3,30}$/).required().description('Password for the account') +// const emailAddressValidator = Joi.string().email() module.exports = [{ method: 'POST', path: '/accounts', handler: Handler.create, - config: { + options: { id: 'accounts', tags: tags, auth: Auth.strategy(), description: 'Create an account.', + payload: { + allow: 'application/json', + failAction: 'error', + output: 'data' + }, validate: { payload: { - name: nameValidator, - password: passwordValidator, - emailAddress: emailAddressValidator + name: Joi.string().alphanum().min(3).max(30).required().description('Name of the account'), + password: Joi.string().regex(/^[a-zA-Z0-9]{3,30}$/).required().description('Password for the account'), + emailAddress: Joi.string().email().required() } } } @@ -29,7 +35,7 @@ module.exports = [{ method: 'GET', path: '/accounts/{name}', handler: Handler.getByName, - config: { + options: { id: 'account', tags: tags, description: 'Retrieve an accounts details by name', @@ -45,17 +51,22 @@ module.exports = [{ method: 'PUT', path: '/accounts/{name}', handler: Handler.updateUserCredentials, - config: { + options: { id: 'account_update_user_credentials', tags: tags, description: 'Update an accounts user credentials', auth: Auth.strategy(), + payload: { + allow: 'application/json', + failAction: 'error' + }, validate: { params: { name: nameValidator }, payload: { - password: passwordValidator + password: passwordValidator, + emailAddress: Joi.string().email().required() } } } @@ -64,11 +75,15 @@ module.exports = [{ method: 'PUT', path: '/accounts/{name}/settlement', handler: Handler.updateAccountSettlement, - config: { + options: { id: 'account_update_account_settlement', tags: tags, description: 'Update an accounts user credentials', auth: Auth.strategy(), + payload: { + allow: 'application/json', + failAction: 'error' + }, validate: { params: { name: nameValidator diff --git a/src/api/auth/account.js b/src/api/auth/account.js index 2b69f81c3..3d386244e 100644 --- a/src/api/auth/account.js +++ b/src/api/auth/account.js @@ -2,14 +2,14 @@ const Config = require('../../lib/config') const AccountService = require('../../domain/account') -const Logger = require('@mojaloop/central-services-shared').Logger -const validate = (request, name, password, cb) => { +/* +const validates = (request, name, password, cb) => { if (!password) { return cb(null, false) } if (Config.ADMIN_KEY && Config.ADMIN_SECRET && name === Config.ADMIN_KEY && password === Config.ADMIN_SECRET) { - return cb(null, true, { name: Config.ADMIN_KEY, is_admin: true }) + return cb(null, true, {name: Config.ADMIN_KEY, is_admin: true}) } return AccountService.verify(name, password) .then(account => cb(null, true, account)) @@ -18,9 +18,25 @@ const validate = (request, name, password, cb) => { return cb(null, false) }) } +*/ + +const validate = async (request, name, password, h) => { + if (!password) { + return {credentials: null, isValid: false} + } + if (Config.ADMIN_KEY && Config.ADMIN_SECRET && name === Config.ADMIN_KEY && password === Config.ADMIN_SECRET) { + return {credentials: {is_admin: true, name}, isValid: true} + } + const account = await AccountService.verify(name, password) + if (account) { + return {credentials: account, isValid: true} + } else { + return {credentials: null, isValid: false} + } +} module.exports = { name: 'account', - scheme: 'basic', + scheme: 'simple', validate } diff --git a/src/api/auth/index.js b/src/api/auth/index.js index 7baa29074..a78989dbc 100644 --- a/src/api/auth/index.js +++ b/src/api/auth/index.js @@ -4,21 +4,20 @@ const Config = require('../../lib/config') const AccountStrategy = require('./account') const TokenStrategy = require('./token') -exports.register = (server, options, next) => { - server.auth.strategy(AccountStrategy.name, AccountStrategy.scheme, { validate: AccountStrategy.validate }) - server.auth.strategy(TokenStrategy.name, TokenStrategy.scheme, { validate: TokenStrategy.validate }) - next() -} - -exports.register.attributes = { - name: 'auth' +exports.plugin = { + name: 'auth', + register: function (server, options) { + server.auth.strategy('simple', 'basic', {validate: AccountStrategy.validate}) + // server.auth.strategy(AccountStrategy.name, AccountStrategy.scheme, { validate: AccountStrategy.validate }) + server.auth.strategy('bearer', 'bearer-access-token', { validate: TokenStrategy.validate }) + } } exports.strategy = (optional = false) => { if (!Config.ENABLE_TOKEN_AUTH && !Config.ENABLE_BASIC_AUTH) { return false } - const strategy = (Config.ENABLE_TOKEN_AUTH ? TokenStrategy.name : AccountStrategy.name) + const strategy = (Config.ENABLE_TOKEN_AUTH ? TokenStrategy.name : AccountStrategy.scheme) const mode = (optional ? 'try' : 'required') return { mode, diff --git a/src/api/auth/token.js b/src/api/auth/token.js index df34b4a01..b733e4d59 100644 --- a/src/api/auth/token.js +++ b/src/api/auth/token.js @@ -3,8 +3,8 @@ const TokenAuth = require('../../domain/token/auth') module.exports = { - name: 'token', + name: 'bearer-access-token', scheme: 'bearer', - validate: TokenAuth.validate(false) + validate: TokenAuth.validate } diff --git a/src/api/charges/handler.js b/src/api/charges/handler.js index 40794fe9b..67b8c74e5 100644 --- a/src/api/charges/handler.js +++ b/src/api/charges/handler.js @@ -14,9 +14,11 @@ function entityItem (charge) { } } -exports.chargeQuote = (request, reply) => { - Charges.quote(request.payload) - .then(results => results.map(entityItem)) - .then(reply) - .catch(reply) +exports.chargeQuote = async function (request, h) { + try { + const charges = await Charges.quote(request.payload) + return charges.map(entityItem) + } catch (err) { + throw err + } } diff --git a/src/api/charges/routes.js b/src/api/charges/routes.js index c50e9a278..e5652f9fd 100644 --- a/src/api/charges/routes.js +++ b/src/api/charges/routes.js @@ -9,11 +9,15 @@ module.exports = [ method: 'POST', path: '/charges/quote', handler: Handler.chargeQuote, - config: { + options: { id: 'charges', tags: tags, auth: Auth.strategy(), description: 'Quote a charge for a transaction amount', + payload: { + allow: 'application/json', + failAction: 'error' + }, validate: { payload: { amount: Joi.number().required().description('Amount for charge quote') diff --git a/src/api/index.js b/src/api/index.js index 593118656..76ade3110 100644 --- a/src/api/index.js +++ b/src/api/index.js @@ -1,19 +1,17 @@ 'use strict' -const Logger = require('@mojaloop/central-services-shared').Logger const Config = require('../lib/config') const Routes = require('./routes') const Auth = require('./auth') const Sockets = require('./sockets') const Worker = require('./worker') -const Account = require('../domain/account') - const Setup = require('../shared/setup') -module.exports = Setup.initialize({ service: 'api', port: Config.PORT, modules: [Auth, Routes, Sockets, Worker], loadEventric: true, runMigrations: true }) - .then(server => { - return Account.createLedgerAccount(Config.LEDGER_ACCOUNT_NAME, Config.LEDGER_ACCOUNT_PASSWORD, Config.LEDGER_ACCOUNT_EMAIL).then(() => server) - }) - .then(server => server.start().then(() => { - Logger.info('Server running at: %s', server.info.uri) - })) +module.exports = Setup.initialize({ + service: 'api', + port: Config.PORT, + modules: [Auth, Routes, Sockets, Worker], + loadEventric: true, + runMigrations: true +}) + diff --git a/src/api/messages/handler.js b/src/api/messages/handler.js index b724a18c3..e60c959b4 100644 --- a/src/api/messages/handler.js +++ b/src/api/messages/handler.js @@ -4,14 +4,11 @@ const Validator = require('./validator') const Events = require('../../lib/events') const Sidecar = require('../../lib/sidecar') -const sendMessage = (req, rep) => { - Sidecar.logRequest(req) - return Validator.validate(req.payload) - .then(message => { - Events.sendMessage(message) - rep().code(201) - }) - .catch(e => rep(e)) +const sendMessage = async function (request, h) { + Sidecar.logRequest(request) + const message = await Validator.validate(request.payload) + Events.sendMessage(message) + return h.response().code(201) } module.exports = { diff --git a/src/api/messages/routes.js b/src/api/messages/routes.js index 4e3404848..3106a9b3b 100644 --- a/src/api/messages/routes.js +++ b/src/api/messages/routes.js @@ -10,11 +10,15 @@ module.exports = [ method: 'POST', path: '/messages', handler: Handler.sendMessage, - config: { + options: { tags, description: 'Send a notification to another account', id: 'message', auth: Auth.strategy(), + payload: { + allow: 'application/json', + failAction: 'error' + }, validate: { payload: { id: Joi.string().optional(), diff --git a/src/api/metadata/handler.js b/src/api/metadata/handler.js index a568b6491..72982848e 100644 --- a/src/api/metadata/handler.js +++ b/src/api/metadata/handler.js @@ -4,24 +4,24 @@ const Config = require('../../lib/config') const extractUrls = (request) => { const urls = {} - request.server.table()[0].table.filter(route => { - return route.settings.id !== undefined && + request.server.table().forEach(route => { + if (route.settings.id !== undefined && Array.isArray(route.settings.tags) && - route.settings.tags.indexOf('api') >= 0 - }).forEach(route => { - urls[route.settings.id] = `${Config.HOSTNAME}${route.path.replace(/\{/g, ':').replace(/\}/g, '')}` + route.settings.tags.indexOf('api') >= 0) { + urls[route.settings.id] = `${Config.HOSTNAME}${route.path.replace(/\{/g, ':').replace(/\}/g, '')}` + } }) const host = Config.HOSTNAME.replace(/^https?:\/\//, '') urls['websocket'] = `ws://${host}/websocket` return urls } -exports.health = (request, reply) => { - reply({ status: 'OK' }).code(200) +exports.health = function (request, h) { + return h.response({status: 'OK'}).code(200) } -exports.metadata = (request, reply) => { - reply({ +exports.metadata = function (request, h) { + return h.response({ currency_code: null, currency_symbol: null, ledger: Config.HOSTNAME, diff --git a/src/api/metadata/routes.js b/src/api/metadata/routes.js index 1cf5b9e42..be5aa844d 100644 --- a/src/api/metadata/routes.js +++ b/src/api/metadata/routes.js @@ -6,7 +6,7 @@ module.exports = [ method: 'GET', path: '/health', handler: Handler.health, - config: { + options: { tags: tags, description: 'Status of ledger', id: 'health' @@ -16,7 +16,7 @@ module.exports = [ method: 'GET', path: '/', handler: Handler.metadata, - config: { + options: { tags: tags, description: 'Metadata' } diff --git a/src/api/positions/handler.js b/src/api/positions/handler.js index 9ecb5b2c4..54cb9a0d4 100644 --- a/src/api/positions/handler.js +++ b/src/api/positions/handler.js @@ -3,14 +3,12 @@ const PositionService = require('../../domain/position') const Account = require('../../domain/account') -exports.calculateForAllAccounts = (request, reply) => { - PositionService.calculateForAllAccounts() - .then(positions => reply({ positions: positions })) +exports.calculateForAllAccounts = async function (request, h) { + const positions = await PositionService.calculateForAllAccounts() + return h.response({positions: positions}) } -exports.calculateForAccount = (request, reply) => { - return Account.getByName(request.params.name).then(account => { - return PositionService.calculateForAccount(account) - .then(position => reply(position)) - }) +exports.calculateForAccount = async function (request, h) { + const account = await Account.getByName(request.params.name) + return await PositionService.calculateForAccount(account) } diff --git a/src/api/positions/routes.js b/src/api/positions/routes.js index 9355b2025..d75326300 100644 --- a/src/api/positions/routes.js +++ b/src/api/positions/routes.js @@ -6,10 +6,10 @@ module.exports = [{ method: 'GET', path: '/positions', handler: Handler.calculateForAllAccounts, - config: { + options: { id: 'positions', - auth: Auth.strategy(), tags: tags, + auth: Auth.strategy(), description: 'Retrieve outstanding positions.' } }, @@ -17,10 +17,10 @@ module.exports = [{ method: 'GET', path: '/positions/{name}', handler: Handler.calculateForAccount, - config: { + options: { id: 'positions_account', - auth: Auth.strategy(), tags: tags, + auth: Auth.strategy(), description: 'Retrieve outstanding positions for an account.' } } diff --git a/src/api/routes.js b/src/api/routes.js index a82a9950b..c5afeaa51 100644 --- a/src/api/routes.js +++ b/src/api/routes.js @@ -2,12 +2,10 @@ const Glob = require('glob') -exports.register = function (server, options, next) { - Glob.sync('**/routes.js', { cwd: __dirname, ignore: 'routes.js' }) - .forEach(x => server.route(require('./' + x))) - next() -} - -exports.register.attributes = { - name: 'api routes' +exports.plugin = { + name: 'api routes', + register: function (server, options) { + Glob.sync('**/routes.js', {cwd: __dirname, ignore: 'routes.js'}) + .forEach(x => server.route(require('./' + x))) + } } diff --git a/src/api/sockets/index.js b/src/api/sockets/index.js index 52f692c15..9afccff2c 100644 --- a/src/api/sockets/index.js +++ b/src/api/sockets/index.js @@ -70,18 +70,15 @@ const wireEvents = () => { Events.onMessageSent(messageHandler) } -exports.register = (server, options, next) => { - manager = SocketManager.create() +exports.plugin = { + name: 'websockets', + register: (server, options) => { + manager = SocketManager.create() - const wss = createWebSocketServer(server.listener) + const wss = createWebSocketServer(server.listener) - wireConnection(wss) + wireConnection(wss) - wireEvents() - - next() -} - -exports.register.attributes = { - name: 'websockets' + wireEvents() + } } diff --git a/src/api/token/handler.js b/src/api/token/handler.js index b7017bcc5..885be504d 100644 --- a/src/api/token/handler.js +++ b/src/api/token/handler.js @@ -3,11 +3,10 @@ const TokenService = require('../../domain/token') const Sidecar = require('../../lib/sidecar') -const create = (req, rep) => { +const create = async function (req, rep) { Sidecar.logRequest(req) - TokenService.create(req.auth.credentials) - .then(token => rep(token)) - .catch(e => rep(e)) + const token = await TokenService.create(req.auth.credentials) + return token } module.exports = { diff --git a/src/api/token/routes.js b/src/api/token/routes.js index 2544cacb7..6d1033609 100644 --- a/src/api/token/routes.js +++ b/src/api/token/routes.js @@ -9,9 +9,9 @@ module.exports = [ method: 'GET', path: '/auth_token', handler: Handler.create, - config: { + options: { tags, - auth: AccountAuthStrategy.name, + auth: AccountAuthStrategy.scheme, description: 'Get a token that can be used to authenticate future requests', id: 'auth_token' } diff --git a/src/api/transfers/handler.js b/src/api/transfers/handler.js index 019cbee0a..ef2257851 100644 --- a/src/api/transfers/handler.js +++ b/src/api/transfers/handler.js @@ -6,6 +6,8 @@ const TransferRejectionType = require('../../domain/transfer/rejection-type') const TransferTranslator = require('../../domain/transfer/translator') const NotFoundError = require('../../errors').NotFoundError const Sidecar = require('../../lib/sidecar') +const Logger = require('@mojaloop/central-services-shared').Logger +const Boom = require('boom') const buildGetTransferResponse = (record) => { if (!record) { @@ -14,27 +16,29 @@ const buildGetTransferResponse = (record) => { return TransferTranslator.toTransfer(record) } -exports.prepareTransfer = function (request, reply) { - Sidecar.logRequest(request) - return Validator.validate(request.payload, request.params.id) - .then(TransferService.prepare) - .then(result => reply(result.transfer).code((result.existing === true) ? 200 : 201)) - .catch(reply) +exports.prepareTransfer = async function (request, h) { + try { + Logger.info('entering prepare transfer') + Sidecar.logRequest(request) + const payload = await Validator.validate(request.payload, request.params.id) + const result = await TransferService.prepare(payload) + return h.response(result.transfer).code((result.existing === true) ? 200 : 201) + } catch (err) { + throw Boom.boomify(err, {statusCode: 400, message: 'An error has occurred'}) + } } -exports.fulfillTransfer = function (request, reply) { +exports.fulfillTransfer = async function (request, h) { Sidecar.logRequest(request) const fulfillment = { id: request.params.id, fulfillment: request.payload } - - return TransferService.fulfill(fulfillment) - .then(transfer => reply(transfer).code(200)) - .catch(reply) + const transfer = await TransferService.fulfill(fulfillment) + return h.response(transfer).code(200) } -exports.rejectTransfer = function (request, reply) { +exports.rejectTransfer = async function (request, h) { Sidecar.logRequest(request) const rejection = { id: request.params.id, @@ -42,21 +46,16 @@ exports.rejectTransfer = function (request, reply) { message: request.payload, requestingAccount: request.auth.credentials } - - return TransferService.reject(rejection) - .then(result => reply(rejection.message).code(result.alreadyRejected ? 200 : 201)) - .catch(reply) + const result = await TransferService.reject(rejection) + return h.response(rejection.message).code(result.alreadyRejected ? 200 : 201) } -exports.getTransferById = function (request, reply) { - return TransferService.getById(request.params.id) - .then(buildGetTransferResponse) - .then(result => reply(result)) - .catch(reply) +exports.getTransferById = async function (request, h) { + const record = await TransferService.getById(request.params.id) + return buildGetTransferResponse(record) } -exports.getTransferFulfillment = function (request, reply) { - return TransferService.getFulfillment(request.params.id) - .then(result => reply(result).type('text/plain')) - .catch(reply) +exports.getTransferFulfillment = async function (request, h) { + const result = await TransferService.getFulfillment(request.params.id) + return h.response(result).type('text/plain') } diff --git a/src/api/transfers/routes.js b/src/api/transfers/routes.js index de4cd8407..c8130027f 100644 --- a/src/api/transfers/routes.js +++ b/src/api/transfers/routes.js @@ -7,11 +7,16 @@ module.exports = [{ method: 'PUT', path: '/transfers/{id}', handler: Handler.prepareTransfer, - config: { + options: { id: 'transfer', tags: tags, auth: Auth.strategy(), description: 'Prepare a transfer', + payload: { + allow: 'application/json', + failAction: 'error', + output: 'data' + }, validate: { params: { id: Joi.string().guid().required().description('Id of transfer to prepare') @@ -41,7 +46,7 @@ module.exports = [{ method: 'GET', path: '/transfers/{id}', handler: Handler.getTransferById, - config: { + options: { tags: tags, auth: Auth.strategy(), description: 'Get transfer by ID', @@ -56,13 +61,16 @@ module.exports = [{ method: 'PUT', path: '/transfers/{id}/fulfillment', handler: Handler.fulfillTransfer, - config: { + options: { id: 'transfer_fulfillment', tags: tags, auth: Auth.strategy(), description: 'Fulfill a transfer', + payload: { + failAction: 'error' + }, validate: { - headers: Joi.object({ 'content-type': Joi.string().required().valid('text/plain') }).unknown(), + headers: Joi.object({'content-type': Joi.string().required().valid('text/plain')}).unknown(), params: { id: Joi.string().guid().required().description('Id of transfer to fulfill') }, @@ -74,11 +82,15 @@ module.exports = [{ method: 'PUT', path: '/transfers/{id}/rejection', handler: Handler.rejectTransfer, - config: { + options: { id: 'transfer_rejection', tags: tags, auth: Auth.strategy(), description: 'Reject a transfer', + payload: { + allow: 'application/json', + failAction: 'error' + }, validate: { params: { id: Joi.string().guid().required().description('Id of transfer to reject') @@ -91,7 +103,7 @@ module.exports = [{ method: 'GET', path: '/transfers/{id}/fulfillment', handler: Handler.getTransferFulfillment, - config: { + options: { tags: tags, description: 'Get transfer fulfillment', auth: Auth.strategy(), diff --git a/src/api/transfers/validator.js b/src/api/transfers/validator.js index 663259c38..c30495f53 100644 --- a/src/api/transfers/validator.js +++ b/src/api/transfers/validator.js @@ -8,6 +8,7 @@ const UrlParser = require('../../lib/urlparser') const Account = require('../../domain/account') const ValidationError = require('../../errors').ValidationError const CryptoConditions = require('../../crypto-conditions') +const Logger = require('@mojaloop/central-services-shared').Logger const allowedScale = Config.AMOUNT.SCALE const allowedPrecision = Config.AMOUNT.PRECISION @@ -50,6 +51,8 @@ exports.validate = (transfer, transferId) => { if (!transfer) { throw new ValidationError('Transfer must be provided') } + Logger.info('transfer') + Logger.info(transfer) const id = UrlParser.idFromTransferUri(transfer.id) if (!id || id !== transferId) { throw new ValidationError('transfer.id: Invalid URI') diff --git a/src/api/worker/index.js b/src/api/worker/index.js index 2f75aad11..f96527474 100644 --- a/src/api/worker/index.js +++ b/src/api/worker/index.js @@ -31,16 +31,14 @@ exports.rejectExpiredTransfers = rejectExpiredTransfers exports.rejectExpiredTokens = rejectExpiredTokens -exports.register = (server, options, next) => { - if (Config.EXPIRES_TIMEOUT && Config.EXPIRES_TIMEOUT > 0) { - setInterval(this.rejectExpiredTransfers, Config.EXPIRES_TIMEOUT) +exports.plugin = { + name: 'worker', + register: (server, options) => { + if (Config.EXPIRES_TIMEOUT && Config.EXPIRES_TIMEOUT > 0) { + setInterval(this.rejectExpiredTransfers, Config.EXPIRES_TIMEOUT) + } + if (Config.TOKEN_EXPIRATION) { + setInterval(this.rejectExpiredTokens, Config.TOKEN_EXPIRATION) + } } - if (Config.TOKEN_EXPIRATION) { - setInterval(this.rejectExpiredTokens, Config.TOKEN_EXPIRATION) - } - next() -} - -exports.register.attributes = { - name: 'worker' } diff --git a/src/domain/account/index.js b/src/domain/account/index.js index 122d66a9d..ebafcff64 100644 --- a/src/domain/account/index.js +++ b/src/domain/account/index.js @@ -101,11 +101,11 @@ const verifyUserCredentials = (account, userCredentials, password) => { }) } -const verify = (name, password) => { - return Model.getByName(name) - .then(accountExists) - .then(account => retrieveUserCredentials(account) - .then(userCredentials => verifyUserCredentials(account, userCredentials, password))) +const verify = async function (name, password) { + const account = await Model.getByName(name) + accountExists(account) + const userCredentials = await retrieveUserCredentials(account) + return verifyUserCredentials(account, userCredentials, password) } module.exports = { diff --git a/src/domain/position/index.js b/src/domain/position/index.js index 1701a687a..cc9152551 100644 --- a/src/domain/position/index.js +++ b/src/domain/position/index.js @@ -101,11 +101,9 @@ exports.calculateForAllAccounts = () => { transferPositionMap.set(UrlParser.toAccountUri(account.name), buildEmptyPosition()) feePositionMap.set(UrlParser.toAccountUri(account.name), buildEmptyPosition()) }) - return P.all([SettleableTransfersReadmodel.getUnsettledTransfers(), Fee.getUnsettledFees()]).then(([transfers, fees]) => { const transferPositions = buildResponse(calculatePositions(transfers, transferPositionMap)) const feePositions = buildResponse(calculatePositions(fees.map(mapFeeToExecuted), feePositionMap)) - var positions = [] accounts.forEach(account => { const accountUri = UrlParser.toAccountUri(account.name) @@ -114,7 +112,6 @@ exports.calculateForAllAccounts = () => { positions.push(generatePosition(accountUri, accountTransferPositions, accountFeePositions)) }) - return positions }) }) diff --git a/src/domain/token/auth.js b/src/domain/token/auth.js index aaaa3a2d4..619d49442 100644 --- a/src/domain/token/auth.js +++ b/src/domain/token/auth.js @@ -13,45 +13,34 @@ const validateToken = (token, bearer) => { return !expired && Crypto.verifyHash(token.token, bearer) } -const getAccount = (name, adminOnly = false) => { +const getAccount = (name) => { if (Config.ADMIN_KEY && Config.ADMIN_KEY === name) { - return P.resolve({ is_admin: true, accountId: null }) - } else if (adminOnly) { - return P.resolve({ is_admin: false }) + return P.resolve({is_admin: true, accountId: null}) } else { return AccountService.getByName(name) } } -const validate = (adminOnly) => { - return (request, token, cb) => { - const headers = request.headers - const apiKey = headers['ledger-api-key'] - if (!apiKey) { - return cb(new UnauthorizedError('"Ledger-Api-Key" header is required')) - } - - getAccount(apiKey, adminOnly) - .then(account => { - if (!account) { - return cb(new UnauthorizedError('"Ledger-Api-Key" header is not valid')) - } - - if (adminOnly && !account.is_admin) { - return cb(null, false) - } - - return TokenService.byAccount(account).then(results => { - if (!results || results.length === 0) { - return cb(null, false) - } - - return P.all(results.map(x => validateToken(x, token))) - .then((verifications) => verifications.some(x => x)) - .then(verified => cb(null, verified, account)) - }) - }) +const validate = async function (request, token, h) { + const headers = request.headers + const apiKey = headers['ledger-api-key'] + if (!apiKey) { + throw new UnauthorizedError('"Ledger-Api-Key" header is required') + } + const account = await getAccount(apiKey) + if (!account) { + throw new UnauthorizedError('"Ledger-Api-Key" header is not valid') + } + if (!account.is_admin) { + return h.response({credentials: null, isValid: false}) + } + const results = await TokenService.byAccount(account) + if (!results || results.length === 0) { + return h.response({credentials: null, isValid: false}) } + return await P.all(results.map(x => validateToken(x, token))) + .then((verifications) => verifications.some(x => x)) + .then(verified => h.response({isValid: verified, credentials: account})) } module.exports = { diff --git a/src/errors/invalid-body.js b/src/errors/invalid-body.js index f1dc8ee83..0ec6e9c78 100644 --- a/src/errors/invalid-body.js +++ b/src/errors/invalid-body.js @@ -3,7 +3,7 @@ const Shared = require('@mojaloop/central-services-shared') class InvalidBodyError extends Shared.BaseError { - constructor (message = 'Invalid body') { + constructor (message) { super(Shared.ErrorCategory.BAD_REQUEST, message) } } diff --git a/src/lib/config.js b/src/lib/config.js index 09eb8a7cc..d1fbcfe51 100644 --- a/src/lib/config.js +++ b/src/lib/config.js @@ -16,7 +16,7 @@ module.exports = { TOKEN_EXPIRATION: RC.TOKEN_EXPIRATION, EXPIRES_TIMEOUT: RC.EXPIRES_TIMEOUT, SIDECAR: RC.SIDECAR, - SIDECAR_DISABLED: RC.SIDECAR.DISABLED === 'true', + SIDECAR_DISABLED: RC.SIDECAR.DISABLED, EMAIL_USER: RC.EMAIL_USER, EMAIL_PASSWORD: RC.EMAIL_PASSWORD, EMAIL_SMTP: RC.EMAIL_SMTP diff --git a/src/lib/request-logger.js b/src/lib/request-logger.js index 60d1f1d57..c5a01207e 100644 --- a/src/lib/request-logger.js +++ b/src/lib/request-logger.js @@ -21,8 +21,11 @@ const logResponse = function (request) { } catch (e) { response = Util.inspect(request.response.source) } - - Logger.info(`L1p-Trace-Id=${traceId} - Response: ${response} Status: ${request.response.statusCode}`) + if (!response) { + Logger.info(`L1p-Trace-Id=${traceId} - Response: ${request.response}`) + } else { + Logger.info(`L1p-Trace-Id=${traceId} - Response: ${response} Status: ${request.response.statusCode}`) + } } } diff --git a/src/shared/plugins.js b/src/shared/plugins.js index 16dc7e21d..33b1daa6b 100644 --- a/src/shared/plugins.js +++ b/src/shared/plugins.js @@ -4,16 +4,13 @@ const Package = require('../../package') const Inert = require('inert') const Vision = require('vision') const Blipp = require('blipp') -const Good = require('good') - -const HapiSwagger = require('hapi-swagger') -const Logger = require('@mojaloop/central-services-shared').Logger +// const GoodWinston = require('good-winston') +// const goodWinstonStream = new GoodWinston({winston: require('winston')}) const ErrorHandling = require('@mojaloop/central-services-error-handling') -const Auth = require('@mojaloop/central-services-auth') -const registerPlugins = (server) => { - server.register({ - register: HapiSwagger, +const registerPlugins = async (server) => { + await server.register({ + plugin: require('hapi-swagger'), options: { info: { 'title': 'Central Ledger API Documentation', @@ -22,31 +19,28 @@ const registerPlugins = (server) => { } }) - server.register({ - register: Good, + await server.register({ + plugin: require('good'), options: { ops: { - interval: 1000 - }, - reporters: { - winston: [{ - module: 'good-winston', - args: [ - Logger, - { - error_level: 'error', - ops_level: 'debug', - request_level: 'debug', - response_level: 'info', - other_level: 'info' - } - ] - }] + interval: 10000 } } }) - server.register([Inert, Vision, Blipp, ErrorHandling, Auth]) + await server.register({ + plugin: require('hapi-auth-basic') + }) + + await server.register({ + plugin: require('@now-ims/hapi-now-auth') + }) + + await server.register({ + plugin: require('hapi-auth-bearer-token') + }) + + await server.register([Inert, Vision, Blipp, ErrorHandling]) } module.exports = { diff --git a/src/shared/setup.js b/src/shared/setup.js index 91468ad78..8abe9239d 100644 --- a/src/shared/setup.js +++ b/src/shared/setup.js @@ -12,6 +12,9 @@ const Sidecar = require('../lib/sidecar') const RequestLogger = require('../lib/request-logger') const Uuid = require('uuid4') const UrlParser = require('../lib/urlparser') +const Logger = require('@mojaloop/central-services-shared').Logger +const Account = require('../domain/account') +const Boom = require('boom') const migrate = (runMigrations) => { return runMigrations ? Migrator.migrate() : P.resolve() @@ -23,55 +26,49 @@ const startEventric = (loadEventric) => { return loadEventric ? Eventric.getContext() : P.resolve() } -const createServer = (port, modules, addRequestLogging = true) => { - return new P((resolve, reject) => { - const server = new Hapi.Server() - server.connection({ +const createServer = (port, modules) => { + return (async () => { + const server = await new Hapi.Server({ port, routes: { - validate: ErrorHandling.validateRoutes() + validate: { + options: ErrorHandling.validateRoutes(), + failAction: async (request, h, err) => { + throw Boom.boomify(err) + } + } } }) - - if (addRequestLogging) { - server.ext('onRequest', onServerRequest) - server.ext('onPreResponse', onServerPreResponse) - } - - Plugins.registerPlugins(server) - server.register(modules) - resolve(server) - }) + server.ext('onRequest', function (request, h) { + const transferId = UrlParser.idFromTransferUri(`${Config.HOSTNAME}${request.url.path}`) + request.headers.traceid = request.headers.traceid || transferId || Uuid() + RequestLogger.logRequest(request) + return h.continue + }) + server.ext('onPreResponse', function (request, h) { + RequestLogger.logResponse(request) + return h.continue + }) + await Plugins.registerPlugins(server) + await server.register(modules) + await server.start() + Logger.info('Server running at: ', server.info.uri) + return server + })() } // Migrator.migrate is called before connecting to the database to ensure all new tables are loaded properly. // Eventric.getContext is called to replay all events through projections (creating the read-model) before starting the server. -const initialize = ({ service, port, modules = [], loadEventric = false, runMigrations = false }) => { - return migrate(runMigrations) - .then(() => connectDatabase()) - .then(() => Sidecar.connect(service)) - .then(() => startEventric(loadEventric)) - .then(() => createServer(port, modules)) - .catch(err => { - cleanup() - throw err - }) -} - -const onServerRequest = (request, reply) => { - const transferId = UrlParser.idFromTransferUri(`${Config.HOSTNAME}${request.url.path}`) - request.headers.traceid = request.headers.traceid || transferId || Uuid() - RequestLogger.logRequest(request) - reply.continue() -} - -const onServerPreResponse = (request, reply) => { - RequestLogger.logResponse(request) - reply.continue() -} - -const cleanup = () => { - Db.disconnect() +const initialize = async function ({service, port, modules = [], loadEventric = false, runMigrations = false}) { + await migrate(runMigrations) + await connectDatabase() + await Sidecar.connect(service) + await startEventric(loadEventric) + const server = await createServer(port, modules) + if (service === 'api') { + await Account.createLedgerAccount(Config.LEDGER_ACCOUNT_NAME, Config.LEDGER_ACCOUNT_PASSWORD, Config.LEDGER_ACCOUNT_EMAIL) + } + return server } module.exports = { diff --git a/test.Dockerfile b/test.Dockerfile index 8456267ae..833ec02f8 100644 --- a/test.Dockerfile +++ b/test.Dockerfile @@ -1,13 +1,22 @@ -FROM dwolla/alpine-node-make +FROM mhart/alpine-node:8.9.4 +USER root WORKDIR /opt/central-ledger -COPY . /opt/central-ledger +COPY src /opt/central-ledger/src +COPY test /opt/central-ledger/test +COPY migrations /opt/central-ledger/migrations +COPY config /opt/central-ledger/config +COPY package.json server.sh /opt/central-ledger/ -RUN apk --no-cache add git -RUN npm link sodium && \ - npm link argon2 && \ - npm install && \ - npm install -g tape tap-xunit +RUN apk add --no-cache -t build-dependencies make gcc g++ python libtool autoconf automake \ + && cd $(npm root -g)/npm \ + && npm install -g node-gyp \ + && apk --no-cache add git + +RUN npm install -g tape tap-xunit \ + && npm install + +RUN apk del build-dependencies EXPOSE 3000 -CMD bin/sh -c +CMD ["/opt/central-ledger/server.sh"] diff --git a/test/.env b/test/.env index 4d1a768f7..8e33fd66b 100644 --- a/test/.env +++ b/test/.env @@ -1,3 +1,4 @@ +export CLEDG_DATABASE_URI="postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:5432/${POSTGRES_DB}" POSTGRES_USER=central_ledger POSTGRES_PASSWORD=cVq8iFqaLuHy8jjKuA CLEDG_ADMIN_KEY=admin diff --git a/test/fixtures/index.js b/test/fixtures/index.js index 5b61e3ffa..f5b180b59 100644 --- a/test/fixtures/index.js +++ b/test/fixtures/index.js @@ -15,7 +15,7 @@ const generateAccountName = () => { } const generateRandomName = () => { - return `dfsp${Uuid().replace(/-/g, '')}` + return `dfsp${Uuid().replace(/-/g, '')}`.substr(0, 25) } const buildDebitOrCredit = (accountName, amount, memo) => { diff --git a/test/functional/admin/accounts/get-all.test.js b/test/functional/admin/accounts/get-all.test.js index c9adea206..ddf157b98 100644 --- a/test/functional/admin/accounts/get-all.test.js +++ b/test/functional/admin/accounts/get-all.test.js @@ -1,32 +1,30 @@ 'use strict' const Test = require('tape') -const bluebird = require('bluebird') +const Logger = require('@mojaloop/central-services-shared').Logger const Base = require('../../base') const Fixtures = require('../../../fixtures') Test('GET /accounts', getTest => { - getTest.test('should return all accounts', function (assert) { + getTest.test('should return all accounts', async function (assert) { const account1Name = 'a' + Fixtures.generateAccountName() const account2Name = 'b' + Fixtures.generateAccountName() - - bluebird.all([Base.createAccount(account1Name), Base.createAccount(account2Name)]) - .then(([account1Res, account2Res]) => { - Base.getAdmin('/accounts') - .expect(200) - .expect('Content-Type', /json/) - .then(res => { - assert.equal(res.body[0].name, account1Res.body.name) - assert.equal(res.body[0].created, account1Res.body.created) - assert.equal(res.body[0].id, account1Res.body.id) - assert.equal(res.body[0].emailAddress, account1Res.body.emailAddress) - assert.equal(res.body[1].name, account2Res.body.name) - assert.equal(res.body[1].created, account2Res.body.created) - assert.equal(res.body[1].id, account2Res.body.id) - assert.equal(res.body[1].emailAddress, account2Res.body.emailAddress) - assert.end() - }) - }) + try { + const account1Res = await Base.createAccount(account1Name) + const account2Res = await Base.createAccount(account2Name) + const res = await Base.getAdmin('/accounts') + assert.equal(res.body[0].name, account1Res.body.name) + assert.equal(res.body[0].created, account1Res.body.created) + assert.equal(res.body[0].id, account1Res.body.id) + assert.equal(res.body[0].emailAddress, account1Res.body.emailAddress) + assert.equal(res.body[1].name, account2Res.body.name) + assert.equal(res.body[1].created, account2Res.body.created) + assert.equal(res.body[1].id, account2Res.body.id) + assert.equal(res.body[1].emailAddress, account2Res.body.emailAddress) + assert.end() + } catch (e) { + Logger.info(e) + } }) getTest.end() diff --git a/test/functional/admin/charges/update.test.js b/test/functional/admin/charges/update.test.js index f5954c3e1..aaf3454e0 100644 --- a/test/functional/admin/charges/update.test.js +++ b/test/functional/admin/charges/update.test.js @@ -5,7 +5,7 @@ const Base = require('../../base') const Fixtures = require('../../../fixtures') Test('PUT /charges/{name}', putTest => { - putTest.test('should update a charge', test => { + putTest.test('should update a charge', async function (test) { const chargeName = Fixtures.generateRandomName() const payload = { name: chargeName, @@ -21,7 +21,7 @@ Test('PUT /charges/{name}', putTest => { } const payload2 = { - name: 'a' + chargeName, + name: chargeName, charge_type: 'fee', is_active: false, maximum: '10.00', @@ -29,34 +29,26 @@ Test('PUT /charges/{name}', putTest => { code: '002' } - Base.createCharge(payload) - .expect(201) - .expect('Content-Type', /json/) - .then(() => { - Base.updateCharge(chargeName, payload2) - .expect(200) - .expect('Content-Type', /json/) - .then(res => { - test.equal(res.body.name, payload2.name) - test.equal(res.body.is_active, payload2.is_active) - test.equal(res.body.charge_type, payload2.charge_type) - test.equal(res.body.minimum, payload2.minimum) - test.equal(res.body.maximum, payload2.maximum) - test.equal(res.body.code, payload2.code) - test.equal(res.body.rate_type, payload.rate_type) - test.equal(res.body.rate, payload.rate) - test.equal(res.body.payer, payload.payer) - test.equal(res.body.payee, payload.payee) - test.end() - }) - }) + await Base.createCharge(payload) + const res = await Base.updateCharge(chargeName, payload2) + test.equal(res.body.name, payload2.name) + test.equal(res.body.is_active, payload2.is_active) + test.equal(res.body.charge_type, payload2.charge_type) + test.equal(res.body.minimum, payload2.minimum) + test.equal(res.body.maximum, payload2.maximum) + test.equal(res.body.code, payload2.code) + test.equal(res.body.rate_type, payload.rate_type) + test.equal(res.body.rate, payload.rate) + test.equal(res.body.payer, payload.payer) + test.equal(res.body.payee, payload.payee) + test.end() }) putTest.end() }) Test('PUT /charges/{name}', putTest => { - putTest.test('should update a charge with null values', test => { + putTest.test('should update a charge with null values', async function (test) { const chargeName = Fixtures.generateRandomName() const payload = { name: chargeName, @@ -72,7 +64,7 @@ Test('PUT /charges/{name}', putTest => { } const payload2 = { - name: 'a' + chargeName, + name: chargeName, charge_type: 'fee', is_active: false, maximum: null, @@ -80,27 +72,19 @@ Test('PUT /charges/{name}', putTest => { code: null } - Base.createCharge(payload) - .expect(201) - .expect('Content-Type', /json/) - .then(() => { - Base.updateCharge(chargeName, payload2) - .expect(200) - .expect('Content-Type', /json/) - .then(res => { - test.equal(res.body.name, payload2.name) - test.equal(res.body.is_active, payload2.is_active) - test.equal(res.body.charge_type, payload2.charge_type) - test.equal(res.body.minimum, payload2.minimum) - test.equal(res.body.maximum, payload2.maximum) - test.equal(res.body.code, payload2.code) - test.equal(res.body.rate_type, payload.rate_type) - test.equal(res.body.rate, payload.rate) - test.equal(res.body.payer, payload.payer) - test.equal(res.body.payee, payload.payee) - test.end() - }) - }) + await Base.createCharge(payload) + const res = await Base.updateCharge(chargeName, payload2) + test.equal(res.body.name, payload2.name) + test.equal(res.body.is_active, payload2.is_active) + test.equal(res.body.charge_type, payload2.charge_type) + test.equal(res.body.minimum, payload2.minimum) + test.equal(res.body.maximum, payload2.maximum) + test.equal(res.body.code, payload2.code) + test.equal(res.body.rate_type, payload.rate_type) + test.equal(res.body.rate, payload.rate) + test.equal(res.body.payer, payload.payer) + test.equal(res.body.payee, payload.payee) + test.end() }) putTest.end() diff --git a/test/functional/admin/webhooks/post-settle-transfers.test.js b/test/functional/admin/webhooks/post-settle-transfers.test.js index 9afd548ee..a2cc918fe 100644 --- a/test/functional/admin/webhooks/post-settle-transfers.test.js +++ b/test/functional/admin/webhooks/post-settle-transfers.test.js @@ -3,9 +3,11 @@ const Test = require('tape') const Base = require('../../base') const Fixtures = require('../../../fixtures') +const Config = require('../../../../src/lib/config') Test('POST /webhooks/settle-transfers', settleTest => { - settleTest.test('should settle transfer and fees', test => { + settleTest.test('should settle transfer and fees', async function (test) { + Config.LEDGER_ACCOUNT_NAME = 'LedgerAccountName' let transferId = Fixtures.generateTransferId() let transfer = Fixtures.buildTransfer(transferId, Fixtures.buildDebitOrCredit(Base.account1Name, '101.00'), Fixtures.buildDebitOrCredit(Base.account2Name, '101.00')) const charge = { @@ -22,19 +24,12 @@ Test('POST /webhooks/settle-transfers', settleTest => { } const response = { fees: [{ amount: { currency_code: 'TZS', description: Base.account1Name, value: charge.rate }, destination: { account_number: Base.account2AccountNumber, routing_number: Base.account2RoutingNumber }, source: { account_number: Base.account1AccountNumber, routing_number: Base.account1RoutingNumber } }], transfers: [{ amount: { currency_code: 'TZS', description: Base.account1Name, value: '101.00' }, destination: { account_number: Base.account2AccountNumber, routing_number: Base.account2RoutingNumber }, source: { account_number: Base.account1AccountNumber, routing_number: Base.account1RoutingNumber } }] } - - Base.createCharge(charge) - .then(() => Base.prepareTransfer(transferId, transfer)) - .then(() => Base.fulfillTransfer(transferId, 'oAKAAA')) - .then(() => { - Base.postAdmin('/webhooks/settle-transfers', {}) - .expect(200) - .expect('Content-Type', /json/) - .then(res => { - test.deepEqual(res.body, response) - test.end() - }) - }) + await Base.createCharge(charge) + await Base.prepareTransfer(transferId, transfer) + await Base.fulfillTransfer(transferId, 'oAKAAA') + const res = await Base.postAdmin('/webhooks/settle-transfers', {}) + test.deepEqual(res.body, response) + test.end() }) settleTest.end() diff --git a/test/functional/api/accounts/routes.test.js b/test/functional/api/accounts/routes.test.js index f6083a867..e72be26fa 100644 --- a/test/functional/api/accounts/routes.test.js +++ b/test/functional/api/accounts/routes.test.js @@ -3,6 +3,7 @@ const Test = require('tape') const Base = require('../../base') const Fixtures = require('../../../fixtures') +const Config = require('../../../../src/lib/config') Test('post and get an account', assert => { const accountName = Fixtures.generateAccountName() @@ -30,28 +31,23 @@ Test('post and get an account', assert => { }) }) -Test('return the net position for the account as the balance', assert => { +Test('return the net position for the account as the balance', async function (assert) { let fulfillment = 'oAKAAA' + Config.LEDGER_ACCOUNT_NAME = 'LedgerAccountName' let transferId = Fixtures.generateTransferId() let transfer = Fixtures.buildTransfer(transferId, Fixtures.buildDebitOrCredit(Base.account1Name, '50'), Fixtures.buildDebitOrCredit(Base.account2Name, '50')) let transfer2Id = Fixtures.generateTransferId() let transfer2 = Fixtures.buildTransfer(transfer2Id, Fixtures.buildDebitOrCredit(Base.account2Name, '15'), Fixtures.buildDebitOrCredit(Base.account1Name, '15')) - Base.prepareTransfer(transferId, transfer) - .then(() => Base.fulfillTransfer(transferId, fulfillment)) - .then(() => Base.prepareTransfer(transfer2Id, transfer2)) - .then(() => Base.fulfillTransfer(transfer2Id, fulfillment)) - .then(() => { - Base.getAccount(Base.account1Name) - .expect(200) - .expect('Content-Type', /json/) - .then(res => { - assert.equal(Base.account1Name, res.body.name) - assert.equal('-35', res.body.balance) - assert.end() - }) - }) + await Base.prepareTransfer(transferId, transfer) + await Base.fulfillTransfer(transferId, fulfillment) + await Base.prepareTransfer(transfer2Id, transfer2) + await Base.fulfillTransfer(transfer2Id, fulfillment) + const res = await Base.getAccount(Base.account1Name) + assert.equal(Base.account1Name, res.body.name) + assert.equal('-35', res.body.balance) + assert.end() }) Test('ensure an account name can only be registered once', assert => { @@ -73,24 +69,16 @@ Test('ensure an account name can only be registered once', assert => { }) }) -Test('update an accounts passsword', test => { +Test('update an accounts password', async function (test) { const accountName = Fixtures.generateAccountName() const password = '1234' - Base.createAccount(accountName, password) - .expect(201) - .expect('Content-Type', /json/) - .then(() => { - Base.putApi(`/accounts/${accountName}`, { password }) - .expect(200) - .expect('Content-Type', /json/) - .then(res => { - test.equal(res.body.id, `http://central-ledger/accounts/${accountName}`) - test.equal(res.body.name, accountName) - test.equal(res.body.ledger, 'http://central-ledger') - test.end() - }) - }) + await Base.createAccount(accountName, password) + const res = await Base.putApi(`/accounts/${accountName}`, {password, emailAddress: accountName + '@test.com'}) + test.equal(res.body.id, `http://central-ledger/accounts/${accountName}`) + test.equal(res.body.name, accountName) + test.equal(res.body.ledger, 'http://central-ledger') + test.end() }) Test('update an accounts settlement', test => { @@ -103,7 +91,7 @@ Test('update an accounts settlement', test => { .expect(201) .expect('Content-Type', /json/) .then(() => { - Base.putApi(`/accounts/${accountName}/settlement`, { account_number: accountNumber, routing_number: routingNumber }) + Base.putApi(`/accounts/${accountName}/settlement`, {account_number: accountNumber, routing_number: routingNumber}) .expect(200) .expect('Content-Type', /json/) .then(res => { diff --git a/test/functional/api/metadata/routes.test.js b/test/functional/api/metadata/routes.test.js index d8733d1a9..06dc7fd18 100644 --- a/test/functional/api/metadata/routes.test.js +++ b/test/functional/api/metadata/routes.test.js @@ -4,33 +4,29 @@ const Test = require('tape') const Base = require('../../base') const Fixtures = require('../../../fixtures') -Test('return metadata', function (assert) { - Base.getApi('/') - .expect(200) - .expect('Content-Type', /json/) - .then(res => { - assert.equal(res.body.currency_code, null) - assert.equal(res.body.currency_symbol, null) - assert.equal(res.body.precision, 10) - assert.equal(res.body.scale, 2) - assert.deepEqual(res.body.connectors, []) - assert.equal(Object.keys(res.body.urls).length, 14) - assert.equal(res.body.urls.health, `http://${Fixtures.hostname}/health`) - assert.equal(res.body.urls.account, `http://${Fixtures.hostname}/accounts/:name`) - assert.equal(res.body.urls.account_update_user_credentials, `http://${Fixtures.hostname}/accounts/:name`) - assert.equal(res.body.urls.account_update_account_settlement, `http://${Fixtures.hostname}/accounts/:name/settlement`) - assert.equal(res.body.urls.accounts, `http://${Fixtures.hostname}/accounts`) - assert.equal(res.body.urls.transfer, `http://${Fixtures.hostname}/transfers/:id`) - assert.equal(res.body.urls.transfer_fulfillment, `http://${Fixtures.hostname}/transfers/:id/fulfillment`) - assert.equal(res.body.urls.transfer_rejection, `http://${Fixtures.hostname}/transfers/:id/rejection`) - assert.equal(res.body.urls.websocket, `ws://${Fixtures.hostname}/websocket`) - assert.equal(res.body.urls.message, `http://${Fixtures.hostname}/messages`) - assert.equal(res.body.urls.charges, `http://${Fixtures.hostname}/charges/quote`) - assert.equal(res.body.urls.positions, `http://${Fixtures.hostname}/positions`) - assert.equal(res.body.urls.positions_account, `http://${Fixtures.hostname}/positions/:name`) - assert.equal(res.body.urls.auth_token, `http://${Fixtures.hostname}/auth_token`) - assert.end() - }) +Test('return metadata', async function (assert) { + const res = await Base.getApi('/') + assert.equal(res.body.currency_code, null) + assert.equal(res.body.currency_symbol, null) + assert.equal(res.body.precision, 10) + assert.equal(res.body.scale, 2) + assert.deepEqual(res.body.connectors, []) + assert.equal(Object.keys(res.body.urls).length, 14) + assert.equal(res.body.urls.health, `http://${Fixtures.hostname}/health`) + assert.equal(res.body.urls.account, `http://${Fixtures.hostname}/accounts/:name`) + assert.equal(res.body.urls.account_update_user_credentials, `http://${Fixtures.hostname}/accounts/:name`) + assert.equal(res.body.urls.account_update_account_settlement, `http://${Fixtures.hostname}/accounts/:name/settlement`) + assert.equal(res.body.urls.accounts, `http://${Fixtures.hostname}/accounts`) + assert.equal(res.body.urls.transfer, `http://${Fixtures.hostname}/transfers/:id`) + assert.equal(res.body.urls.transfer_fulfillment, `http://${Fixtures.hostname}/transfers/:id/fulfillment`) + assert.equal(res.body.urls.transfer_rejection, `http://${Fixtures.hostname}/transfers/:id/rejection`) + assert.equal(res.body.urls.websocket, `ws://${Fixtures.hostname}/websocket`) + assert.equal(res.body.urls.message, `http://${Fixtures.hostname}/messages`) + assert.equal(res.body.urls.charges, `http://${Fixtures.hostname}/charges/quote`) + assert.equal(res.body.urls.positions, `http://${Fixtures.hostname}/positions`) + assert.equal(res.body.urls.positions_account, `http://${Fixtures.hostname}/positions/:name`) + assert.equal(res.body.urls.auth_token, `http://${Fixtures.hostname}/auth_token`) + assert.end() }) Test('return api documentation', function (assert) { diff --git a/test/functional/api/token/get-auth-token.test.js b/test/functional/api/token/get-auth-token.test.js index 777d6b2d7..91fc5f77f 100644 --- a/test/functional/api/token/get-auth-token.test.js +++ b/test/functional/api/token/get-auth-token.test.js @@ -5,22 +5,18 @@ const Base = require('../../base') const Fixtures = require('../../../fixtures') Test('GET /auth_token', getTest => { - getTest.test('should return token', test => { + getTest.test('should return token', async function (test) { const accountName = Fixtures.generateAccountName() const password = '1234' - Base.createAccount(accountName, password) - .then(res => { - Base.getApi('/auth_token', Base.basicAuth(accountName, password)) - .expect('Content-Type', /json/) - .then(res => { - const token = res.body.token - test.ok(token) - test.ok(token.length > 74) - test.notEqual(token, password) - test.end() - }) - }) + await Base.createAccount(accountName, password) + const basicAuth = await Base.basicAuth(accountName, password) + const res = await Base.getApi('/auth_token', basicAuth) + const token = res.body.token + test.ok(token) + test.ok(token.length > 74) + test.notEqual(token, password) + test.end() }) getTest.end() diff --git a/test/functional/api/transfers/get-fulfillment.test.js b/test/functional/api/transfers/get-fulfillment.test.js index 67f383c64..7c7ad5b38 100644 --- a/test/functional/api/transfers/get-fulfillment.test.js +++ b/test/functional/api/transfers/get-fulfillment.test.js @@ -5,22 +5,16 @@ const Base = require('../../base') const Fixtures = require('../../../fixtures') Test('GET /transfers/:id/fulfillment', getTest => { - getTest.test('should return fulfillment for transfer', test => { + getTest.test('should return fulfillment for transfer', async function (test) { const fulfillment = 'oAKAAA' const transferId = Fixtures.generateTransferId() const transfer = Fixtures.buildTransfer(transferId, Fixtures.buildDebitOrCredit(Base.account1Name, '25'), Fixtures.buildDebitOrCredit(Base.account2Name, '25')) - Base.prepareTransfer(transferId, transfer) - .then(() => Base.fulfillTransfer(transferId, fulfillment)) - .then(() => { - Base.getFulfillment(transferId) - .expect(200) - .expect('Content-Type', 'text/plain; charset=utf-8') - .then(res => { - test.equal(res.text, fulfillment) - test.end() - }) - }) + await Base.prepareTransfer(transferId, transfer) + await Base.fulfillTransfer(transferId, fulfillment) + const res = await Base.getFulfillment(transferId) + test.equal(res.text, fulfillment) + test.end() }) getTest.test('should return error is transfer does not exist', test => { diff --git a/test/functional/base.js b/test/functional/base.js index 1940b5ffe..f4af084c7 100644 --- a/test/functional/base.js +++ b/test/functional/base.js @@ -18,7 +18,7 @@ const account2RoutingNumber = '4567' const basicAuth = (name, password) => { const credentials = Encoding.toBase64(name + ':' + password) - return { 'Authorization': `Basic ${credentials}` } + return {'Authorization': `Basic ${credentials}`} } let account1promise @@ -43,9 +43,17 @@ const account2 = () => { const getApi = (path, headers = {}) => RequestApi.get(path).auth('admin', 'admin').set(headers) -const postApi = (path, data, auth = { name: 'admin', password: 'admin', emailAddress: 'admin@test.com' }, contentType = 'application/json') => RequestApi.post(path).auth(auth.name, auth.password, auth.emailAddress).set('Content-Type', contentType).send(data) +const postApi = (path, data, auth = { + name: 'admin', + password: 'admin', + emailAddress: 'admin@test.com' +}, contentType = 'application/json') => RequestApi.post(path).auth(auth.name, auth.password, auth.emailAddress).set('Content-Type', contentType).send(data) -const putApi = (path, data, auth = { name: 'admin', password: 'admin', emailAddress: 'admin@test.com' }, contentType = 'application/json') => RequestApi.put(path).auth(auth.name, auth.password, auth.emailAddress).set('Content-Type', contentType).send(data) +const putApi = (path, data, auth = { + name: 'admin', + password: 'admin', + emailAddress: 'admin@test.com' +}, contentType = 'application/json') => RequestApi.put(path).auth(auth.name, auth.password, auth.emailAddress).set('Content-Type', contentType).send(data) const getAdmin = (path, headers = {}) => RequestAdmin.get(path).set(headers) @@ -53,13 +61,20 @@ const postAdmin = (path, data, contentType = 'application/json') => RequestAdmin const putAdmin = (path, data, contentType = 'application/json') => RequestAdmin.put(path).set('Content-Type', contentType).send(data) -const createAccount = (accountName, password = '1234', emailAddress = accountName + '@test.com') => postApi('/accounts', { name: accountName, password: password, emailAddress: emailAddress }) +const createAccount = (accountName, password = '1234', emailAddress = accountName + '@test.com') => postApi('/accounts', { + name: accountName, + password: password, + emailAddress: emailAddress +}) -const createAccountSettlement = (accountName, accountNumber, routingNumber) => putApi(`/accounts/${accountName}/settlement`, { account_number: accountNumber, routing_number: routingNumber }) +const createAccountSettlement = (accountName, accountNumber, routingNumber) => putApi(`/accounts/${accountName}/settlement`, { + account_number: accountNumber, + routing_number: routingNumber +}) const getAccount = (accountName) => getApi(`/accounts/${accountName}`) -const updateAccount = (accountName, isDisabled) => putAdmin(`/accounts/${accountName}`, { is_disabled: isDisabled }) +const updateAccount = (accountName, isDisabled) => putAdmin(`/accounts/${accountName}`, {is_disabled: isDisabled}) const getTransfer = (transferId) => getApi(`/transfers/${transferId}`) diff --git a/test/integration-runner.env b/test/integration-runner.env new file mode 100644 index 000000000..a3dcb2988 --- /dev/null +++ b/test/integration-runner.env @@ -0,0 +1,14 @@ +DOCKER_IMAGE=${DOCKER_IMAGE:-'central-ledger'} +DOCKER_TAG=${DOCKER_TAG:-'test'} +DOCKER_FILE=${DOCKER_FILE:-"test.Dockerfile"} +DOCKER_WORKING_DIR=${DOCKER_WORKING_DIR:-"/opt/central-ledger"} +POSTGRES_USER=${POSTGRES_USER:-"central_ledger"} +POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-"cVq8iFqaLuHy8jjKuA"} +POSTGRES_HOST=${HOST_IP:-"postgres-int"} +POSTGRES_PORT=${POSTGRES_PORT:-5432} +POSTGRES_DB=${POSTGRES_DB:-"central_ledger_integration"} +POSTGRES_IMAGE=${POSTGRES_DOCKER:-"postgres"} +POSTGRES_TAG=${POSTGRES_DOCKER:-"9.4"} +APP_HOST=${APP_HOST:-"centralleadger-int"} +APP_DIR_TEST_RESULTS=${APP_DIR_TEST_RESULTS:-"test/results"} +TEST_CMD=${TEST_CMD:-"tape 'test/integration/**/*.test.js' | tap-xunit > ./test/results/tape-integration.xml; cat ./test/results/tape-integration.xml"} diff --git a/test/integration-runner.sh b/test/integration-runner.sh index fcba38ba9..6bf369ef5 100644 --- a/test/integration-runner.sh +++ b/test/integration-runner.sh @@ -1,31 +1,54 @@ #!/bin/bash -export API_IMAGE=${API_IMAGE:-'central-ledger'} -export POSTGRES_USER=${POSTGRES_USER:-"postgres"} -export POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-"postgres"} -export CENRRALLEDGER_TEST_HOST=${HOST_IP:-"centralledger-int"} -export POSTGRES_HOST=${HOST_IP:-"postgres-int"} -env_file=$1 -INTG_TEST_CMD=${INTG_TEST_CMD:-"source $env_file; tape 'test/integration/**/*.test.js' | tap-xunit > ./test/results/tape-integration.xml; cat ./test/results/tape-integration.xml"} -# INTG_TEST_CMD=${INTG_TEST_CMD:-"tape 'test/integration/**/*.test.js'"} - -#create a directory for test results -mkdir -p ./test/results +>&2 echo "--==== Integration Tests Runner ====--" if [ $# -ne 1 ]; then - echo "Usage: $0 env-file" + echo "" + echo "Usage: $0 {env-file}" + echo "{env-file} must contain the following variables:" + echo " - DOCKER_IMAGE: Name of Image" + echo " - DOCKER_TAG: Tag/Version of Image" + echo " - DOCKER_FILE: Recipe to be used for Docker build" + echo " - DOCKER_WORKING_DIR: Docker working directory" + echo " - POSTGRES_USER: Posgres user" + echo " - POSTGRES_PASSWORD: Posgres password" + echo " - POSTGRES_HOST: Posgres host name" + echo " - POSTGRES_PORT: Posgres container port" + echo " - POSTGRES_DB: Posgres database" + echo " - POSTGRES_IMAGE: Docker Image for Posgres" + echo " - POSTGRES_TAG: Docker tag/version for Posgres" + echo " - APP_HOST: Application host name" + echo " - APP_DIR_TEST_RESULTS: Location of test results relative to the working directory" + echo " - TEST_CMD: Interation test command to be executed" + echo "" + echo " * IMPORTANT: Ensure you have the required env in the test/integration-runner.env to execute the application" + echo "" exit 1 fi +>&2 echo "" +>&2 echo "====== Loading environment variables ======" +cat $1 +. $1 +>&2 echo "===========================================" +>&2 echo "" + +>&2 echo "Executing Integration Tests for $APP_HOST ..." + +>&2 echo "Creating local directory to store test results" +mkdir -p test/results fpsql() { docker run --rm -i \ --entrypoint psql \ --link $POSTGRES_HOST \ + -e PGUSER=$POSTGRES_USER \ -e PGPASSWORD=$POSTGRES_PASSWORD \ - "postgres:9.4" \ + -e PGDATABASE=$POSTGRES_DB \ + -e POSTGRES_DB=$POSTGRES_DBNAME \ + "$POSTGRES_IMAGE:$POSTGRES_TAG" \ --host $POSTGRES_HOST \ --username $POSTGRES_USER \ - --dbname postgres \ + --dbname $POSTGRES_DB \ --quiet --no-align --tuples-only \ "$@" } @@ -33,8 +56,13 @@ fpsql() { ftest() { docker run --rm -i \ --link $POSTGRES_HOST \ - --env CLEDG_DATABASE_URI="postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:5432/central_ledger_integration" \ - $API_IMAGE:test \ + --env POSTGRES_USER="$POSTGRES_USER" \ + --env POSTGRES_PASSWORD="$POSTGRES_PASSWORD" \ + --env POSTGRES_HOST="$POSTGRES_HOST" \ + --env POSTGRES_PORT="$POSTGRES_PORT" \ + --env POSTGRES_DB="$POSTGRES_DB" \ + --env CLEDG_DATABASE_URI="postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:5432/${POSTGRES_DB}" \ + "$DOCKER_IMAGE:$DOCKER_TAG" \ /bin/sh \ -c \ "$@" @@ -45,44 +73,71 @@ is_psql_up() { } stop_docker() { - >&2 echo "Posgres-int is shutting down" + >&2 echo "Posgres-int is shutting down $POSTGRES_HOST" (docker stop $POSTGRES_HOST && docker rm $POSTGRES_HOST) > /dev/null 2>&1 - >&2 echo "Central Ledger Test environment is shutting down" - (docker stop $CENRRALLEDGER_TEST_HOST && docker rm $CENRRALLEDGER_TEST_HOST) > /dev/null 2>&1 + >&2 echo "$APP_HOST environment is shutting down" + (docker stop $APP_HOST && docker rm $APP_HOST) > /dev/null 2>&1 +} + +clean_docker() { + stop_docker + >&2 echo "Removing docker test image $DOCKER_IMAGE:$DOCKER_TAG" + (docker rmi $DOCKER_IMAGE:$DOCKER_TAG) > /dev/null 2>&1 } run_test_command() { - >&2 echo "Running Central Ledger Test command: $INTG_TEST_CMD" + >&2 echo "Running $APP_HOST Test command: $TEST_CMD" docker run -i \ --link $POSTGRES_HOST \ - --name $CENRRALLEDGER_TEST_HOST \ - --env CLEDG_DATABASE_URI="postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:5432/central_ledger_integration" \ - $API_IMAGE:test \ + --name $APP_HOST \ + --env POSTGRES_USER="$POSTGRES_USER" \ + --env POSTGRES_PASSWORD="$POSTGRES_PASSWORD" \ + --env POSTGRES_HOST="$POSTGRES_HOST" \ + --env POSTGRES_PORT="$POSTGRES_PORT" \ + --env POSTGRES_DB="$POSTGRES_DB" \ + $DOCKER_IMAGE:$DOCKER_TAG \ /bin/sh \ - -c "$INTG_TEST_CMD" + -c "source test/.env; $TEST_CMD" } ->&2 echo "Loading environment variables" -. $env_file +>&2 echo "Building Docker Image $DOCKER_IMAGE:$DOCKER_TAG with $DOCKER_FILE" +docker build --no-cache -t $DOCKER_IMAGE:$DOCKER_TAG -f $DOCKER_FILE . +#Docker build for local testing below +# docker build -t $DOCKER_IMAGE:$DOCKER_TAG -f $DOCKER_FILE . +echo "result "$?"" +if [ "$?" != 0 ] +then + >&2 echo "Build failed...exiting" + clean_docker + exit 1 +fi >&2 echo "Postgres is starting" stop_docker -docker run --name $POSTGRES_HOST -d -p 15432:5432 -e POSTGRES_PASSWORD=$POSTGRES_PASSWORD -e POSTGRES_USER=$POSTGRES_USER "postgres:9.4" > /dev/null 2>&1 +docker run --name $POSTGRES_HOST -d -p $POSTGRES_PORT:$POSTGRES_PORT -e POSTGRES_PASSWORD=$POSTGRES_PASSWORD -e POSTGRES_USER=$POSTGRES_USER -e POSTGRES_DB=$POSTGRES_DB "$POSTGRES_IMAGE:$POSTGRES_TAG" > /dev/null 2>&1 + +if [ "$?" != 0 ] +then + >&2 echo "Starting Postgres failed...exiting" + clean_docker + exit 1 +fi until is_psql_up; do - >&2 echo "Postgres is unavailable - sleeping" + >&2 echo "Postgres is unavailable...sleeping" sleep 1 done ->&2 echo "Postgres is up - creating integration database" -fpsql <<'EOSQL' - DROP DATABASE IF EXISTS "central_ledger_integration"; - CREATE DATABASE "central_ledger_integration"; -EOSQL - >&2 echo "Running migrations" -ftest "npm run migrate > /dev/null 2>&1" +ftest "source test/.env; npm run migrate" + +if [ "$?" != 0 ] +then + >&2 echo "Migration failed...exiting" + clean_docker + exit 1 +fi >&2 echo "Integration tests are starting" run_test_command @@ -90,13 +145,16 @@ test_exit_code=$? if [ "$test_exit_code" != 0 ] then + >&2 echo "Integration tests failed...exiting" >&2 echo "Test environment logs..." - docker logs $CENRRALLEDGER_TEST_HOST + docker logs $APP_HOST + clean_docker + exit 1 fi >&2 echo "Copy results to local directory" -docker cp $CENRRALLEDGER_TEST_HOST:/opt/central-ledger/test/results ./test +docker cp $APP_HOST:$DOCKER_WORKING_DIR/$APP_DIR_TEST_RESULTS test -stop_docker +clean_docker exit "$test_exit_code" diff --git a/test/unit/admin/accounts/handler.test.js b/test/unit/admin/accounts/handler.test.js index 9c33de3f6..46b832ce3 100644 --- a/test/unit/admin/accounts/handler.test.js +++ b/test/unit/admin/accounts/handler.test.js @@ -31,7 +31,7 @@ Test('accounts handler', handlerTest => { }) handlerTest.test('getAll should', getAllTest => { - getAllTest.test('get all accounts and format list', test => { + getAllTest.test('get all accounts and format list', async function (test) { const account1 = { name: 'account1', createdDate: new Date(), @@ -45,43 +45,40 @@ Test('accounts handler', handlerTest => { const accounts = [account1, account2] Account.getAll.returns(P.resolve(accounts)) - - const reply = response => { - test.equal(response.length, 2) - const item1 = response[0] - test.equal(item1.name, account1.name) - test.equal(item1.id, `${hostname}/accounts/${account1.name}`) - test.equal(item1.is_disabled, false) - test.equal(item1.created, account1.createdDate) - test.equal(item1._links.self, `${hostname}/accounts/${account1.name}`) - const item2 = response[1] - test.equal(item2.name, account2.name) - test.equal(item2.id, `${hostname}/accounts/${account2.name}`) - test.equal(item2.is_disabled, false) - test.equal(item2.created, account2.createdDate) - test.equal(item2._links.self, `${hostname}/accounts/${account2.name}`) - test.end() - } - - Handler.getAll({}, reply) + const response = await Handler.getAll({}, {}) + test.equal(response.length, 2) + const item1 = response[0] + test.equal(item1.name, account1.name) + test.equal(item1.id, `${hostname}/accounts/${account1.name}`) + test.equal(item1.is_disabled, false) + test.equal(item1.created, account1.createdDate) + test.equal(item1._links.self, `${hostname}/accounts/${account1.name}`) + const item2 = response[1] + test.equal(item2.name, account2.name) + test.equal(item2.id, `${hostname}/accounts/${account2.name}`) + test.equal(item2.is_disabled, false) + test.equal(item2.created, account2.createdDate) + test.equal(item2._links.self, `${hostname}/accounts/${account2.name}`) + test.end() }) - getAllTest.test('reply with error if Account services throws', test => { + getAllTest.test('reply with error if Account services throws', async function (test) { const error = new Error() Account.getAll.returns(P.reject(error)) - const reply = (e) => { - test.equal(e, error) + try { + await Handler.getAll({}, {}) + } catch (err) { + test.equal(err, error) test.end() } - Handler.getAll({}, reply) }) getAllTest.end() }) handlerTest.test('getByName should', getByNameTest => { - getByNameTest.test('get and format an account', test => { + getByNameTest.test('get and format an account', async function (test) { const account1 = { name: 'account1', createdDate: new Date(), @@ -90,30 +87,28 @@ Test('accounts handler', handlerTest => { Account.getByName.returns(P.resolve(account1)) - const reply = response => { - test.equal(response.name, account1.name) - test.equal(response.id, `${hostname}/accounts/${account1.name}`) - test.equal(response.is_disabled, false) - test.equal(response.created, account1.createdDate) - test.equal(response._links.self, `${hostname}/accounts/${account1.name}`) - test.end() - } - - Handler.getByName({ params: { name: account1.name } }, reply) + const response = await Handler.getByName({params: {name: account1.name}}, {}) + test.equal(response.name, account1.name) + test.equal(response.id, `${hostname}/accounts/${account1.name}`) + test.equal(response.is_disabled, false) + test.equal(response.created, account1.createdDate) + test.equal(response._links.self, `${hostname}/accounts/${account1.name}`) + test.end() }) - getByNameTest.test('reply with not found error if Account does not exist', test => { + getByNameTest.test('reply with not found error if Account does not exist', async function (test) { const error = new Errors.NotFoundError('The requested resource could not be found.') Account.getByName.returns(P.resolve(null)) - const reply = (e) => { - test.deepEqual(e, error) + try { + await Handler.getByName({params: {name: 'name'}}, {}) + } catch (err) { + test.deepEqual(err, error) test.end() } - Handler.getByName({ params: { name: 'name' } }, reply) }) - getByNameTest.test('reply with error if Account services throws', test => { + getByNameTest.test('reply with error if Account services throws', async function (test) { const error = new Error() Account.getByName.returns(P.reject(error)) @@ -121,14 +116,19 @@ Test('accounts handler', handlerTest => { test.equal(e, error) test.end() } - Handler.getByName({ params: { name: 'name' } }, reply) + try { + await Handler.getByName({params: {name: 'name'}}, reply) + } catch (e) { + test.equal(e, error) + test.end() + } }) getByNameTest.end() }) handlerTest.test('updateAccount should', updateAccountTest => { - updateAccountTest.test('update an account to disabled', test => { + updateAccountTest.test('update an account to disabled', async function (test) { const account = { name: 'account1', id: `${hostname}/accounts/account1`, @@ -139,76 +139,75 @@ Test('accounts handler', handlerTest => { Account.update.returns(P.resolve(account)) const request = { - payload: { is_disabled: false }, - params: { name: 'name' } - } - - const reply = response => { - test.equal(response.name, account.name) - test.equal(response.id, `${hostname}/accounts/${account.name}`) - test.equal(response.is_disabled, account.isDisabled) - test.equal(response.created, account.createdDate) - test.ok(Sidecar.logRequest.calledWith(request)) - test.end() + payload: {is_disabled: false}, + params: {name: 'name'} } - Handler.update(request, reply) + const response = await Handler.update(request, {}) + test.equal(response.name, account.name) + test.equal(response.id, `${hostname}/accounts/${account.name}`) + test.equal(response.is_disabled, account.isDisabled) + test.equal(response.created, account.createdDate) + test.ok(Sidecar.logRequest.calledWith(request)) + test.end() }) - updateAccountTest.test('reply with error if Account services throws', test => { + updateAccountTest.test('reply with error if Account services throws', async function (test) { const error = new Error() Account.update.returns(P.reject(error)) const request = { - payload: { is_disabled: false }, - params: { name: 'name' } + payload: {is_disabled: false}, + params: {name: 'name'} } - const reply = (e) => { + try { + await Handler.update(request, {}) + } catch (e) { test.equal(e, error) test.end() } - - Handler.update(request, reply) }) updateAccountTest.end() }) handlerTest.test('create should', createTest => { - createTest.test('return created account', test => { - const payload = { name: 'dfsp1', password: 'dfsp1' } - const account = { name: payload.name, createdDate: 'today', isDisabled: true } + createTest.test('return created account', async function (test) { + const payload = {name: 'dfsp1', password: 'dfsp1'} + const account = {name: payload.name, createdDate: 'today', isDisabled: true} Account.getByName.returns(P.resolve(null)) Account.create.withArgs(payload).returns(P.resolve(account)) const accountId = UrlParser.toAccountUri(account.name) - const reply = (response) => { - test.equal(response.id, accountId) - test.equal(response.is_disabled, account.isDisabled) - test.equal(response.created, account.createdDate) - test.ok(Sidecar.logRequest.calledWith({ payload })) - return { - code: (statusCode) => { - test.equal(statusCode, 201) - test.end() + const reply = { + response: (output) => { + test.equal(output.id, accountId) + test.equal(output.is_disabled, account.isDisabled) + test.equal(output.created, account.createdDate) + test.ok(Sidecar.logRequest.calledWith({payload})) + return { + code: (statusCode) => { + test.equal(statusCode, 201) + test.end() + } } } } - - Handler.create({ payload }, reply) + await Handler.create({payload}, reply) }) - createTest.test('return RecordExistsError if name already registered', test => { - const payload = { name: 'dfsp1', password: 'dfsp1' } - Account.getByName.returns(P.resolve({})) + createTest.test('return RecordExistsError if name already registered', async function (test) { + const payload = {name: 'dfsp1', password: 'dfsp1'} + const account = {name: payload.name, createdDate: 'today', isDisabled: true} + Account.getByName.returns(P.resolve({account})) - const reply = response => { - test.ok(response instanceof Errors.RecordExistsError) - test.equal(response.message, 'The account has already been registered') + try { + await Handler.create({payload}, {}) + } catch (e) { + test.ok(e instanceof Errors.RecordExistsError) + test.equal(e.message, 'The account has already been registered') test.end() } - - Handler.create({ payload }, reply) }) createTest.end() diff --git a/test/unit/admin/auth/admin.test.js b/test/unit/admin/auth/admin.test.js index 7d41fed19..d94f188cd 100644 --- a/test/unit/admin/auth/admin.test.js +++ b/test/unit/admin/auth/admin.test.js @@ -4,14 +4,6 @@ const Test = require('tapes')(require('tape')) const Config = require('../../../../src/lib/config') const AdminAuth = require('../../../../src/admin/auth/admin') -const invalid = (test) => { - return (err, isValid) => { - test.notOk(err) - test.equal(isValid, false) - test.end() - } -} - Test('admin auth module', authTest => { let originalAdminKey let originalAdminSecret @@ -33,61 +25,72 @@ Test('admin auth module', authTest => { test.end() }) - authTest.test('scheme should be basic', test => { - test.equal(AdminAuth.scheme, 'basic') + authTest.test('scheme should be simple', test => { + test.equal(AdminAuth.scheme, 'simple') test.end() }) authTest.test('validate should', validateTest => { - validateTest.test('return false if config admin_key not set', test => { + validateTest.test('return false if config admin_key not set', async function (test) { Config.ADMIN_SECRET = 'admin' - AdminAuth.validate({}, 'admin', 'admin', invalid(test)) + const response = await AdminAuth.validate({}, 'admin', 'admin', {}) + test.notOk(response.credentials) + test.equal(response.isValid, false) + test.end() }) - validateTest.test('return false if config admin_secret not set', test => { + validateTest.test('return false if config admin_secret not set', async function (test) { Config.ADMIN_KEY = 'admin' - AdminAuth.validate({}, 'admin', 'admin', invalid(test)) + const response = await AdminAuth.validate({}, 'admin', 'admin', {}) + test.notOk(response.credentials) + test.equal(response.isValid, false) + test.end() }) - validateTest.test('return false if admin key or secret is empty string', test => { + validateTest.test('return false if admin key or secret is empty string', async function (test) { Config.ADMIN_KEY = '' Config.ADMIN_SECRET = '' - AdminAuth.validate({}, '', '', invalid(test)) + const response = await AdminAuth.validate({}, '', '', {}) + test.notOk(response.credentials) + test.equal(response.isValid, false) + test.end() }) - validateTest.test('return false if username does not equal admin key', test => { + validateTest.test('return false if username does not equal admin key', async function (test) { Config.ADMIN_KEY = 'admin' Config.ADMIN_SECRET = 'admin' - AdminAuth.validate({}, 'ADMIN', 'admin', invalid(test)) + const response = await AdminAuth.validate({}, 'ADMIN', 'admin', {}) + test.notOk(response.credentials) + test.equal(response.isValid, false) + test.end() }) - validateTest.test('return false if username does not equal admin key', test => { + validateTest.test('return false if username does not equal admin key', async function (test) { Config.ADMIN_KEY = 'admin' Config.ADMIN_SECRET = 'admin' - AdminAuth.validate({}, 'admin', 'ADMIN', invalid(test)) + const response = await AdminAuth.validate({}, 'admin', 'ADMIN', {}) + test.notOk(response.credentials) + test.equal(response.isValid, false) + test.end() }) - validateTest.test('return is_admin if username matches admin key and password matches admin secret', test => { + validateTest.test('return is_admin if username matches admin key and password matches admin secret', async function (test) { const adminKey = 'some key' const adminSecret = 'some secret' Config.ADMIN_KEY = adminKey Config.ADMIN_SECRET = adminSecret - const cb = (err, isValid, credentials) => { - test.notOk(err) - test.equal(isValid, true) - test.ok(credentials) - test.equal(credentials.is_admin, true) - test.end() - } - - AdminAuth.validate({}, adminKey, adminSecret, cb) + const response = await AdminAuth.validate({}, adminKey, adminSecret, {}) + test.equal(response.isValid, true) + test.ok(response.credentials) + test.equal(response.credentials.is_admin, true) + test.end() }) validateTest.end() diff --git a/test/unit/admin/auth/index.test.js b/test/unit/admin/auth/index.test.js index 76cfc8ee7..52bbdbeb5 100644 --- a/test/unit/admin/auth/index.test.js +++ b/test/unit/admin/auth/index.test.js @@ -23,24 +23,22 @@ Test('Auth module', authTest => { }) authTest.test('should be named "admin auth"', test => { - test.equal(AuthModule.register.attributes.name, 'admin auth') + test.equal(AuthModule.plugin.name, 'admin auth') test.end() }) authTest.test('register should', registerTest => { - registerTest.test('add AdminStrategy to server auth strategies', test => { + registerTest.test('add AdminStrategy to server auth strategies', async function (test) { const strategySpy = Sinon.spy() const server = { auth: { strategy: strategySpy } } - const next = () => { - test.ok(strategySpy.calledWith(AdminStrategy.name, AdminStrategy.scheme, Sinon.match({ validate: AdminStrategy.validate }))) - test.end() - } - AuthModule.register(server, {}, next) + await AuthModule.plugin.register(server, {}, {}) + test.ok(strategySpy.calledWith(AdminStrategy.scheme, 'basic', Sinon.match({ validate: AdminStrategy.validate }))) + test.end() }) registerTest.test('add TokenStrategy to server auth strategies', test => { @@ -51,12 +49,9 @@ Test('Auth module', authTest => { } } - const next = () => { - test.ok(strategySpy.calledWith(TokenStrategy.name, TokenStrategy.scheme, Sinon.match({ validate: TokenStrategy.validate }))) - test.end() - } - - AuthModule.register(server, {}, next) + AuthModule.plugin.register(server, {}, {}) + test.ok(strategySpy.calledWith(TokenStrategy.scheme, 'hapi-now-auth', Sinon.match({ validate: TokenStrategy.validate }))) + test.end() }) registerTest.end() diff --git a/test/unit/admin/auth/token.test.js b/test/unit/admin/auth/token.test.js index be3baf39d..3e6af37ad 100644 --- a/test/unit/admin/auth/token.test.js +++ b/test/unit/admin/auth/token.test.js @@ -22,32 +22,33 @@ Test('token auth strategy', tokenTest => { }) tokenTest.test('validate should', validateTest => { - validateTest.test('should yield error if token verification fails', test => { - JWT.verify.returns(Promise.reject(new Error('Invalid token'))) - const cb = (err, verified) => { - test.equal(err.message, 'Invalid token') - test.equal(verified, false) - test.end() - } - - TokenAuth.validate({}, '', cb) + validateTest.test('should yield error if token verification fails', async function (test) { + await JWT.verify.returns(Promise.reject(new Error('Invalid token'))) + const response = await TokenAuth.validate({}, '', {}) + test.equal(response.e.message, 'Invalid token') + test.equal(response.verified, false) + test.end() }) - validateTest.test('should pass if token verification passes', test => { + validateTest.test('should yield error if token verification fails', async function (test) { + await JWT.verify.returns(Promise.resolve(null)) + const response = await TokenAuth.validate({}, '', {}) + test.equal(response.e.message, 'Invalid token') + test.equal(response.verified, false) + test.end() + }) + + validateTest.test('should pass if token verification passes', async function (test) { const userId = Uuid() const user = { userId } const roles = [{ permissions: ['ONE', 'TWO', 'THREE'] }, { permissions: ['ONE', 'FOUR', 'FIVE'] }] const token = 'some.jwt.token' - JWT.verify.withArgs(token).returns(Promise.resolve({ user, roles })) - - const cb = (err, verified, credentials) => { - test.notOk(err) - test.equal(verified, true) - test.deepEqual(credentials, { userId, scope: [ 'ONE', 'TWO', 'THREE', 'FOUR', 'FIVE' ] }) - test.end() - } + await JWT.verify.withArgs(token).returns(Promise.resolve({ user, roles })) - TokenAuth.validate({}, token, cb) + const response = await TokenAuth.validate({}, token, {}) + test.equal(response.isValid, true) + test.deepEqual(response.credentials, { userId, scope: [ 'ONE', 'TWO', 'THREE', 'FOUR', 'FIVE' ] }) + test.end() }) validateTest.end() diff --git a/test/unit/admin/charges/handler.test.js b/test/unit/admin/charges/handler.test.js index 414faef83..c3ce52b31 100644 --- a/test/unit/admin/charges/handler.test.js +++ b/test/unit/admin/charges/handler.test.js @@ -7,6 +7,7 @@ const Config = require('../../../../src/lib/config') const Handler = require('../../../../src/admin/charges/handler') const Charge = require('../../../../src/domain/charge') const Sidecar = require('../../../../src/lib/sidecar') +const Errors = require('../../../../src/errors') function createCharge (name = 'charge') { return { @@ -47,7 +48,7 @@ Test('charges handler', handlerTest => { }) handlerTest.test('getAll should', getAllTest => { - getAllTest.test('get all charges and format list', test => { + getAllTest.test('get all charges and format list', async function (test) { const charge1 = createCharge('charge1') const charge2 = createCharge('charge2') @@ -55,52 +56,49 @@ Test('charges handler', handlerTest => { Charge.getAll.returns(P.resolve(charges)) - const reply = response => { - test.equal(response.length, 2) - const item1 = response[0] - test.equal(item1.name, charge1.name) - test.equal(item1.id, charge1.chargeId) - test.equal(item1.charge_type, charge1.chargeType) - test.equal(item1.rate_type, charge1.rateType) - test.equal(item1.rate, charge1.rate) - test.equal(item1.minimum, charge1.minimum) - test.equal(item1.maximum, charge1.maximum) - test.equal(item1.code, charge1.code) - test.equal(item1.is_active, charge1.isActive) - test.equal(item1.created, charge1.createdDate) - const item2 = response[1] - test.equal(item2.name, charge2.name) - test.equal(item2.id, charge2.chargeId) - test.equal(item2.charge_type, charge2.chargeType) - test.equal(item2.rate_type, charge2.rateType) - test.equal(item2.rate, charge2.rate) - test.equal(item2.minimum, charge2.minimum) - test.equal(item2.maximum, charge2.maximum) - test.equal(item2.code, charge2.code) - test.equal(item2.is_active, charge2.isActive) - test.equal(item2.created, charge2.createdDate) - test.end() - } - - Handler.getAll({}, reply) + const output = await Handler.getAll({}, {}) + test.equal(output.length, 2) + const item1 = output[0] + test.equal(item1.name, charge1.name) + test.equal(item1.id, charge1.chargeId) + test.equal(item1.charge_type, charge1.chargeType) + test.equal(item1.rate_type, charge1.rateType) + test.equal(item1.rate, charge1.rate) + test.equal(item1.minimum, charge1.minimum) + test.equal(item1.maximum, charge1.maximum) + test.equal(item1.code, charge1.code) + test.equal(item1.is_active, charge1.isActive) + test.equal(item1.created, charge1.createdDate) + const item2 = output[1] + test.equal(item2.name, charge2.name) + test.equal(item2.id, charge2.chargeId) + test.equal(item2.charge_type, charge2.chargeType) + test.equal(item2.rate_type, charge2.rateType) + test.equal(item2.rate, charge2.rate) + test.equal(item2.minimum, charge2.minimum) + test.equal(item2.maximum, charge2.maximum) + test.equal(item2.code, charge2.code) + test.equal(item2.is_active, charge2.isActive) + test.equal(item2.created, charge2.createdDate) + test.end() }) - getAllTest.test('reply with error if Charge services throws', test => { + getAllTest.test('reply with error if Charge services throws an error', async function (test) { const error = new Error() Charge.getAll.returns(P.reject(error)) - - const reply = (e) => { + try { + await Handler.getAll({}, {}) + } catch (e) { test.equal(e, error) test.end() } - Handler.getAll({}, reply) }) getAllTest.end() }) handlerTest.test('create should', createTest => { - createTest.test('create a charge', test => { + createTest.test('create a charge', async function (test) { const charge = createCharge() const payload = { @@ -119,32 +117,32 @@ Test('charges handler', handlerTest => { Charge.getByName.withArgs(payload.name).returns(P.resolve(null)) Charge.create.withArgs(payload).returns(P.resolve(charge)) - const reply = response => { - test.equal(response.name, charge.name) - test.equal(response.id, charge.chargeId) - test.equal(response.charge_type, charge.chargeType) - test.equal(response.rate_type, charge.rateType) - test.equal(response.rate, charge.rate) - test.equal(response.minimum, charge.minimum) - test.equal(response.maximum, charge.maximum) - test.equal(response.code, charge.code) - test.equal(response.is_active, charge.isActive) - test.equal(response.created, charge.createdDate) - test.ok(Sidecar.logRequest.calledWith({ payload })) - return { - code: (statusCode) => { - test.equal(statusCode, 201) - test.end() + const reply = { + response: (output) => { + test.equal(output.name, charge.name) + test.equal(output.id, charge.chargeId) + test.equal(output.charge_type, charge.chargeType) + test.equal(output.rate_type, charge.rateType) + test.equal(output.rate, charge.rate) + test.equal(output.minimum, charge.minimum) + test.equal(output.maximum, charge.maximum) + test.equal(output.code, charge.code) + test.equal(output.is_active, charge.isActive) + test.equal(output.created, charge.createdDate) + test.ok(Sidecar.logRequest.calledWith({payload})) + return { + code: (statusCode) => { + test.equal(statusCode, 201) + test.end() + } } } } - Handler.create({ payload }, reply) + await Handler.create({payload}, reply) }) - createTest.test('reply with error if Charge services throws', test => { - const error = new Error() - + createTest.test('reply with error if Charge services throws', async function (test) { const payload = { name: 'charge', chargeType: 'fee', @@ -159,16 +157,19 @@ Test('charges handler', handlerTest => { } Charge.getByName.withArgs(payload.name).returns(P.resolve(null)) + const error = new Error() + Charge.create.withArgs(payload).returns(P.reject(error)) - const reply = (e) => { + try { + await Handler.create({payload}, {}) + } catch (e) { test.equal(e, error) test.end() } - Handler.create({ payload }, reply) }) - createTest.test('reply with validation error if payer and payee match', test => { + createTest.test('reply with validation error if payer and payee match', async function (test) { const charge = createCharge('charge') charge.payer = 'ledger' charge.payee = 'ledger' @@ -189,15 +190,16 @@ Test('charges handler', handlerTest => { Charge.getByName.withArgs(payload.name).returns(P.resolve(null)) Charge.create.withArgs(payload).returns(P.resolve(charge)) - const reply = (e) => { + try { + await Handler.create({payload}, {}) + } catch (e) { test.equal(e.name, 'ValidationError') test.equal(e.payload.message, 'Payer and payee should be set to \'sender\', \'receiver\', or \'ledger\' and should not have the same value.') test.end() } - Handler.create({ payload }, reply) }) - createTest.test('reply with already exists error if a charge with the given name already exists', test => { + createTest.test('reply with already exists error if a charge with the given name already exists', async function (test) { const charge = createCharge('charge') charge.payer = 'sender' charge.payee = 'receiver' @@ -216,20 +218,20 @@ Test('charges handler', handlerTest => { } Charge.getByName.withArgs(payload.name).returns(P.resolve(charge)) - - const reply = (e) => { + try { + await Handler.create({payload}, {}) + } catch (e) { test.equal(e.name, 'RecordExistsError') test.equal(e.payload.message, 'The charge has already been created') test.end() } - Handler.create({ payload }, reply) }) createTest.end() }) handlerTest.test('update should', updateTest => { - updateTest.test('update a charge', test => { + updateTest.test('update a charge', async function (test) { const charge = { name: 'charge_b', charge_type: 'fee', @@ -244,6 +246,7 @@ Test('charges handler', handlerTest => { } const payload = { + name: 'charge_b', chargeType: 'fee', minimum: '10', maximum: '5', @@ -253,33 +256,71 @@ Test('charges handler', handlerTest => { const request = { payload: payload, - params: { name: 'name' } + params: {name: 'charge_b'} } Charge.getByName.withArgs(request.payload.name).returns(P.resolve(null)) Charge.getByName.withArgs(charge.name).returns(P.resolve(charge)) Charge.update.withArgs(request.params.name, payload).returns(P.resolve(charge)) - const reply = response => { - test.equal(response.name, charge.name) - test.equal(response.id, charge.chargeId) - test.equal(response.charge_type, charge.chargeType) - test.equal(response.rate_type, charge.rateType) - test.equal(response.rate, charge.rate) - test.equal(response.minimum, charge.minimum) - test.equal(response.maximum, charge.maximum) - test.equal(response.code, charge.code) - test.equal(response.is_active, charge.isActive) - test.equal(response.created, charge.createdDate) - test.ok(Sidecar.logRequest.calledWith(request)) - test.end() + const response = await Handler.update(request, {}) + test.equal(response.name, charge.name) + test.equal(response.id, charge.chargeId) + test.equal(response.charge_type, charge.chargeType) + test.equal(response.rate_type, charge.rateType) + test.equal(response.rate, charge.rate) + test.equal(response.minimum, charge.minimum) + test.equal(response.maximum, charge.maximum) + test.equal(response.code, charge.code) + test.equal(response.is_active, charge.isActive) + test.equal(response.created, charge.createdDate) + test.ok(Sidecar.logRequest.calledWith(request)) + test.end() + }) + + updateTest.test('reply with error if Charge services throws Validation Error', async function (test) { + const error = new Errors.ValidationError('Charge names need to be the values') + + const charge = { + name: 'charge_b', + charge_type: 'fee', + rate_type: 'flat', + rate: '1.00', + minimum: '10', + maximum: '5', + code: '2', + is_active: false, + payer: 'ledger', + payee: 'sender' + } + + const payload = { + name: 'charge_b', + chargeType: 'fee', + minimum: '10', + maximum: '5', + code: '2', + is_active: false } - Handler.update(request, reply) + const request = { + payload: payload, + params: {name: 'charge_c'} + } + + Charge.getByName.withArgs(request.payload.name).returns(P.resolve(null)) + Charge.getByName.withArgs(charge.name).returns(P.resolve(charge)) + Charge.update.withArgs(request.params.name, payload).returns(P.resolve(charge)) + try { + await Handler.update(request, {}) + } catch (e) { + test.deepEqual(e, error) + test.end() + } }) - updateTest.test('reply with error if Charge services throws', test => { - const error = new Error() + updateTest.test('reply with error if Charge services throws Record Exists Error', async function (test) { + const error = new Errors.RecordExistsError('No record currently exists with the name charge') const payload = { name: 'charge', @@ -296,20 +337,51 @@ Test('charges handler', handlerTest => { const request = { payload: payload, - params: { name: 'name' } + params: {name: 'name'} } Charge.getByName.withArgs(payload.name).returns(P.resolve(null)) Charge.update.withArgs(request.params.name, payload).returns(P.reject(error)) + try { + await Handler.update(request, {}) + } catch (e) { + test.deepEqual(e, error) + test.end() + } + }) - const reply = (e) => { - test.equal(e, error) + updateTest.test('reply with error if Charge services throws Record Exists Error', async function (test) { + const error = new Errors.RecordExistsError('No record currently exists with the name name') + + const payload = { + name: 'name', + chargeType: 'fee', + rateType: 'flat', + rate: '1.00', + minimum: '1.00', + maximum: '100.00', + code: '001', + is_active: true, + payer: 'ledger', + payee: 'sender' + } + + const request = { + payload: payload, + params: {name: 'name'} + } + + Charge.getByName.withArgs(payload.name).returns(P.resolve(null)) + Charge.update.withArgs(request.params.name, payload).returns(P.reject(error)) + try { + await Handler.update(request, {}) + } catch (e) { + test.deepEqual(e, error) test.end() } - Handler.update(request, reply) }) - updateTest.test('reply with already exists error if a charge with the given name already exists', test => { + updateTest.test('reply with already exists error if a charge with the given name already exists', async function (test) { const charge = createCharge('charge') charge.payer = 'sender' charge.payee = 'receiver' @@ -329,17 +401,17 @@ Test('charges handler', handlerTest => { const request = { payload: payload, - params: { name: 'name' } + params: {name: 'name'} } Charge.getByName.withArgs(payload.name).returns(P.resolve(charge)) - - const reply = (e) => { + try { + await Handler.create(request, {}) + } catch (e) { test.equal(e.name, 'RecordExistsError') test.equal(e.payload.message, 'The charge has already been created') test.end() } - Handler.update(request, reply) }) updateTest.end() diff --git a/test/unit/admin/index.test.js b/test/unit/admin/index.test.js index a8fef64f3..405879d3b 100644 --- a/test/unit/admin/index.test.js +++ b/test/unit/admin/index.test.js @@ -26,7 +26,7 @@ Test('Admin index', indexTest => { }) indexTest.test('export should', exportTest => { - exportTest.test('initialize server', test => { + exportTest.test('initialize server', async function (test) { const server = { start: sandbox.stub(), info: { @@ -38,8 +38,6 @@ Test('Admin index', indexTest => { require('../../../src/admin/index').then(() => { test.ok(Setup.initialize.calledWith({ service: 'admin', port: Config.ADMIN_PORT, modules: [Auth, Routes] })) - test.ok(server.start.called) - test.ok(Logger.info.called) test.end() }) }) diff --git a/test/unit/admin/permissions/handler.test.js b/test/unit/admin/permissions/handler.test.js index ac10f581e..0cd16541a 100644 --- a/test/unit/admin/permissions/handler.test.js +++ b/test/unit/admin/permissions/handler.test.js @@ -6,13 +6,10 @@ const Handler = require('../../../../src/admin/permissions/handler') Test('Permissions handler', handlerTest => { handlerTest.test('getPermissions should', permissionsTest => { - permissionsTest.test('return defined permissions', test => { - const reply = (response) => { - test.deepEqual(response, Object.keys(Permissions).map(x => Permissions[x])) - test.end() - } - - Handler.getPermissions({}, reply) + permissionsTest.test('return defined permissions', async function (test) { + const response = Handler.getPermissions({}, {}) + test.deepEqual(response, Object.keys(Permissions).map(x => Permissions[x])) + test.end() }) permissionsTest.end() }) diff --git a/test/unit/admin/positions/handler.test.js b/test/unit/admin/positions/handler.test.js index ec23902c4..d15afe4a0 100644 --- a/test/unit/admin/positions/handler.test.js +++ b/test/unit/admin/positions/handler.test.js @@ -26,19 +26,21 @@ Test('positions handler', (handlerTest) => { }) handlerTest.test('calculateForAllAccounts should', (performTest) => { - performTest.test('return no positions if there are no settleable transfers', test => { + performTest.test('return no positions if there are no settleable transfers', async function (test) { PositionService.calculateForAllAccounts.returns(P.resolve([])) let expectedResponse = { positions: [] } - let reply = function (response) { - test.ok(PositionService.calculateForAllAccounts.calledOnce) - test.deepEqual(response, expectedResponse) - test.end() + let reply = { + response: (output) => { + test.ok(PositionService.calculateForAllAccounts.calledOnce) + test.deepEqual(output, expectedResponse) + test.end() + } } - Handler.calculateForAllAccounts('', reply) + await Handler.calculateForAllAccounts('', reply) }) - performTest.test('return expected positions if settleable transfers exist', test => { + performTest.test('return expected positions if settleable transfers exist', async function (test) { let positions = [{ account: `${hostname}/accounts/account1`, payments: '5', @@ -62,30 +64,34 @@ Test('positions handler', (handlerTest) => { PositionService.calculateForAllAccounts.returns(P.resolve(positions)) let expectedResponse = { positions: positions } - let reply = function (response) { - test.ok(PositionService.calculateForAllAccounts.calledOnce) - test.deepEqual(response, expectedResponse) - test.end() + let reply = { + response: (output) => { + test.ok(PositionService.calculateForAllAccounts.calledOnce) + test.deepEqual(output, expectedResponse) + test.end() + } } - Handler.calculateForAllAccounts('', reply) + await Handler.calculateForAllAccounts('', reply) }) performTest.end() }) handlerTest.test('calculateForAccount should', (performTest) => { - performTest.test('return positions if there are no settleable transfers or fees', test => { + performTest.test('return positions if there are no settleable transfers or fees', async function (test) { PositionService.calculateForAccount.returns(P.resolve({})) Account.getByName.returns(P.resolve({ accountId: 11 })) - let reply = function (response) { - test.ok(PositionService.calculateForAccount.calledOnce) - test.deepEqual(response, []) - test.end() + let reply = { + response: (output) => { + test.ok(PositionService.calculateForAccount.calledOnce) + test.deepEqual(output, []) + test.end() + } } - Handler.calculateForAccount({ params: { name: 'dfsp1' } }, reply) + await Handler.calculateForAccount({ params: { name: 'dfsp1' } }, reply) }) - performTest.test('return expected position if settleable transfers and fees exist', test => { + performTest.test('return expected position if settleable transfers and fees exist', async function (test) { let positions = { account: `${hostname}/accounts/dfsp1`, fees: { @@ -104,12 +110,14 @@ Test('positions handler', (handlerTest) => { PositionService.calculateForAccount.returns(P.resolve(positions)) Account.getByName.returns(P.resolve({ accountId: 11 })) - let reply = function (response) { - test.ok(PositionService.calculateForAccount.calledOnce) - test.deepEqual(response, positions) - test.end() + let reply = { + response: (output) => { + test.ok(PositionService.calculateForAccount.calledOnce) + test.deepEqual(output, positions) + test.end() + } } - Handler.calculateForAccount({ params: { name: 'dfsp1' } }, reply) + await Handler.calculateForAccount({ params: { name: 'dfsp1' } }, reply) }) performTest.end() }) diff --git a/test/unit/admin/roles/handler.test.js b/test/unit/admin/roles/handler.test.js index 8be7e34fa..d6f758008 100644 --- a/test/unit/admin/roles/handler.test.js +++ b/test/unit/admin/roles/handler.test.js @@ -24,57 +24,51 @@ Test('Security handler', handlerTest => { }) handlerTest.test('getRoles should', getRolesTest => { - getRolesTest.test('return roles from SecurityService', test => { - const roles = [{ name: 'role1' }, { name: 'role2' }] + getRolesTest.test('return roles from SecurityService', async function (test) { + const roles = [{name: 'role1'}, {name: 'role2'}] SecurityService.getAllRoles.returns(P.resolve(roles)) - const reply = (response) => { - test.deepEqual(response, roles) - test.end() - } - - Handler.getRoles({}, reply) + const response = await Handler.getRoles({}, {}) + test.deepEqual(response, roles) + test.end() }) - getRolesTest.test('return error if SecurityService getAllRoles throws', test => { + getRolesTest.test('return error if SecurityService getAllRoles throws', async function (test) { const error = new Error() SecurityService.getAllRoles.returns(P.reject(error)) - const reply = (response) => { - test.deepEqual(response, error) + try { + await Handler.getRoles({}, {}) + } catch (e) { + test.deepEqual(e, error) test.end() } - - Handler.getRoles({}, reply) }) getRolesTest.end() }) handlerTest.test('createRole should', createTest => { - createTest.test('create role in SecurityService', test => { - const role = { name: 'test', permissions: ['PERMISSION1', 'PERMISSION2'] } + createTest.test('create role in SecurityService', async function (test) { + const role = {name: 'test', permissions: ['PERMISSION1', 'PERMISSION2']} SecurityService.createRole.withArgs(role).returns(P.resolve(role)) const request = { payload: role } - const reply = (response) => { - test.deepEqual(response, role) - test.ok(Sidecar.logRequest.calledWith(request)) - test.end() - } - - Handler.createRole(request, reply) + const response = await Handler.createRole(request, {}) + test.deepEqual(response, role) + test.ok(Sidecar.logRequest.calledWith(request)) + test.end() }) createTest.end() }) handlerTest.test('updateRole should', updateTest => { - updateTest.test('update role in SecurityService', test => { + updateTest.test('update role in SecurityService', async function (test) { const roleId = Uuid() - const role = { roleId, name: 'test', permissions: ['PERMISSION1', 'PERMISSION2'] } - const payload = { name: 'test' } + const role = {roleId, name: 'test', permissions: ['PERMISSION1', 'PERMISSION2']} + const payload = {name: 'test'} SecurityService.updateRole.withArgs(roleId, payload).returns(P.resolve(role)) const request = { @@ -84,55 +78,54 @@ Test('Security handler', handlerTest => { } } - const reply = (response) => { - test.deepEqual(response, role) - test.ok(Sidecar.logRequest.calledWith(request)) - test.end() - } - - Handler.updateRole(request, reply) + const response = await Handler.updateRole(request, {}) + test.deepEqual(response, role) + test.ok(Sidecar.logRequest.calledWith(request)) + test.end() }) updateTest.end() }) handlerTest.test('deleteRole should', deleteTest => { - deleteTest.test('delete role in security service and return 204', test => { + deleteTest.test('delete role in security service and return 204', async function (test) { const roleId = Uuid() SecurityService.deleteRole.withArgs(roleId).returns(P.resolve()) const request = { - params: { id: roleId } + params: {id: roleId} } - const reply = response => { - test.notOk(response) - test.ok(Sidecar.logRequest.calledWith(request)) - return { - code: statusCode => { - test.equal(statusCode, 204) - test.end() + const reply = { + response: (output) => { + test.notOk(output) + test.ok(Sidecar.logRequest.calledWith(request)) + return { + code: statusCode => { + test.equal(statusCode, 204) + test.end() + } } } } - Handler.deleteRole(request, reply) + await Handler.deleteRole(request, reply) }) - deleteTest.test('reply with error if SecurityService throws', test => { + deleteTest.test('reply with error if SecurityService throws', async function (test) { const error = new Error() SecurityService.deleteRole.returns(P.reject(error)) - const reply = response => { - test.equal(response, error) - test.end() - } - const request = { - params: { id: Uuid() } + params: {id: Uuid()} } - Handler.deleteRole(request, reply) + try { + await Handler.deleteRole(request, {}) + } catch (e) { + test.equal(e, error) + test.end() + } }) deleteTest.end() diff --git a/test/unit/admin/root/routes.test.js b/test/unit/admin/root/routes.test.js index 1c9abba5e..c8be6d1f6 100644 --- a/test/unit/admin/root/routes.test.js +++ b/test/unit/admin/root/routes.test.js @@ -6,12 +6,14 @@ const Routes = require('../../../../src/admin/root/routes') Test('health handler should', healthTest => { healthTest.test('return status OK', test => { - const reply = (response) => { - test.deepEqual(response, { status: 'OK' }) - return { - code: (statusCode) => { - test.equal(statusCode, 200) - test.end() + const reply = { + response: (respObj) => { + test.deepEqual(respObj, { status: 'OK' }) + return { + code: (statusCode) => { + test.equal(statusCode, 200) + test.end() + } } } } @@ -19,12 +21,14 @@ Test('health handler should', healthTest => { Routes[0].handler({}, reply) }) healthTest.test('return status OK', test => { - const reply = (response) => { - test.deepEqual(response, { status: 'OK' }) - return { - code: (statusCode) => { - test.equal(statusCode, 200) - test.end() + const reply = { + response: (respObj) => { + test.deepEqual(respObj, { status: 'OK' }) + return { + code: (statusCode) => { + test.equal(statusCode, 200) + test.end() + } } } } diff --git a/test/unit/admin/route-config.test.js b/test/unit/admin/route-config.test.js index ef5b2f297..c88870537 100644 --- a/test/unit/admin/route-config.test.js +++ b/test/unit/admin/route-config.test.js @@ -33,14 +33,14 @@ Test('routeConfig', routeConfigTest => { configTest.test('populate tags', test => { const result = RouteConfig.config(tags) - test.deepEqual(result, { tags }) + test.deepEqual(result, {tags}) test.end() }) configTest.test('set description', test => { const description = 'some description' const result = RouteConfig.config(tags, description) - test.deepEqual(result, { tags, description }) + test.deepEqual(result, {tags, description}) test.end() }) @@ -53,7 +53,7 @@ Test('routeConfig', routeConfigTest => { configTest.test('set auth from permission', test => { const permission = Permissions.ACCOUNTS_LIST - const auth = { strategy: 'test', prop2: 'prop2' } + const auth = {strategy: 'test', prop2: 'prop2'} Auth.tokenAuth.withArgs(permission).returns(auth) const result = RouteConfig.config(tags, permission) @@ -61,11 +61,20 @@ Test('routeConfig', routeConfigTest => { test.end() }) - configTest.test('set validation', test => { - const validation = { params: { id: 'test' }, payload: { id: 'test' } } + configTest.test('set validation', async function (test) { + const validation = { + payload: {allow: 'application/json', failAction: 'error', output: 'data'}, + validate: {params: {id: 'test'}, payload: {id: 'test'}} + } + const validatedConfig = { + description: 'description', + payload: {allow: 'application/json', failAction: 'error', output: 'data'}, + tags: ['tag1', 'tag2'], + validate: {params: {id: 'test'}, payload: {id: 'test'}} + } const result = RouteConfig.config(tags, 'description', validation) - test.deepEqual(result.validate, validation) + test.deepEqual(result, validatedConfig) test.end() }) diff --git a/test/unit/admin/routes.test.js b/test/unit/admin/routes.test.js index 3c7a5fdad..b79d869e3 100644 --- a/test/unit/admin/routes.test.js +++ b/test/unit/admin/routes.test.js @@ -12,10 +12,9 @@ Test('admin routes', routesTest => { route: Sinon.spy() } const next = Sinon.spy() - Routes.register(server, {}, next) + Routes.plugin.register(server, {}, next) test.ok(server.route.called) - test.ok(next.called) test.end() }) registerTest.end() diff --git a/test/unit/admin/token/handler.test.js b/test/unit/admin/token/handler.test.js index 3d7a42a4b..752e36029 100644 --- a/test/unit/admin/token/handler.test.js +++ b/test/unit/admin/token/handler.test.js @@ -23,7 +23,7 @@ Test('token handler', handlerTest => { }) handlerTest.test('create should', createTest => { - createTest.test('create token from user key', test => { + createTest.test('create token from user key', async function (test) { const userKey = 'user-key' const account = { accountId: 1 } const token = 'generated-token' @@ -37,25 +37,22 @@ Test('token handler', handlerTest => { } } - const reply = (response) => { - test.deepEqual(response, { token }) - test.ok(Sidecar.logRequest.calledWith(request)) - test.end() - } - - Handler.create(request, reply) + const response = await Handler.create(request, {}) + test.deepEqual(response, token) + test.ok(Sidecar.logRequest.calledWith(request)) + test.end() }) - createTest.test('reply with error if thrown', test => { + createTest.test('reply with error if thrown', async function (test) { const error = new Error() JWT.create.returns(P.reject(error)) - const reply = (response) => { - test.equal(response, error) + try { + await Handler.create({ auth: { credentials: {} }, payload: { key: 'key' } }, {}) + } catch (e) { + test.equal(e, error) test.end() } - - Handler.create({ auth: { credentials: {} }, payload: { key: 'key' } }, reply) }) createTest.end() diff --git a/test/unit/admin/transfers/handler.test.js b/test/unit/admin/transfers/handler.test.js index aff9e6dd9..e34dc8d1b 100644 --- a/test/unit/admin/transfers/handler.test.js +++ b/test/unit/admin/transfers/handler.test.js @@ -29,7 +29,7 @@ Test('transfers handler', handlerTest => { }) handlerTest.test('getAll should', getAllTest => { - getAllTest.test('get all transfers and format list', test => { + getAllTest.test('get all transfers and format list', async function (test) { const transfer1 = { transferUuid: '90b5af57-256c-4b85-b2e1-cf6975c1a4b8', state: 'executed', @@ -44,29 +44,26 @@ Test('transfers handler', handlerTest => { Transfer.getAll.returns(P.resolve(transfers)) - const reply = response => { - test.equal(response.length, 2) - const item1 = response[0] - test.equal(item1.transferUuid, transfer1.transferUuid) - test.equal(item1.state, transfer1.state) - const item2 = response[1] - test.equal(item2.transferUuid, transfer2.transferUuid) - test.equal(item2.state, transfer2.state) - test.end() - } - - Handler.getAll({}, reply) + const response = await Handler.getAll({}, {}) + test.equal(response.length, 2) + const item1 = response[0] + test.equal(item1.transferUuid, transfer1.transferUuid) + test.equal(item1.state, transfer1.state) + const item2 = response[1] + test.equal(item2.transferUuid, transfer2.transferUuid) + test.equal(item2.state, transfer2.state) + test.end() }) - getAllTest.test('reply with error if Transfer service throws', test => { + getAllTest.test('reply with error if Transfer service throws', async function (test) { const error = new Error() Transfer.getAll.returns(P.reject(error)) - - const reply = (e) => { + try { + await Handler.getAll({}, {}) + } catch (e) { test.equal(e, error) test.end() } - Handler.getAll({}, reply) }) getAllTest.end() diff --git a/test/unit/admin/users/handler.test.js b/test/unit/admin/users/handler.test.js index 086776cce..00c4b6de1 100644 --- a/test/unit/admin/users/handler.test.js +++ b/test/unit/admin/users/handler.test.js @@ -23,8 +23,8 @@ Test('User handler', handlerTest => { test.end() }) - handlerTest.test('create should createUser in service', test => { - const user = { firstName: 'dave' } + handlerTest.test('create should createUser in service', async function (test) { + const user = {firstName: 'dave'} SecurityService.createUser.returns(P.resolve(user)) @@ -32,109 +32,88 @@ Test('User handler', handlerTest => { payload: user } - const reply = (response) => { - test.equal(response, user) - test.ok(Sidecar.logRequest.calledWith(request)) - test.end() - } - - Handler.create(request, reply) + const response = await Handler.create(request, {}) + test.equal(response, user) + test.ok(Sidecar.logRequest.calledWith(request)) + test.end() }) - handlerTest.test('getAll should get all users from service', test => { + handlerTest.test('getAll should get all users from service', async function (test) { const users = [{}, {}] SecurityService.getAllUsers.returns(P.resolve(users)) - const reply = (response) => { - test.equal(response, users) - test.end() - } - - Handler.getAll({}, reply) + const response = await Handler.getAll({}, {}) + test.equal(response, users) + test.end() }) - handlerTest.test('getById should get user by id from service', test => { - const user = { firstName: 'Dave' } + handlerTest.test('getById should get user by id from service', async function (test) { + const user = {firstName: 'Dave'} const userId = Uuid() SecurityService.getUserById.withArgs(userId).returns(P.resolve(user)) - const reply = (response) => { - test.equal(response, user) - test.end() - } - - Handler.getById({ params: { id: userId } }, reply) + const response = await Handler.getById({params: {id: userId}}, {}) + test.equal(response, user) + test.end() }) - handlerTest.test('remove should deleteUser in service and return empty', test => { + handlerTest.test('remove should deleteUser in service and return empty', async function (test) { const userId = Uuid() SecurityService.deleteUser.returns(P.resolve({})) - const request = { params: { id: userId } } - const reply = (response) => { - test.deepEqual(response, {}) - test.ok(Sidecar.logRequest.calledWith(request)) - test.ok(SecurityService.deleteUser.calledWith(userId)) - test.end() - } + const request = {params: {id: userId}} - Handler.remove(request, reply) + const response = await Handler.remove(request, {}) + test.deepEqual(response, {}) + test.ok(Sidecar.logRequest.calledWith(request)) + test.ok(SecurityService.deleteUser.calledWith(userId)) + test.end() }) - handlerTest.test('update should update user by id', test => { + handlerTest.test('update should update user by id', async function (test) { const userId = Uuid() - const details = { firstName: 'Dave' } - const user = { lastName: 'Superuser' } + const details = {firstName: 'Dave'} + const user = {lastName: 'Superuser'} SecurityService.updateUser.returns(P.resolve(user)) const request = { - params: { id: userId }, + params: {id: userId}, payload: details } - const reply = (response) => { - test.deepEqual(response, user) - test.ok(Sidecar.logRequest.calledWith(request)) - test.ok(SecurityService.updateUser.calledWith(userId, details)) - test.end() - } - - Handler.update(request, reply) + const response = await Handler.update(request, {}) + test.deepEqual(response, user) + test.ok(Sidecar.logRequest.calledWith(request)) + test.ok(SecurityService.updateUser.calledWith(userId, details)) + test.end() }) - handlerTest.test('getRoles should return roles from service', test => { + handlerTest.test('getRoles should return roles from service', async function (test) { const roles = [{}, {}] const userId = Uuid() SecurityService.getUserRoles.withArgs(userId).returns(P.resolve(roles)) - const reply = (response) => { - test.deepEqual(response, roles) - test.end() - } - - Handler.getRoles({ params: { id: userId } }, reply) + const response = await Handler.getRoles({params: {id: userId}}, {}) + test.deepEqual(response, roles) + test.end() }) - handlerTest.test('updateRoles should update roles in service', test => { + handlerTest.test('updateRoles should update roles in service', async function (test) { const updatedRoles = [{}, {}] const roleIds = [Uuid(), Uuid()] const userId = Uuid() SecurityService.updateUserRoles.withArgs(userId, roleIds).returns(P.resolve(updatedRoles)) - - const reply = (response) => { - test.deepEqual(response, updatedRoles) - test.ok(Sidecar.logRequest.calledWith(request)) - test.end() - } - const request = { - params: { id: userId }, + params: {id: userId}, payload: roleIds } - Handler.updateRoles(request, reply) + const response = await Handler.updateRoles(request, {}) + test.deepEqual(response, updatedRoles) + test.ok(Sidecar.logRequest.calledWith(request)) + test.end() }) handlerTest.end() diff --git a/test/unit/admin/webhooks/handler.test.js b/test/unit/admin/webhooks/handler.test.js index b278a5baf..a735e4e56 100644 --- a/test/unit/admin/webhooks/handler.test.js +++ b/test/unit/admin/webhooks/handler.test.js @@ -16,7 +16,7 @@ function createRequest (id, payload) { let requestPayload = payload || {} return { payload: requestPayload, - params: { id: requestId }, + params: {id: requestId}, server: { log: function () { } } @@ -67,39 +67,34 @@ Test('Handler Test', handlerTest => { }) handlerTest.test('rejectExpired should', rejectExpiredTest => { - rejectExpiredTest.test('return rejected transfer ids', test => { + rejectExpiredTest.test('return rejected transfer ids', async function (test) { let transferIds = [Uuid(), Uuid(), Uuid()] TransferService.rejectExpired.returns(P.resolve(transferIds)) - - let reply = response => { - test.equal(response, transferIds) - test.ok(Sidecar.logRequest.calledWith({})) - test.end() - } - - Handler.rejectExpired({}, reply) + const response = await Handler.rejectExpired({}, {}) + test.equal(response, transferIds) + test.ok(Sidecar.logRequest.calledWith({})) + test.end() }) - rejectExpiredTest.test('return error if rejectExpired fails', test => { + rejectExpiredTest.test('return error if rejectExpired fails', async function (test) { let error = new Error() TransferService.rejectExpired.returns(P.reject(error)) - - let reply = response => { - test.equal(response, error) + try { + await Handler.rejectExpired(createRequest(), {}) + } catch (e) { + test.equal(e, error) test.end() } - - Handler.rejectExpired(createRequest(), reply) }) rejectExpiredTest.end() }) handlerTest.test('settle should', settleTest => { - settleTest.test('return settled transfer and fee ids', test => { - const account1 = { accountNumber: '1234', routingNumber: '5678', name: 'Bill' } - const account2 = { accountNumber: '2345', routingNumber: '6789', name: 'Will' } - const account3 = { accountNumber: '3456', routingNumber: '7890', name: 'Rob' } + settleTest.test('return settled transfer and fee ids', async function (test) { + const account1 = {accountNumber: '1234', routingNumber: '5678', name: 'Bill'} + const account2 = {accountNumber: '2345', routingNumber: '6789', name: 'Will'} + const account3 = {accountNumber: '3456', routingNumber: '7890', name: 'Rob'} let transfers = [ generateTransfer(account1, account2, '10.00'), generateTransfer(account1, account2, '10.00'), @@ -150,55 +145,45 @@ Test('Handler Test', handlerTest => { routing_number: account1.routingNumber } }] - - let reply = () => { - test.deepEqual(settledTransfers, settledFees) - test.ok(Sidecar.logRequest.calledWith({})) - test.end() - } - - Handler.settle({}, reply) + await Handler.settle({}, {}) + test.deepEqual(settledTransfers, settledFees) + test.ok(Sidecar.logRequest.calledWith({})) + test.end() }) - settleTest.test('return error if settlement failed', test => { + settleTest.test('return error if settlement failed', async function (test) { let error = new Error() TransferService.settle.returns(P.reject(error)) - - let reply = response => { - test.equal(response, error) + try { + await Handler.settle(createRequest(), {}) + } catch (e) { + test.equal(e, error) test.end() } - - Handler.settle(createRequest(), reply) }) settleTest.end() }) handlerTest.test('removeExpired should', removeExpiredTest => { - removeExpiredTest.test('return expired tokens', test => { + removeExpiredTest.test('return expired tokens', async function (test) { let tokenIds = [Uuid(), Uuid(), Uuid()] TokenService.removeExpired.returns(P.resolve(tokenIds)) - - let reply = response => { - test.equal(response, tokenIds) - test.ok(Sidecar.logRequest.calledWith({})) - test.end() - } - - Handler.rejectExpiredTokens({}, reply) + const response = await Handler.rejectExpiredTokens({}, {}) + test.equal(response, tokenIds) + test.ok(Sidecar.logRequest.calledWith({})) + test.end() }) - removeExpiredTest.test('return error if removeExpired fails', test => { + removeExpiredTest.test('return error if removeExpired fails', async function (test) { let error = new Error() TokenService.removeExpired.returns(P.reject(error)) - - let reply = response => { - test.equal(response, error) + try { + await Handler.rejectExpiredTokens(createRequest(), {}) + } catch (e) { + test.equal(e, error) test.end() } - - Handler.rejectExpiredTokens(createRequest(), reply) }) removeExpiredTest.end() diff --git a/test/unit/api/accounts/handler.test.js b/test/unit/api/accounts/handler.test.js index 071984b2e..71aab5820 100644 --- a/test/unit/api/accounts/handler.test.js +++ b/test/unit/api/accounts/handler.test.js @@ -12,8 +12,8 @@ const Sidecar = require('../../../../src/lib/sidecar') const createGet = (name, credentials = null) => { return { - params: { name: name || 'name' }, - server: { log: () => { } }, + params: {name: name || 'name'}, + server: {log: () => { }}, auth: { credentials } @@ -22,8 +22,8 @@ const createGet = (name, credentials = null) => { const createPut = (name, credentials = null) => { return { - params: { name: name || 'name' }, - server: { log: () => { } }, + params: {name: name || 'name'}, + server: {log: () => { }}, auth: { credentials } @@ -33,12 +33,12 @@ const createPut = (name, credentials = null) => { const createPost = payload => { return { payload: payload || {}, - server: { log: () => { } } + server: {log: () => { }} } } const createAccount = (name, accountId = 1, isDisabled = true) => { - return { accountId: 1, name: name, createdDate: new Date(), isDisabled: isDisabled } + return {accountId: 1, name: name, createdDate: new Date(), isDisabled: isDisabled} } Test('accounts handler', handlerTest => { @@ -76,180 +76,158 @@ Test('accounts handler', handlerTest => { } handlerTest.test('getByName should', getByNameTest => { - getByNameTest.test('get account by name and set balance to position', test => { + getByNameTest.test('get account by name and set balance to position', async function (test) { const name = 'somename' const account = createAccount(name) Account.getByName.returns(P.resolve(account)) PositionService.calculateForAccount.withArgs(account).returns(P.resolve(buildPosition(account.name, '50', '0', '-50'))) - const request = createGet(name, { name }) - const reply = response => { - test.equal(response.id, `${hostname}/accounts/${response.name}`) - test.equal(response.name, name) - test.equal(response.created, account.createdDate) - test.equal(response.balance, '-50') - test.equal(response.is_disabled, true) - test.equal(response.ledger, hostname) - test.notOk(response.hasOwnProperty('key')) - test.notOk(response.hasOwnProperty('secret')) - test.notOk(response.hasOwnProperty('credentials')) - test.ok(Sidecar.logRequest.calledWith(request)) - test.end() - } - - Handler.getByName(request, reply) + const request = createGet(name, {name}) + const response = await Handler.getByName(request, {}) + test.equal(response.id, `${hostname}/accounts/${response.name}`) + test.equal(response.name, name) + test.equal(response.created, account.createdDate) + test.equal(response.balance, '-50') + test.equal(response.is_disabled, true) + test.equal(response.ledger, hostname) + test.notOk(response.hasOwnProperty('key')) + test.notOk(response.hasOwnProperty('secret')) + test.notOk(response.hasOwnProperty('credentials')) + test.ok(Sidecar.logRequest.calledWith(request)) + test.end() }) - getByNameTest.test('get account by name and set balance to position if admin', test => { + getByNameTest.test('get account by name and set balance to position if admin', async function (test) { const name = 'somename' const account = createAccount(name) Account.getByName.returns(P.resolve(account)) PositionService.calculateForAccount.withArgs(account).returns(P.resolve(buildPosition(account.name, '50', '0', '-50'))) - - const reply = response => { - test.equal(response.id, `${hostname}/accounts/${response.name}`) - test.equal(response.name, name) - test.equal(response.created, account.createdDate) - test.equal(response.balance, '-50') - test.equal(response.is_disabled, true) - test.equal(response.ledger, hostname) - test.notOk(response.hasOwnProperty('key')) - test.notOk(response.hasOwnProperty('secret')) - test.notOk(response.hasOwnProperty('credentials')) - test.end() - } - - Handler.getByName(createGet(name, { name: 'not' + name, is_admin: true }), reply) + const response = await Handler.getByName(createGet(name, {name: 'not' + name, is_admin: true}), {}) + test.equal(response.id, `${hostname}/accounts/${response.name}`) + test.equal(response.name, name) + test.equal(response.created, account.createdDate) + test.equal(response.balance, '-50') + test.equal(response.is_disabled, true) + test.equal(response.ledger, hostname) + test.notOk(response.hasOwnProperty('key')) + test.notOk(response.hasOwnProperty('secret')) + test.notOk(response.hasOwnProperty('credentials')) + test.end() }) - getByNameTest.test('get account by name and set balance to position and default is_disabled to false', test => { + getByNameTest.test('get account by name and set balance to position and default is_disabled to false', async function (test) { const name = 'somename' - const account = { accountId: 1, name: name, createdDate: new Date() } + const account = {accountId: 1, name: name, createdDate: new Date()} Account.getByName.returns(P.resolve(account)) PositionService.calculateForAccount.withArgs(account).returns(P.resolve(buildPosition(account.name, '50', '0', '-50'))) - - const reply = response => { - test.equal(response.id, `${hostname}/accounts/${response.name}`) - test.equal(response.is_disabled, false) - test.end() - } - - Handler.getByName(createGet(name, { name }), reply) + const response = await Handler.getByName(createGet(name, {name}), {}) + test.equal(response.id, `${hostname}/accounts/${response.name}`) + test.equal(response.is_disabled, false) + test.end() }) - getByNameTest.test('reply with limited fields if requesting account is not account', test => { + getByNameTest.test('reply with limited fields if requesting account is not account', async function (test) { const name = 'dfsp1' const account = createAccount(name) Account.getByName.returns(P.resolve(account)) - - const reply = response => { - test.equal(response.id, `${hostname}/accounts/${response.name}`) - test.equal(response.name, name) - test.equal(response.ledger, hostname) - test.equal(PositionService.calculateForAccount.callCount, 0) - test.notOk(response.hasOwnProperty('created')) - test.notOk(response.hasOwnProperty('balance')) - test.notOk(response.hasOwnProperty('is_disabled')) - test.notOk(response.hasOwnProperty('key')) - test.notOk(response.hasOwnProperty('secret')) - test.notOk(response.hasOwnProperty('credentials')) - test.end() - } - - Handler.getByName(createGet(name), reply) + const response = await Handler.getByName(createGet(name), {}) + test.equal(response.id, `${hostname}/accounts/${response.name}`) + test.equal(response.name, name) + test.equal(response.ledger, hostname) + test.equal(PositionService.calculateForAccount.callCount, 0) + test.notOk(response.hasOwnProperty('created')) + test.notOk(response.hasOwnProperty('balance')) + test.notOk(response.hasOwnProperty('is_disabled')) + test.notOk(response.hasOwnProperty('key')) + test.notOk(response.hasOwnProperty('secret')) + test.notOk(response.hasOwnProperty('credentials')) + test.end() }) - getByNameTest.test('reply with NotFoundError if account null', test => { + getByNameTest.test('reply with NotFoundError if account null', async function (test) { Account.getByName.returns(P.resolve(null)) - - const reply = response => { - test.ok(response instanceof Errors.NotFoundError) - test.equal(response.message, 'The requested resource could not be found.') + try { + await Handler.getByName(createGet(), {}) + } catch (e) { + test.ok(e instanceof Errors.NotFoundError) + test.equal(e.message, 'The requested resource could not be found.') test.end() } - - Handler.getByName(createGet(), reply) }) - getByNameTest.test('reply with error if Account throws error', test => { + getByNameTest.test('reply with error if Account throws error', async function (test) { const error = new Error() Account.getByName.returns(P.reject(error)) - - const reply = e => { + try { + await Handler.getByName(createGet(), {}) + } catch (e) { test.equal(e, error) test.end() } - - Handler.getByName(createGet(), reply) }) - getByNameTest.test('reply with NotFoundError if position null', test => { + getByNameTest.test('reply with NotFoundError if position null', async function (test) { const name = 'somename' const account = createAccount(name) Account.getByName.returns(P.resolve(account)) PositionService.calculateForAccount.withArgs(account).returns(P.resolve(null)) - - const reply = response => { - test.ok(response instanceof Errors.NotFoundError) - test.equal(response.message, 'The requested resource could not be found.') + try { + await Handler.getByName(createGet(name, {name}), {}) + } catch (e) { + test.ok(e instanceof Errors.NotFoundError) + test.equal(e.message, 'The requested resource could not be found.') test.end() } - - Handler.getByName(createGet(name, { name }), reply) }) - getByNameTest.test('reply with error if PositionService throws error', test => { + getByNameTest.test('reply with error if PositionService throws error', async function (test) { const name = 'somename' const account = createAccount(name) Account.getByName.returns(P.resolve(account)) const error = new Error() PositionService.calculateForAccount.withArgs(account).returns(P.reject(error)) - - const reply = e => { + try { + await Handler.getByName(createGet(name, {name}), {}) + } catch (e) { test.equal(e, error) test.end() } - - Handler.getByName(createGet(name, { name }), reply) }) getByNameTest.end() }) handlerTest.test('updateUserCredentials should', updateUserCredentialsTest => { - updateUserCredentialsTest.test('update a users credentials', test => { + updateUserCredentialsTest.test('update a users credentials', async function (test) { const name = 'somename' const account = createAccount(name) Account.getByName.returns(P.resolve(account)) Account.updateUserCredentials.returns(P.resolve(account)) - const request = createPut(name, { name }) - request.payload = { password: '1234' } - const reply = response => { - test.equal(response.id, `${hostname}/accounts/${response.name}`) - test.equal(response.name, name) - test.equal(response.ledger, hostname) - test.notOk(response.hasOwnProperty('key')) - test.notOk(response.hasOwnProperty('secret')) - test.notOk(response.hasOwnProperty('credentials')) - test.ok(Sidecar.logRequest.calledWith(request)) - test.end() - } - - Handler.updateUserCredentials(request, reply) + const request = createPut(name, {name}) + request.payload = {password: '1234'} + const response = await Handler.updateUserCredentials(request, {}) + test.equal(response.id, `${hostname}/accounts/${response.name}`) + test.equal(response.name, name) + test.equal(response.ledger, hostname) + test.notOk(response.hasOwnProperty('key')) + test.notOk(response.hasOwnProperty('secret')) + test.notOk(response.hasOwnProperty('credentials')) + test.ok(Sidecar.logRequest.calledWith(request)) + test.end() }) - updateUserCredentialsTest.test('reply with unauthorized error if user credentials do not match', test => { + updateUserCredentialsTest.test('reply with unauthorized error if user credentials do not match', async function (test) { const name = 'somename' const account = createAccount(name) Account.getByName.returns(P.resolve(account)) - const request = createPut(name, { name: '1234' }) - request.payload = { password: '1234' } + const request = createPut(name, {name: '1234'}) + request.payload = {password: '1234'} try { - Handler.updateUserCredentials(request) + await Handler.updateUserCredentials(request) } catch (error) { test.assert(error instanceof Errors.UnauthorizedError) test.equal(error.message, 'Invalid attempt updating the password.') @@ -261,9 +239,9 @@ Test('accounts handler', handlerTest => { }) handlerTest.test('create should', createTest => { - createTest.test('return created account', assert => { - const payload = { name: 'dfsp1' } - const credentials = { key: 'key', secret: 'secret' } + createTest.test('return created account', async function (assert) { + const payload = {name: 'dfsp1'} + const credentials = {key: 'key', secret: 'secret'} const account = createAccount(payload.name) account.credentials = credentials @@ -271,148 +249,145 @@ Test('accounts handler', handlerTest => { Account.create.withArgs(payload).returns(P.resolve(account)) const request = createPost(payload) - const reply = response => { - assert.equal(response.id, `${hostname}/accounts/${account.name}`) - assert.equal(response.name, account.name) - assert.equal(response.created, account.createdDate) - assert.equal(response.balance, '0') - assert.equal(response.is_disabled, account.isDisabled) - assert.equal(response.ledger, hostname) - assert.equal(response.credentials.key, credentials.key) - assert.equal(response.credentials.secret, credentials.secret) - assert.ok(Sidecar.logRequest.calledWith(request)) - return { - code: (statusCode) => { - assert.equal(statusCode, 201) - assert.end() + const reply = { + response: (output) => { + assert.equal(output.id, `${hostname}/accounts/${account.name}`) + assert.equal(output.name, account.name) + assert.equal(output.created, account.createdDate) + assert.equal(output.balance, '0') + assert.equal(output.is_disabled, account.isDisabled) + assert.equal(output.ledger, hostname) + assert.equal(output.credentials.key, credentials.key) + assert.equal(output.credentials.secret, credentials.secret) + assert.ok(Sidecar.logRequest.calledWith(request)) + return { + code: (statusCode) => { + assert.equal(statusCode, 201) + assert.end() + } } } } - Handler.create(request, reply) + await Handler.create(request, reply) }) - createTest.test('return RecordExistsError if name already registered', test => { - const payload = { name: 'dfsp1' } - const account = { name: payload.name, createdDate: new Date() } + createTest.test('return RecordExistsError if name already registered', async function (test) { + const payload = {name: 'dfsp1'} + const account = {name: payload.name, createdDate: new Date()} Account.getByName.withArgs(payload.name).returns(P.resolve(account)) - - const reply = response => { - test.ok(response instanceof Errors.RecordExistsError) - test.equal(response.message, 'The account has already been registered') + try { + await Handler.create(createPost(payload), {}) + } catch (e) { + test.ok(e instanceof Errors.RecordExistsError) + test.equal(e.message, 'An error has occurred: The account has already been registered') test.end() } - - Handler.create(createPost(payload), reply) }) - createTest.test('return error if Account throws error on checking for existing account', test => { - const payload = { name: 'dfsp1' } + createTest.test('return error if Account throws error on checking for existing account', async function (test) { + const payload = {name: 'dfsp1'} const error = new Error() Account.getByName.returns(P.reject(error)) - - const reply = e => { + try { + await Handler.create(createPost(payload), {}) + } catch (e) { test.equal(e, error) test.end() } - - Handler.create(createPost(payload), reply) }) - createTest.test('return error if Account throws error on register', test => { - const payload = { name: 'dfsp1' } + createTest.test('return error if Account throws error on register', async function (test) { + const payload = {name: 'dfsp1'} const error = new Error() Account.getByName.returns(P.resolve(null)) Account.create.returns(P.reject(error)) - - const reply = e => { + try { + await Handler.create(createPost(payload), {}) + } catch (e) { test.equal(e, error) test.end() } - - Handler.create(createPost(payload), reply) }) createTest.end() }) handlerTest.test('update settlement should', updateSettlementTest => { - updateSettlementTest.test('return updated settlement', assert => { + updateSettlementTest.test('return updated settlement', async function (assert) { const name = 'dfsp1' - const payload = { account_number: '123', routing_number: '456' } - const credentials = { key: 'key', secret: 'secret' } + const payload = {account_number: '123', routing_number: '456'} + const credentials = {key: 'key', secret: 'secret'} const account = createAccount(name) account.credentials = credentials - const settlement = { accountName: account.name, accountNumber: payload.account_number, routingNumber: payload.routing_number } + const settlement = { + accountName: account.name, + accountNumber: payload.account_number, + routingNumber: payload.routing_number + } Account.getByName.withArgs(name).returns(P.resolve(account)) Account.updateAccountSettlement.withArgs(account, payload).returns(P.resolve(settlement)) - const request = createPut(name, { name }) + const request = createPut(name, {name}) request.payload = payload - const reply = response => { - assert.equal(response.account_id, `${hostname}/accounts/${account.name}`) - assert.equal(response.account_number, payload.account_number) - assert.equal(response.routing_number, payload.routing_number) - assert.ok(Sidecar.logRequest.calledWith(request)) - assert.end() - } - - Handler.updateAccountSettlement(request, reply) + const response = await Handler.updateAccountSettlement(request, {}) + assert.equal(response.account_id, `${hostname}/accounts/${account.name}`) + assert.equal(response.account_number, payload.account_number) + assert.equal(response.routing_number, payload.routing_number) + assert.ok(Sidecar.logRequest.calledWith(request)) + assert.end() }) - updateSettlementTest.test('return error if Account throws error on checking for existing account', test => { + updateSettlementTest.test('return error if Account throws error on checking for existing account', async function (test) { const name = 'dfsp1' - const payload = { account_number: '123', routing_number: '456' } - const credentials = { key: 'key', secret: 'secret' } + const payload = {account_number: '123', routing_number: '456'} + const credentials = {key: 'key', secret: 'secret'} const account = createAccount(name) account.credentials = credentials const error = new Error() - Account.getByName.returns(P.reject(error)) - - const reply = e => { + const request = createPut(name, {name}) + request.payload = payload + try { + await Handler.updateAccountSettlement(request, {}) + } catch (e) { test.equal(e, error) test.end() } - - const request = createPut(name, { name }) - request.payload = payload - Handler.updateAccountSettlement(request, reply) }) - updateSettlementTest.test('return error if Account throws error on updateAccountSettlement', test => { + updateSettlementTest.test('return error if Account throws error on updateAccountSettlement', async function (test) { const name = 'dfsp1' - const payload = { account_number: '123', routing_number: '456' } - const credentials = { key: 'key', secret: 'secret' } + const payload = {account_number: '123', routing_number: '456'} + const credentials = {key: 'key', secret: 'secret'} const account = createAccount(name) account.credentials = credentials const error = new Error() Account.getByName.returns(P.resolve(account)) Account.updateAccountSettlement.returns(P.reject(error)) - - const reply = e => { + const request = createPut(name, {name}) + request.payload = payload + try { + await Handler.updateAccountSettlement(request, {}) + } catch (e) { test.equal(e, error) test.end() } - - const request = createPut(name, { name }) - request.payload = payload - Handler.updateAccountSettlement(request, reply) }) - updateSettlementTest.test('return error if not authenticated', test => { + updateSettlementTest.test('return error if not authenticated', async function (test) { const name = 'dfsp1' - const payload = { account_number: '123', routing_number: '456' } + const payload = {account_number: '123', routing_number: '456'} - const request = createPut(name, { name: '1234' }) + const request = createPut(name, {name: '1234'}) request.payload = payload try { - Handler.updateAccountSettlement(request) + await Handler.updateAccountSettlement(request) } catch (error) { test.assert(error instanceof Errors.UnauthorizedError) test.equal(error.message, 'Invalid attempt updating the settlement.') diff --git a/test/unit/api/accounts/routes.test.js b/test/unit/api/accounts/routes.test.js index 68e87cede..26d27c0df 100644 --- a/test/unit/api/accounts/routes.test.js +++ b/test/unit/api/accounts/routes.test.js @@ -2,36 +2,31 @@ const Test = require('tape') const Base = require('../../base') +// const Logger = require('@mojaloop/central-services-shared').Logger -Test('return error if required field missing', assert => { - let req = Base.buildRequest({ url: '/accounts', method: 'POST', payload: {} }) - - Base.setup().then(server => { - server.inject(req, res => { - Base.assertBadRequestError(assert, res, [{ message: 'name is required', params: { key: 'name' } }, { message: 'password is required', params: { key: 'password' } }]) - assert.end() - }) - }) +Test('return error if required field missing', async function (assert) { + let req = Base.buildRequest({url: '/accounts', method: 'POST', payload: {}}) + const server = await Base.setup() + const res = await server.inject(req) + Base.assertBadRequestError(assert, res, 'child "name" fails because [name is required]. child "password" fails because [password is required]. child "emailAddress" fails because [emailAddress is required]') + await server.stop() + assert.end() }) -Test('return error if name is not a token', assert => { - let req = Base.buildRequest({ url: '/accounts', method: 'POST', payload: { name: 'this contains spaces' } }) - - Base.setup().then(server => { - server.inject(req, res => { - Base.assertBadRequestError(assert, res, [{ message: 'name must only contain alpha-numeric and underscore characters', params: { key: 'name', value: 'this contains spaces' } }, { message: 'password is required', params: { key: 'password' } }]) - assert.end() - }) - }) +Test('return error if name contains spaces', async function (assert) { + let req = Base.buildRequest({url: '/accounts', method: 'POST', payload: {name: 'this contains spaces'}}) + const server = await Base.setup() + const res = await server.inject(req) + Base.assertBadRequestError(assert, res, 'child "name" fails because [name must only contain alpha-numeric characters]. child "password" fails because [password is required]. child "emailAddress" fails because [emailAddress is required]') + await server.stop() + assert.end() }) -Test('return error if name is not a token', assert => { - let req = Base.buildRequest({ url: '/accounts/some%20bad%20name', method: 'GET' }) - - Base.setup().then(server => { - server.inject(req, res => { - Base.assertInvalidUriParameterError(assert, res, [{ message: 'name must only contain alpha-numeric and underscore characters', params: { key: 'name', value: 'some bad name' } }]) - assert.end() - }) - }) +Test('return error if name is not a token', async function (assert) { + let req = Base.buildRequest({url: '/accounts/some%20bad%20name', method: 'GET'}) + const server = await Base.setup() + const res = await server.inject(req) + Base.assertInvalidUriParameterError(assert, res, 'child "name" fails because [name must only contain alpha-numeric characters]') + await server.stop() + assert.end() }) diff --git a/test/unit/api/auth/account.test.js b/test/unit/api/auth/account.test.js index 035ea7f33..b897aac41 100644 --- a/test/unit/api/auth/account.test.js +++ b/test/unit/api/auth/account.test.js @@ -28,68 +28,51 @@ Test('account auth module', authTest => { test.end() }) - authTest.test('scheme should be basic', test => { - test.equal(AccountAuth.scheme, 'basic') + authTest.test('scheme should be simple', test => { + test.equal(AccountAuth.scheme, 'simple') test.end() }) authTest.test('validate should', validateTest => { - validateTest.test('return false if password missing', test => { - const cb = (err, isValid) => { - test.notOk(err) - test.equal(isValid, false) - test.end() - } - - AccountAuth.validate({}, 'username', '', cb) + validateTest.test('return false if password missing', async function (test) { + const response = await AccountAuth.validate({}, 'username', '', {}) + test.notOk(response.credentials) + test.equal(response.isValid, false) + test.end() }) - validateTest.test('return false if password cannot be verified', test => { + validateTest.test('return false if password cannot be verified', async function (test) { const name = 'name' const password = 'password' - AccountService.verify.withArgs(name, password).returns(P.reject({})) - - const cb = (err, isValid) => { - test.notOk(err) - test.equal(isValid, false) - test.end() - } - - AccountAuth.validate({}, name, password, cb) + AccountService.verify.withArgs(name, password).returns(P.reject({}).catch(() => { console.log('error occurred') })) + const response = await AccountAuth.validate({}, name, password, {}) + test.notOk(response.credentials) + test.equal(response.isValid, false) + test.end() }) - validateTest.test('return true if user is configured admin', test => { + validateTest.test('return true if user is configured admin', async function (test) { const adminName = 'admin' const adminSecret = 'admin' Config.ADMIN_KEY = adminName Config.ADMIN_SECRET = adminSecret - - const cb = (err, isValid, credentials) => { - test.notOk(err) - test.equal(isValid, true) - test.equal(credentials.is_admin, true) - test.equal(credentials.name, adminName) - test.equal(AccountService.verify.callCount, 0) - test.end() - } - - AccountAuth.validate({}, adminName, adminSecret, cb) + const response = await AccountAuth.validate({}, adminName, adminSecret, {}) + test.equal(response.isValid, true) + test.equal(response.credentials.is_admin, true) + test.equal(response.credentials.name, adminName) + test.equal(await AccountService.verify.callCount, 0) + test.end() }) - validateTest.test('return true and account if password verified', test => { + validateTest.test('return true and account if password verified', async function (test) { const name = 'name' const password = 'password' const account = { name, password } AccountService.verify.withArgs(name, password).returns(P.resolve(account)) - - const cb = (err, isValid, credentials) => { - test.notOk(err) - test.equal(isValid, true) - test.equal(credentials, account) - test.end() - } - - AccountAuth.validate({}, name, password, cb) + const response = await AccountAuth.validate({}, name, password, {}) + test.equal(response.isValid, true) + test.equal(response.credentials, account) + test.end() }) validateTest.end() diff --git a/test/unit/api/auth/index.test.js b/test/unit/api/auth/index.test.js index 8037c85a8..ed16d051a 100644 --- a/test/unit/api/auth/index.test.js +++ b/test/unit/api/auth/index.test.js @@ -10,27 +10,24 @@ const AuthModule = require('../../../../src/api/auth') Test('Auth module', authTest => { authTest.test('should be named "auth"', test => { - test.equal(AuthModule.register.attributes.name, 'auth') + test.equal(AuthModule.plugin.name, 'auth') test.end() }) authTest.test('register should', registerTest => { - registerTest.test('add AccountStrategy to server auth strategies', test => { + registerTest.test('add AccountStrategy to server auth strategies', async function (test) { const strategySpy = Sinon.spy() const server = { auth: { strategy: strategySpy } } - const next = () => { - test.ok(strategySpy.calledWith(AccountStrategy.name, AccountStrategy.scheme, Sinon.match({ validate: AccountStrategy.validate }))) - test.end() - } - - AuthModule.register(server, {}, next) + await AuthModule.plugin.register(server, {}) + test.ok(strategySpy.calledWith(AccountStrategy.scheme, 'basic', Sinon.match({ validate: AccountStrategy.validate }))) + test.end() }) - registerTest.test('add TokenStrategy to server auth strategies', test => { + registerTest.test('add TokenStrategy to server auth strategies', async function (test) { const strategySpy = Sinon.spy() const server = { auth: { @@ -38,12 +35,9 @@ Test('Auth module', authTest => { } } - const next = () => { - test.ok(strategySpy.calledWith(TokenStrategy.name, TokenStrategy.scheme, Sinon.match({ validate: TokenStrategy.validate }))) - test.end() - } - - AuthModule.register(server, {}, next) + AuthModule.plugin.register(server, {}) + test.ok(strategySpy.calledWith(TokenStrategy.scheme, TokenStrategy.name, Sinon.match({ validate: TokenStrategy.validate }))) + test.end() }) registerTest.end() @@ -53,21 +47,21 @@ Test('Auth module', authTest => { strategyTest.test('return token if ENABLE_TOKEN_AUTH true', test => { Config.ENABLE_TOKEN_AUTH = true Config.ENABLE_BASIC_AUTH = false - test.deepEqual(AuthModule.strategy(), { strategy: 'token', mode: 'required' }) + test.deepEqual(AuthModule.strategy(), { strategy: 'bearer-access-token', mode: 'required' }) test.end() }) strategyTest.test('return account if ENABLE_BASIC_AUTH true', test => { Config.ENABLE_TOKEN_AUTH = false Config.ENABLE_BASIC_AUTH = true - test.deepEqual(AuthModule.strategy(), { strategy: 'account', mode: 'required' }) + test.deepEqual(AuthModule.strategy(), { strategy: 'simple', mode: 'required' }) test.end() }) strategyTest.test('return account if ENABLE_TOKEN_AUTH and ENABLE_BASIC_AUTH true', test => { Config.ENABLE_TOKEN_AUTH = true Config.ENABLE_BASIC_AUTH = true - test.deepEqual(AuthModule.strategy(), { strategy: 'token', mode: 'required' }) + test.deepEqual(AuthModule.strategy(), { strategy: 'bearer-access-token', mode: 'required' }) test.end() }) @@ -81,7 +75,7 @@ Test('Auth module', authTest => { strategyTest.test('return try if optional', test => { Config.ENABLE_TOKEN_AUTH = false Config.ENABLE_BASIC_AUTH = true - test.deepEqual(AuthModule.strategy(true), { strategy: 'account', mode: 'try' }) + test.deepEqual(AuthModule.strategy(true), { strategy: 'simple', mode: 'try' }) test.end() }) diff --git a/test/unit/api/charges/handler.test.js b/test/unit/api/charges/handler.test.js index cd489e7ac..46e18ae05 100644 --- a/test/unit/api/charges/handler.test.js +++ b/test/unit/api/charges/handler.test.js @@ -27,7 +27,7 @@ Test('charges handler', handlerTest => { }) handlerTest.test('chargeQuote should', chargeQuoteTest => { - chargeQuoteTest.test('get all charge quotes and format charge quote list', test => { + chargeQuoteTest.test('get all charge quotes and format charge quote list', async function (test) { const chargeQuote1 = { name: 'charge1', charge_type: 'flat', @@ -43,34 +43,30 @@ Test('charges handler', handlerTest => { const charges = [chargeQuote1, chargeQuote2] Charge.quote.returns(P.resolve(charges)) - - const reply = response => { - test.equal(response.length, 2) - const item1 = response[0] - test.equal(item1.name, chargeQuote1.name) - test.equal(item1.charge_type, chargeQuote1.charge_type) - test.equal(item1.code, chargeQuote1.code) - test.equal(item1.amount, chargeQuote1.amount) - const item2 = response[1] - test.equal(item2.name, chargeQuote2.name) - test.equal(item2.charge_type, chargeQuote2.charge_type) - test.equal(item2.code, chargeQuote2.code) - test.equal(item2.amount, chargeQuote2.amount) - test.end() - } - - Handler.chargeQuote({}, reply) + const response = await Handler.chargeQuote({}, {}) + test.equal(response.length, 2) + const item1 = response[0] + test.equal(item1.name, chargeQuote1.name) + test.equal(item1.charge_type, chargeQuote1.charge_type) + test.equal(item1.code, chargeQuote1.code) + test.equal(item1.amount, chargeQuote1.amount) + const item2 = response[1] + test.equal(item2.name, chargeQuote2.name) + test.equal(item2.charge_type, chargeQuote2.charge_type) + test.equal(item2.code, chargeQuote2.code) + test.equal(item2.amount, chargeQuote2.amount) + test.end() }) - chargeQuoteTest.test('reply with error if Charge services throws', test => { + chargeQuoteTest.test('reply with error if Charge services throws', async function (test) { const error = new Error() Charge.quote.returns(P.reject(error)) - - const reply = (e) => { + try { + await Handler.chargeQuote({}, {}) + } catch (e) { test.equal(e, error) test.end() } - Handler.chargeQuote({}, reply) }) chargeQuoteTest.end() diff --git a/test/unit/api/charges/routes.test.js b/test/unit/api/charges/routes.test.js index 9a6e787fa..39ee5595b 100644 --- a/test/unit/api/charges/routes.test.js +++ b/test/unit/api/charges/routes.test.js @@ -3,14 +3,12 @@ const Test = require('tape') const Base = require('../../base') -Test('return error if required field missing', assert => { - let req = Base.buildRequest({ url: '/charges/quote', method: 'POST', payload: { } }) - - Base.setup().then(server => { - server.inject(req, res => { - Base.assertBadRequestError(assert, res, [{ message: 'amount is required', params: { key: 'amount' } }]) - assert.end() - }) - }) +Test('return error if required field missing', async function (assert) { + let req = Base.buildRequest({url: '/charges/quote', method: 'POST', payload: {}}) + const server = await Base.setup() + const res = await server.inject(req) + Base.assertBadRequestError(assert, res, 'child "amount" fails because [amount is required]') + await server.stop() + assert.end() }) diff --git a/test/unit/api/index.test.js b/test/unit/api/index.test.js index 8ae16e188..c56b17b85 100644 --- a/test/unit/api/index.test.js +++ b/test/unit/api/index.test.js @@ -30,7 +30,7 @@ Test('Api index', indexTest => { }) indexTest.test('export should', exportTest => { - exportTest.test('initialize server', test => { + exportTest.test('initialize server', async function (test) { const server = { start: sandbox.stub(), info: { @@ -39,15 +39,16 @@ Test('Api index', indexTest => { } server.start.returns(P.resolve({})) Setup.initialize.returns(P.resolve(server)) - Account.createLedgerAccount.returns(P.resolve({})) - - require('../../../src/api/index').then(() => { - test.ok(Setup.initialize.calledWith({ service: 'api', port: Config.PORT, modules: [Auth, Routes, Sockets, Worker], loadEventric: true, runMigrations: true })) - test.ok(Account.createLedgerAccount.calledWith(Config.LEDGER_ACCOUNT_NAME, Config.LEDGER_ACCOUNT_PASSWORD)) - test.ok(server.start.called) - test.ok(Logger.info.called) - test.end() - }) + + await require('../../../src/api/index') + test.ok(Setup.initialize.calledWith({ + service: 'api', + port: Config.PORT, + modules: [Auth, Routes, Sockets, Worker], + loadEventric: true, + runMigrations: true + })) + test.end() }) exportTest.end() }) diff --git a/test/unit/api/messages/handler.test.js b/test/unit/api/messages/handler.test.js index 69f8d846c..a1e370f9c 100644 --- a/test/unit/api/messages/handler.test.js +++ b/test/unit/api/messages/handler.test.js @@ -26,17 +26,18 @@ Test('Message Handler', handlerTest => { }) handlerTest.test('sendMessage should', sendTest => { - sendTest.test('respond with error if validator fails', test => { + sendTest.test('respond with error if validator fails', async function (test) { const error = new Error() Validator.validate.returns(P.reject(error)) - - Handler.sendMessage({}, (response) => { - test.equal(response, error) + try { + await Handler.sendMessage({}, {}) + } catch (e) { + test.equal(e, error) test.end() - }) + } }) - sendTest.test('send message', test => { + sendTest.test('send message', async function (test) { const message = { to: '', from: '', @@ -46,28 +47,33 @@ Test('Message Handler', handlerTest => { payload: message } Validator.validate.withArgs(request.payload).returns(P.resolve(message)) - Handler.sendMessage(request, () => { - test.ok(Events.sendMessage.calledWith(message)) - test.ok(Sidecar.logRequest.calledWith(request)) - return { - code: () => { - test.end() + const reply = { + response: () => { + test.ok(Events.sendMessage.calledWith(message)) + test.ok(Sidecar.logRequest.calledWith(request)) + return { + code: () => { + test.end() + } } } - }) + } + await Handler.sendMessage(request, reply) }) - sendTest.test('reply with 201', test => { - const reply = (response) => { - return { - code: (statusCode) => { - test.notOk(response) - test.equal(statusCode, 201) - test.end() + sendTest.test('reply with 201', async function (test) { + const reply = { + response: (output) => { + return { + code: (statusCode) => { + test.notOk(output) + test.equal(statusCode, 201) + test.end() + } } } } - Handler.sendMessage({}, reply) + await Handler.sendMessage({}, reply) }) sendTest.end() diff --git a/test/unit/api/messages/routes.test.js b/test/unit/api/messages/routes.test.js index 0840fbffa..c605f508d 100644 --- a/test/unit/api/messages/routes.test.js +++ b/test/unit/api/messages/routes.test.js @@ -11,7 +11,7 @@ const Sidecar = require('../../../../src/lib/sidecar') const toAccount = 'http://central-ledger/accounts/to' const fromAccount = 'http://central-ledger/accounts/from' -const createPayload = ({ ledger = Config.HOSTNAME, from = fromAccount, to = toAccount, data = {} }) => { +const createPayload = ({ledger = Config.HOSTNAME, from = fromAccount, to = toAccount, data = {}}) => { return { ledger, from, @@ -21,7 +21,7 @@ const createPayload = ({ ledger = Config.HOSTNAME, from = fromAccount, to = toAc } const buildRequest = (payload = {}) => { - return Base.buildRequest({ url: '/messages', method: 'POST', payload }) + return Base.buildRequest({url: '/messages', method: 'POST', payload}) } Test('POST /messages', postTest => { @@ -40,41 +40,31 @@ Test('POST /messages', postTest => { test.end() }) - postTest.test('return error if required fields are missing', test => { + postTest.test('return error if required fields are missing', async function (test) { let req = buildRequest({}) - - Base.setup().then(server => { - server.inject(req, res => { - Base.assertBadRequestError(test, res, [ - { message: 'ledger is required', params: { key: 'ledger' } }, - { message: 'from is required', params: { key: 'from' } }, - { message: 'to is required', params: { key: 'to' } }, - { message: 'data is required', params: { key: 'data' } } - ]) - test.end() - }) - }) + const server = await Base.setup() + const res = await server.inject(req) + Base.assertBadRequestError(test, res, 'child "ledger" fails because [ledger is required]. child "from" fails because [from is required]. child "to" fails because [to is required]. child "data" fails because [data is required]') + await server.stop() + test.end() }) - postTest.test('return error if ledger is not url', test => { - let req = buildRequest(createPayload({ ledger: 'test' })) - - Base.setup().then(server => { - server.inject(req, res => { - Base.assertBadRequestError(test, res, [{ message: 'ledger must be a valid uri', params: { key: 'ledger', value: 'test' } }]) - test.end() - }) - }) + postTest.test('return error if ledger is not url', async function (test) { + let req = buildRequest(createPayload({ledger: 'test'})) + const server = await Base.setup() + const res = await server.inject(req) + Base.assertBadRequestError(test, res, 'child "ledger" fails because [ledger must be a valid uri]') + await server.stop() + test.end() }) - postTest.test('return error if ledger is not valid', test => { - let req = buildRequest(createPayload({ ledger: 'http://not-valid' })) - Base.setup().then(server => { - server.inject(req, res => { - Base.assertBadRequestError(test, res, [{ message: 'ledger is not valid for this ledger', params: { key: 'ledger', value: 'http://not-valid' } }]) - test.end() - }) - }) + postTest.test('return error if ledger is not valid', async function (test) { + let req = buildRequest(createPayload({ledger: 'http://not-valid'})) + const server = await Base.setup() + const res = await server.inject(req) + Base.assertInvalidBodyError(test, res, 'Body does not match schema') + await server.stop() + test.end() }) postTest.end() diff --git a/test/unit/api/metadata/handler.test.js b/test/unit/api/metadata/handler.test.js index ed9972aaa..feef35fb5 100644 --- a/test/unit/api/metadata/handler.test.js +++ b/test/unit/api/metadata/handler.test.js @@ -8,11 +8,9 @@ const apiTags = ['api'] function createRequest (routes) { return { server: { - table: () => [ - { - table: routes || [] - } - ] + table: () => { + return routes || [] + } } } } @@ -40,13 +38,15 @@ Test('metadata handler', (handlerTest) => { }) handlerTest.test('health should', (healthTest) => { - healthTest.test('return status ok', (assert) => { - let reply = function (response) { - assert.equal(response.status, 'OK') - return { - code: (statusCode) => { - assert.equal(statusCode, 200) - assert.end() + healthTest.test('return status ok', async function (assert) { + let reply = { + response: (response) => { + assert.equal(response.status, 'OK') + return { + code: (statusCode) => { + assert.equal(statusCode, 200) + assert.end() + } } } } @@ -57,20 +57,21 @@ Test('metadata handler', (handlerTest) => { }) handlerTest.test('metadata should', function (metadataTest) { - metadataTest.test('return 200 httpStatus', (t) => { - let reply = (response) => { - return { - code: statusCode => { - t.equal(statusCode, 200) - t.end() + metadataTest.test('return 200 httpStatus', async function (t) { + let reply = { + response: () => { + return { + code: statusCode => { + t.equal(statusCode, 200) + t.end() + } } } } - - Handler.metadata(createRequest(), reply) + await Handler.metadata(createRequest(), reply) }) - metadataTest.test('return default values', t => { + metadataTest.test('return default values', async function (t) { let host = 'example-hostname' let hostName = `http://${host}` Config.HOSTNAME = hostName @@ -80,15 +81,17 @@ Test('metadata handler', (handlerTest) => { Config.AMOUNT.SCALE = scale Config.AMOUNT.PRECISION = precision - let reply = response => { - t.equal(response.currency_code, null) - t.equal(response.currency_symbol, null) - t.equal(response.ledger, hostName) - t.equal(response.precision, precision) - t.equal(response.scale, scale) - t.equal(response.urls['websocket'], `ws://${host}/websocket`) - t.deepEqual(response.connectors, []) - return { code: statusCode => { t.end() } } + let reply = { + response: (response) => { + t.equal(response.currency_code, null) + t.equal(response.currency_symbol, null) + t.equal(response.ledger, hostName) + t.equal(response.precision, precision) + t.equal(response.scale, scale) + t.equal(response.urls['websocket'], `ws://${host}/websocket`) + t.deepEqual(response.connectors, []) + return {code: statusCode => { t.end() }} + } } Handler.metadata(createRequest(), reply) @@ -98,44 +101,48 @@ Test('metadata handler', (handlerTest) => { let hostName = 'some-host-name' Config.HOSTNAME = hostName let request = createRequest([ - { settings: { id: 'first_route', tags: apiTags }, path: '/first' } + {settings: {id: 'first_route', tags: apiTags}, path: '/first'} ]) - let reply = response => { - t.equal(response.urls['first_route'], `${hostName}/first`) - return { code: statusCode => { t.end() } } + let reply = { + response: (response) => { + t.equal(response.urls['first_route'], `${hostName}/first`) + return {code: statusCode => { t.end() }} + } } - Handler.metadata(request, reply) }) metadataTest.test('only return urls with id', t => { let request = createRequest([ - { settings: { tags: apiTags }, path: '/' }, - { settings: { id: 'expected', tags: apiTags }, path: '/expected' } + {settings: {tags: apiTags}, path: '/'}, + {settings: {id: 'expected', tags: apiTags}, path: '/expected'} ]) - let reply = response => { - t.equal(Object.keys(response.urls).length, 2) - t.equal(response.urls['expected'], '/expected') - return { code: statusCode => { t.end() } } + let reply = { + response: (response) => { + t.equal(Object.keys(response.urls).length, 2) + t.equal(response.urls['expected'], '/expected') + return {code: statusCode => { t.end() }} + } } - Handler.metadata(request, reply) }) metadataTest.test('only return urls tagged with api', t => { let request = createRequest([ - { settings: { id: 'nottagged' }, path: '/nottagged' }, - { settings: { id: 'tagged', tags: apiTags }, path: '/tagged' }, - { settings: { id: 'wrongtag', tags: ['notapi'] }, path: '/wrongtag' } + {settings: {id: 'nottagged'}, path: '/nottagged'}, + {settings: {id: 'tagged', tags: apiTags}, path: '/tagged'}, + {settings: {id: 'wrongtag', tags: ['notapi']}, path: '/wrongtag'} ]) - let reply = response => { - t.equal(Object.keys(response.urls).length, 2) - t.equal(response.urls['tagged'], '/tagged') - t.notOk(response.urls['nottagged']) - return { code: statusCode => { t.end() } } + let reply = { + response: (response) => { + t.equal(Object.keys(response.urls).length, 2) + t.equal(response.urls['tagged'], '/tagged') + t.notOk(response.urls['nottagged']) + return {code: statusCode => { t.end() }} + } } Handler.metadata(request, reply) @@ -143,14 +150,16 @@ Test('metadata handler', (handlerTest) => { metadataTest.test('format url parameters with colons', t => { let request = createRequest([ - { settings: { id: 'path', tags: apiTags }, path: '/somepath/{id}' }, - { settings: { id: 'manyargs', tags: apiTags }, path: '/somepath/{id}/{path*}/{test2}/' } + {settings: {id: 'path', tags: apiTags}, path: '/somepath/{id}'}, + {settings: {id: 'manyargs', tags: apiTags}, path: '/somepath/{id}/{path*}/{test2}/'} ]) - let reply = response => { - t.equal(response.urls['path'], '/somepath/:id') - t.equal(response.urls['manyargs'], '/somepath/:id/:path*/:test2/') - return { code: statusCode => { t.end() } } + let reply = { + response: (response) => { + t.equal(response.urls['path'], '/somepath/:id') + t.equal(response.urls['manyargs'], '/somepath/:id/:path*/:test2/') + return {code: statusCode => { t.end() }} + } } Handler.metadata(request, reply) diff --git a/test/unit/api/positions/handler.test.js b/test/unit/api/positions/handler.test.js index cfed52db0..23863a5f0 100644 --- a/test/unit/api/positions/handler.test.js +++ b/test/unit/api/positions/handler.test.js @@ -26,19 +26,21 @@ Test('positions handler', (handlerTest) => { }) handlerTest.test('calculateForAllAccounts should', (performTest) => { - performTest.test('return no positions if there are no settleable transfers', test => { + performTest.test('return no positions if there are no settleable transfers', async function (test) { PositionService.calculateForAllAccounts.returns(P.resolve([])) - let expectedResponse = { positions: [] } - let reply = function (response) { - test.ok(PositionService.calculateForAllAccounts.calledOnce) - test.deepEqual(response, expectedResponse) - test.end() + let expectedResponse = {positions: []} + let reply = { + response: (response) => { + test.ok(PositionService.calculateForAllAccounts.calledOnce) + test.deepEqual(response, expectedResponse) + test.end() + } } - Handler.calculateForAllAccounts('', reply) + await Handler.calculateForAllAccounts('', reply) }) - performTest.test('return expected positions if settleable transfers exist', test => { + performTest.test('return expected positions if settleable transfers exist', async function (test) { let positions = [{ account: `${hostname}/accounts/account1`, payments: '5', @@ -60,32 +62,31 @@ Test('positions handler', (handlerTest) => { ] PositionService.calculateForAllAccounts.returns(P.resolve(positions)) - let expectedResponse = { positions: positions } + let expectedResponse = {positions: positions} - let reply = function (response) { - test.ok(PositionService.calculateForAllAccounts.calledOnce) - test.deepEqual(response, expectedResponse) - test.end() + let reply = { + response: (response) => { + test.ok(PositionService.calculateForAllAccounts.calledOnce) + test.deepEqual(response, expectedResponse) + test.end() + } } - Handler.calculateForAllAccounts('', reply) + await Handler.calculateForAllAccounts('', reply) }) performTest.end() }) handlerTest.test('calculateForAccount should', (performTest) => { - performTest.test('return positions if there are no settleable transfers or fees', test => { + performTest.test('return positions if there are no settleable transfers or fees', async function (test) { PositionService.calculateForAccount.returns(P.resolve({})) - Account.getByName.returns(P.resolve({ accountId: 11 })) - - let reply = function (response) { - test.ok(PositionService.calculateForAccount.calledOnce) - test.deepEqual(response, []) - test.end() - } - Handler.calculateForAccount({ params: { name: 'dfsp1' } }, reply) + Account.getByName.returns(P.resolve({accountId: 11})) + const response = await Handler.calculateForAccount({params: {name: 'dfsp1'}}, {}) + test.ok(PositionService.calculateForAccount.calledOnce) + test.deepEqual(response, []) + test.end() }) - performTest.test('return expected position if settleable transfers and fees exist', test => { + performTest.test('return expected position if settleable transfers and fees exist', async function (test) { let positions = { account: `${hostname}/accounts/dfsp1`, fees: { @@ -102,14 +103,11 @@ Test('positions handler', (handlerTest) => { } PositionService.calculateForAccount.returns(P.resolve(positions)) - Account.getByName.returns(P.resolve({ accountId: 11 })) - - let reply = function (response) { - test.ok(PositionService.calculateForAccount.calledOnce) - test.deepEqual(response, positions) - test.end() - } - Handler.calculateForAccount({ params: { name: 'dfsp1' } }, reply) + Account.getByName.returns(P.resolve({accountId: 11})) + const response = await Handler.calculateForAccount({params: {name: 'dfsp1'}}, {}) + test.ok(PositionService.calculateForAccount.calledOnce) + test.deepEqual(response, positions) + test.end() }) performTest.end() }) diff --git a/test/unit/api/sockets/index.test.js b/test/unit/api/sockets/index.test.js index cb630bec8..36f4ad117 100644 --- a/test/unit/api/sockets/index.test.js +++ b/test/unit/api/sockets/index.test.js @@ -56,43 +56,40 @@ Test('Socket Module', moduleTest => { }) moduleTest.test('register should', registerTest => { - registerTest.test('create new instance of WS.Server', test => { + registerTest.test('create new instance of WS.Server', async function (test) { const listener = {} WS.Server.withArgs(Sinon.match({ server: listener })).returns(new EventEmitter()) - Index.register(mockServer(listener), {}, () => { - test.ok(WS.Server.called) - test.end() - }) + Index.plugin.register(mockServer(listener), {}, {}) + test.ok(WS.Server.called) + test.end() }) - registerTest.test('listen for WS connection events', test => { + registerTest.test('listen for WS connection events', async function (test) { const wsServer = { on: sandbox.stub() } WS.Server.returns(wsServer) - Index.register(mockServer(), {}, () => { - test.ok(wsServer.on.calledWith('connection')) - test.end() - }) + Index.plugin.register(mockServer(), {}, {}) + test.ok(wsServer.on.calledWith('connection')) + test.end() }) - registerTest.test('Wire up event handlers', test => { + registerTest.test('Wire up event handlers', async function (test) { WS.Server.returns(new EventEmitter()) - Index.register(mockServer(), {}, () => { - test.ok(Events.onTransferExecuted.called) - test.ok(Events.onTransferPrepared.called) - test.end() - }) + Index.plugin.register(mockServer(), {}, {}) + test.ok(Events.onTransferExecuted.called) + test.ok(Events.onTransferPrepared.called) + test.end() }) registerTest.end() }) moduleTest.test('on socket connection should', connectionTest => { - connectionTest.test('initialize WebSocket if url is /websocket', test => { + connectionTest.test('initialize WebSocket if url is /websocket', async function (test) { const ws = { upgradeReq: { url: '/websocket' @@ -100,16 +97,14 @@ Test('Socket Module', moduleTest => { } const wsServer = new EventEmitter() WS.Server.returns(wsServer) - - Index.register(mockServer(), {}, () => { - wsServer.emit('connection', ws) - test.ok(WebSocket.initialize.calledWith(ws, Sinon.match(socketManager))) - test.notOk(AccountTransfers.initialize.called) - test.end() - }) + Index.plugin.register(mockServer(), {}, {}) + wsServer.emit('connection', ws) + test.ok(WebSocket.initialize.calledWith(ws, Sinon.match(socketManager))) + test.notOk(AccountTransfers.initialize.called) + test.end() }) - connectionTest.test('initialize AccountTransfers if url is not /websocket', test => { + connectionTest.test('initialize AccountTransfers if url is not /websocket', async function (test) { const url = '/notwebsocket' const ws = { upgradeReq: { @@ -119,33 +114,31 @@ Test('Socket Module', moduleTest => { const wsServer = new EventEmitter() WS.Server.returns(wsServer) - Index.register(mockServer(), {}, () => { - wsServer.emit('connection', ws) - test.ok(AccountTransfers.initialize.calledWith(ws, url, Sinon.match(socketManager))) - test.notOk(WebSocket.initialize.called) - test.end() - }) + Index.plugin.register(mockServer(), {}, {}) + wsServer.emit('connection', ws) + test.ok(AccountTransfers.initialize.calledWith(ws, url, Sinon.match(socketManager))) + test.notOk(WebSocket.initialize.called) + test.end() }) connectionTest.end() }) - moduleTest.test('Events should', eventsTest => { + moduleTest.test('Events should', async function (eventsTest) { eventsTest.beforeEach(test => { WS.Server.returns(new EventEmitter()) test.end() }) - eventsTest.test('onTransferPrepared should do nothing if transfer credits and debits are empty', test => { + eventsTest.test('onTransferPrepared should do nothing if transfer credits and debits are empty', async function (test) { const message = { resource: {} } Events.onTransferPrepared.yields(message) - Index.register(mockServer(), {}, () => { - test.equal(socketManager.send.callCount, 0) - test.end() - }) + Index.plugin.register(mockServer(), {}, {}) + test.equal(socketManager.send.callCount, 0) + test.end() }) - eventsTest.test('onTransferPrepared should send message to socket manager for each account', test => { + eventsTest.test('onTransferPrepared should send message to socket manager for each account', async function (test) { const creditAccount = 'http://credit-account' const debitAccount = 'http://debit-account' const transfer = { @@ -158,28 +151,26 @@ Test('Socket Module', moduleTest => { } const message = { resource: transfer } Events.onTransferPrepared.yields(message) - Index.register(mockServer(), {}, () => { - const creditAccountSendArgs = socketManager.send.firstCall.args - test.equal(creditAccountSendArgs[0], creditAccount) - assertEvent(test, creditAccountSendArgs[1], 'transfer.create', transfer) - - const debitAccountSendArgs = socketManager.send.secondCall.args - test.equal(debitAccountSendArgs[0], debitAccount) - assertEvent(test, debitAccountSendArgs[1], 'transfer.create', transfer) - test.end() - }) + Index.plugin.register(mockServer(), {}, {}) + const creditAccountSendArgs = socketManager.send.firstCall.args + test.equal(creditAccountSendArgs[0], creditAccount) + assertEvent(test, creditAccountSendArgs[1], 'transfer.create', transfer) + + const debitAccountSendArgs = socketManager.send.secondCall.args + test.equal(debitAccountSendArgs[0], debitAccount) + assertEvent(test, debitAccountSendArgs[1], 'transfer.create', transfer) + test.end() }) - eventsTest.test('onTransferExecuted should do nothing if transfer credits and debits are empty', test => { + eventsTest.test('onTransferExecuted should do nothing if transfer credits and debits are empty', async function (test) { const message = { resource: {} } Events.onTransferExecuted.yields(message) - Index.register(mockServer(), {}, () => { - test.equal(socketManager.send.callCount, 0) - test.end() - }) + Index.plugin.register(mockServer(), {}, {}) + test.equal(socketManager.send.callCount, 0) + test.end() }) - eventsTest.test('onTransferExecuted should send message to socket manager for each account', test => { + eventsTest.test('onTransferExecuted should send message to socket manager for each account', async function (test) { const creditAccount = 'http://credit-account' const debitAccount = 'http://debit-account' const transfer = { @@ -193,28 +184,26 @@ Test('Socket Module', moduleTest => { const relatedResources = { execution_condition_fulfillment: 'aaaa' } const message = { resource: transfer, related_resources: relatedResources } Events.onTransferExecuted.yields(message) - Index.register(mockServer(), {}, () => { - const creditAccountSendArgs = socketManager.send.firstCall.args - test.equal(creditAccountSendArgs[0], creditAccount) - assertEvent(test, creditAccountSendArgs[1], 'transfer.update', transfer, relatedResources) - - const debitAccountSendArgs = socketManager.send.secondCall.args - test.equal(debitAccountSendArgs[0], debitAccount) - assertEvent(test, debitAccountSendArgs[1], 'transfer.update', transfer, relatedResources) - test.end() - }) + Index.plugin.register(mockServer(), {}, {}) + const creditAccountSendArgs = socketManager.send.firstCall.args + test.equal(creditAccountSendArgs[0], creditAccount) + assertEvent(test, creditAccountSendArgs[1], 'transfer.update', transfer, relatedResources) + + const debitAccountSendArgs = socketManager.send.secondCall.args + test.equal(debitAccountSendArgs[0], debitAccount) + assertEvent(test, debitAccountSendArgs[1], 'transfer.update', transfer, relatedResources) + test.end() }) - eventsTest.test('onTransferRejected should do nothing if transfer credits and debits are empty', test => { + eventsTest.test('onTransferRejected should do nothing if transfer credits and debits are empty', async function (test) { const message = { resource: {} } Events.onTransferRejected.yields(message) - Index.register(mockServer(), {}, () => { - test.equal(socketManager.send.callCount, 0) - test.end() - }) + Index.plugin.register(mockServer(), {}, {}) + test.equal(socketManager.send.callCount, 0) + test.end() }) - eventsTest.test('onTransferRejected should send message to socket manager for each account', test => { + eventsTest.test('onTransferRejected should send message to socket manager for each account', async function (test) { const creditAccount = 'http://credit-account' const debitAccount = 'http://debit-account' const transfer = { @@ -227,19 +216,18 @@ Test('Socket Module', moduleTest => { } const message = { resource: transfer } Events.onTransferRejected.yields(message) - Index.register(mockServer(), {}, () => { - const creditAccountSendArgs = socketManager.send.firstCall.args - test.equal(creditAccountSendArgs[0], creditAccount) - assertEvent(test, creditAccountSendArgs[1], 'transfer.update', transfer) - - const debitAccountSendArgs = socketManager.send.secondCall.args - test.equal(debitAccountSendArgs[0], debitAccount) - assertEvent(test, debitAccountSendArgs[1], 'transfer.update', transfer) - test.end() - }) + Index.plugin.register(mockServer(), {}, {}) + const creditAccountSendArgs = socketManager.send.firstCall.args + test.equal(creditAccountSendArgs[0], creditAccount) + assertEvent(test, creditAccountSendArgs[1], 'transfer.update', transfer) + + const debitAccountSendArgs = socketManager.send.secondCall.args + test.equal(debitAccountSendArgs[0], debitAccount) + assertEvent(test, debitAccountSendArgs[1], 'transfer.update', transfer) + test.end() }) - eventsTest.test('onMessageSent should send message to socket manager for to account', test => { + eventsTest.test('onMessageSent should send message to socket manager for to account', async function (test) { const toAccount = 'http://to-account' const fromAccount = 'http://from-account' const data = { something: 'test' } @@ -249,12 +237,11 @@ Test('Socket Module', moduleTest => { data } Events.onMessageSent.yields(message) - Index.register(mockServer(), {}, () => { - const args = socketManager.send.firstCall.args - test.equal(args[0], toAccount) - assertEvent(test, args[1], 'message.send', message) - test.end() - }) + Index.plugin.register(mockServer(), {}, {}) + const args = socketManager.send.firstCall.args + test.equal(args[0], toAccount) + assertEvent(test, args[1], 'message.send', message) + test.end() }) eventsTest.end() diff --git a/test/unit/api/token/handler.test.js b/test/unit/api/token/handler.test.js index 8282d3bed..f13f9bb4e 100644 --- a/test/unit/api/token/handler.test.js +++ b/test/unit/api/token/handler.test.js @@ -23,7 +23,7 @@ Test('token handler', handlerTest => { }) handlerTest.test('create should', createTest => { - createTest.test('create token from auth credentials', test => { + createTest.test('create token from auth credentials', async function (test) { const token = { token: 'token' } const account = { accountId: 1 } TokenService.create.withArgs(account).returns(P.resolve(token)) @@ -33,25 +33,21 @@ Test('token handler', handlerTest => { } } - const reply = (response) => { - test.equal(response, token) - test.ok(Sidecar.logRequest.calledWith(request)) - test.end() - } - - Handler.create(request, reply) + const response = await Handler.create(request, {}) + test.equal(response, token) + test.ok(Sidecar.logRequest.calledWith(request)) + test.end() }) - createTest.test('reply with error if thrown', test => { + createTest.test('reply with error if thrown', async function (test) { const error = new Error() TokenService.create.returns(P.reject(error)) - - const reply = (response) => { - test.equal(response, error) + try { + await Handler.create({ auth: { credentials: {} } }, {}) + } catch (e) { + test.equal(e, error) test.end() } - - Handler.create({ auth: { credentials: {} } }, reply) }) createTest.end() diff --git a/test/unit/api/transfers/handler.test.js b/test/unit/api/transfers/handler.test.js index f69b39fab..da707b0ee 100644 --- a/test/unit/api/transfers/handler.test.js +++ b/test/unit/api/transfers/handler.test.js @@ -19,7 +19,7 @@ const createRequest = (id, payload) => { const requestPayload = payload || {} return { payload: requestPayload, - params: { id: requestId }, + params: {id: requestId}, server: { log: () => { } } @@ -58,7 +58,7 @@ Test('transfer handler', handlerTest => { }) handlerTest.test('prepareTransfer should', prepareTransferTest => { - prepareTransferTest.test('reply with status code 200 if transfer exists', test => { + prepareTransferTest.test('reply with status code 200 if transfer exists', async function (test) { const payload = { id: 'https://central-ledger/transfers/3a2a1d9e-8640-4d2d-b06c-84f2cd613204', ledger: 'http://usd-ledger.example/USD', @@ -87,25 +87,24 @@ Test('transfer handler', handlerTest => { expires_at: payload.expires_at, timeline: {} } - - TransferService.prepare.returns(P.resolve({ transfer, existing: true })) - + TransferService.prepare.returns(P.resolve({transfer, existing: true})) const request = createRequest(Uuid(), payload) - const reply = response => { - test.equal(response.id, transfer.id) - return { - code: statusCode => { - test.equal(statusCode, 200) - test.ok(Sidecar.logRequest.calledWith(request)) - test.end() + const reply = { + response: (response) => { + test.equal(response.id, transfer.id) + return { + code: statusCode => { + test.equal(statusCode, 200) + test.ok(Sidecar.logRequest.calledWith(request)) + test.end() + } } } } - - Handler.prepareTransfer(request, reply) + await Handler.prepareTransfer(request, reply) }) - prepareTransferTest.test('reply with status code 201 if transfer does not exist', test => { + prepareTransferTest.test('reply with status code 201 if transfer does not exist', async function (test) { const payload = { id: 'https://central-ledger/transfers/3a2a1d9e-8640-4d2d-b06c-84f2cd613204', ledger: 'http://usd-ledger.example/USD', @@ -135,22 +134,24 @@ Test('transfer handler', handlerTest => { timeline: {} } - TransferService.prepare.returns(P.resolve({ transfer, existing: false })) + TransferService.prepare.returns(P.resolve({transfer, existing: false})) - const reply = response => { - test.equal(response.id, transfer.id) - return { - code: statusCode => { - test.equal(statusCode, 201) - test.end() + const reply = { + response: (response) => { + test.equal(response.id, transfer.id) + return { + code: statusCode => { + test.equal(statusCode, 201) + test.end() + } } } } - Handler.prepareTransfer(createRequest(Uuid(), payload), reply) + await Handler.prepareTransfer(createRequest(Uuid(), payload), reply) }) - prepareTransferTest.test('return error if transfer not validated', test => { + prepareTransferTest.test('return error if transfer not validated', async function (test) { const payload = {} const errorMessage = 'Error message' sandbox.restore() @@ -160,16 +161,16 @@ Test('transfer handler', handlerTest => { sandbox.stub(Sidecar, 'logRequest') const request = createRequest(transferId, payload) - const reply = response => { - test.equal(response, error) + try { + await Handler.prepareTransfer(request, {}) + } catch (e) { + test.equal(e, error) test.ok(Sidecar.logRequest.calledWith(request)) test.end() } - - Handler.prepareTransfer(request, reply) }) - prepareTransferTest.test('return error if transfer prepare throws', test => { + prepareTransferTest.test('return error if transfer prepare throws', async function (test) { const payload = { id: 'https://central-ledger/transfers/3a2a1d9e-8640-4d2d-b06c-84f2cd613204', ledger: 'http://usd-ledger.example/USD', @@ -191,20 +192,19 @@ Test('transfer handler', handlerTest => { const error = new Error() TransferService.prepare.returns(P.reject(error)) - - const reply = response => { - test.equal(response, error) + try { + await Handler.prepareTransfer(createRequest(Uuid(), payload), {}) + } catch (e) { + test.equal(e, error) test.end() } - - Handler.prepareTransfer(createRequest(Uuid(), payload), reply) }) prepareTransferTest.end() }) handlerTest.test('fulfillTransfer should', fulfillTransferTest => { - fulfillTransferTest.test('return fulfilled transfer', test => { + fulfillTransferTest.test('return fulfilled transfer', async function (test) { const transfer = { id: 'https://central-ledger/transfers/3a2a1d9e-8640-4d2d-b06c-84f2cd613204', ledger: 'http://usd-ledger.example/USD', @@ -225,114 +225,126 @@ Test('transfer handler', handlerTest => { timeline: {} } - const fulfillment = { id: '3a2a1d9e-8640-4d2d-b06c-84f2cd613204', fulfillment: 'oAKAAA' } + const fulfillment = {id: '3a2a1d9e-8640-4d2d-b06c-84f2cd613204', fulfillment: 'oAKAAA'} TransferService.fulfill.returns(P.resolve(transfer)) const request = createRequest(fulfillment.id, fulfillment.fulfillment) - const reply = response => { - test.equal(response.id, transfer.id) - test.ok(Sidecar.logRequest.calledWith(request)) - return { - code: statusCode => { - test.equal(statusCode, 200) - test.end() + const reply = { + response: (response) => { + test.equal(response.id, transfer.id) + test.ok(Sidecar.logRequest.calledWith(request)) + return { + code: statusCode => { + test.equal(statusCode, 200) + test.end() + } } } } - Handler.fulfillTransfer(request, reply) + await Handler.fulfillTransfer(request, reply) }) - fulfillTransferTest.test('return error if transfer service fulfill throws', test => { - const fulfillment = { id: '3a2a1d9e-8640-4d2d-b06c-84f2cd613204', fulfillment: 'oAKAAA' } + fulfillTransferTest.test('return error if transfer service fulfill throws', async function (test) { + const fulfillment = {id: '3a2a1d9e-8640-4d2d-b06c-84f2cd613204', fulfillment: 'oAKAAA'} const error = new Error() TransferService.fulfill.returns(P.reject(error)) - - const reply = response => { - test.equal(response, error) + try { + await Handler.fulfillTransfer(createRequest(fulfillment.id, fulfillment.fulfillment), {}) + } catch (e) { + test.equal(e, error) test.end() } - - Handler.fulfillTransfer(createRequest(fulfillment.id, fulfillment.fulfillment), reply) }) fulfillTransferTest.end() }) handlerTest.test('reject transfer', rejectTransferTest => { - rejectTransferTest.test('should reject transfer', test => { + rejectTransferTest.test('should reject transfer', async function (test) { const rejectionMessage = Fixtures.rejectionMessage() const transferId = '3a2a1d9e-8640-4d2d-b06c-84f2cd613204' const request = { - params: { id: transferId }, + params: {id: transferId}, payload: rejectionMessage, auth } - TransferService.reject.returns(P.resolve({ alreadyRejected: false, transfer: {} })) - - const reply = response => { - test.deepEqual(response, rejectionMessage) - test.ok(TransferService.reject.calledWith(Sinon.match({ id: transferId, rejection_reason: 'cancelled', message: rejectionMessage }))) - test.ok(Sidecar.logRequest.calledWith(request)) - return { - code: statusCode => { - test.equal(statusCode, 201) - test.end() + TransferService.reject.returns(P.resolve({alreadyRejected: false, transfer: {}})) + + const reply = { + response: (response) => { + test.deepEqual(response, rejectionMessage) + test.ok(TransferService.reject.calledWith(Sinon.match({ + id: transferId, + rejection_reason: 'cancelled', + message: rejectionMessage + }))) + test.ok(Sidecar.logRequest.calledWith(request)) + return { + code: statusCode => { + test.equal(statusCode, 201) + test.end() + } } } } - Handler.rejectTransfer(request, reply) + await Handler.rejectTransfer(request, reply) }) - rejectTransferTest.test('should reject rejected transfer', test => { + rejectTransferTest.test('should reject rejected transfer', async function (test) { const rejectionMessage = Fixtures.rejectionMessage() const transferId = '3a2a1d9e-8640-4d2d-b06c-84f2cd613204' const request = { - params: { id: transferId }, + params: {id: transferId}, payload: rejectionMessage, auth } - TransferService.reject.returns(P.resolve({ alreadyRejected: true, transfer: {} })) - - const reply = response => { - test.deepEqual(response, rejectionMessage) - test.ok(TransferService.reject.calledWith(Sinon.match({ id: transferId, rejection_reason: 'cancelled', message: rejectionMessage }))) - return { - code: statusCode => { - test.equal(statusCode, 200) - test.end() + TransferService.reject.returns(P.resolve({alreadyRejected: true, transfer: {}})) + + const reply = { + response: (response) => { + test.deepEqual(response, rejectionMessage) + test.ok(TransferService.reject.calledWith(Sinon.match({ + id: transferId, + rejection_reason: 'cancelled', + message: rejectionMessage + }))) + return { + code: statusCode => { + test.equal(statusCode, 200) + test.end() + } } } } - Handler.rejectTransfer(request, reply) + await Handler.rejectTransfer(request, reply) }) - rejectTransferTest.test('return error if transfer server reject throws', test => { + rejectTransferTest.test('return error if transfer server reject throws', async function (test) { const rejectReason = 'error reason' const request = { - params: { id: '3a2a1d9e-8640-4d2d-b06c-84f2cd613204' }, + params: {id: '3a2a1d9e-8640-4d2d-b06c-84f2cd613204'}, payload: rejectReason, auth } const error = new Error() TransferService.reject.returns(P.reject(error)) - - const reply = response => { - test.equal(response, error) + try { + await Handler.rejectTransfer(request, {}) + } catch (e) { + test.equal(e, error) test.end() } - - Handler.rejectTransfer(request, reply) }) rejectTransferTest.end() }) handlerTest.test('getTransferById should', getTransferByIdTest => { - getTransferByIdTest.test('get transfer by transfer id', test => { + getTransferByIdTest.test('get transfer by transfer id', async function (test) { const id = Uuid() const readModelTransfer = { @@ -351,85 +363,81 @@ Test('transfer handler', handlerTest => { preparedDate: new Date() } TransferService.getById.returns(P.resolve(readModelTransfer)) - - const reply = response => { - test.equal(response.id, `${hostname}/transfers/${readModelTransfer.transferUuid}`) - test.equal(response.ledger, readModelTransfer.ledger) - test.equal(response.debits.length, 1) - test.equal(response.debits[0].account, `${hostname}/accounts/${readModelTransfer.debitAccountName}`) - test.equal(response.debits[0].amount, readModelTransfer.debitAmount) - test.equal(response.credits.length, 1) - test.equal(response.credits[0].account, `${hostname}/accounts/${readModelTransfer.creditAccountName}`) - test.equal(response.credits[0].amount, readModelTransfer.creditAmount) - test.notOk(response.credits[0].rejected) - test.notOk(response.credits[0].rejection_message) - test.equal(response.execution_condition, readModelTransfer.executionCondition) - test.equal(response.expires_at, readModelTransfer.expiresAt) - test.equal(response.state, readModelTransfer.state) - test.ok(response.timeline) - test.equal(response.timeline.prepared_at, readModelTransfer.preparedDate) - test.end() - } - - Handler.getTransferById(createRequest(id), reply) + const response = await Handler.getTransferById(createRequest(id), {}) + test.equal(response.id, `${hostname}/transfers/${readModelTransfer.transferUuid}`) + test.equal(response.ledger, readModelTransfer.ledger) + test.equal(response.debits.length, 1) + test.equal(response.debits[0].account, `${hostname}/accounts/${readModelTransfer.debitAccountName}`) + test.equal(response.debits[0].amount, readModelTransfer.debitAmount) + test.equal(response.credits.length, 1) + test.equal(response.credits[0].account, `${hostname}/accounts/${readModelTransfer.creditAccountName}`) + test.equal(response.credits[0].amount, readModelTransfer.creditAmount) + test.notOk(response.credits[0].rejected) + test.notOk(response.credits[0].rejection_message) + test.equal(response.execution_condition, readModelTransfer.executionCondition) + test.equal(response.expires_at, readModelTransfer.expiresAt) + test.equal(response.state, readModelTransfer.state) + test.ok(response.timeline) + test.equal(response.timeline.prepared_at, readModelTransfer.preparedDate) + test.end() }) - getTransferByIdTest.test('reply with NotFoundError if transfer null', test => { + getTransferByIdTest.test('reply with NotFoundError if transfer null', async function (test) { TransferService.getById.returns(P.resolve(null)) - const reply = response => { - test.ok(response instanceof Errors.NotFoundError) - test.equal(response.message, 'The requested resource could not be found.') + try { + await Handler.getTransferById(createRequest(), {}) + } catch (e) { + test.ok(e instanceof Errors.NotFoundError) + test.equal(e.message, 'The requested resource could not be found.') test.end() } - - Handler.getTransferById(createRequest(), reply) }) - getTransferByIdTest.test('return error if model throws error', test => { + getTransferByIdTest.test('return error if model throws error', async function (test) { const error = new Error() TransferService.getById.returns(P.reject(error)) - - const reply = response => { - test.equal(response, error) + try { + await Handler.getTransferById(createRequest(), {}) + } catch (e) { + test.equal(e, error) test.end() } - - Handler.getTransferById(createRequest(), reply) }) getTransferByIdTest.end() }) handlerTest.test('getTransferFulfillment should', getTransferFulfillmentTest => { - getTransferFulfillmentTest.test('get fulfillment by transfer id', test => { + getTransferFulfillmentTest.test('get fulfillment by transfer id', async function (test) { const id = Uuid() const fulfillment = 'oAKAAA' TransferService.getFulfillment.withArgs(id).returns(P.resolve(fulfillment)) - const reply = response => { - test.equal(response, fulfillment) - return { - type: type => { - test.equal(type, 'text/plain') - test.end() + const reply = { + response: (response) => { + test.equal(response, fulfillment) + return { + type: type => { + test.equal(type, 'text/plain') + test.end() + } } } } - Handler.getTransferFulfillment(createRequest(id), reply) + await Handler.getTransferFulfillment(createRequest(id), reply) }) - getTransferFulfillmentTest.test('reply with error if service throws', test => { + getTransferFulfillmentTest.test('reply with error if service throws', async function (test) { const error = new Error() TransferService.getFulfillment.returns(P.reject(error)) - - const reply = response => { - test.equal(response, error) + try { + await Handler.getTransferFulfillment(createRequest(), {}) + } catch (e) { + test.equal(e, error) test.end() } - - Handler.getTransferFulfillment(createRequest(), reply) }) getTransferFulfillmentTest.end() diff --git a/test/unit/api/transfers/routes.test.js b/test/unit/api/transfers/routes.test.js index 0a36326db..f8b2ea9dc 100644 --- a/test/unit/api/transfers/routes.test.js +++ b/test/unit/api/transfers/routes.test.js @@ -3,100 +3,99 @@ const Test = require('tape') const Base = require('../../base') -Test('return error if required field missing on prepare', function (assert) { - let req = Base.buildRequest({ url: '/transfers/3a2a1d9e-8640-4d2d-b06c-84f2cd613204', method: 'PUT', payload: {} }) - - Base.setup().then(server => { - server.inject(req, function (res) { - Base.assertBadRequestError(assert, res, [{ message: 'id is required', params: { key: 'id' } }, { message: 'ledger is required', params: { key: 'ledger' } }, { message: 'debits is required', params: { key: 'debits' } }, { message: 'credits is required', params: { key: 'credits' } }]) - assert.end() - }) - }) +Test('return error if required field missing on prepare', async function (assert) { + let req = Base.buildRequest({url: '/transfers/3a2a1d9e-8640-4d2d-b06c-84f2cd613204', method: 'PUT', payload: {}}) + const server = await Base.setup() + const res = await server.inject(req) + Base.assertBadRequestError(assert, res, 'child "id" fails because [id is required]. child "ledger" fails because [ledger is required]. child "debits" fails because [debits is required]. child "credits" fails because [credits is required]') + await server.stop() + assert.end() }) -Test('return error if id is not a guid on prepare', function (assert) { - let req = Base.buildRequest({ url: '/transfers/abcd', method: 'PUT' }) - - Base.setup().then(server => { - server.inject(req, function (res) { - Base.assertInvalidUriParameterError(assert, res, [{ message: 'id must be a valid GUID', params: { key: 'id', value: 'abcd' } }]) - assert.end() - }) - }) +Test('return error if id is not a guid on prepare', async function (assert) { + let req = Base.buildRequest({url: '/transfers/abcd', method: 'PUT'}) + const server = await Base.setup() + const res = await server.inject(req) + Base.assertInvalidUriParameterError(assert, res, 'child "id" fails because [id must be a valid GUID]') + await server.stop() + assert.end() }) -Test('return error if id is not a guid on get prepare', function (assert) { - let req = Base.buildRequest({ url: '/transfers/abcd', method: 'GET' }) - - Base.setup().then(server => { - server.inject(req, function (res) { - Base.assertInvalidUriParameterError(assert, res, [{ message: 'id must be a valid GUID', params: { key: 'id', value: 'abcd' } }]) - assert.end() - }) - }) +Test('return error if id is not a guid on get prepare', async function (assert) { + let req = Base.buildRequest({url: '/transfers/abcd', method: 'GET'}) + const server = await Base.setup() + const res = await server.inject(req) + Base.assertInvalidUriParameterError(assert, res, 'child "id" fails because [id must be a valid GUID]') + await server.stop() + assert.end() }) -Test('return error if invalid content type on fulfillment', function (assert) { - let req = Base.buildRequest({ url: '/transfers/3a2a1d9e-8640-4d2d-b06c-84f2cd613204/fulfillment', method: 'PUT', headers: { 'Content-Type': 'application/json' } }) - - Base.setup().then(server => { - server.inject(req, function (res) { - Base.assertInvalidHeaderError(assert, res, [{ message: 'content-type must be one of [text/plain]', params: { key: 'content-type', valids: ['text/plain'] } }]) - assert.end() - }) +Test('return error if invalid content type on fulfillment', async function (assert) { + let req = Base.buildRequest({ + url: '/transfers/3a2a1d9e-8640-4d2d-b06c-84f2cd613204/fulfillment', + method: 'PUT', + headers: {'Content-Type': 'application/json'} }) + const server = await Base.setup() + const res = await server.inject(req) + Base.assertBadRequestError(assert, res, 'child "content-type" fails because [content-type must be one of [text/plain]]') + await server.stop() + assert.end() }) -Test('return error if fulfillment missing', function (assert) { - let req = Base.buildRequest({ url: '/transfers/3a2a1d9e-8640-4d2d-b06c-84f2cd613204/fulfillment', method: 'PUT', headers: { 'Content-Type': 'text/plain' } }) - - Base.setup().then(server => { - server.inject(req, function (res) { - Base.assertBadRequestError(assert, res, [{ message: 'value is not allowed to be empty', params: { key: 'value' } }]) - assert.end() - }) +Test('return error if fulfillment missing', async function (assert) { + let req = Base.buildRequest({ + url: '/transfers/3a2a1d9e-8640-4d2d-b06c-84f2cd613204/fulfillment', + method: 'PUT', + headers: {'Content-Type': 'text/plain'} }) + const server = await Base.setup() + const res = await server.inject(req) + Base.assertBadRequestError(assert, res, 'undefined is not allowed to be empty') + await server.stop() + assert.end() }) -Test('return error if id is not a guid on fulfill', function (assert) { - let req = Base.buildRequest({ url: '/transfers/abcd/fulfillment', method: 'PUT', headers: { 'Content-Type': 'text/plain' } }) - - Base.setup().then(server => { - server.inject(req, function (res) { - Base.assertInvalidUriParameterError(assert, res, [{ message: 'id must be a valid GUID', params: { key: 'id', value: 'abcd' } }]) - assert.end() - }) +Test('return error if id is not a guid on fulfill', async function (assert) { + let req = Base.buildRequest({ + url: '/transfers/abcd/fulfillment', + method: 'PUT', + headers: {'Content-Type': 'text/plain'} }) + const server = await Base.setup() + const res = await server.inject(req) + Base.assertBadRequestError(assert, res, 'child "id" fails because [id must be a valid GUID]') + await server.stop() + assert.end() }) -Test('return error if id is not a guid on rejection', function (assert) { - let req = Base.buildRequest({ url: '/transfers/abcd/rejection', method: 'PUT' }) - - Base.setup().then(server => { - server.inject(req, function (res) { - Base.assertInvalidUriParameterError(assert, res, [{ message: 'id must be a valid GUID', params: { key: 'id', value: 'abcd' } }]) - assert.end() - }) - }) +Test('return error if id is not a guid on rejection', async function (assert) { + let req = Base.buildRequest({url: '/transfers/abcd/rejection', method: 'PUT'}) + const server = await Base.setup() + const res = await server.inject(req) + Base.assertInvalidUriParameterError(assert, res, 'child "id" fails because [id must be a valid GUID]') + await server.stop() + assert.end() }) -Test('return error if rejection reason missing', function (assert) { - let req = Base.buildRequest({ url: '/transfers/3a2a1d9e-8640-4d2d-b06c-84f2cd613204/rejection', method: 'PUT' }) - Base.setup().then(server => { - server.inject(req, function (res) { - Base.assertBadRequestError(assert, res, [{ message: 'value must be an object', params: { key: 'value' } }]) - assert.end() - }) - }) +Test('return error if rejection reason missing', async function (assert) { + let req = Base.buildRequest({url: '/transfers/3a2a1d9e-8640-4d2d-b06c-84f2cd613204/rejection', method: 'PUT'}) + const server = await Base.setup() + const res = await server.inject(req) + Base.assertBadRequestError(assert, res, 'undefined must be an object') + await server.stop() + assert.end() }) -Test('return error if id is not a guid on get fulfillment', function (assert) { - let req = Base.buildRequest({ url: '/transfers/abcd/fulfillment', method: 'GET', headers: { 'Content-Type': 'text/plain' } }) - - Base.setup().then(server => { - server.inject(req, function (res) { - Base.assertInvalidUriParameterError(assert, res, [{ message: 'id must be a valid GUID', params: { key: 'id', value: 'abcd' } }]) - assert.end() - }) +Test('return error if id is not a guid on get fulfillment', async function (assert) { + let req = Base.buildRequest({ + url: '/transfers/abcd/fulfillment', + method: 'GET', + headers: {'Content-Type': 'text/plain'} }) + const server = await Base.setup() + const res = await server.inject(req) + Base.assertBadRequestError(assert, res, 'child "id" fails because [id must be a valid GUID]') + await server.stop() + assert.end() }) diff --git a/test/unit/api/worker/index.test.js b/test/unit/api/worker/index.test.js index ac0b9fe20..76524925d 100644 --- a/test/unit/api/worker/index.test.js +++ b/test/unit/api/worker/index.test.js @@ -35,46 +35,36 @@ Test('Worker test', workerTest => { t.end() }) - setupTest.test('should not set timeout when EXPIRES_TIMEOUT config value undefined', test => { + setupTest.test('should not set timeout when EXPIRES_TIMEOUT config value undefined', async function (test) { let expiresTimeout = 1000 Config.TOKEN_EXPIRATION = null - let next = () => { - test.notOk(global.setInterval.calledWith(Worker.rejectExpiredTransfers, expiresTimeout)) - test.end() - } - Worker.register({}, {}, next) + await Worker.plugin.register({}, {}) + test.notOk(global.setInterval.calledWith(Worker.rejectExpiredTransfers, expiresTimeout)) + test.end() }) - setupTest.test('should setTimeout when EXPIRES_TIMEOUT config value set', test => { + setupTest.test('should setTimeout when EXPIRES_TIMEOUT config value set', async function (test) { let expiresTimeout = 1000 Config.EXPIRES_TIMEOUT = expiresTimeout - let next = () => { - test.ok(global.setInterval.calledWith(Worker.rejectExpiredTransfers, expiresTimeout)) - test.end() - } - - Worker.register({}, {}, next) + await Worker.plugin.register({}, {}) + test.ok(global.setInterval.calledWith(Worker.rejectExpiredTransfers, expiresTimeout)) + test.end() }) - setupTest.test('should not set tokenExpiration when TOKEN_EXPIRATION config value undefined', test => { + setupTest.test('should not set tokenExpiration when TOKEN_EXPIRATION config value undefined', async function (test) { let tokenExpiration = 1000 Config.TOKEN_EXPIRATION = null - let next = () => { - test.notOk(global.setInterval.calledWith(Worker.rejectExpiredTokens, tokenExpiration)) - test.end() - } - Worker.register({}, {}, next) + await Worker.plugin.register({}, {}) + test.notOk(global.setInterval.calledWith(Worker.rejectExpiredTokens, tokenExpiration)) + test.end() }) - setupTest.test('should set tokenExpiration when TOKEN_EXPIRATION config value set', test => { + setupTest.test('should set tokenExpiration when TOKEN_EXPIRATION config value set', async function (test) { let tokenExpiration = 1000 Config.TOKEN_EXPIRATION = tokenExpiration - let next = () => { - test.ok(global.setInterval.calledWith(Worker.rejectExpiredTokens, tokenExpiration)) - test.end() - } - - Worker.register({}, {}, next) + await Worker.plugin.register({}, {}) + test.ok(global.setInterval.calledWith(Worker.rejectExpiredTokens, tokenExpiration)) + test.end() }) setupTest.end() @@ -93,45 +83,41 @@ Test('Worker test', workerTest => { t.end() }) - runTest.test('should call Worker.rejectExpiredTransfers after interval elapse', test => { + runTest.test('should call Worker.rejectExpiredTransfers after interval elapse', async function (test) { let expiresTimeout = 1000 sandbox.stub(Worker, 'rejectExpiredTransfers') Worker.rejectExpiredTransfers.returns(P.resolve([])) Config.EXPIRES_TIMEOUT = expiresTimeout Config.TOKEN_EXPIRATION = null - let next = () => { - test.notOk(Worker.rejectExpiredTransfers.called) - clock.tick(expiresTimeout) - test.ok(Worker.rejectExpiredTransfers.calledOnce) - clock.tick(expiresTimeout) - test.ok(Worker.rejectExpiredTransfers.calledTwice) - test.end() - } - Worker.register({}, {}, next) + await Worker.plugin.register({}, {}) + test.notOk(Worker.rejectExpiredTransfers.called) + clock.tick(expiresTimeout) + test.ok(Worker.rejectExpiredTransfers.calledOnce) + clock.tick(expiresTimeout) + test.ok(Worker.rejectExpiredTransfers.calledTwice) + test.end() }) - runTest.test('should call Worker.rejectExpiredTokens after interval elapse', test => { + runTest.test('should call Worker.rejectExpiredTokens after interval elapse', async function (test) { let tokenExpiration = 1000 sandbox.stub(Worker, 'rejectExpiredTokens') Worker.rejectExpiredTokens.returns(P.resolve([])) Config.EXPIRES_TIMEOUT = null Config.TOKEN_EXPIRATION = tokenExpiration - let next = () => { - test.notOk(Worker.rejectExpiredTokens.called) - clock.tick(tokenExpiration) - test.ok(Worker.rejectExpiredTokens.calledOnce) - clock.tick(tokenExpiration) - test.ok(Worker.rejectExpiredTokens.calledTwice) - test.end() - } - Worker.register({}, {}, next) + Worker.plugin.register({}, {}) + test.notOk(Worker.rejectExpiredTokens.called) + clock.tick(tokenExpiration) + test.ok(Worker.rejectExpiredTokens.calledOnce) + clock.tick(tokenExpiration) + test.ok(Worker.rejectExpiredTokens.calledTwice) + test.end() }) runTest.end() }) workerTest.test('rejectExpiredTransfers should', rejectTest => { - rejectTest.test('call TransferService.rejectExpired and log results', test => { + rejectTest.test('call TransferService.rejectExpired and log results', async function (test) { let expiredTransfers = [1, 2] TransferService.rejectExpired.returns(P.resolve(expiredTransfers)) @@ -143,7 +129,7 @@ Test('Worker test', workerTest => { }) }) - rejectTest.test('call TransferService.rejectExpired and log error if thrown', test => { + rejectTest.test('call TransferService.rejectExpired and log error if thrown', async function (test) { let error = new Error() TransferService.rejectExpired.returns(P.reject(error)) @@ -159,7 +145,7 @@ Test('Worker test', workerTest => { }) workerTest.test('rejectExpiredTokens should', rejectTest => { - rejectTest.test('call TokenService.removeExpired and log results', test => { + rejectTest.test('call TokenService.removeExpired and log results', async function (test) { let expiredTokens = [1, 2] TokenService.removeExpired.returns(P.resolve(expiredTokens)) @@ -171,7 +157,7 @@ Test('Worker test', workerTest => { }) }) - rejectTest.test('call TokenService.removeExpired and log error if thrown', test => { + rejectTest.test('call TokenService.removeExpired and log error if thrown', async function (test) { let error = new Error() TokenService.removeExpired.returns(P.reject(error)) diff --git a/test/unit/base.js b/test/unit/base.js index b6ee9cdbc..017916693 100644 --- a/test/unit/base.js +++ b/test/unit/base.js @@ -3,36 +3,46 @@ const ServerSetup = require('../../src/shared/setup') const ApiAuth = require('../../src/api/auth') const ApiRoutes = require('../../src/api/routes') +// const Logger = require('@mojaloop/central-services-shared').Logger -let serverPromise - -const setupServer = () => { - if (!serverPromise) { - serverPromise = ServerSetup.createServer(3000, [ApiAuth, ApiRoutes], false) - } - return serverPromise +const setupServer = async () => { + const server = await ServerSetup.createServer(3000, [ApiAuth, ApiRoutes]) + return server } -exports.setup = (connection = 'api') => { +exports.setup = () => { return setupServer() } exports.buildRequest = (options) => { - return { url: options.url, method: options.method || 'GET', payload: options.payload || '', headers: options.headers || {} } + return { + url: options.url, + method: options.method || 'GET', + payload: options.payload || '', + headers: options.headers || {}, + credentials: { + username: 'admin', + password: 'admin' + } + } } exports.assertBadRequestError = (assert, response, validationErrors) => { + assert.equal(response.statusCode, 400) + assert.equal(response.result.id, 'BadRequestError') + assert.equal(response.result.message, validationErrors) +} + +exports.assertInvalidBodyError = (assert, response, validationErrors) => { assert.equal(response.statusCode, 400) assert.equal(response.result.id, 'InvalidBodyError') - assert.equal(response.result.message, 'Body does not match schema') - assert.deepEqual(response.result.validationErrors, validationErrors) + assert.equal(response.result.message, validationErrors) } exports.assertInvalidUriParameterError = (assert, response, validationErrors) => { assert.equal(response.statusCode, 400) - assert.equal(response.result.id, 'InvalidUriParameterError') - assert.equal(response.result.message, 'Error validating one or more uri parameters') - assert.deepEqual(response.result.validationErrors, validationErrors) + assert.equal(response.result.id, 'BadRequestError') + assert.equal(response.result.message, validationErrors) } exports.assertInvalidHeaderError = (assert, response, validationErrors) => { @@ -41,3 +51,9 @@ exports.assertInvalidHeaderError = (assert, response, validationErrors) => { assert.equal(response.result.message, 'Error validating one or more headers') assert.deepEqual(response.result.validationErrors, validationErrors) } + +exports.assertUnsupportedMediaTypeError = (assert, response, validationErrors) => { + assert.equal(response.statusCode, 415) + assert.equal(response.result.id, 'UnsupportedMediaTypeError') + assert.equal(response.result.message, validationErrors) +} diff --git a/test/unit/domain/settlements/index.test.js b/test/unit/domain/settlements/index.test.js index 464d41999..6b4ddbddb 100644 --- a/test/unit/domain/settlements/index.test.js +++ b/test/unit/domain/settlements/index.test.js @@ -66,6 +66,12 @@ const settledFees = [{ } }] +const settledTransfersInverse = [{ + amount: {currency_code: 'TZS', description: 'Bill', value: '1.00'}, + destination: {account_number: '2345', routing_number: '6789'}, + source: {account_number: '1234', routing_number: '5678'} +}] + const mockedCompletedSettlement = { transfers: settledTransfers, fees: settledFees @@ -110,7 +116,21 @@ Test('Settlements Test', settlementTest => { generateFee(account2, account1, '5.00') ] const settledPosition = Settlements.performSettlement(transfers, fees) - test.deepEqual({ fees: [], transfers: [] }, settledPosition) + test.deepEqual({fees: [], transfers: []}, settledPosition) + test.end() + }) + + performSettlementTest.test('return flattened transfers and fees when amounts are inverse but initial is higher', test => { + let transfers = [ + generateTransfer(account1, account2, '11.00'), + generateTransfer(account2, account1, '10.00') + ] + let fees = [ + generateFee(account1, account2, '5.00'), + generateFee(account2, account1, '5.00') + ] + const settledPosition = Settlements.performSettlement(transfers, fees) + test.deepEqual({fees: [], transfers: settledTransfersInverse}, settledPosition) test.end() }) @@ -125,7 +145,7 @@ Test('Settlements Test', settlementTest => { generateFee(account2, account1, '5.00') ] const settledPosition = Settlements.performSettlement(transfers, fees) - test.deepEqual({ fees: [], transfers: [] }, settledPosition) + test.deepEqual({fees: [], transfers: []}, settledPosition) test.end() }) diff --git a/test/unit/domain/token/auth.test.js b/test/unit/domain/token/auth.test.js index 285b8dded..7493e1012 100644 --- a/test/unit/domain/token/auth.test.js +++ b/test/unit/domain/token/auth.test.js @@ -43,108 +43,125 @@ Test('Token Auth', tokenTest => { }) tokenTest.test('all token validate should', validateTest => { - validateTest.test('be unauthorized if Ledger-Api-Key header not set', test => { + validateTest.test('be unauthorized if Ledger-Api-Key header not set', async function (test) { const request = createRequest() - - const cb = (err) => { + try { + await TokenAuth.validate(request, 'token', {}) + } catch (err) { test.ok(err) test.ok(err instanceof UnauthorizedError) test.equal(err.message, '"Ledger-Api-Key" header is required') test.end() } - - TokenAuth.validate(false)(request, 'token', cb) }) - validateTest.test('be unauthorized if Ledger-Api-Key not found', test => { + validateTest.test('be unauthorized if Ledger-Api-Key not found', async function (test) { const name = 'some-name' AccountService.getByName.withArgs(name).returns(P.resolve(null)) const request = createRequest(name) - - const cb = (err) => { + try { + await TokenAuth.validate(request, 'token', {}) + } catch (err) { test.ok(err) test.ok(err instanceof UnauthorizedError) test.equal(err.message, '"Ledger-Api-Key" header is not valid') test.end() } - - TokenAuth.validate(false)(request, 'token', cb) }) - validateTest.test('be invalid if token not found by account', test => { + validateTest.test('be invalid if token not found by account', async function (test) { const name = 'some-name' const accountId = Uuid().toString() - const account = { accountId } + const account = {accountId} AccountService.getByName.withArgs(name).returns(P.resolve(account)) TokenService.byAccount.withArgs(account).returns(P.resolve([])) const request = createRequest(name) - const cb = (err, isValid) => { - test.notOk(err) - test.equal(isValid, false) - test.end() + const reply = { + response: (response) => { + test.notOk(response.credentials) + test.equal(response.isValid, false) + test.end() + } } + await TokenAuth.validate(request, 'token', reply) + }) - TokenAuth.validate(false)(request, 'token', cb) + validateTest.test('be invalid if token not found by account and is admin', async function (test) { + const name = 'admin' + const accountId = Uuid().toString() + const account = {accountId, is_admin: true} + AccountService.getByName.withArgs(name).returns(P.resolve(account)) + TokenService.byAccount.withArgs(account).returns(P.resolve(null)) + const request = createRequest(name) + + const reply = { + response: (response) => { + test.notOk(response.credentials) + test.equal(response.isValid, false) + test.end() + } + } + await TokenAuth.validate(request, 'token', reply) }) - validateTest.test('be invalid if no account tokens can be verified', test => { + validateTest.test('be invalid if no account tokens can be verified', async function (test) { const name = 'some-name' const token = 'token' const accountId = Uuid().toString() - const account = { accountId } + const account = {accountId} AccountService.getByName.withArgs(name).returns(P.resolve(account)) const tokens = [ - { token: 'bad-token1' }, - { token: 'bad-token2' } + {token: 'bad-token1'}, + {token: 'bad-token2'} ] Crypto.verifyHash.returns(P.resolve(false)) TokenService.byAccount.withArgs(account).returns(P.resolve(tokens)) const request = createRequest(name) - const cb = (err, isValid) => { - test.notOk(err) - test.equal(isValid, false) - test.end() + const cb = { + response: (response) => { + test.notOk(response.credentials) + test.equal(response.isValid, false) + test.end() + } } - - TokenAuth.validate(false)(request, token, cb) + await TokenAuth.validate(request, token, cb) }) - validateTest.test('pass with account if one token can be verified', test => { + validateTest.test('pass with account if one token can be verified', async function (test) { const name = 'some-name' const token = 'token' const accountId = Uuid().toString() - const account = { accountId } + const account = {accountId, is_admin: true} AccountService.getByName.withArgs(name).returns(P.resolve(account)) const tokens = [ - { token: 'bad-token1' }, - { token: 'bad-token2' }, - { token } + {token: 'bad-token1'}, + {token: 'bad-token2'}, + {token} ] Crypto.verifyHash.returns(P.resolve(false)) Crypto.verifyHash.withArgs(token).returns(P.resolve(true)) TokenService.byAccount.withArgs(account).returns(P.resolve(tokens)) const request = createRequest(name) - - const cb = (err, isValid, credentials) => { - test.notOk(err) - test.equal(isValid, true) - test.equal(credentials, account) - test.end() + const cb = { + response: (response) => { + test.equal(response.isValid, true) + test.equal(response.credentials, account) + test.end() + } } - - TokenAuth.validate(false)(request, token, cb) + await TokenAuth.validate(request, token, cb) }) - validateTest.test('be invalid if a token has expired', test => { + validateTest.test('be invalid if a token has expired', async function (test) { const name = 'some-name' const tokenVal = 'token' const expiration = 1 - const token = { token: tokenVal, expiration } + const token = {token: tokenVal, expiration} const bearer = 'bearer' const accountId = Uuid().toString() - const account = { accountId } + const account = {accountId, is_admin: true} AccountService.getByName.withArgs(name).returns(P.resolve(account)) const tokens = [ token @@ -155,55 +172,55 @@ Test('Token Auth', tokenTest => { const request = createRequest(name) Config.TOKEN_EXPIRATION = 1 - const cb = (err, isValid, credentials) => { - test.notOk(err) - test.equal(isValid, false) - test.equal(credentials, account) - test.end() + const cb = { + response: (response) => { + test.equal(response.isValid, false) + test.equal(response.credentials, account) + test.end() + } } - - TokenAuth.validate(false)(request, bearer, cb) + await TokenAuth.validate(request, bearer, cb) }) validateTest.end() }) tokenTest.test('admin token validate should', validateTest => { - validateTest.test('return invalid if admin only and key is not admin key', test => { + validateTest.test('return invalid if admin only and key is not admin key', async function (test) { const adminKey = 'ADMIN_KEY' Config.ADMIN_KEY = adminKey const notAdminKey = 'not_admin_key' const request = createRequest(notAdminKey) - - const cb = (err, isValid) => { - test.notOk(err) - test.equal(isValid, false) + try { + await TokenAuth.validate(request, 'token', {}) + } catch (err) { + test.ok(err) + test.ok(err instanceof UnauthorizedError) + test.equal(err.message, '"Ledger-Api-Key" header is not valid') test.end() } - - TokenAuth.validate(true)(request, 'token', cb) }) - validateTest.test('return admin if admin only and key is admin key', test => { + validateTest.test('return admin if admin only and key is admin key', async function (test) { const adminKey = 'some-admin-key' Config.ADMIN_KEY = adminKey const request = createRequest(adminKey) const token = 'token' - TokenService.byAccount.returns(P.resolve([{ token }])) + TokenService.byAccount.returns(P.resolve([{token}])) Crypto.verifyHash.returns(P.resolve(false)) Crypto.verifyHash.withArgs(token).returns(P.resolve(true)) - const cb = (err, isValid, credentials) => { - test.notOk(err) - test.equal(isValid, true) - test.equal(credentials.is_admin, true) - test.notOk(credentials.accountId) - test.end() + const cb = { + response: (response) => { + test.equal(response.isValid, true) + test.equal(response.credentials.is_admin, true) + test.notOk(response.credentials.accountId) + test.end() + } } - - TokenAuth.validate(true)(request, token, cb) + await TokenAuth.validate(request, token, cb) }) validateTest.end() diff --git a/test/unit/lib/events.test.js b/test/unit/lib/events.test.js index ae590adc7..85bcd43e0 100644 --- a/test/unit/lib/events.test.js +++ b/test/unit/lib/events.test.js @@ -26,17 +26,17 @@ Test('events', eventTest => { emitTest.test('publish transfer prepared event', (t) => { let spy = Sinon.spy() Events.onTransferPrepared(spy) - let transfer = { id: 12 } + let transfer = {id: 12} TransferTranslator.toTransfer.returns(transfer) Events.emitTransferPrepared(transfer) - t.ok(spy.calledWith({ resource: transfer })) + t.ok(spy.calledWith({resource: transfer})) t.end() }) emitTest.test('not push transfer executed event', (t) => { let spy = Sinon.spy() Events.onTransferExecuted(spy) - let transfer = { id: 12 } + let transfer = {id: 12} TransferTranslator.toTransfer.returns(transfer) Events.emitTransferPrepared({}) t.notOk(spy.called) @@ -46,7 +46,7 @@ Test('events', eventTest => { emitTest.test('not push transfer rejected event', (t) => { let spy = Sinon.spy() Events.onTransferRejected(spy) - let transfer = { id: 12 } + let transfer = {id: 12} TransferTranslator.toTransfer.returns(transfer) Events.emitTransferPrepared({}) t.notOk(spy.called) @@ -60,18 +60,18 @@ Test('events', eventTest => { emitTest.test('publish transfer executed event', (t) => { let spy = Sinon.spy() Events.onTransferExecuted(spy) - let transfer = { id: 12 } + let transfer = {id: 12} TransferTranslator.toTransfer.returns(transfer) - let relatedResources = { execution_condition_fulfillment: 'oAKAAA' } + let relatedResources = {execution_condition_fulfillment: 'oAKAAA'} Events.emitTransferExecuted(transfer, relatedResources) - t.ok(spy.calledWith({ resource: transfer, related_resources: relatedResources })) + t.ok(spy.calledWith({resource: transfer, related_resources: relatedResources})) t.end() }) emitTest.test('not push transfer prepared event', (t) => { let spy = Sinon.spy() Events.onTransferPrepared(spy) - let transfer = { id: 12 } + let transfer = {id: 12} TransferTranslator.toTransfer.returns(transfer) Events.emitTransferExecuted({}) t.notOk(spy.called) @@ -81,7 +81,7 @@ Test('events', eventTest => { emitTest.test('not push transfer rejected event', (t) => { let spy = Sinon.spy() Events.onTransferRejected(spy) - let transfer = { id: 12 } + let transfer = {id: 12} TransferTranslator.toTransfer.returns(transfer) Events.emitTransferExecuted({}) t.notOk(spy.called) @@ -95,12 +95,12 @@ Test('events', eventTest => { emitTest.test('publish transfer rejected event', (t) => { let spy = Sinon.spy() Events.onTransferRejected(spy) - let transfer = { id: 12 } + let transfer = {id: 12} TransferTranslator.toTransfer.returns(transfer) - let resource = { id: 12 } - let relatedResources = { execution_condition_fulfillment: 'oAKAAA' } + let resource = {id: 12} + let relatedResources = {execution_condition_fulfillment: 'oAKAAA'} Events.emitTransferRejected(resource, relatedResources) - t.ok(spy.calledWith({ resource: transfer, related_resources: relatedResources })) + t.ok(spy.calledWith({resource: transfer, related_resources: relatedResources})) t.end() }) @@ -134,5 +134,18 @@ Test('events', eventTest => { }) sendTest.end() }) + + eventTest.test('emailSettlementCsv should', sendTest => { + sendTest.test('publish message.send event', test => { + const spy = Sinon.spy() + Events.onEmailSettlementCsv(spy) + const message = {} + Events.emailSettlementCsv(message) + test.ok(spy.calledWith(message)) + test.end() + }) + sendTest.end() + }) + eventTest.end() }) diff --git a/test/unit/models/settlements.test.js b/test/unit/models/settlements.test.js index 67bead843..460c309a0 100644 --- a/test/unit/models/settlements.test.js +++ b/test/unit/models/settlements.test.js @@ -28,17 +28,15 @@ Test('settlements model', function (modelTest) { }) modelTest.test('create should', createTest => { - createTest.test('insert and return new settlement record for a transfer', test => { + createTest.test('insert and return new settlement record for a transfer', async function (test) { let settlementId = Uuid() let settlement = { settlementId: settlementId, settlementType: 'transfer' } Db.settlements.insert.returns(P.resolve(settlement)) - Model.create(settlementId, 'transfer') - .then(c => { - test.equal(c, settlement) - test.end() - }) + const c = await Model.create(settlementId, 'transfer') + test.equal(c, settlement) + test.end() }) createTest.end() diff --git a/test/unit/shared/plugins.test.js b/test/unit/shared/plugins.test.js index 27dfcb807..27d1bb685 100644 --- a/test/unit/shared/plugins.test.js +++ b/test/unit/shared/plugins.test.js @@ -6,7 +6,6 @@ const Inert = require('inert') const Blipp = require('blipp') const Vision = require('vision') const ErrorHandling = require('@mojaloop/central-services-error-handling') -const Auth = require('@mojaloop/central-services-auth') class Server { constructor () { @@ -27,10 +26,10 @@ class Server { } Test('registerPlugins should', pluginsTest => { - pluginsTest.test('registers base modules', test => { - const server = new Server() - Plugins.registerPlugins(server) - const modules = [Inert, Vision, Blipp, ErrorHandling, Auth] + pluginsTest.test('registers base modules', async function (test) { + const server = await new Server() + await Plugins.registerPlugins(server) + const modules = [Inert, Vision, Blipp, ErrorHandling] modules.forEach(x => test.ok(server.contains(x))) test.end() }) diff --git a/test/unit/shared/setup.test.js b/test/unit/shared/setup.test.js index 8722b18be..61750107a 100644 --- a/test/unit/shared/setup.test.js +++ b/test/unit/shared/setup.test.js @@ -4,11 +4,11 @@ const Test = require('tapes')(require('tape')) const Sinon = require('sinon') const Hapi = require('hapi') const P = require('bluebird') -const ErrorHandling = require('@mojaloop/central-services-error-handling') const Migrator = require('../../../src/lib/migrator') const Db = require('../../../src/db') const Config = require('../../../src/lib/config') const Eventric = require('../../../src/eventric') +const Account = require('../../../src/domain/account') const Plugins = require('../../../src/shared/plugins') const RequestLogger = require('../../../src/lib/request-logger') const UrlParser = require('../../../src/lib/urlparser') @@ -30,6 +30,7 @@ Test('setup', setupTest => { sandbox.stub(Plugins, 'registerPlugins') sandbox.stub(Migrator) sandbox.stub(Eventric) + sandbox.stub(Account) sandbox.stub(UrlParser, 'idFromTransferUri') sandbox.stub(RequestLogger, 'logRequest') sandbox.stub(RequestLogger, 'logResponse') @@ -60,144 +61,31 @@ Test('setup', setupTest => { const server = { connection: sandbox.stub(), register: sandbox.stub(), - ext: sandbox.stub() + ext: sandbox.stub(), + start: sandbox.stub(), + info: { + uri: sandbox.stub() + } } Hapi.Server.returns(server) return server } - setupTest.test('createServer should', createServerTest => { - createServerTest.test('return Hapi Server', test => { - const server = createServer() - - Setup.createServer().then(s => { - test.deepEqual(s, server) - test.end() - }) - }) - - createServerTest.test('setup connection', test => { - const server = createServer() - const port = 1234 - - Setup.createServer(port).then(() => { - test.ok(server.connection.calledWith(Sinon.match({ - port, - routes: { - validate: ErrorHandling.validateRoutes() - } - }))) - test.end() - }) - }) - - createServerTest.test('log request and traceid', test => { - const server = createServer() - const port = 1234 - - let request = { headers: { traceid: '1234' }, url: { path: '/test' } } - let reply = { continue: sandbox.stub() } - server.ext.onFirstCall().callsArgWith(1, request, reply) - - Setup.createServer(port).then(() => { - test.ok(RequestLogger.logRequest.calledWith(request)) - test.ok(reply.continue.calledOnce) - test.end() - }) - }) - - createServerTest.test('use transfer id if traceid not found', test => { - const server = createServer() - const port = 1234 - const transferId = 'transfer-id' - const path = '/test' - - UrlParser.idFromTransferUri.returns(transferId) - - let request = { headers: { }, url: { path } } - let reply = { continue: sandbox.stub() } - server.ext.onFirstCall().callsArgWith(1, request, reply) - - Setup.createServer(port).then(() => { - test.ok(RequestLogger.logRequest.calledWith(sandbox.match({ - headers: { - traceid: transferId - } - }))) - test.ok(UrlParser.idFromTransferUri.calledWith(`${hostName}${path}`)) - test.ok(reply.continue.calledOnce) - test.end() - }) - }) - - createServerTest.test('create new uuid if traceid and transfer id not found', test => { - const server = createServer() - const port = 1234 - const uuid = 'new-trace-id' - - uuidStub.returns(uuid) - - let request = { headers: { }, url: { path: '/' } } - let reply = { continue: sandbox.stub() } - server.ext.onFirstCall().callsArgWith(1, request, reply) - - Setup.createServer(port).then(() => { - test.ok(RequestLogger.logRequest.calledWith(sandbox.match({ - headers: { - traceid: uuid - } - }))) - test.ok(reply.continue.calledOnce) - test.end() - }) - }) - - createServerTest.test('log response', test => { - const server = createServer() - const port = 1234 - - let request = { headers: { traceid: '1234' } } - let reply = { continue: sandbox.stub() } - server.ext.onSecondCall().callsArgWith(1, request, reply) - - Setup.createServer(port).then(() => { - test.ok(RequestLogger.logResponse.calledWith(request)) - test.ok(reply.continue.calledOnce) - test.end() - }) - }) - - createServerTest.test('register shared plugins', test => { - const server = createServer() - Setup.createServer().then(() => { - test.ok(Plugins.registerPlugins.calledWith(server)) - test.end() - }) - }) - - createServerTest.test('register provide modules', test => { - const server = createServer() - const modules = ['one', 'two'] - Setup.createServer(1234, modules).then(() => { - test.ok(server.register.calledWith(modules)) - test.end() - }) - }) - - createServerTest.end() - }) - setupTest.test('initialize should', initializeTest => { - const setupPromises = () => { + const setupPromises = ({service}) => { Migrator.migrate.returns(P.resolve()) Db.connect.returns(P.resolve()) - Eventric.getContext.returns(P.resolve()) Sidecar.connect.returns(P.resolve()) - return createServer() + Eventric.getContext.returns(P.resolve()) + const server = createServer() + if (service === 'api') { + Account.createLedgerAccount().returns(P.resolve()) + } + return server } initializeTest.test('connect to sidecar', test => { - const server = setupPromises() + const server = setupPromises({}) const service = 'test' Setup.initialize({ service }).then(s => { @@ -211,7 +99,7 @@ Test('setup', setupTest => { }) initializeTest.test('connect to db and return hapi server', test => { - const server = setupPromises() + const server = setupPromises({}) Setup.initialize({}).then(s => { test.ok(Db.connect.calledWith(databaseUri)) @@ -223,7 +111,7 @@ Test('setup', setupTest => { }) initializeTest.test('run migrations if runMigrations flag enabled', test => { - setupPromises() + setupPromises({}) Setup.initialize({ runMigrations: true }).then(() => { test.ok(Db.connect.called) @@ -234,7 +122,7 @@ Test('setup', setupTest => { }) initializeTest.test('setup eventric context if loadEventric flag enabled', test => { - setupPromises() + setupPromises({}) Setup.initialize({ loadEventric: true }).then(() => { test.ok(Db.connect.called) @@ -244,20 +132,10 @@ Test('setup', setupTest => { }) }) - initializeTest.test('cleanup on error and rethrow', test => { - setupPromises() - - let err = new Error('bad stuff') - Sidecar.connect.returns(P.reject(err)) - - const service = 'test' - Setup.initialize({ service }).then(s => { - test.fail('Should have thrown error') - test.end() - }) - .catch(e => { - test.ok(Db.disconnect.calledOnce) - test.equal(e, err) + initializeTest.test('create ledger account on api service call', (test) => { + setupPromises({}) + Setup.initialize({ service: 'api' }).then(() => { + test.ok(Account.createLedgerAccount.called) test.end() }) })