test_avatars.py 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. from pathlib import Path
  2. from unittest.mock import Mock
  3. from django.core.exceptions import ValidationError
  4. from django.test import TestCase
  5. from django.utils.crypto import get_random_string
  6. from PIL import Image
  7. from ...conf import settings
  8. from ..avatars import dynamic, gallery, gravatar, set_default_avatar, store, uploaded
  9. from ..models import Avatar, AvatarGallery
  10. from ..test import create_test_user
  11. class AvatarsStoreTests(TestCase):
  12. def test_store(self):
  13. """store successfully stores and deletes avatar"""
  14. user = create_test_user("User", "user@example.com")
  15. test_image = Image.new("RGBA", (100, 100), 0)
  16. store.store_new_avatar(user, test_image)
  17. # reload user
  18. user.refresh_from_db()
  19. # assert that avatars were stored in media
  20. avatars_dict = {}
  21. for avatar in user.avatar_set.all():
  22. self.assertTrue(avatar.image.url)
  23. self.assertEqual(avatar.url, avatar.image.url)
  24. avatars_dict[avatar.size] = avatar
  25. # asserts that user.avatars cache was set
  26. self.assertEqual(len(avatars_dict), len(settings.MISAGO_AVATARS_SIZES))
  27. self.assertEqual(len(user.avatars), len(settings.MISAGO_AVATARS_SIZES))
  28. self.assertEqual(len(user.avatars), len(avatars_dict))
  29. for avatar in user.avatars:
  30. self.assertIn(avatar["size"], settings.MISAGO_AVATARS_SIZES)
  31. self.assertEqual(avatar["url"], avatars_dict[avatar["size"]].url)
  32. # another avatar change deleted old avatars
  33. store.store_new_avatar(user, test_image)
  34. for old_avatar in avatars_dict.values():
  35. avatar_path = Path(old_avatar.image.path)
  36. self.assertFalse(avatar_path.exists())
  37. self.assertFalse(avatar_path.is_file())
  38. with self.assertRaises(Avatar.DoesNotExist):
  39. Avatar.objects.get(pk=old_avatar.pk)
  40. # and updated user avatars again
  41. new_avatars_dict = {}
  42. for size in settings.MISAGO_AVATARS_SIZES:
  43. avatar = user.avatar_set.get(size=size)
  44. self.assertTrue(avatar.image.url)
  45. self.assertEqual(avatar.url, avatar.image.url)
  46. new_avatars_dict[size] = avatar
  47. self.assertTrue(avatars_dict != new_avatars_dict)
  48. # asserts that user.avatars cache was updated
  49. self.assertEqual(len(user.avatars), len(settings.MISAGO_AVATARS_SIZES))
  50. for avatar in user.avatars:
  51. self.assertIn(avatar["size"], settings.MISAGO_AVATARS_SIZES)
  52. self.assertEqual(avatar["url"], new_avatars_dict[avatar["size"]].url)
  53. # delete avatar
  54. store.delete_avatar(user)
  55. for removed_avatar in new_avatars_dict.values():
  56. avatar_path = Path(removed_avatar.image.path)
  57. self.assertFalse(avatar_path.exists())
  58. self.assertFalse(avatar_path.is_file())
  59. with self.assertRaises(Avatar.DoesNotExist):
  60. Avatar.objects.get(pk=removed_avatar.pk)
  61. class AvatarSetterTests(TestCase):
  62. def setUp(self):
  63. self.user = create_test_user("User", "user@example.com", avatars=None)
  64. def tearDown(self):
  65. store.delete_avatar(self.user)
  66. def get_current_user(self):
  67. self.user.refresh_from_db()
  68. return self.user
  69. def assertNoAvatarIsSet(self):
  70. user = self.get_current_user()
  71. self.assertFalse(user.avatars)
  72. def assertAvatarWasSet(self):
  73. user = self.get_current_user()
  74. avatars_dict = {}
  75. for avatar in user.avatar_set.all():
  76. avatar_path = Path(avatar.image.path)
  77. self.assertTrue(avatar_path.exists())
  78. self.assertTrue(avatar_path.is_file())
  79. avatars_dict[avatar.size] = avatar
  80. self.assertEqual(len(user.avatars), len(avatars_dict))
  81. self.assertEqual(len(user.avatars), len(settings.MISAGO_AVATARS_SIZES))
  82. def test_dynamic_avatar(self):
  83. """dynamic avatar gets created"""
  84. self.assertNoAvatarIsSet()
  85. dynamic.set_avatar(self.user)
  86. self.assertAvatarWasSet()
  87. def test_random_gallery_avatar_no_gallery(self):
  88. """runtime error is raised when no gallery exists"""
  89. with self.assertRaises(RuntimeError):
  90. gallery.set_random_avatar(self.user)
  91. def test_random_gallery_avatar(self):
  92. """dynamic avatar gets created"""
  93. gallery.load_avatar_galleries()
  94. self.assertNoAvatarIsSet()
  95. gallery.set_random_avatar(self.user)
  96. self.assertAvatarWasSet()
  97. def test_selected_gallery_avatar(self):
  98. """dynamic avatar gets created"""
  99. gallery.load_avatar_galleries()
  100. self.assertNoAvatarIsSet()
  101. test_avatar = AvatarGallery.objects.order_by("id").last()
  102. gallery.set_avatar(self.user, test_avatar)
  103. self.assertAvatarWasSet()
  104. def test_gravatar(self):
  105. """dynamic avatar gets created"""
  106. self.assertNoAvatarIsSet()
  107. self.user.set_email("rafio.xudb@gmail.com")
  108. gravatar.set_avatar(self.user)
  109. self.assertAvatarWasSet()
  110. def test_default_avatar_gravatar(self):
  111. """default gravatar gets set"""
  112. self.assertNoAvatarIsSet()
  113. set_default_avatar(self.user, "gravatar", "dynamic")
  114. self.assertAvatarWasSet()
  115. def test_default_avatar_gravatar_fallback_dynamic(self):
  116. """default gravatar fails but fallback dynamic works"""
  117. gibberish_email = "%s@%s.%s" % (
  118. get_random_string(6),
  119. get_random_string(6),
  120. get_random_string(3),
  121. )
  122. self.user.set_email(gibberish_email)
  123. self.user.save()
  124. self.assertNoAvatarIsSet()
  125. set_default_avatar(self.user, "gravatar", "dynamic")
  126. self.assertAvatarWasSet()
  127. def test_default_avatar_gravatar_fallback_empty_gallery(self):
  128. """default both gravatar and fallback fail set"""
  129. gibberish_email = "%s@%s.%s" % (
  130. get_random_string(6),
  131. get_random_string(6),
  132. get_random_string(3),
  133. )
  134. self.user.set_email(gibberish_email)
  135. self.user.save()
  136. self.assertNoAvatarIsSet()
  137. self.user.save()
  138. set_default_avatar(self.user, "gravatar", "gallery")
  139. self.assertAvatarWasSet()
  140. class MockAvatarFile(object):
  141. def __init__(self, size=None, name=None, mime=None):
  142. self.size = size
  143. self.name = name
  144. self.content_type = mime
  145. class UploadedAvatarTests(TestCase):
  146. def test_clean_crop(self):
  147. """crop validation and cleaning"""
  148. image = Image.new("RGBA", (200, 200), 0)
  149. with self.assertRaises(ValidationError):
  150. uploaded.clean_crop(image, "abc")
  151. with self.assertRaises(ValidationError):
  152. uploaded.clean_crop(image, {})
  153. with self.assertRaises(ValidationError):
  154. uploaded.clean_crop(image, {"offset": {"x": "ugabuga"}})
  155. with self.assertRaises(ValidationError):
  156. uploaded.clean_crop(image, {"offset": {"x": 0, "y": 0}, "zoom": -2})
  157. with self.assertRaises(ValidationError):
  158. uploaded.clean_crop(image, {"offset": {"x": 0, "y": 0}, "zoom": 2})
  159. def test_uploaded_image_size_validation(self):
  160. """uploaded image size is validated"""
  161. settings = Mock(avatar_upload_limit=1) # no. of MBs
  162. image = MockAvatarFile(size=1025)
  163. with self.assertRaises(ValidationError):
  164. uploaded.validate_file_size(settings, image)
  165. image = MockAvatarFile(size=1024)
  166. uploaded.validate_file_size(settings, image)
  167. def test_uploaded_image_extension_validation(self):
  168. """uploaded image extension is validated"""
  169. for invalid_extension in (".txt", ".zip", ".py", ".tiff"):
  170. with self.assertRaises(ValidationError):
  171. image = MockAvatarFile(name="test%s" % invalid_extension)
  172. uploaded.validate_extension(image)
  173. for valid_extension in uploaded.ALLOWED_EXTENSIONS:
  174. image = MockAvatarFile(name="test%s" % valid_extension)
  175. uploaded.validate_extension(image)
  176. def test_uploaded_image_mime_validation(self):
  177. """uploaded image mime type is validated"""
  178. image = MockAvatarFile(mime="fake/mime")
  179. with self.assertRaises(ValidationError):
  180. uploaded.validate_mime(image)
  181. for valid_mime in uploaded.ALLOWED_MIME_TYPES:
  182. image = MockAvatarFile(mime=valid_mime)
  183. uploaded.validate_mime(image)