diff --git a/.github/workflows/db-migrations.yml b/.github/workflows/db-migrations.yml deleted file mode 100644 index 78f8b0361..000000000 --- a/.github/workflows/db-migrations.yml +++ /dev/null @@ -1,51 +0,0 @@ -name: Database Migrations - -on: - pull_request: - paths: - - .github/workflows/db-migrations.yml - - lib/bin/create-docker-databases.js - - lib/model/migrations/** - - test/db-migrations/** - - package.json - - package-lock.json - - Makefile - push: - paths: - - .github/workflows/db-migrations.yml - - lib/bin/create-docker-databases.js - - lib/model/migrations/** - - test/db-migrations/** - - package.json - - package-lock.json - - Makefile - -jobs: - db-migration-tests: - timeout-minutes: 2 - # TODO should we use the same container as circle & central? - runs-on: ubuntu-latest - services: - # see: https://docs.github.com/en/enterprise-server@3.5/actions/using-containerized-services/creating-postgresql-service-containers - postgres: - image: postgres:14.20 - env: - POSTGRES_PASSWORD: odktest - ports: - - 5432:5432 - # Set health checks to wait until postgres has started - options: >- - --health-cmd pg_isready - --health-interval 1s - --health-timeout 5s - --health-retries 50 - steps: - - uses: actions/checkout@v6 - - name: Set node version - uses: actions/setup-node@v6 - with: - node-version-file: package.json - cache: 'npm' - - run: npm ci - - run: node lib/bin/create-docker-databases.js - - run: make test-db-migrations diff --git a/.github/workflows/oidc-e2e.yml b/.github/workflows/oidc-e2e.yml deleted file mode 100644 index 5b5851459..000000000 --- a/.github/workflows/oidc-e2e.yml +++ /dev/null @@ -1,49 +0,0 @@ -name: OIDC e2e tests - -on: - push: - pull_request: - -env: - DEBUG: pw:api - ODK_PLAYWRIGHT_BROWSERS: chromium,firefox,webkit - -jobs: - oidc-e2e-test: - timeout-minutes: 6 - # TODO should we use the same container as circle & central? - runs-on: ubuntu-latest - services: - # see: https://docs.github.com/en/enterprise-server@3.5/actions/using-containerized-services/creating-postgresql-service-containers - postgres: - image: postgres:14.20 - env: - POSTGRES_PASSWORD: odktest - ports: - - 5432:5432 - # Set health checks to wait until postgres has started - options: >- - --health-cmd pg_isready - --health-interval 1s - --health-timeout 5s - --health-retries 50 - steps: - - # This one weird trick speeds up every build! - # see: https://github.com/getodk/central-backend/pull/1642 - # see: https://github.com/actions/runner/issues/4030 - - run: sudo apt-get remove --purge man-db - - - uses: actions/checkout@v6 - - name: Set node version - uses: actions/setup-node@v6 - with: - node-version-file: package.json - cache: 'npm' - - run: make test-oidc-e2e - - name: Archive Playwright Test Report - if: failure() - uses: actions/upload-artifact@v4 - with: - name: Playwright Test Report - path: test/e2e/oidc/playwright-tests/results/html-report/ diff --git a/.github/workflows/oidc-integration.yml b/.github/workflows/oidc-integration.yml deleted file mode 100644 index b38e1a7e0..000000000 --- a/.github/workflows/oidc-integration.yml +++ /dev/null @@ -1,39 +0,0 @@ -name: OIDC integration tests - -on: - push: - pull_request: - -jobs: - oidc-integration-test: - timeout-minutes: 6 - # TODO should we use the same container as circle & central? - runs-on: ubuntu-latest - services: - # see: https://docs.github.com/en/enterprise-server@3.5/actions/using-containerized-services/creating-postgresql-service-containers - postgres: - image: postgres:14.20 - env: - POSTGRES_PASSWORD: odktest - ports: - - 5432:5432 - # Set health checks to wait until postgres has started - options: >- - --health-cmd pg_isready - --health-interval 1s - --health-timeout 5s - --health-retries 50 - steps: - - uses: actions/checkout@v6 - - name: Set node version - uses: actions/setup-node@v6 - with: - node-version-file: package.json - cache: 'npm' - - run: npm ci - - run: FAKE_OIDC_ROOT_URL=http://localhost:9898 make fake-oidc-server-ci > fake-oidc-server.log & - - run: node lib/bin/create-docker-databases.js - - run: make test-oidc-integration - - name: Fake OIDC Server Logs - if: always() - run: "! [[ -f ./fake-oidc-server.log ]] || cat ./fake-oidc-server.log" diff --git a/.github/workflows/soak-test.yml b/.github/workflows/soak-test.yml deleted file mode 100644 index 2215a73d7..000000000 --- a/.github/workflows/soak-test.yml +++ /dev/null @@ -1,41 +0,0 @@ -name: Soak Test - -on: - push: - branches: master - -jobs: - soak-test: - timeout-minutes: 15 - # TODO should we use the same container as circle & central? - runs-on: ubuntu-latest - services: - # see: https://docs.github.com/en/enterprise-server@3.5/actions/using-containerized-services/creating-postgresql-service-containers - postgres: - image: postgres:14.20 - env: - POSTGRES_PASSWORD: odktest - ports: - - 5432:5432 - # Set health checks to wait until postgres has started - options: >- - --health-cmd pg_isready - --health-interval 1s - --health-timeout 5s - --health-retries 50 - steps: - - uses: actions/checkout@v6 - - run: ./test/e2e/soak/ci/prepare-postgres.sh - - name: Set node version - uses: actions/setup-node@v6 - with: - node-version-file: package.json - cache: 'npm' - - run: npm ci - - run: node lib/bin/create-docker-databases.js - - name: Soak Test - timeout-minutes: 10 - run: ./test/e2e/soak/ci/run-tests.sh - - name: Backend Logs - if: always() - run: "! [[ -f ./backend.log ]] || cat ./backend.log" diff --git a/.github/workflows/standard-e2e.yml b/.github/workflows/standard-e2e.yml deleted file mode 100644 index 5109f94b2..000000000 --- a/.github/workflows/standard-e2e.yml +++ /dev/null @@ -1,61 +0,0 @@ -name: Standard E2E Tests - -on: - push: - pull_request: - -env: - LOG_LEVEL: DEBUG - -jobs: - standard-e2e: - timeout-minutes: 15 - # TODO should we use the same container as circle & central? - runs-on: ubuntu-latest - services: - # see: https://docs.github.com/en/enterprise-server@3.5/actions/using-containerized-services/creating-postgresql-service-containers - postgres: - image: postgres:14.20 - env: - POSTGRES_PASSWORD: odktest - ports: - - 5432:5432 - # Set health checks to wait until postgres has started - options: >- - --health-cmd pg_isready - --health-interval 1s - --health-timeout 5s - --health-retries 50 - steps: - - uses: actions/checkout@v6 - - name: Set node version - uses: actions/setup-node@v6 - with: - node-version-file: package.json - cache: 'npm' - - run: npm ci - - run: node lib/bin/create-docker-databases.js - - - name: E2E Test - timeout-minutes: 10 - run: ./test/e2e/standard/run-tests.sh - - - uses: ./.github/actions/install-postgres-client - with: - postgres-version: 14 - - name: Grant postgres superuser role - # As per #1368, this role is required to create the pgrowlocks extension - run: psql -c 'ALTER ROLE jubilant SUPERUSER' postgresql://postgres:odktest@localhost/postgres - - name: Backup/restore tests - timeout-minutes: 10 - run: ./test/e2e/standard/backup-restore.sh - - name: Backup test - test detection of aborted backup process - sabotage DB - run: psql -c 'ALTER ROLE jubilant NOSUPERUSER; REVOKE SELECT ON TABLE knex_migrations FROM jubilant;' postgresql://postgres:odktest@localhost/jubilant - - name: Backup test - test detection of aborted backup process - timeout-minutes: 2 - run: ./test/e2e/standard/backup-abortstream.sh - - name: Backup test - test detection of aborted backup process - unsabotage DB - run: psql -c 'GRANT SELECT ON TABLE knex_migrations TO jubilant' postgresql://postgres:odktest@localhost/jubilant - - name: Backend Logs - if: always() - run: "! [[ -f ./server.log ]] || cat ./server.log" diff --git a/lib/external/s3.js b/lib/external/s3.js index ed4697007..fe56e7248 100644 --- a/lib/external/s3.js +++ b/lib/external/s3.js @@ -101,6 +101,13 @@ const init = (config) => { const isErrUpstream = err => err.name === 'S3Error' && err.code === 'InternalError'; const wrappedOrUnhandled = (err, operation, blobOrBlobs) => { const details = { amzRequestId: err.requestid, operation }; + + console.log('s3.wrappedOrUnhandled()', 'err:', err); // eslint-disable-line no-console + console.log('s3.wrappedOrUnhandled()', 'err.name:', err.name); // eslint-disable-line no-console + console.log('s3.wrappedOrUnhandled()', 'err.code:', err.code); // eslint-disable-line no-console + console.log('s3.wrappedOrUnhandled()', 'err.message:', err.message); // eslint-disable-line no-console + console.log('s3.wrappedOrUnhandled()', 'err.props:', Object.keys(err)); // eslint-disable-line no-console + if (isErrUpstream(err)) { if (Array.isArray(blobOrBlobs)) details.blobIds = blobOrBlobs.map(blob => blob.id); else details.blobId = blobOrBlobs.id; diff --git a/test/e2e/s3/test.js b/test/e2e/s3/test.js index 03f86bd23..026cfad54 100644 --- a/test/e2e/s3/test.js +++ b/test/e2e/s3/test.js @@ -15,6 +15,8 @@ const TIMEOUT = 240_000; // ms const { exec, execSync } = require('node:child_process'); const fs = require('node:fs'); const { randomBytes } = require('node:crypto'); + +const express = require('express'); const _ = require('lodash'); const should = require('should'); @@ -34,11 +36,16 @@ describe('s3 support', () => { const minioTerminated = () => { if(_minioTerminated) return; + log('Terminating minio...'); + + console.log(execSync('docker ps')); + // It should be possible to use docker more precisely here, e.g. // docker stop $(docker ps --quiet --filter "ancestor=minio/minio") // However, the ancestor filter requries specifying the exact tag used. // See: https://docs.docker.com/reference/cli/docker/container/ls/#ancestor execSync(`docker ps | awk '/minio/ { print $1 }' | xargs docker kill`); + console.log(execSync('docker ps')); _minioTerminated = true; }; @@ -304,6 +311,37 @@ describe('s3 support', () => { }); }); + describe('with minio 5xx', () => { + let server; + + before(() => { + minioTerminated(); + + const app = express(); + + app.all('/*', (req, res) => res.sendStatus(500)); + + return new Promise((resolve, reject) => { + server = app.listen(9000, err => { + if(err) return reject(err); + resolve(); + }); + }); + }); + + after(() => { + if(server) return new Promise(resolve => server.close(resolve)); // eslint-disable-line no-promise-executor-return + }); + + it('should handle upload failure gracefully', async () => { + throw new Error('implement me'); + }); + + it('should handle download failure gracefully', async () => { + await expectRejectionFrom(forSacrifice(cli('upload-pending')), /Error: TODO/); + }); + }); + // Guard against a Promise resolving when it was expected to reject. This has // specifically been seen when upload-pending returns immediately, but later // test code is expecting it to spend time uploading. In those cases, this @@ -420,6 +458,7 @@ function cli(cmd) { const promise = new Promise((resolve, reject) => { const child = exec(cmd, { env, cwd:'../../..' }, (err, stdout, stderr) => { + console.log({ stdout, stderr }); if (err) { err.stdout = stdout; // eslint-disable-line no-param-reassign err.stderr = stderr; // eslint-disable-line no-param-reassign