Added tests for migrations

refs https://github.com/TryGhost/DevOps/issues/39

- up until now, we've had a CI job which does a really basic test for
  migrations, but it barely functions and misses bugs all the time
- this commit removes that and switches to an actual test suite for our
  migrations, so we can ensure they function as expected
- also removes the env var hack I came up with for those migrations
  tests
- this should lead to safer migrations and faster tests
This commit is contained in:
Daniel Lockyer 2023-07-05 09:36:23 +02:00 committed by Daniel Lockyer
parent ebad10e242
commit 289e459283
3 changed files with 57 additions and 83 deletions

View File

@ -78,9 +78,6 @@ jobs:
sodo-search:
- *shared
- 'apps/sodo-search/**'
migrations:
- *shared
- 'ghost/core/core/server/data/migrations/**'
any-code:
- '!**/*.md'
outputs:
@ -92,7 +89,6 @@ jobs:
changed_portal: ${{ steps.changed.outputs.portal }}
changed_signup_form: ${{ steps.changed.outputs.signup-form }}
changed_sodo_search: ${{ steps.changed.outputs.sodo-search }}
changed_migrations: ${{ steps.changed.outputs.migrations }}
changed_any_code: ${{ steps.changed.outputs.any-code }}
commit_label: '${{ env.COMMIT_SHA }}: ${{ env.COMMIT_MESSAGE }}'
is_git_sync: ${{ github.head_ref == 'main' || github.ref == 'refs/heads/main' }}
@ -209,72 +205,6 @@ jobs:
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
job_migrations:
runs-on: ubuntu-latest
needs: [job_get_metadata, job_install_deps]
if: needs.job_get_metadata.outputs.changed_migrations == 'true' && (github.event_name == 'push' || (github.event_name == 'pull_request' && !startsWith(github.head_ref, 'renovate/')))
strategy:
matrix:
env:
- DB: sqlite3
DB_CLIENT: sqlite3
- DB: mysql8
DB_CLIENT: mysql
env:
database__client: ${{ matrix.env.DB_CLIENT }}
name: Migrations checks (${{ matrix.env.DB }})
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
submodules: true
- uses: actions/setup-node@v3
env:
FORCE_COLOR: 0
with:
node-version: '18.12.1'
- name: Shutdown MySQL
run: sudo service mysql stop
if: matrix.env.DB == 'mysql8'
- uses: daniellockyer/mysql-action@main
if: matrix.env.DB == 'mysql8'
with:
authentication plugin: 'caching_sha2_password'
mysql version: '8.0'
mysql database: 'ghost_testing'
mysql root password: 'root'
- name: Set env vars (SQLite)
if: contains(matrix.env.DB, 'sqlite')
run: echo "database__connection__filename=/dev/shm/ghost-test.db" >> $GITHUB_ENV
- name: Set env vars (MySQL)
if: contains(matrix.env.DB, 'mysql')
run: |
echo "database__connection__host=127.0.0.1" >> $GITHUB_ENV
echo "database__connection__user=root" >> $GITHUB_ENV
echo "database__connection__password=root" >> $GITHUB_ENV
echo "database__connection__database=ghost_testing" >> $GITHUB_ENV
- name: Restore caches
uses: ./.github/actions/restore-cache
env:
DEPENDENCY_CACHE_KEY: ${{ needs.job_install_deps.outputs.dependency_cache_key }}
- name: Run Ghost and then kill it
run: yarn workspace ghost run start
env:
GHOST_TESTS_KILL_SERVER_AFTER_BOOT: true
- run: sqlite3 ${{ env.database__connection__filename }} "DELETE FROM migrations WHERE version LIKE '5.%';"
if: matrix.env.DB == 'sqlite3'
- run: mysql -h127.0.0.1 -uroot -proot ghost_testing -e "DELETE FROM migrations WHERE version LIKE '5.%';"
if: matrix.env.DB == 'mysql8'
- run: yarn knex-migrator migrate --force
job_unit-tests:
runs-on: ubuntu-latest
needs: [job_get_metadata, job_install_deps]
@ -768,7 +698,6 @@ jobs:
job_lint,
job_ghost-cli,
job_admin-tests,
job_migrations,
job_unit-tests,
job_database-tests,
job_regression-tests,
@ -790,7 +719,6 @@ jobs:
job_lint,
job_ghost-cli,
job_admin-tests,
job_migrations,
job_unit-tests,
job_database-tests,
job_regression-tests

View File

@ -536,14 +536,6 @@ async function bootGhost({backend = true, frontend = true, server = true} = {})
// Step 7 - Init our background services, we don't wait for this to finish
initBackgroundServices({config});
// Step 8 - Kill the process - what??
// During the migration tests, we want to boot ghost, run migrations, then shut down
// This is the easiest way to get Ghost to boot and then kill itself
if (process.env.GHOST_TESTS_KILL_SERVER_AFTER_BOOT === 'true') {
debug('Killing Ghost Server after boot');
process.exit(0);
}
// We return the server purely for testing purposes
if (server) {
debug('End Boot: Returning Ghost Server');

View File

@ -4,13 +4,67 @@ const testUtils = require('../../utils');
const _ = require('lodash');
const Models = require('../../../core/server/models');
describe('Database Migration (special functions)', function () {
before(testUtils.teardownDb);
afterEach(testUtils.teardownDb);
const KnexMigrator = require('knex-migrator');
const path = require('path');
const semver = require('semver');
const knexMigrator = new KnexMigrator({
knexMigratorFilePath: path.join(__dirname, '../../../')
});
const db = require('../../../core/server/data/db');
const dbUtils = require('../../utils/db-utils');
const currentVersion = require('@tryghost/version');
const currentMajor = semver.major(currentVersion.original);
const previousMinor = semver.minor(currentVersion.original) - 1;
const previousVersion = `${currentMajor}.${previousMinor}`;
describe('Migrations', function () {
beforeEach(async function () {
await dbUtils.teardown();
});
afterEach(function () {
sinon.restore();
});
describe('Database initialization + rollback', function () {
beforeEach(async function () {
await knexMigrator.init();
});
it('can rollback to the previous minor version', async function () {
await knexMigrator.rollback({
version: previousVersion,
force: true
});
});
it('can rollback to the previous minor version and then forwards again', async function () {
await knexMigrator.rollback({
version: previousVersion,
force: true
});
await knexMigrator.migrate({
force: true
});
});
it('should have idempotent migrations', async function () {
// Delete all knowledge that we've run migrations so we can run them again
if (dbUtils.isMySQL()) {
await db.knex('migrations').whereILike('version', `${currentMajor}.%`).del();
} else {
await db.knex('migrations').whereLike('version', `${currentMajor}.%`).del();
}
await knexMigrator.migrate({
force: true
});
});
});
describe('Fixtures', function () {
// Custom assertion for detection that a permissions is assigned to the correct roles
should.Assertion.add('AssignedToRoles', function (roles) {