From 53e674d5744faad61e52d8459c9198b2aa6f63dd Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Tue, 11 Jun 2024 19:27:49 +0100 Subject: Fixed #35520 -- Avoided opening transaction for read-only ModelAdmin requests. --- tests/admin_views/test_multidb.py | 75 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 72 insertions(+), 3 deletions(-) (limited to 'tests/admin_views/test_multidb.py') diff --git a/tests/admin_views/test_multidb.py b/tests/admin_views/test_multidb.py index 654161e11d..0f18aeb315 100644 --- a/tests/admin_views/test_multidb.py +++ b/tests/admin_views/test_multidb.py @@ -40,6 +40,7 @@ urlpatterns = [ @override_settings(ROOT_URLCONF=__name__, DATABASE_ROUTERS=["%s.Router" % __name__]) class MultiDatabaseTests(TestCase): databases = {"default", "other"} + READ_ONLY_METHODS = {"get", "options", "head", "trace"} @classmethod def setUpTestData(cls): @@ -56,48 +57,116 @@ class MultiDatabaseTests(TestCase): b.save(using=db) cls.test_book_ids[db] = b.id + def tearDown(self): + # Reset the routers' state between each test. + Router.target_db = None + @mock.patch("django.contrib.admin.options.transaction") def test_add_view(self, mock): for db in self.databases: with self.subTest(db=db): + mock.mock_reset() Router.target_db = db self.client.force_login(self.superusers[db]) - self.client.post( + response = self.client.post( reverse("test_adminsite:admin_views_book_add"), {"name": "Foobar: 5th edition"}, ) + self.assertEqual(response.status_code, 302) + self.assertEqual( + response.url, reverse("test_adminsite:admin_views_book_changelist") + ) mock.atomic.assert_called_with(using=db) + @mock.patch("django.contrib.admin.options.transaction") + def test_read_only_methods_add_view(self, mock): + for db in self.databases: + for method in self.READ_ONLY_METHODS: + with self.subTest(db=db, method=method): + mock.mock_reset() + Router.target_db = db + self.client.force_login(self.superusers[db]) + response = getattr(self.client, method)( + reverse("test_adminsite:admin_views_book_add"), + ) + self.assertEqual(response.status_code, 200) + mock.atomic.assert_not_called() + @mock.patch("django.contrib.admin.options.transaction") def test_change_view(self, mock): for db in self.databases: with self.subTest(db=db): + mock.mock_reset() Router.target_db = db self.client.force_login(self.superusers[db]) - self.client.post( + response = self.client.post( reverse( "test_adminsite:admin_views_book_change", args=[self.test_book_ids[db]], ), {"name": "Test Book 2: Test more"}, ) + self.assertEqual(response.status_code, 302) + self.assertEqual( + response.url, reverse("test_adminsite:admin_views_book_changelist") + ) mock.atomic.assert_called_with(using=db) + @mock.patch("django.contrib.admin.options.transaction") + def test_read_only_methods_change_view(self, mock): + for db in self.databases: + for method in self.READ_ONLY_METHODS: + with self.subTest(db=db, method=method): + mock.mock_reset() + Router.target_db = db + self.client.force_login(self.superusers[db]) + response = getattr(self.client, method)( + reverse( + "test_adminsite:admin_views_book_change", + args=[self.test_book_ids[db]], + ), + data={"name": "Test Book 2: Test more"}, + ) + self.assertEqual(response.status_code, 200) + mock.atomic.assert_not_called() + @mock.patch("django.contrib.admin.options.transaction") def test_delete_view(self, mock): for db in self.databases: with self.subTest(db=db): + mock.mock_reset() Router.target_db = db self.client.force_login(self.superusers[db]) - self.client.post( + response = self.client.post( reverse( "test_adminsite:admin_views_book_delete", args=[self.test_book_ids[db]], ), {"post": "yes"}, ) + self.assertEqual(response.status_code, 302) + self.assertEqual( + response.url, reverse("test_adminsite:admin_views_book_changelist") + ) mock.atomic.assert_called_with(using=db) + @mock.patch("django.contrib.admin.options.transaction") + def test_read_only_methods_delete_view(self, mock): + for db in self.databases: + for method in self.READ_ONLY_METHODS: + with self.subTest(db=db, method=method): + mock.mock_reset() + Router.target_db = db + self.client.force_login(self.superusers[db]) + response = getattr(self.client, method)( + reverse( + "test_adminsite:admin_views_book_delete", + args=[self.test_book_ids[db]], + ) + ) + self.assertEqual(response.status_code, 200) + mock.atomic.assert_not_called() + class ViewOnSiteRouter: def db_for_read(self, model, instance=None, **hints): -- cgit v1.3