rDrama/files/tests/test_migrations_up_to_date.py
faul-sname 4892b58d10
Add migrations using alembic.
* #39 Add Flask-Migrate dep

* #39 Make it such that flask db init can run

https://github.com/miguelgrinberg/Flask-Migrate/issues/196#issuecomment-381343393

* Run flask db init, update migrations.env, commit artifacts

* Set up a script such that you can `docker-compose exec files bash -c 'cd /service; FLASK_APP="files/cli:app" flask '` and have it do whatever flask thing you want

* Fix circular dependency

* import * is evil

* Initial alembic migration, has issues with constraints and nullable columns

* Bring alts table up to date with alembic autogenerate

* Rerun flask db revision autogenerate

* Bring award_relationships table up to date with alembic autogenerate

* [#39/alembic] files/classes/__init__.py is evil but is at least explicitly evil now

* #39 fix model in files/classes/badges.py

* #39 fix model in files/classes/domains.py and files/classes/clients.py

* #39 fix models: comment saves, comment flags

* #39 fix models: comments

* Few more imports

* #39 columns that are not nullable should be flagged as not nullable

* #39 Add missing indexes to model defs

* [#39] add missing unique constraints to model defs

* [#39] Temporarily undo any model changes which cause the sqlalchemy model to be out of sync with the actual dump

* #39 Deforeignkeyify the correct column to make alembic happy

* #39 flask db revision --autogenerate now creates an empty migration

* #39 Migration format such that files are listed in creation order

* #39 Better first revision

* #39 Revert the model changes that were required to get to zero differences between db revision --autogenerate and the existing schema

* #39 The first real migration

* #39 Ensure that foreign key constraints are named in migration

* #39 Alembic migrations for FK constraints, column defs

* [#39] Run DB migrations before starting tests

* [#39] New test to ensure migrations are up to date

* [#39] More descriptive test failure message

* Add -T flag to docker-compose exec

* [#39] Run alembic migrations when starting the container
2022-05-17 18:55:17 -05:00

78 lines
2.5 KiB
Python

import inspect
import migrations.versions
import os
import subprocess
from files.__main__ import app
APP_PATH = app.root_path
BASE_PATH = os.path.join(*os.path.split(APP_PATH)[:-1])
VERSIONS_PATH = migrations.versions.__path__._path[0];
def test_migrations_up_to_date():
def get_versions():
all_versions = [f.path for f in os.scandir(VERSIONS_PATH)]
filtered_versions = []
for entry in all_versions:
if not os.path.isfile(entry):
continue
*dir_parts, filename = os.path.split(entry)
base, ext = os.path.splitext(filename)
if ext == '.py':
filtered_versions.append(entry)
return filtered_versions
def get_method_body_lines(method):
method_lines, _ = inspect.getsourcelines(method)
return [l.strip() for l in method_lines if not l.strip().startswith('#')][1:]
versions_before = get_versions()
result = subprocess.run(
[
'python3',
'-m',
'flask',
'db',
'revision',
'--autogenerate',
'--rev-id=ci_verify_empty_revision',
'--message=should_be_empty',
],
cwd=BASE_PATH,
env={
**os.environ,
'FLASK_APP': 'files/cli:app',
},
capture_output=True,
text=True,
check=True
)
versions_after = get_versions()
new_versions = [v for v in versions_after if v not in versions_before]
try:
for version in new_versions:
filename = os.path.split(version)[-1]
base, ext = os.path.splitext(filename)
__import__(f'migrations.versions.{base}')
migration = getattr(migrations.versions, base)
upgrade_lines = get_method_body_lines(migration.upgrade)
assert ["pass"] == upgrade_lines, "\n".join([
"",
"Expected upgrade script to be empty (pass) but got",
*[f"\t>\t{l}" for l in upgrade_lines],
"To fix this issue, please run",
"\t$ flask db revision --autogenerate --message='short description of schema changes'",
"to generate a candidate migration, and make any necessary changes to that candidate migration (e.g. naming foreign key constraints)",
])
downgrade_lines = get_method_body_lines(migration.downgrade)
assert ["pass"] == downgrade_lines, "\n".join([
"",
"Expected downgrade script to be empty (pass) but got",
*[f"\t>{l}" for l in downgrade_lines],
"To fix this issue, please run",
"\tflask db revision --autogenerate --message='short description of schema changes'",
"to generate a candidate migration, and make any necessary changes to that candidate migration (e.g. naming foreign key constraints)",
])
finally:
for version in new_versions:
os.remove(version)