Problem
I’m trying to set up a test stage in Gitlab’s CI/CD. Locally, running the unit tests goes fine and as expected. In Gitlab’s CI/CD, though, when running the script coverage run manage.py test -v 2 && coverage report
the unit tests are executing before the migrations are completed in the test database, which is unexpected, and will always fail. Migrations on the test database need to run prior to unit tests executing.
Any idea why this behavior might happen?
When running python manage.py test
these are the steps that happen by default:
Creation of test databases.
Database migration.
Run system checks.
Running tests.
Report on the number of tests and success / failure.
Removing test databases.
In the local test run output below, you can see those exact steps, in that sequence happening. The problem is that in Gitlab’s CI/CD pipeline, step 2 and 4 are switched for some mysterious reason to me.
Things I’ve already tried
- Removing coverage, and only executing
python manage.py test
Result: same error - Removing user test, where Gitlab says the test fails: Result: same error
- Removing all but one unit test to attempt to isolate: Result: same error
- Adding and activating a virtual environment inside Gitlab’s container: Result: same error
- Trying a SQLite3: Result: migrations fail due to necessary array field necessary in the project not supported in SQLite3
Gitlab CI/CD Output
My actual output is much bigger. But here’s the relevant parts:
$ echo $TEST_SECRETS | base64 -d > config/settings/local.py
$ echo RUNNING UNIT TESTS
RUNNING UNIT TESTS
$ coverage run manage.py test -v 2 && coverage report
Creating test database for alias 'default' ('test_mia')
test_dataconnector_category_creation_delete (apps.core.tests.test_models.DataConnectorCategoryTestCase)
Verify data connector category creation ok
test_compare_airbytesetting (apps.services.tests.test_model_airbytesetting.AirbyteSettingModel_TestClass)
Compare object from self.airbytesetting to ensure data is in proper format. ok
test_fieldconstraints_airbytesetting (apps.services.tests.test_model_airbytesetting.AirbyteSettingModel_TestClass)
Compares Field Constraint Values for Accuracy ok
test_update_airbytesetting (apps.services.tests.test_model_airbytesetting.AirbyteSettingModel_TestClass)
Test updating values in self.airbytesetting and saving that to the test database. ok
test_compare_airbytesource (apps.services.tests.test_model_airbytesource.AirbyteSourceModel_TestClass)
Compare object from self.airbytesource to ensure data is in proper format. ok
test_delete_airbytesource (apps.services.tests.test_model_airbytesource.AirbyteSourceModel_TestClass)
Test Deleting self.airbytesource object from database ok
test_fieldconstraints_airbytesource (apps.services.tests.test_model_airbytesource.AirbyteSourceModel_TestClass)
Compares Field Constraint Values for Accuracy ok
test_update_airbytesource (apps.services.tests.test_model_airbytesource.AirbyteSourceModel_TestClass)
Test updating values in self.airbytesource and saving that to the test database. ok
test_compare_airbytestream (apps.services.tests.test_model_airbytestream.AirbyteStreamModel_TestClass)
Compare object from self.airbytestream to ensure data is in proper format. ok
test_delete_airbytestream (apps.services.tests.test_model_airbytestream.AirbyteStreamModel_TestClass)
Test Deleting self.airbytestream object from database ok
test_fieldconstraints_airbytestream (apps.services.tests.test_model_airbytestream.AirbyteStreamModel_TestClass)
Compares Field Constraint Values for Accuracy ok
test_update_airbytestream (apps.services.tests.test_model_airbytestream.AirbyteStreamModel_TestClass)
Test updating values in self.airbytestream and saving that to the test database. ok
test_compare_airbytesynccatalog (apps.services.tests.test_model_airbytesynccatalog.AirbyteSyncCatalogModel_TestClass)
Compare object from self.airbytesynccatalog to ensure data is in proper format. ok
test_delete_airbytesynccatalog (apps.services.tests.test_model_airbytesynccatalog.AirbyteSyncCatalogModel_TestClass)
Test Deleting self.airbytesynccatalog object from database ok
test_fieldconstraints_airbytesynccatalog (apps.services.tests.test_model_airbytesynccatalog.AirbyteSyncCatalogModel_TestClass)
Compares Field Constraint Values for Accuracy ok
test_update_airbytesynccatalog (apps.services.tests.test_model_airbytesynccatalog.AirbyteSyncCatalogModel_TestClass)
Test updating values in self.airbytesynccatalog and saving that to the test database. ok
test_compare_tableausetting (apps.services.tests.test_model_tableausetting.TableauSettingModel_TestClass)
Compare object from self.tableausetting to ensure data is in proper format. ok
test_createrandom_tableausetting (apps.services.tests.test_model_tableausetting.TableauSettingModel_TestClass)
Test Creating a New (Second) TableauSetting Model Object with Random Values. ok
test_delete_tableausetting (apps.services.tests.test_model_tableausetting.TableauSettingModel_TestClass)
Test Deleting self.tableausetting object from database ok
test_fieldconstraints_tableausetting (apps.services.tests.test_model_tableausetting.TableauSettingModel_TestClass)
Compares Field Constraint Values for Accuracy ok
test_update_tableausetting (apps.services.tests.test_model_tableausetting.TableauSettingModel_TestClass)
Test updating values in self.tableausetting and saving that to the test database. ok
test_get_namespace_custom_format (apps.services.tests.test_scripts_airbyte.ServicesTestCase)
TO-DO: this method should live in AirByte class ok
test_retrieve_me_user (apps.user.tests.test_views.UserViewTest) ok
test_retrieve_user (apps.user.tests.test_views.UserViewTest) ok
apps.user.tests.test_models (unittest.loader._FailedTest) ERROR
======================================================================
ERROR: apps.user.tests.test_models (unittest.loader._FailedTest)
----------------------------------------------------------------------
ImportError: Failed to import test module: apps.user.tests.test_models
Traceback (most recent call last):
File "/usr/local/lib/python3.8/site-packages/django/db/backends/utils.py", line 84, in _execute
return self.cursor.execute(sql, params)
psycopg2.errors.UndefinedTable: relation "user_user" does not exist
LINE 1: INSERT INTO "user_user" ("password", "last_login", "is_super...
^
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/usr/local/lib/python3.8/unittest/loader.py", line 436, in _find_test_path
module = self._get_module_from_name(name)
File "/usr/local/lib/python3.8/unittest/loader.py", line 377, in _get_module_from_name
__import__(name)
File "/builds/americommerce/mia/mia-ms-main/apps/user/tests/test_models.py", line 3, in <module>
from apps.user.tests.factories import UserFactory, CompanyFactory, SignUpTokenFactory
File "/builds/americommerce/mia/mia-ms-main/apps/user/tests/factories.py", line 23, in <module>
class SignUpTokenFactory(factory.django.DjangoModelFactory):
File "/builds/americommerce/mia/mia-ms-main/apps/user/tests/factories.py", line 28, in SignUpTokenFactory
user = UserFactory()
File "/usr/local/lib/python3.8/site-packages/factory/base.py", line 40, in __call__
return cls.create(**kwargs)
File "/usr/local/lib/python3.8/site-packages/factory/base.py", line 528, in create
return cls._generate(enums.CREATE_STRATEGY, kwargs)
File "/usr/local/lib/python3.8/site-packages/factory/django.py", line 117, in _generate
return super()._generate(strategy, params)
File "/usr/local/lib/python3.8/site-packages/factory/base.py", line 465, in _generate
return step.build()
File "/usr/local/lib/python3.8/site-packages/factory/builder.py", line 262, in build
instance = self.factory_meta.instantiate(
File "/usr/local/lib/python3.8/site-packages/factory/base.py", line 317, in instantiate
return self.factory._create(model, *args, **kwargs)
File "/usr/local/lib/python3.8/site-packages/factory/django.py", line 166, in _create
return manager.create(*args, **kwargs)
File "/usr/local/lib/python3.8/site-packages/django/db/models/manager.py", line 85, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/usr/local/lib/python3.8/site-packages/django/db/models/query.py", line 447, in create
obj.save(force_insert=True, using=self.db)
File "/usr/local/lib/python3.8/site-packages/django/contrib/auth/base_user.py", line 67, in save
super().save(*args, **kwargs)
File "/usr/local/lib/python3.8/site-packages/django/db/models/base.py", line 753, in save
self.save_base(using=using, force_insert=force_insert,
File "/usr/local/lib/python3.8/site-packages/django/db/models/base.py", line 790, in save_base
updated = self._save_table(
File "/usr/local/lib/python3.8/site-packages/django/db/models/base.py", line 895, in _save_table
results = self._do_insert(cls._base_manager, using, fields, returning_fields, raw)
File "/usr/local/lib/python3.8/site-packages/django/db/models/base.py", line 933, in _do_insert
return manager._insert(
File "/usr/local/lib/python3.8/site-packages/django/db/models/manager.py", line 85, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/usr/local/lib/python3.8/site-packages/django/db/models/query.py", line 1254, in _insert
return query.get_compiler(using=using).execute_sql(returning_fields)
File "/usr/local/lib/python3.8/site-packages/django/db/models/sql/compiler.py", line 1397, in execute_sql
cursor.execute(sql, params)
File "/usr/local/lib/python3.8/site-packages/sentry_sdk/integrations/django/__init__.py", line 508, in execute
return real_execute(self, sql, params)
File "/usr/local/lib/python3.8/site-packages/django/db/backends/utils.py", line 66, in execute
return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
File "/usr/local/lib/python3.8/site-packages/django/db/backends/utils.py", line 75, in _execute_with_wrappers
return executor(sql, params, many, context)
File "/usr/local/lib/python3.8/site-packages/django/db/backends/utils.py", line 84, in _execute
return self.cursor.execute(sql, params)
File "/usr/local/lib/python3.8/site-packages/django/db/utils.py", line 90, in __exit__
raise dj_exc_value.with_traceback(traceback) from exc_value
File "/usr/local/lib/python3.8/site-packages/django/db/backends/utils.py", line 84, in _execute
return self.cursor.execute(sql, params)
django.db.utils.ProgrammingError: relation "user_user" does not exist
LINE 1: INSERT INTO "user_user" ("password", "last_login", "is_super...
^
----------------------------------------------------------------------
Ran 25 tests in 0.648s
FAILED (errors=1)
Destroying test database for alias 'default' ('test_mia')
Operations to perform:
Synchronize unmigrated apps: corsheaders, debug_toolbar, delete_migrations, django_filters, generic_relations, messages, mptt, rest_framework, rest_framework_jwt, rest_framework_swagger, staticfiles
Apply all migrations: admin, auth, contenttypes, core, dashboard, reports, services, sessions, store, user
Synchronizing apps without migrations:
Creating tables
Running deferred SQL
Running migrations:
Applying contenttypes.0001_initial OK
Applying contenttypes.0002_remove_content_type_name OK
Applying auth.0001_initial OK
Applying auth.0002_alter_permission_name_max_length OK
Applying auth.0003_alter_user_email_max_length OK
Applying auth.0004_alter_user_username_opts OK
Applying auth.0005_alter_user_last_login_null OK
Applying auth.0006_require_contenttypes_0002 OK
Applying auth.0007_alter_validators_add_error_messages OK
Applying auth.0008_alter_user_username_max_length OK
Applying auth.0009_alter_user_last_name_max_length OK
Applying auth.0010_alter_group_name_max_length OK
Applying auth.0011_update_proxy_permissions OK
Applying auth.0012_alter_user_first_name_max_length OK
Applying user.0001_initial OK
Applying admin.0001_initial OK
Applying admin.0002_logentry_remove_auto_add OK
Applying admin.0003_logentry_add_action_flag_choices OK
Applying store.0001_initial OK
Applying dashboard.0001_initial OK
Applying core.0001_initial OK
Applying reports.0001_initial OK
Applying reports.0002_emailreport_store OK
Applying reports.0003_initial OK
Applying reports.0004_remove_emailreport_segments OK
Applying core.0002_dataconnectorcategory OK
Applying core.0003_auto_20220331_1610 OK
Applying core.0004_delete_segment OK
Applying dashboard.0002_auto_20220331_1804 OK
Applying dashboard.0003_flag_tableauview_widget_widgetsection OK
Applying reports.0005_emailreport_segments OK
Applying services.0001_initial OK
Applying services.0002_auto_20220325_0426 OK
Applying services.0003_auto_20220331_1610 OK
Applying sessions.0001_initial OK
Applying store.0002_initial OK
Applying store.0003_storefrontdataconnector OK
Applying user.0002_auto_20220325_0426 OK
Applying user.0003_auto_20220331_1610 OK
Applying user.0004_auto_20220331_1804 OK
Applying user.0005_user_flags OK
System check identified no issues (0 silenced).
Cleaning up project directory and file based variables
00:01
ERROR: Job failed: exit code 1
Local Test Run Output
Creating test database for alias 'default' ('test_mia')
Operations to perform:
Synchronize unmigrated apps: corsheaders, debug_toolbar, delete_migrations, django_filters, generic_relations, messages, mptt, rest_framework, rest_framework_jwt, rest_framework_swagger, staticfiles
Apply all migrations: admin, auth, contenttypes, core, dashboard, reports, services, sessions, store, user
Synchronizing apps without migrations:
Creating tables
Running deferred SQL
Running migrations:
Applying contenttypes.0001_initial OK
Applying contenttypes.0002_remove_content_type_name OK
Applying auth.0001_initial OK
Applying auth.0002_alter_permission_name_max_length OK
Applying auth.0003_alter_user_email_max_length OK
Applying auth.0004_alter_user_username_opts OK
Applying auth.0005_alter_user_last_login_null OK
Applying auth.0006_require_contenttypes_0002 OK
Applying auth.0007_alter_validators_add_error_messages OK
Applying auth.0008_alter_user_username_max_length OK
Applying auth.0009_alter_user_last_name_max_length OK
Applying auth.0010_alter_group_name_max_length OK
Applying auth.0011_update_proxy_permissions OK
Applying auth.0012_alter_user_first_name_max_length OK
Applying user.0001_initial OK
Applying admin.0001_initial OK
Applying admin.0002_logentry_remove_auto_add OK
Applying admin.0003_logentry_add_action_flag_choices OK
Applying store.0001_initial OK
Applying dashboard.0001_initial OK
Applying core.0001_initial OK
Applying reports.0001_initial OK
Applying reports.0002_emailreport_store OK
Applying reports.0003_initial OK
Applying reports.0004_remove_emailreport_segments OK
Applying core.0002_dataconnectorcategory OK
Applying core.0003_auto_20220331_1610 OK
Applying core.0004_delete_segment OK
Applying dashboard.0002_auto_20220331_1804 OK
Applying dashboard.0003_flag_tableauview_widget_widgetsection OK
Applying reports.0005_emailreport_segments OK
Applying services.0001_initial OK
Applying services.0002_auto_20220325_0426 OK
Applying services.0003_auto_20220331_1610 OK
Applying sessions.0001_initial OK
Applying store.0002_initial OK
Applying store.0003_storefrontdataconnector OK
Applying user.0002_auto_20220325_0426 OK
Applying user.0003_auto_20220331_1610 OK
Applying user.0004_auto_20220331_1804 OK
Applying user.0005_user_flags OK
System check identified no issues (0 silenced).
test_dataconnector_category_creation_delete (apps.core.tests.test_models.DataConnectorCategoryTestCase)
Verify data connector category creation ok
test_compare_airbytesetting (apps.services.tests.test_model_airbytesetting.AirbyteSettingModel_TestClass)
Compare object from self.airbytesetting to ensure data is in proper format. ok
test_fieldconstraints_airbytesetting (apps.services.tests.test_model_airbytesetting.AirbyteSettingModel_TestClass)
Compares Field Constraint Values for Accuracy ok
test_update_airbytesetting (apps.services.tests.test_model_airbytesetting.AirbyteSettingModel_TestClass)
Test updating values in self.airbytesetting and saving that to the test database. ok
test_compare_airbytesource (apps.services.tests.test_model_airbytesource.AirbyteSourceModel_TestClass)
Compare object from self.airbytesource to ensure data is in proper format. ok
test_delete_airbytesource (apps.services.tests.test_model_airbytesource.AirbyteSourceModel_TestClass)
Test Deleting self.airbytesource object from database ok
test_fieldconstraints_airbytesource (apps.services.tests.test_model_airbytesource.AirbyteSourceModel_TestClass)
Compares Field Constraint Values for Accuracy ok
test_update_airbytesource (apps.services.tests.test_model_airbytesource.AirbyteSourceModel_TestClass)
Test updating values in self.airbytesource and saving that to the test database. ok
test_compare_airbytestream (apps.services.tests.test_model_airbytestream.AirbyteStreamModel_TestClass)
Compare object from self.airbytestream to ensure data is in proper format. ok
test_delete_airbytestream (apps.services.tests.test_model_airbytestream.AirbyteStreamModel_TestClass)
Test Deleting self.airbytestream object from database ok
test_fieldconstraints_airbytestream (apps.services.tests.test_model_airbytestream.AirbyteStreamModel_TestClass)
Compares Field Constraint Values for Accuracy ok
test_update_airbytestream (apps.services.tests.test_model_airbytestream.AirbyteStreamModel_TestClass)
Test updating values in self.airbytestream and saving that to the test database. ok
test_compare_airbytesynccatalog (apps.services.tests.test_model_airbytesynccatalog.AirbyteSyncCatalogModel_TestClass)
Compare object from self.airbytesynccatalog to ensure data is in proper format. ok
test_delete_airbytesynccatalog (apps.services.tests.test_model_airbytesynccatalog.AirbyteSyncCatalogModel_TestClass)
Test Deleting self.airbytesynccatalog object from database ok
test_fieldconstraints_airbytesynccatalog (apps.services.tests.test_model_airbytesynccatalog.AirbyteSyncCatalogModel_TestClass)
Compares Field Constraint Values for Accuracy ok
test_update_airbytesynccatalog (apps.services.tests.test_model_airbytesynccatalog.AirbyteSyncCatalogModel_TestClass)
Test updating values in self.airbytesynccatalog and saving that to the test database. ok
test_compare_tableausetting (apps.services.tests.test_model_tableausetting.TableauSettingModel_TestClass)
Compare object from self.tableausetting to ensure data is in proper format. ok
test_createrandom_tableausetting (apps.services.tests.test_model_tableausetting.TableauSettingModel_TestClass)
Test Creating a New (Second) TableauSetting Model Object with Random Values. ok
test_delete_tableausetting (apps.services.tests.test_model_tableausetting.TableauSettingModel_TestClass)
Test Deleting self.tableausetting object from database ok
test_fieldconstraints_tableausetting (apps.services.tests.test_model_tableausetting.TableauSettingModel_TestClass)
Compares Field Constraint Values for Accuracy ok
test_update_tableausetting (apps.services.tests.test_model_tableausetting.TableauSettingModel_TestClass)
Test updating values in self.tableausetting and saving that to the test database. ok
test_get_namespace_custom_format (apps.services.tests.test_scripts_airbyte.ServicesTestCase)
TO-DO: this method should live in AirByte class ok
test_company_creation (apps.user.tests.test_models.UserTestCase)
Verify Company creation ok
test_signup_token_creation (apps.user.tests.test_models.UserTestCase)
Verify token creation ok
test_user_creation (apps.user.tests.test_models.UserTestCase)
Verify User creation ok
test_user_creation_with_company (apps.user.tests.test_models.UserTestCase)
Verify User can be assigned company ok
test_user_creation_with_signup_token (apps.user.tests.test_models.UserTestCase)
Verify User can be assigned token ok
test_retrieve_me_user (apps.user.tests.test_views.UserViewTest) ok
test_retrieve_user (apps.user.tests.test_views.UserViewTest) ok
----------------------------------------------------------------------
Ran 29 tests in 0.521s
OK
Destroying test database for alias 'default' ('test_mia')
Name Stmts Miss Cover
---------------------------------------------------------------------
apps/core/admin.py 5 0 100%
apps/core/exceptions.py 22 3 86%
apps/core/mixins.py 10 3 70%
apps/core/models.py 8 1 88%
apps/core/serializers.py 18 0 100%
apps/core/urls.py 5 0 100%
apps/core/utils.py 69 33 52%
apps/core/views.py 42 26 38%
apps/dashboard/admin.py 15 0 100%
apps/dashboard/models.py 34 7 79%
apps/dashboard/urls.py 6 0 100%
apps/dashboard/views.py 27 16 41%
apps/delete_migrations/admin.py 1 0 100%
apps/delete_migrations/models.py 1 0 100%
apps/reports/admin.py 14 0 100%
apps/reports/mixins.py 16 9 44%
apps/reports/models/alert.py 47 3 94%
apps/reports/models/email_report.py 31 1 97%
apps/reports/serializers/alert.py 49 14 71%
apps/reports/serializers/email_report.py 49 22 55%
apps/reports/tasks.py 71 43 39%
apps/reports/urls.py 9 0 100%
apps/reports/utils.py 12 9 25%
apps/reports/views/alerts.py 40 23 42%
apps/reports/views/reports.py 55 26 53%
apps/services/admin.py 23 6 74%
apps/services/models/airbyte.py 37 0 100%
apps/services/models/tableau.py 9 0 100%
apps/services/scripts/airbyte.py 157 126 20%
apps/services/scripts/tableau.py 69 50 28%
apps/services/urls.py 3 0 100%
apps/services/views.py 15 8 47%
apps/store/admin.py 41 0 100%
apps/store/mixins.py 12 7 42%
apps/store/models/amazon_ads.py 18 2 89%
apps/store/models/amazon_seller_partner.py 21 2 90%
apps/store/models/data_connector_base.py 28 5 82%
apps/store/models/data_connector_settings.py 18 3 83%
apps/store/models/facebook.py 17 2 88%
apps/store/models/google_ads.py 20 2 90%
apps/store/models/google_analytics.py 18 2 89%
apps/store/models/google_search_console.py 18 2 89%
apps/store/models/hubspot.py 14 2 86%
apps/store/models/klaviyo.py 12 1 92%
apps/store/models/mailchimp.py 14 2 86%
apps/store/models/shopify.py 17 2 88%
apps/store/models/store.py 13 3 77%
apps/store/models/storefront.py 19 8 58%
apps/store/serializers/amazon_ads.py 22 11 50%
apps/store/serializers/amazon_seller_partner.py 26 14 46%
apps/store/serializers/base.py 8 0 100%
apps/store/serializers/credentials.py 3 0 100%
apps/store/serializers/facebook.py 15 7 53%
apps/store/serializers/google_ads.py 23 12 48%
apps/store/serializers/google_analytics.py 22 11 50%
apps/store/serializers/google_search_console.py 22 11 50%
apps/store/serializers/hubspot.py 6 0 100%
apps/store/serializers/klaviyo.py 6 0 100%
apps/store/serializers/list_data_connectors.py 24 0 100%
apps/store/serializers/mailchimp.py 6 0 100%
apps/store/serializers/shopify.py 21 10 52%
apps/store/serializers/store.py 30 3 90%
apps/store/serializers/storefront.py 6 0 100%
apps/store/tasks.py 104 80 23%
apps/store/urls.py 26 0 100%
apps/store/utils.py 89 66 26%
apps/store/views/check_data_connector_store.py 21 13 38%
apps/store/views/credentials.py 13 3 77%
apps/store/views/delete_data_connector.py 19 10 47%
apps/store/views/detail_data_connectors.py 42 0 100%
apps/store/views/list_data_connectors.py 50 32 36%
apps/store/views/reset_data_connector.py 18 9 50%
apps/store/views/store.py 15 8 47%
apps/store/views/sync_data_connector.py 18 9 50%
apps/user/admin.py 29 7 76%
apps/user/apps.py 5 0 100%
apps/user/forms.py 14 1 93%
apps/user/models.py 72 13 82%
apps/user/serializers.py 88 31 65%
apps/user/signals.py 11 4 64%
apps/user/tasks.py 15 6 60%
apps/user/urls.py 7 0 100%
apps/user/utils.py 4 0 100%
apps/user/validators.py 7 2 71%
apps/user/views.py 61 26 57%
manage.py 13 6 54%
---------------------------------------------------------------------
TOTAL 2250 879 61%
.gitlab-ci.yml file
My actual file is much bigger. But here’s the relevant parts:
services:
- docker:20.10.7-dind
- postgres:latest
stages:
- test
variables:
POSTGRES_DB: test_mia
POSTGRES_USER: mia_dev
POSTGRES_PASSWORD: test123
build_test_db:
image: postgres
script:
- export PGPASSWORD=$POSTGRES_PASSWORD
- psql -h "postgres" -U "$POSTGRES_USER" -d "$POSTGRES_DB" -c "SELECT 'OK' AS status;"
test:
image: python:3.8-slim-buster
stage: test
before_script:
- |
apt-get update && apt-get install -y --no-install-recommends
gcc
musl-dev
python3-dev
libpq-dev
libgnutls28-dev
git
&& rm -rf /var/lib/apt/lists/*
- python -m pip install --upgrade pip
- pip install uwsgi
- pip install -r requirements.txt
- echo $TEST_SECRETS | base64 -d > config/settings/local.py
script:
- echo RUNNING UNIT TESTS
- coverage run manage.py test -v 2 && coverage report
needs:
- ["build_test_db"]
environment: test
# only:
# - develop
Advertisement
Answer
Add a python manage.py migrate
line before coverage run manage.py test ...
in the scripts section of your gitlab-ci.yml
.