diff --git a/news/migrations/0010_news_audience_newscomment.py b/news/migrations/0010_news_audience_newscomment.py index 0431fd93..903f341d 100644 --- a/news/migrations/0010_news_audience_newscomment.py +++ b/news/migrations/0010_news_audience_newscomment.py @@ -26,6 +26,8 @@ def set_existing_news_audiences(apps, schema_editor): class Migration(migrations.Migration): + atomic = False + dependencies = [ migrations.swappable_dependency(settings.AUTH_USER_MODEL), ("news", "0009_news_pin"), @@ -53,9 +55,7 @@ class Migration(migrations.Migration): migrations.AddConstraint( model_name="news", constraint=models.CheckConstraint( - check=models.Q( - audience__in=("platform", "program_participants") - ), + check=models.Q(audience__in=("platform", "program_participants")), name="news_valid_audience", ), ), diff --git a/news/tests/test_news_migration_0010.py b/news/tests/test_news_migration_0010.py new file mode 100644 index 00000000..fc42639c --- /dev/null +++ b/news/tests/test_news_migration_0010.py @@ -0,0 +1,81 @@ +from importlib import import_module +import unittest + +from django.db import connection, migrations +from django.db.migrations.executor import MigrationExecutor +from django.test import SimpleTestCase, TransactionTestCase + + +class NewsMigration0010MetadataTests(SimpleTestCase): + def test_migration_is_non_atomic(self): + migration = import_module("news.migrations.0010_news_audience_newscomment") + + self.assertIs(migration.Migration.atomic, False) + + def test_runpython_does_not_reintroduce_atomic_transaction(self): + migration = import_module("news.migrations.0010_news_audience_newscomment") + run_python_operations = [ + operation + for operation in migration.Migration.operations + if isinstance(operation, migrations.RunPython) + ] + + self.assertEqual(len(run_python_operations), 1) + self.assertIsNone(run_python_operations[0].atomic) + + +@unittest.skipUnless( + connection.vendor == "postgresql", + "PostgreSQL-only regression for pending trigger events during migration 0010.", +) +class NewsMigration0010PostgreSQLTests(TransactionTestCase): + migrate_from = [("news", "0009_news_pin")] + migrate_to = [("news", "0010_news_audience_newscomment")] + + def setUp(self): + super().setUp() + self.executor = MigrationExecutor(connection) + self.executor.migrate(self.migrate_from) + self.apps = self.executor.loader.project_state(self.migrate_from).apps + + def tearDown(self): + self.executor.loader.build_graph() + self.executor.migrate(self.migrate_to) + super().tearDown() + + def test_applies_after_updating_existing_news_rows(self): + ContentType = self.apps.get_model("contenttypes", "ContentType") + News = self.apps.get_model("news", "News") + project_content_type, _ = ContentType.objects.get_or_create( + app_label="projects", + model="project", + ) + program_content_type, _ = ContentType.objects.get_or_create( + app_label="partner_programs", + model="partnerprogram", + ) + + News.objects.create( + content_type=project_content_type, + object_id=1, + text="Project news", + ) + News.objects.create( + content_type=program_content_type, + object_id=1, + text="Program news", + ) + + self.executor.loader.build_graph() + self.executor.migrate(self.migrate_to) + migrated_apps = self.executor.loader.project_state(self.migrate_to).apps + MigratedNews = migrated_apps.get_model("news", "News") + + self.assertEqual( + MigratedNews.objects.get(content_type_id=project_content_type.id).audience, + "platform", + ) + self.assertEqual( + MigratedNews.objects.get(content_type_id=program_content_type.id).audience, + "program_participants", + )