Skip to content
Advertisement

Gitlab CI/CD Pipeline Runs Django Unit Tests Before Migrations

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:

  1. Creation of test databases.

  2. Database migration.

  3. Run system checks.

  4. Running tests.

  5. Report on the number of tests and success / failure.

  6. 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.

User contributions licensed under: CC BY-SA
1 People found this is helpful
Advertisement