diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 75c6e1ff6659e3ffdafe74b814666de236fe784e..91d65299800a695cc7684ab763e43eb399548030 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -47,19 +47,6 @@ db_migrations_updated: - FLASK_APP=uffd FLASK_ENV=testing flask db upgrade - FLASK_APP=uffd FLASK_ENV=testing flask db migrate 2>&1 | grep -q 'No changes in schema detected' -test_db_migrations:sqlite: - stage: test - needs: [] - script: - - python3 check_migrations.py sqlite - -test_db_migrations:mysql: - stage: test - needs: [] - script: - - service mysql start - - python3 check_migrations.py mysql - linter:buster: image: registry.git.cccv.de/uffd/docker-images/buster stage: test @@ -88,12 +75,16 @@ linter:bullseye: reports: codequality: codeclimate.json -unittests:buster:sqlite: +tests:buster:sqlite: image: registry.git.cccv.de/uffd/docker-images/buster stage: test needs: [] script: - - python3-coverage run --include 'uffd/*.py' -m pytest --junitxml=report.xml || touch failed + - rm -rf pages + - mkdir -p pages + - cp -r uffd/static pages/static + - DUMP_PAGES=pages python3-coverage run --include 'uffd/*.py' -m pytest --junitxml=report.xml || touch failed + - sed -i -e 's/href="\/static\//href=".\/static\//g' -e 's/src="\/static\//src=".\/static\//g' pages/*.html || true - python3-coverage report -m - python3-coverage html - python3-coverage xml @@ -103,6 +94,7 @@ unittests:buster:sqlite: paths: - htmlcov/index.html - htmlcov + - pages expose_as: 'Coverage Report' reports: coverage_report: @@ -111,7 +103,7 @@ unittests:buster:sqlite: junit: report.xml coverage: '/^TOTAL.*\s+(\d+\%)$/' -unittests:buster:mysql: +tests:buster:mysql: image: registry.git.cccv.de/uffd/docker-images/buster stage: test needs: [] @@ -123,7 +115,7 @@ unittests:buster:mysql: reports: junit: report.xml -unittests:bullseye:sqlite: +tests:bullseye:sqlite: image: registry.git.cccv.de/uffd/docker-images/bullseye stage: test needs: [] @@ -134,7 +126,7 @@ unittests:bullseye:sqlite: reports: junit: report.xml -unittests:bullseye:mysql: +tests:bullseye:mysql: image: registry.git.cccv.de/uffd/docker-images/bullseye stage: test needs: [] @@ -148,13 +140,9 @@ unittests:bullseye:mysql: html5validator: stage: test - needs: [] + needs: + - job: tests:buster:sqlite script: - - rm -rf pages - - mkdir -p pages - - cp -r uffd/static pages/static - - DUMP_PAGES=pages python3 -m unittest discover tests/views - - sed -i -e 's/href="\/static\//href=".\/static\//g' -e 's/src="\/static\//src=".\/static\//g' pages/*.html - html5validator --root pages 2>&1 | tee html5validator.log artifacts: when: on_failure @@ -176,18 +164,18 @@ trans_de: test:package:pip:buster: image: registry.git.cccv.de/uffd/docker-images/buster stage: test + needs: + - job: build:pip script: - pip3 install dist/*.tar.gz - dependencies: - - build:pip test:package:pip:bullseye: image: registry.git.cccv.de/uffd/docker-images/bullseye stage: test + needs: + - job: build:pip script: - pip3 install dist/*.tar.gz - dependencies: - - build:pip # Since we want to test if the package installs correctly on a fresh Debian # install (has correct dependencies, etc.), we don't use uffd/docker-images @@ -195,6 +183,8 @@ test:package:pip:bullseye: test:package:apt:buster: image: ${CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX}/debian:buster stage: test + needs: + - job: build:apt before_script: [] script: - apt -y update @@ -204,12 +194,12 @@ test:package:apt:buster: - service nginx start || ( service nginx status; nginx -t; exit 1; ) - uffd-admin routes - curl -Lv 127.0.0.1:5000 - dependencies: - - build:apt test:package:apt:bullseye: image: ${CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX}/debian:bullseye stage: test + needs: + - job: build:apt before_script: [] script: - apt -y update @@ -219,8 +209,6 @@ test:package:apt:bullseye: - service nginx start || ( service nginx status; nginx -t; exit 1; ) - uffd-admin routes - curl -Lv 127.0.0.1:5000 - dependencies: - - build:apt .publish: stage: deploy diff --git a/check_migrations.py b/tests/migrations/test_fuzzy.py old mode 100755 new mode 100644 similarity index 52% rename from check_migrations.py rename to tests/migrations/test_fuzzy.py index 4c7d0af0e785fdbe91c04673b30c873cef5ce95e..7200267b7ba403c61850cf91d1ff2fe175be898b --- a/check_migrations.py +++ b/tests/migrations/test_fuzzy.py @@ -1,12 +1,8 @@ -#!/usr/bin/python3 import os import sys -import logging import datetime -import flask_migrate - -from uffd import create_app, db +from uffd.database import db from uffd.models import ( User, UserEmail, Group, RecoveryCodeMethod, TOTPMethod, WebauthnMethod, @@ -19,37 +15,32 @@ from uffd.models import ( PasswordToken, ) -def run_test(dburi, revision): - config = { - 'TESTING': True, - 'DEBUG': True, - 'SQLALCHEMY_DATABASE_URI': dburi, - 'SECRET_KEY': 'DEBUGKEY', - 'MAIL_SKIP_SEND': True, - 'SELF_SIGNUP': True, - 'ENABLE_INVITE': True, - 'ENABLE_PASSWORDRESET': True, - 'LDAP_SERVICE_MOCK': True, - 'OAUTH2_CLIENTS': { - 'test': { - 'service_name': 'test', - 'client_secret': 'testsecret', - 'redirect_uris': ['http://localhost:5004/oauthproxy/callback'], - 'logout_urls': ['http://localhost:5004/oauthproxy/logout'] - } - }, - 'API_CLIENTS_2': { +from tests.utils import MigrationTestCase + +class TestFuzzy(MigrationTestCase): + def setUpApp(self): + self.app.config['LDAP_SERVICE_MOCK'] = True + self.app.config['OAUTH2_CLIENTS'] = { + 'test': { + 'service_name': 'test', + 'client_secret': 'testsecret', + 'redirect_uris': ['http://localhost:5004/oauthproxy/callback'], + 'logout_urls': ['http://localhost:5004/oauthproxy/logout'] + } + } + self.app.config['API_CLIENTS_2'] = { 'test': { 'service_name': 'test', 'client_secret': 'testsecret', 'scopes': ['checkpassword', 'getusers', 'getmails'] }, - }, - } - app = create_app(config) - with app.test_request_context(): - flask_migrate.upgrade(revision='head') - # Add a few rows to all tables to make sure that the migrations work with data + } + + # Runs every upgrade/downgrade script with data. To do this we first upgrade + # to head, create data, then downgrade, upgrade, downgrade for every revision. + def test_migrations_fuzzy(self): + self.upgrade('head') + # Users and groups were created by 878b25c4fae7_ldap_to_db because we set LDAP_SERVICE_MOCK to True user = User.query.first() group = Group.query.first() db.session.add(RecoveryCodeMethod(user=user)) @@ -74,44 +65,8 @@ def run_test(dburi, revision): db.session.add(OAuth2DeviceLoginInitiation(client=oauth2_client, confirmations=[DeviceLoginConfirmation(user=user)])) db.session.add(PasswordToken(user=user)) db.session.commit() - flask_migrate.downgrade(revision=revision) - flask_migrate.upgrade(revision='head') - -if __name__ == '__main__': - if len(sys.argv) != 2 or sys.argv[1] not in ['sqlite', 'mysql']: - print('usage: check_migrations.py {sqlite|mysql}') - exit(1) - dbtype = sys.argv[1] - revs = [s.split('_', 1)[0] for s in os.listdir('uffd/migrations/versions') if '_' in s and s.endswith('.py')] + ['base'] - logging.getLogger().setLevel(logging.INFO) - failures = 0 - for rev in revs: - logging.info(f'Testing "upgrade to head, add objects, downgrade to {rev}, upgrade to head"') - # Cleanup/drop database - if dbtype == 'sqlite': - try: - os.remove('/tmp/uffd_check_migrations_db.sqlite3') - except FileNotFoundError: - pass - dburi = 'sqlite:////tmp/uffd_check_migrations_db.sqlite3' - elif dbtype == 'mysql': - import MySQLdb - conn = MySQLdb.connect(user='root', unix_socket='/var/run/mysqld/mysqld.sock') - cur = conn.cursor() - try: - cur.execute('DROP DATABASE uffd_tests') - except: - pass - cur.execute('CREATE DATABASE uffd_tests CHARACTER SET utf8mb4 COLLATE utf8mb4_nopad_bin') - conn.close() - dburi = 'mysql+mysqldb:///uffd_tests?unix_socket=/var/run/mysqld/mysqld.sock&charset=utf8mb4' - try: - run_test(dburi, rev) - except Exception as ex: - failures += 1 - logging.error('Test failed', exc_info=ex) - if failures: - logging.info(f'{failures} tests failed') - exit(1) - logging.info('All tests succeeded') - exit(0) + revs = [s.split('_', 1)[0] for s in os.listdir('uffd/migrations/versions') if '_' in s and s.endswith('.py')] + for rev in revs: + self.downgrade('-1') + self.upgrade('+1') + self.downgrade('-1')