diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d9f32c010f2..334d51143ea 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -58,8 +58,6 @@ jobs: uses: actions/setup-node@v4 with: node-version: ${{ env.NODE_VERSION }} - - name: Couch Start - run: ./scripts/ci/couch-start - name: Create logs directory run: mkdir tests/logs - run: npm ci diff --git a/api/src/migrations/extract-person-contacts.js b/api/src/migrations/extract-person-contacts.js index af6e262cb53..5564d632f28 100644 --- a/api/src/migrations/extract-person-contacts.js +++ b/api/src/migrations/extract-person-contacts.js @@ -136,6 +136,7 @@ const createPerson = function(id, callback) { .catch(() => { // we tried our best - log the details and exit logger.error(`Failed to restore contact on facility "${facilityId}", contact: ${JSON.stringify(oldContact)}`); + callback(); }); }; diff --git a/api/tests/integration/.mocharc.js b/api/tests/integration/.mocharc.js new file mode 100644 index 00000000000..f6fc80ed789 --- /dev/null +++ b/api/tests/integration/.mocharc.js @@ -0,0 +1,12 @@ +process.env.COUCH_URL='http://admin:pass@localhost:5984/medic'; + +module.exports = { + allowUncaught: false, + color: true, + checkLeaks: true, + fullTrace: true, + asyncOnly: false, + spec: './api/tests/integration/**/*.js', + timeout: 20000, + reporter: 'spec', +}; diff --git a/api/tests/integration/compose.yml b/api/tests/integration/compose.yml new file mode 100644 index 00000000000..d7ea81458c1 --- /dev/null +++ b/api/tests/integration/compose.yml @@ -0,0 +1,9 @@ +services: + couchdb: + build: ../../../couchdb + ports: + - "5984:5984" + environment: + - "COUCHDB_USER=admin" + - "COUCHDB_PASSWORD=pass" + - "SVC_NAME=couchdb" diff --git a/api/tests/integration/couch-start.sh b/api/tests/integration/couch-start.sh new file mode 100755 index 00000000000..4dce7823a60 --- /dev/null +++ b/api/tests/integration/couch-start.sh @@ -0,0 +1,10 @@ +#!/bin/bash -eu + +set -e + +docker compose -f ./api/tests/integration/compose.yml up -d +echo "Starting CouchDB" + +until nc -z localhost 5984; do sleep 1; done +sleep 2 +echo "CouchDB Started" diff --git a/api/tests/integration/couch-stop.sh b/api/tests/integration/couch-stop.sh new file mode 100755 index 00000000000..0afaa9bf709 --- /dev/null +++ b/api/tests/integration/couch-stop.sh @@ -0,0 +1,3 @@ +#!/bin/bash -eu +set -e +docker compose -f ./api/tests/integration/compose.yml down --remove-orphans diff --git a/api/tests/integration/migrations/add-contact-id-to-user-docs.js b/api/tests/integration/migrations/add-contact-id-to-user-docs.js index 9593dc6b708..44ad3968ec3 100644 --- a/api/tests/integration/migrations/add-contact-id-to-user-docs.js +++ b/api/tests/integration/migrations/add-contact-id-to-user-docs.js @@ -33,7 +33,6 @@ const getUserDoc = async (id) => db.users.get(id); describe('add-contact-id-to-user migration', function() { afterEach(() => { sinon.restore(); - utils.tearDown(); }); it('migrates the contact_id value from user-settings to _users for all users', async () => { diff --git a/api/tests/integration/migrations/add-meta-validate-doc-update.spec.js b/api/tests/integration/migrations/add-meta-validate-doc-update.spec.js index 5074b227982..8df07aad64b 100644 --- a/api/tests/integration/migrations/add-meta-validate-doc-update.spec.js +++ b/api/tests/integration/migrations/add-meta-validate-doc-update.spec.js @@ -53,8 +53,6 @@ const assertUserDb = (name) => { }; describe('add-meta-validate-doc-update migration', () => { - afterEach(() => utils.tearDown()); - it('should work with no user dbs', () => { return utils .initDb([]) diff --git a/api/tests/integration/migrations/add-uuid-to-scheduled-tasks.spec.js b/api/tests/integration/migrations/add-uuid-to-scheduled-tasks.spec.js index bc9a38c297c..da08b430380 100644 --- a/api/tests/integration/migrations/add-uuid-to-scheduled-tasks.spec.js +++ b/api/tests/integration/migrations/add-uuid-to-scheduled-tasks.spec.js @@ -3,10 +3,6 @@ const utils = require('./utils'); const UUID_REGEX = /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/; describe('add-uuid-to-scheduled-tasks migration', function() { - afterEach(function() { - return utils.tearDown(); - }); - const FUTURE = moment().add(1, 'week').toISOString(); const PAST = moment().subtract(1, 'week').toISOString(); diff --git a/api/tests/integration/migrations/clean-up-corrupted-users.spec.js b/api/tests/integration/migrations/clean-up-corrupted-users.spec.js index 121ae0bb04d..3c2b5aa2031 100644 --- a/api/tests/integration/migrations/clean-up-corrupted-users.spec.js +++ b/api/tests/integration/migrations/clean-up-corrupted-users.spec.js @@ -1,10 +1,6 @@ const utils = require('./utils'); describe('clean-up-corrupted-users migration', function() { - afterEach(function() { - return utils.tearDown(); - }); - it('cleans up users with $promise and $resolved fields', function() { // given return utils.initDb([ diff --git a/api/tests/integration/migrations/convert-translation-messages-fix.spec.js b/api/tests/integration/migrations/convert-translation-messages-fix.spec.js index ca97301eed7..ee468684ef6 100644 --- a/api/tests/integration/migrations/convert-translation-messages-fix.spec.js +++ b/api/tests/integration/migrations/convert-translation-messages-fix.spec.js @@ -2,10 +2,6 @@ const utils = require('./utils'); const DDOC_ID = '_design/medic'; describe('convert-translation-messages-fix migration', function() { - afterEach(function() { - return utils.tearDown(); - }); - it('converts translation messages structure', () => { // given diff --git a/api/tests/integration/migrations/create-patient-contacts.spec.js b/api/tests/integration/migrations/create-patient-contacts.spec.js index 3da75fed723..02633bd5fc4 100644 --- a/api/tests/integration/migrations/create-patient-contacts.spec.js +++ b/api/tests/integration/migrations/create-patient-contacts.spec.js @@ -5,10 +5,6 @@ const migrate = function() { }; describe('create-patient-contacts migration', function() { - afterEach(function() { - return utils.tearDown(); - }); - it('should run cleanly with no registered patients', function() { return utils.initDb([]) .then(migrate) diff --git a/api/tests/integration/migrations/emit-complete.spec.js b/api/tests/integration/migrations/emit-complete.spec.js index 81014bcf0a9..d38f1b02bcb 100644 --- a/api/tests/integration/migrations/emit-complete.spec.js +++ b/api/tests/integration/migrations/emit-complete.spec.js @@ -1,5 +1,3 @@ -const sinon = require('sinon'); - const utils = require('./utils'); describe('emit-complete', function() { @@ -7,11 +5,6 @@ describe('emit-complete', function() { await utils.initDb([]); }); - afterEach(() => { - utils.tearDown(); - sinon.restore(); - }); - it('should do nothing when tasks not configured', function() { // given return utils.initSettings({ tasks: { rules: '' } }) diff --git a/api/tests/integration/migrations/extract-person-contacts.spec.js b/api/tests/integration/migrations/extract-person-contacts.spec.js index 1bd952aa0f0..40491d51de1 100644 --- a/api/tests/integration/migrations/extract-person-contacts.spec.js +++ b/api/tests/integration/migrations/extract-person-contacts.spec.js @@ -60,7 +60,6 @@ const settings = { describe('extract-person-contacts migration', () => { afterEach(() => { sinon.restore(); - return utils.tearDown(); }); it('converts and minifies a 0.4 structure into a 2.x one', async () => { diff --git a/api/tests/integration/migrations/extract-transition-seq.spec.js b/api/tests/integration/migrations/extract-transition-seq.spec.js index 51d7f79d223..ce13113edce 100644 --- a/api/tests/integration/migrations/extract-transition-seq.spec.js +++ b/api/tests/integration/migrations/extract-transition-seq.spec.js @@ -11,7 +11,6 @@ const MIGRATION = 'extract-transition-seq'; describe(`${MIGRATION} migration`, function() { before(async () => utils.initDb([])); - after(async () => utils.tearDown()); const wipe = (dbRef, docName) => { return dbRef.get(docName) diff --git a/api/tests/integration/migrations/extract-translations.spec.js b/api/tests/integration/migrations/extract-translations.spec.js index 2c22a9197db..e61fa27393d 100644 --- a/api/tests/integration/migrations/extract-translations.spec.js +++ b/api/tests/integration/migrations/extract-translations.spec.js @@ -3,7 +3,6 @@ const utils = require('./utils'); describe('extract-translations', function() { afterEach(() => { - utils.tearDown(); sinon.restore(); }); diff --git a/api/tests/integration/migrations/namespace-form-fields.spec.js b/api/tests/integration/migrations/namespace-form-fields.spec.js index a2d0cd145d4..526f89ac42a 100644 --- a/api/tests/integration/migrations/namespace-form-fields.spec.js +++ b/api/tests/integration/migrations/namespace-form-fields.spec.js @@ -1,9 +1,6 @@ const utils = require('./utils'); describe('namespace-form-fields migration', function() { - afterEach(function() { - return utils.tearDown(); - }); it('should put form fields in fields property', function() { // given diff --git a/api/tests/integration/migrations/remove-empty-parents.spec.js b/api/tests/integration/migrations/remove-empty-parents.spec.js index 98ed5eaf539..175b63bdba2 100644 --- a/api/tests/integration/migrations/remove-empty-parents.spec.js +++ b/api/tests/integration/migrations/remove-empty-parents.spec.js @@ -1,9 +1,6 @@ const utils = require('./utils'); describe('remove-empty-parents migration', function() { - afterEach(function() { - return utils.tearDown(); - }); it('should not affect well-defined parents', function() { // given diff --git a/api/tests/integration/migrations/remove-user-language.spec.js b/api/tests/integration/migrations/remove-user-language.spec.js index 9554fe5e5d7..9f9fc728008 100644 --- a/api/tests/integration/migrations/remove-user-language.spec.js +++ b/api/tests/integration/migrations/remove-user-language.spec.js @@ -1,7 +1,6 @@ const utils = require('./utils'); describe('remove-user-language migration', function() { - afterEach(() => utils.tearDown()); it('cleans up users with language field', function() { const initialUsers = [ diff --git a/api/tests/integration/migrations/test-framework.spec.js b/api/tests/integration/migrations/test-framework.spec.js index 4a78da23bf3..b08b76beaaa 100644 --- a/api/tests/integration/migrations/test-framework.spec.js +++ b/api/tests/integration/migrations/test-framework.spec.js @@ -6,10 +6,6 @@ const utils = require('./utils'); describe('migrations integration test framework', function() { - afterEach(function() { - return utils.tearDown(); - }); - describe('no-op', function() { it('should leave an empty db empty', function() { // given diff --git a/api/tests/integration/migrations/utils.js b/api/tests/integration/migrations/utils.js index 917e92a2c44..b0fc106fae4 100644 --- a/api/tests/integration/migrations/utils.js +++ b/api/tests/integration/migrations/utils.js @@ -3,7 +3,6 @@ const {promisify} = require('util'); const fs = require('fs'); const path = require('path'); const readFileAsync = promisify(fs.readFile); -const logger = require('@medic/logger'); const db = require('../../../src/db'); const { expect } = require('chai'); @@ -67,7 +66,7 @@ const matches = (expected, actual) => { const assertDb = expected => { return db - .get('medic-test').allDocs({ include_docs: true }) + .get('medic').allDocs({ include_docs: true }) .then(results => { let actual = results.rows.map(row => _.omit(row.doc, ['_rev'])); expected.sort(byId); @@ -153,31 +152,7 @@ const matchDbs = (expected, actual) => { } }; -const realMedicDb = db.medic; -const realSentinelDb = db.sentinel; -const realUsersDb = db.users; -const switchToRealDbs = () => { - db.medic = realMedicDb; - db.sentinel = realSentinelDb; - db.users = realUsersDb; -}; - -const switchToTestDbs = () => { - db.medic = new PouchDB( - realMedicDb.name.replace(/medic$/, 'medic-test') - ); - db.sentinel = new PouchDB( - realSentinelDb.name.replace(/medic-sentinel$/, 'medic-sentinel-test') - ); - db.users = new PouchDB( - realUsersDb.name.replace(/_users$/, 'users-test') - ); -}; - const initDb = content => { - - switchToTestDbs(); - return _resetDb() .then(() => { const medicPath = path.join(__dirname, '../../../../build/ddocs/medic.json'); @@ -196,31 +171,10 @@ const initDb = content => { }); }; -const _resetDb = (attempts = 0) => { - if (attempts === 3) { - return Promise.reject(new Error('Unable to reset medic-test db')); - } - - return db.exists('medic-test') - .then(exists => { - if (exists) { - return db.get('medic-test').destroy(); - } - }) - .then(() => { - return db.get('medic-test'); - }) - .catch(err => { - logger.error('Could not create "medic-test" directly after deleting, pausing and trying again'); - logger.error(err); - return new Promise(resolve => { - setTimeout(() => resolve(_resetDb(attempts + 1)), 3000); - }); - }); -}; - -const tearDown = () => { - switchToRealDbs(); +const _resetDb = async () => { + const res = await db.medic.allDocs(); + const toDelete = res.rows.map(row => ({ _id: row.id, _rev: row.value.rev, _deleted: true })); + await db.medic.bulkDocs(toDelete); }; const runMigration = migration => { @@ -273,7 +227,6 @@ module.exports = { initSettings: initSettings, getSettings: getSettings, runMigration: runMigration, - tearDown: tearDown, getDdoc: getDdoc, insertAttachment: insertAttachment, getDocStub diff --git a/couchdb/prod.couchdb-cluster.yml b/couchdb/prod.couchdb-cluster.yml deleted file mode 100644 index 0186b9e4b31..00000000000 --- a/couchdb/prod.couchdb-cluster.yml +++ /dev/null @@ -1,74 +0,0 @@ -version: "3.3" - -networks: - cht-net: - driver: bridge - -services: - couchdb.1: - image: medicmobile/cht-couchdb:${CHT_CORE_RELEASE:-clustered-042622-test37} - volumes: - - ${DB1_DATA:-./srv1}:/opt/couchdb/data - - cht-credentials:/opt/couchdb/etc/local.d/ - environment: - - "COUCHDB_USER=${COUCHDB_USER:-admin}" - - "COUCHDB_PASSWORD=${COUCHDB_PASSWORD}" - - "COUCHDB_SECRET=${COUCHDB_SECRET:-6c1953b6-e64d-4b0c-9268-2528396f2f58}" - - "COUCHDB_UUID=${COUCHDB_UUID:-5c265815-b9e3-47f1-ba8d-c1d50495eeb2}" - - "SVC_NAME=${SVC1_NAME:-couchdb.1}" - - "CLUSTER_PEER_IPS=couchdb.2,couchdb.3" - - "COUCHDB_LOG_LEVEL=${COUCHDB_LOG_LEVEL:-error}" - restart: always - networks: - cht-net: - - couchdb.2: - image: medicmobile/cht-couchdb:${CHT_CORE_RELEASE:-clustered-042622-test37} - volumes: - - ${DB2_DATA:-./srv2}:/opt/couchdb/data - environment: - - "COUCHDB_USER=${COUCHDB_USER:-admin}" - - "COUCHDB_PASSWORD=${COUCHDB_PASSWORD}" - - "COUCHDB_SECRET=${COUCHDB_SECRET:-6c1953b6-e64d-4b0c-9268-2528396f2f58}" - - "COUCHDB_UUID=${COUCHDB_UUID:-5c265815-b9e3-47f1-ba8d-c1d50495eeb2}" - - "SVC_NAME=${SVC2_NAME:-couchdb.2}" - - "COUCHDB_LOG_LEVEL=${COUCHDB_LOG_LEVEL:-error}" - - "COUCHDB_SYNC_ADMINS_NODE=${COUCHDB_SYNC_ADMINS_NODE:-couchdb.1}" - restart: always - networks: - cht-net: - - couchdb.3: - image: medicmobile/cht-couchdb:${CHT_CORE_RELEASE:-clustered-042622-test37} - volumes: - - ${DB3_DATA:-./srv3}:/opt/couchdb/data - environment: - - "COUCHDB_USER=${COUCHDB_USER:-admin}" - - "COUCHDB_PASSWORD=${COUCHDB_PASSWORD}" - - "COUCHDB_SECRET=${COUCHDB_SECRET:-6c1953b6-e64d-4b0c-9268-2528396f2f58}" - - "COUCHDB_UUID=${COUCHDB_UUID:-5c265815-b9e3-47f1-ba8d-c1d50495eeb2}" - - "SVC_NAME=${SVC3_NAME:-couchdb.3}" - - "COUCHDB_LOG_LEVEL=${COUCHDB_LOG_LEVEL:-error}" - - "COUCHDB_SYNC_ADMINS_NODE=${COUCHDB_SYNC_ADMINS_NODE:-couchdb.1}" - restart: always - networks: - cht-net: - - haproxy: - image: medicmobile/cht-haproxy:${CHT_CORE_RELEASE:-archv3-042822-v256} - hostname: haproxy - environment: - - "HAPROXY_IP=${HAPROXY_IP:-haproxy}" - - "COUCHDB_USER=${COUCHDB_USER:-admin}" - - "COUCHDB_PASSWORD=${COUCHDB_PASSWORD}" - - "COUCHDB1_SERVER=${COUCHDB1_SERVER:-couchdb.1}" - - "COUCHDB2_SERVER=${COUCHDB2_SERVER:-couchdb.2}" - - "COUCHDB3_SERVER=${COUCHDB3_SERVER:-couchdb.3}" - - "HAPROXY_PORT=${HAPROXY_PORT:-5984}" - networks: - cht-net: - ports: - - ${HAPROXY_PORT:-5984}:${HAPROXY_PORT:-5984} - -volumes: - cht-credentials: diff --git a/couchdb/tests/compose.yml b/couchdb/tests/compose.yml index d11c704c689..bf21860a061 100644 --- a/couchdb/tests/compose.yml +++ b/couchdb/tests/compose.yml @@ -1,5 +1,3 @@ -version: "3.7" - services: couchdb.1: build: diff --git a/couchdb/tests/tests.bats b/couchdb/tests/tests.bats index aa1f0be6562..0b8b76a73aa 100644 --- a/couchdb/tests/tests.bats +++ b/couchdb/tests/tests.bats @@ -34,7 +34,7 @@ setup() { assert_output --partial '"status":"ok"' } -@test "data inserted on one couchb can be retrieved from a peer" { +@test "data inserted on one server can be retrieved from a peer" { local id id=$(