diff options
Diffstat (limited to 'tests/contenttypes_tests/tests.py')
| -rw-r--r-- | tests/contenttypes_tests/tests.py | 530 |
1 files changed, 0 insertions, 530 deletions
diff --git a/tests/contenttypes_tests/tests.py b/tests/contenttypes_tests/tests.py deleted file mode 100644 index 14e14e0913..0000000000 --- a/tests/contenttypes_tests/tests.py +++ /dev/null @@ -1,530 +0,0 @@ -import datetime -from unittest import mock - -from django.apps.registry import Apps, apps -from django.conf import settings -from django.contrib.contenttypes import management as contenttypes_management -from django.contrib.contenttypes.fields import ( - GenericForeignKey, GenericRelation, -) -from django.contrib.contenttypes.models import ContentType -from django.contrib.sites.models import Site -from django.core import checks, management -from django.core.management import call_command -from django.db import connections, migrations, models -from django.test import ( - SimpleTestCase, TestCase, TransactionTestCase, override_settings, -) -from django.test.utils import captured_stdout, isolate_apps - -from .models import ( - Article, Author, ModelWithNullFKToSite, Post, SchemeIncludedURL, - Site as MockSite, -) - - -@override_settings(ROOT_URLCONF='contenttypes_tests.urls') -class ContentTypesViewsTests(TestCase): - - @classmethod - def setUpTestData(cls): - # don't use the manager because we want to ensure the site exists - # with pk=1, regardless of whether or not it already exists. - cls.site1 = Site(pk=1, domain='testserver', name='testserver') - cls.site1.save() - cls.author1 = Author.objects.create(name='Boris') - cls.article1 = Article.objects.create( - title='Old Article', slug='old_article', author=cls.author1, - date_created=datetime.datetime(2001, 1, 1, 21, 22, 23) - ) - cls.article2 = Article.objects.create( - title='Current Article', slug='current_article', author=cls.author1, - date_created=datetime.datetime(2007, 9, 17, 21, 22, 23) - ) - cls.article3 = Article.objects.create( - title='Future Article', slug='future_article', author=cls.author1, - date_created=datetime.datetime(3000, 1, 1, 21, 22, 23) - ) - cls.scheme1 = SchemeIncludedURL.objects.create(url='http://test_scheme_included_http/') - cls.scheme2 = SchemeIncludedURL.objects.create(url='https://test_scheme_included_https/') - cls.scheme3 = SchemeIncludedURL.objects.create(url='//test_default_scheme_kept/') - - def setUp(self): - Site.objects.clear_cache() - - def test_shortcut_with_absolute_url(self): - "Can view a shortcut for an Author object that has a get_absolute_url method" - for obj in Author.objects.all(): - short_url = '/shortcut/%s/%s/' % (ContentType.objects.get_for_model(Author).id, obj.pk) - response = self.client.get(short_url) - self.assertRedirects(response, 'http://testserver%s' % obj.get_absolute_url(), - status_code=302, target_status_code=404) - - def test_shortcut_with_absolute_url_including_scheme(self): - """ - Can view a shortcut when object's get_absolute_url returns a full URL - the tested URLs are: "http://...", "https://..." and "//..." - """ - for obj in SchemeIncludedURL.objects.all(): - short_url = '/shortcut/%s/%s/' % (ContentType.objects.get_for_model(SchemeIncludedURL).id, obj.pk) - response = self.client.get(short_url) - self.assertRedirects(response, obj.get_absolute_url(), - status_code=302, - fetch_redirect_response=False) - - def test_shortcut_no_absolute_url(self): - "Shortcuts for an object that has no get_absolute_url method raises 404" - for obj in Article.objects.all(): - short_url = '/shortcut/%s/%s/' % (ContentType.objects.get_for_model(Article).id, obj.pk) - response = self.client.get(short_url) - self.assertEqual(response.status_code, 404) - - def test_wrong_type_pk(self): - short_url = '/shortcut/%s/%s/' % (ContentType.objects.get_for_model(Author).id, 'nobody/expects') - response = self.client.get(short_url) - self.assertEqual(response.status_code, 404) - - def test_shortcut_bad_pk(self): - short_url = '/shortcut/%s/%s/' % (ContentType.objects.get_for_model(Author).id, '42424242') - response = self.client.get(short_url) - self.assertEqual(response.status_code, 404) - - def test_nonint_content_type(self): - an_author = Author.objects.all()[0] - short_url = '/shortcut/%s/%s/' % ('spam', an_author.pk) - response = self.client.get(short_url) - self.assertEqual(response.status_code, 404) - - def test_bad_content_type(self): - an_author = Author.objects.all()[0] - short_url = '/shortcut/%s/%s/' % (42424242, an_author.pk) - response = self.client.get(short_url) - self.assertEqual(response.status_code, 404) - - @mock.patch('django.apps.apps.get_model') - def test_shortcut_view_with_null_site_fk(self, get_model): - """ - The shortcut view works if a model's ForeignKey to site is None. - """ - get_model.side_effect = lambda *args, **kwargs: MockSite if args[0] == 'sites.Site' else ModelWithNullFKToSite - - obj = ModelWithNullFKToSite.objects.create(title='title') - url = '/shortcut/%s/%s/' % (ContentType.objects.get_for_model(ModelWithNullFKToSite).id, obj.pk) - response = self.client.get(url) - self.assertRedirects( - response, '%s' % obj.get_absolute_url(), - fetch_redirect_response=False, - ) - - def test_create_contenttype_on_the_spot(self): - """ - Make sure ContentTypeManager.get_for_model creates the corresponding - content type if it doesn't exist in the database (for some reason). - """ - - class ModelCreatedOnTheFly(models.Model): - name = models.CharField() - - class Meta: - verbose_name = 'a model created on the fly' - app_label = 'my_great_app' - apps = Apps() - - ct = ContentType.objects.get_for_model(ModelCreatedOnTheFly) - self.assertEqual(ct.app_label, 'my_great_app') - self.assertEqual(ct.model, 'modelcreatedonthefly') - self.assertEqual(str(ct), 'modelcreatedonthefly') - - -@override_settings(SILENCED_SYSTEM_CHECKS=['fields.W342']) # ForeignKey(unique=True) -@isolate_apps('contenttypes_tests', attr_name='apps') -class GenericForeignKeyTests(SimpleTestCase): - - def test_str(self): - class Model(models.Model): - field = GenericForeignKey() - self.assertEqual(str(Model.field), "contenttypes_tests.Model.field") - - def test_missing_content_type_field(self): - class TaggedItem(models.Model): - # no content_type field - object_id = models.PositiveIntegerField() - content_object = GenericForeignKey() - - errors = TaggedItem.content_object.check() - expected = [ - checks.Error( - "The GenericForeignKey content type references the nonexistent field 'TaggedItem.content_type'.", - obj=TaggedItem.content_object, - id='contenttypes.E002', - ) - ] - self.assertEqual(errors, expected) - - def test_invalid_content_type_field(self): - class Model(models.Model): - content_type = models.IntegerField() # should be ForeignKey - object_id = models.PositiveIntegerField() - content_object = GenericForeignKey( - 'content_type', 'object_id') - - errors = Model.content_object.check() - expected = [ - checks.Error( - "'Model.content_type' is not a ForeignKey.", - hint=( - "GenericForeignKeys must use a ForeignKey to " - "'contenttypes.ContentType' as the 'content_type' field." - ), - obj=Model.content_object, - id='contenttypes.E003', - ) - ] - self.assertEqual(errors, expected) - - def test_content_type_field_pointing_to_wrong_model(self): - class Model(models.Model): - content_type = models.ForeignKey('self', models.CASCADE) # should point to ContentType - object_id = models.PositiveIntegerField() - content_object = GenericForeignKey( - 'content_type', 'object_id') - - errors = Model.content_object.check() - expected = [ - checks.Error( - "'Model.content_type' is not a ForeignKey to 'contenttypes.ContentType'.", - hint=( - "GenericForeignKeys must use a ForeignKey to " - "'contenttypes.ContentType' as the 'content_type' field." - ), - obj=Model.content_object, - id='contenttypes.E004', - ) - ] - self.assertEqual(errors, expected) - - def test_missing_object_id_field(self): - class TaggedItem(models.Model): - content_type = models.ForeignKey(ContentType, models.CASCADE) - # missing object_id field - content_object = GenericForeignKey() - - errors = TaggedItem.content_object.check() - expected = [ - checks.Error( - "The GenericForeignKey object ID references the nonexistent field 'object_id'.", - obj=TaggedItem.content_object, - id='contenttypes.E001', - ) - ] - self.assertEqual(errors, expected) - - def test_field_name_ending_with_underscore(self): - class Model(models.Model): - content_type = models.ForeignKey(ContentType, models.CASCADE) - object_id = models.PositiveIntegerField() - content_object_ = GenericForeignKey( - 'content_type', 'object_id') - - errors = Model.content_object_.check() - expected = [ - checks.Error( - 'Field names must not end with an underscore.', - obj=Model.content_object_, - id='fields.E001', - ) - ] - self.assertEqual(errors, expected) - - @override_settings(INSTALLED_APPS=['django.contrib.auth', 'django.contrib.contenttypes', 'contenttypes_tests']) - def test_generic_foreign_key_checks_are_performed(self): - class Model(models.Model): - content_object = GenericForeignKey() - - with mock.patch.object(GenericForeignKey, 'check') as check: - checks.run_checks(app_configs=self.apps.get_app_configs()) - check.assert_called_once_with() - - -@isolate_apps('contenttypes_tests') -class GenericRelationshipTests(SimpleTestCase): - - def test_valid_generic_relationship(self): - class TaggedItem(models.Model): - content_type = models.ForeignKey(ContentType, models.CASCADE) - object_id = models.PositiveIntegerField() - content_object = GenericForeignKey() - - class Bookmark(models.Model): - tags = GenericRelation('TaggedItem') - - errors = Bookmark.tags.field.check() - self.assertEqual(errors, []) - - def test_valid_generic_relationship_with_explicit_fields(self): - class TaggedItem(models.Model): - custom_content_type = models.ForeignKey(ContentType, models.CASCADE) - custom_object_id = models.PositiveIntegerField() - content_object = GenericForeignKey( - 'custom_content_type', 'custom_object_id') - - class Bookmark(models.Model): - tags = GenericRelation( - 'TaggedItem', - content_type_field='custom_content_type', - object_id_field='custom_object_id', - ) - - errors = Bookmark.tags.field.check() - self.assertEqual(errors, []) - - def test_pointing_to_missing_model(self): - class Model(models.Model): - rel = GenericRelation('MissingModel') - - errors = Model.rel.field.check() - expected = [ - checks.Error( - "Field defines a relation with model 'MissingModel', " - "which is either not installed, or is abstract.", - obj=Model.rel.field, - id='fields.E300', - ) - ] - self.assertEqual(errors, expected) - - def test_valid_self_referential_generic_relationship(self): - class Model(models.Model): - rel = GenericRelation('Model') - content_type = models.ForeignKey(ContentType, models.CASCADE) - object_id = models.PositiveIntegerField() - content_object = GenericForeignKey( - 'content_type', 'object_id') - - errors = Model.rel.field.check() - self.assertEqual(errors, []) - - def test_missing_generic_foreign_key(self): - class TaggedItem(models.Model): - content_type = models.ForeignKey(ContentType, models.CASCADE) - object_id = models.PositiveIntegerField() - - class Bookmark(models.Model): - tags = GenericRelation('TaggedItem') - - errors = Bookmark.tags.field.check() - expected = [ - checks.Error( - "The GenericRelation defines a relation with the model " - "'contenttypes_tests.TaggedItem', but that model does not have a " - "GenericForeignKey.", - obj=Bookmark.tags.field, - id='contenttypes.E004', - ) - ] - self.assertEqual(errors, expected) - - @override_settings(TEST_SWAPPED_MODEL='contenttypes_tests.Replacement') - def test_pointing_to_swapped_model(self): - class Replacement(models.Model): - pass - - class SwappedModel(models.Model): - content_type = models.ForeignKey(ContentType, models.CASCADE) - object_id = models.PositiveIntegerField() - content_object = GenericForeignKey() - - class Meta: - swappable = 'TEST_SWAPPED_MODEL' - - class Model(models.Model): - rel = GenericRelation('SwappedModel') - - errors = Model.rel.field.check() - expected = [ - checks.Error( - "Field defines a relation with the model " - "'contenttypes_tests.SwappedModel', " - "which has been swapped out.", - hint="Update the relation to point at 'settings.TEST_SWAPPED_MODEL'.", - obj=Model.rel.field, - id='fields.E301', - ) - ] - self.assertEqual(errors, expected) - - def test_field_name_ending_with_underscore(self): - class TaggedItem(models.Model): - content_type = models.ForeignKey(ContentType, models.CASCADE) - object_id = models.PositiveIntegerField() - content_object = GenericForeignKey() - - class InvalidBookmark(models.Model): - tags_ = GenericRelation('TaggedItem') - - errors = InvalidBookmark.tags_.field.check() - expected = [ - checks.Error( - 'Field names must not end with an underscore.', - obj=InvalidBookmark.tags_.field, - id='fields.E001', - ) - ] - self.assertEqual(errors, expected) - - -class UpdateContentTypesTests(TestCase): - def setUp(self): - self.before_count = ContentType.objects.count() - self.content_type = ContentType.objects.create(app_label='contenttypes_tests', model='Fake') - self.app_config = apps.get_app_config('contenttypes_tests') - - def test_interactive_true_with_dependent_objects(self): - """ - interactive mode of remove_stale_contenttypes (the default) should - delete stale contenttypes and warn of dependent objects. - """ - post = Post.objects.create(title='post', content_type=self.content_type) - # A related object is needed to show that a custom collector with - # can_fast_delete=False is needed. - ModelWithNullFKToSite.objects.create(post=post) - with mock.patch('builtins.input', return_value='yes'): - with captured_stdout() as stdout: - call_command('remove_stale_contenttypes', verbosity=2, stdout=stdout) - self.assertEqual(Post.objects.count(), 0) - output = stdout.getvalue() - self.assertIn('- Content type for contenttypes_tests.Fake', output) - self.assertIn('- 1 contenttypes_tests.Post object(s)', output) - self.assertIn('- 1 contenttypes_tests.ModelWithNullFKToSite', output) - self.assertIn('Deleting stale content type', output) - self.assertEqual(ContentType.objects.count(), self.before_count) - - def test_interactive_true_without_dependent_objects(self): - """ - interactive mode of remove_stale_contenttypes (the default) should - delete stale contenttypes even if there aren't any dependent objects. - """ - with mock.patch('builtins.input', return_value='yes'): - with captured_stdout() as stdout: - call_command('remove_stale_contenttypes', verbosity=2) - self.assertIn("Deleting stale content type", stdout.getvalue()) - self.assertEqual(ContentType.objects.count(), self.before_count) - - def test_interactive_false(self): - """ - non-interactive mode of remove_stale_contenttypes shouldn't delete - stale content types. - """ - with captured_stdout() as stdout: - call_command('remove_stale_contenttypes', interactive=False, verbosity=2) - self.assertIn("Stale content types remain.", stdout.getvalue()) - self.assertEqual(ContentType.objects.count(), self.before_count + 1) - - def test_unavailable_content_type_model(self): - """ - A ContentType shouldn't be created if the model isn't available. - """ - apps = Apps() - with self.assertNumQueries(0): - contenttypes_management.create_contenttypes(self.app_config, interactive=False, verbosity=0, apps=apps) - self.assertEqual(ContentType.objects.count(), self.before_count + 1) - - -class TestRouter: - def db_for_read(self, model, **hints): - return 'other' - - def db_for_write(self, model, **hints): - return 'default' - - -@override_settings(DATABASE_ROUTERS=[TestRouter()]) -class ContentTypesMultidbTestCase(TestCase): - - def setUp(self): - # Whenever a test starts executing, only the "default" database is - # connected. We explicitly connect to the "other" database here. If we - # don't do it, then it will be implicitly connected later when we query - # it, but in that case some database backends may automatically perform - # extra queries upon connecting (notably mysql executes - # "SET SQL_AUTO_IS_NULL = 0"), which will affect assertNumQueries(). - connections['other'].ensure_connection() - - def test_multidb(self): - """ - When using multiple databases, ContentType.objects.get_for_model() uses - db_for_read(). - """ - ContentType.objects.clear_cache() - - with self.assertNumQueries(0, using='default'), \ - self.assertNumQueries(1, using='other'): - ContentType.objects.get_for_model(Author) - - -@override_settings( - MIGRATION_MODULES=dict(settings.MIGRATION_MODULES, contenttypes_tests='contenttypes_tests.operations_migrations'), -) -class ContentTypeOperationsTests(TransactionTestCase): - available_apps = [ - 'contenttypes_tests', - 'django.contrib.contenttypes', - ] - - def setUp(self): - app_config = apps.get_app_config('contenttypes_tests') - models.signals.post_migrate.connect(self.assertOperationsInjected, sender=app_config) - - def tearDown(self): - app_config = apps.get_app_config('contenttypes_tests') - models.signals.post_migrate.disconnect(self.assertOperationsInjected, sender=app_config) - - def assertOperationsInjected(self, plan, **kwargs): - for migration, _backward in plan: - operations = iter(migration.operations) - for operation in operations: - if isinstance(operation, migrations.RenameModel): - next_operation = next(operations) - self.assertIsInstance(next_operation, contenttypes_management.RenameContentType) - self.assertEqual(next_operation.app_label, migration.app_label) - self.assertEqual(next_operation.old_model, operation.old_name_lower) - self.assertEqual(next_operation.new_model, operation.new_name_lower) - - def test_existing_content_type_rename(self): - ContentType.objects.create(app_label='contenttypes_tests', model='foo') - management.call_command( - 'migrate', 'contenttypes_tests', database='default', interactive=False, verbosity=0, - ) - self.assertFalse(ContentType.objects.filter(app_label='contenttypes_tests', model='foo').exists()) - self.assertTrue(ContentType.objects.filter(app_label='contenttypes_tests', model='renamedfoo').exists()) - management.call_command( - 'migrate', 'contenttypes_tests', 'zero', database='default', interactive=False, verbosity=0, - ) - self.assertTrue(ContentType.objects.filter(app_label='contenttypes_tests', model='foo').exists()) - self.assertFalse(ContentType.objects.filter(app_label='contenttypes_tests', model='renamedfoo').exists()) - - def test_missing_content_type_rename_ignore(self): - management.call_command( - 'migrate', 'contenttypes_tests', database='default', interactive=False, verbosity=0, - ) - self.assertFalse(ContentType.objects.filter(app_label='contenttypes_tests', model='foo').exists()) - self.assertTrue(ContentType.objects.filter(app_label='contenttypes_tests', model='renamedfoo').exists()) - management.call_command( - 'migrate', 'contenttypes_tests', 'zero', database='default', interactive=False, verbosity=0, - ) - self.assertTrue(ContentType.objects.filter(app_label='contenttypes_tests', model='foo').exists()) - self.assertFalse(ContentType.objects.filter(app_label='contenttypes_tests', model='renamedfoo').exists()) - - def test_content_type_rename_conflict(self): - ContentType.objects.create(app_label='contenttypes_tests', model='foo') - ContentType.objects.create(app_label='contenttypes_tests', model='renamedfoo') - management.call_command( - 'migrate', 'contenttypes_tests', database='default', interactive=False, verbosity=0, - ) - self.assertTrue(ContentType.objects.filter(app_label='contenttypes_tests', model='foo').exists()) - self.assertTrue(ContentType.objects.filter(app_label='contenttypes_tests', model='renamedfoo').exists()) - management.call_command( - 'migrate', 'contenttypes_tests', 'zero', database='default', interactive=False, verbosity=0, - ) - self.assertTrue(ContentType.objects.filter(app_label='contenttypes_tests', model='foo').exists()) - self.assertTrue(ContentType.objects.filter(app_label='contenttypes_tests', model='renamedfoo').exists()) |
