test_fallback.py 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. import random
  2. from django.contrib.messages import constants
  3. from django.contrib.messages.storage.fallback import (
  4. CookieStorage, FallbackStorage,
  5. )
  6. from django.test import SimpleTestCase
  7. from django.utils.crypto import get_random_string
  8. from .base import BaseTests
  9. from .test_cookie import set_cookie_data, stored_cookie_messages_count
  10. from .test_session import set_session_data, stored_session_messages_count
  11. class FallbackTests(BaseTests, SimpleTestCase):
  12. storage_class = FallbackStorage
  13. def get_request(self):
  14. self.session = {}
  15. request = super().get_request()
  16. request.session = self.session
  17. return request
  18. def get_cookie_storage(self, storage):
  19. return storage.storages[-2]
  20. def get_session_storage(self, storage):
  21. return storage.storages[-1]
  22. def stored_cookie_messages_count(self, storage, response):
  23. return stored_cookie_messages_count(self.get_cookie_storage(storage), response)
  24. def stored_session_messages_count(self, storage, response):
  25. return stored_session_messages_count(self.get_session_storage(storage))
  26. def stored_messages_count(self, storage, response):
  27. """
  28. Return the storage totals from both cookie and session backends.
  29. """
  30. return (
  31. self.stored_cookie_messages_count(storage, response) +
  32. self.stored_session_messages_count(storage, response)
  33. )
  34. def test_get(self):
  35. request = self.get_request()
  36. storage = self.storage_class(request)
  37. cookie_storage = self.get_cookie_storage(storage)
  38. # Set initial cookie data.
  39. example_messages = [str(i) for i in range(5)]
  40. set_cookie_data(cookie_storage, example_messages)
  41. # Overwrite the _get method of the fallback storage to prove it is not
  42. # used (it would cause a TypeError: 'NoneType' object is not callable).
  43. self.get_session_storage(storage)._get = None
  44. self.assertEqual(list(storage), example_messages)
  45. def test_get_empty(self):
  46. request = self.get_request()
  47. storage = self.storage_class(request)
  48. # Overwrite the _get method of the fallback storage to prove it is not
  49. # used (it would cause a TypeError: 'NoneType' object is not callable).
  50. self.get_session_storage(storage)._get = None
  51. self.assertEqual(list(storage), [])
  52. def test_get_fallback(self):
  53. request = self.get_request()
  54. storage = self.storage_class(request)
  55. cookie_storage = self.get_cookie_storage(storage)
  56. session_storage = self.get_session_storage(storage)
  57. # Set initial cookie and session data.
  58. example_messages = [str(i) for i in range(5)]
  59. set_cookie_data(cookie_storage, example_messages[:4] + [CookieStorage.not_finished])
  60. set_session_data(session_storage, example_messages[4:])
  61. self.assertEqual(list(storage), example_messages)
  62. def test_get_fallback_only(self):
  63. request = self.get_request()
  64. storage = self.storage_class(request)
  65. cookie_storage = self.get_cookie_storage(storage)
  66. session_storage = self.get_session_storage(storage)
  67. # Set initial cookie and session data.
  68. example_messages = [str(i) for i in range(5)]
  69. set_cookie_data(cookie_storage, [CookieStorage.not_finished], encode_empty=True)
  70. set_session_data(session_storage, example_messages)
  71. self.assertEqual(list(storage), example_messages)
  72. def test_flush_used_backends(self):
  73. request = self.get_request()
  74. storage = self.storage_class(request)
  75. cookie_storage = self.get_cookie_storage(storage)
  76. session_storage = self.get_session_storage(storage)
  77. # Set initial cookie and session data.
  78. set_cookie_data(cookie_storage, ['cookie', CookieStorage.not_finished])
  79. set_session_data(session_storage, ['session'])
  80. # When updating, previously used but no longer needed backends are
  81. # flushed.
  82. response = self.get_response()
  83. list(storage)
  84. storage.update(response)
  85. session_storing = self.stored_session_messages_count(storage, response)
  86. self.assertEqual(session_storing, 0)
  87. def test_no_fallback(self):
  88. """
  89. (1) A short number of messages whose data size doesn't exceed what is
  90. allowed in a cookie will all be stored in the CookieBackend.
  91. (2) If the CookieBackend can store all messages, the SessionBackend
  92. won't be written to at all.
  93. """
  94. storage = self.get_storage()
  95. response = self.get_response()
  96. # Overwrite the _store method of the fallback storage to prove it isn't
  97. # used (it would cause a TypeError: 'NoneType' object is not callable).
  98. self.get_session_storage(storage)._store = None
  99. for i in range(5):
  100. storage.add(constants.INFO, str(i) * 100)
  101. storage.update(response)
  102. cookie_storing = self.stored_cookie_messages_count(storage, response)
  103. self.assertEqual(cookie_storing, 5)
  104. session_storing = self.stored_session_messages_count(storage, response)
  105. self.assertEqual(session_storing, 0)
  106. def test_session_fallback(self):
  107. """
  108. If the data exceeds what is allowed in a cookie, messages which did
  109. not fit are stored in the SessionBackend.
  110. """
  111. storage = self.get_storage()
  112. response = self.get_response()
  113. # see comment in CookieTests.test_cookie_max_length()
  114. msg_size = int((CookieStorage.max_cookie_size - 54) / 4.5 - 37)
  115. # Generate the same (tested) content every time that does not get run
  116. # through zlib compression.
  117. random.seed(42)
  118. for i in range(5):
  119. storage.add(constants.INFO, get_random_string(msg_size))
  120. storage.update(response)
  121. cookie_storing = self.stored_cookie_messages_count(storage, response)
  122. self.assertEqual(cookie_storing, 4)
  123. session_storing = self.stored_session_messages_count(storage, response)
  124. self.assertEqual(session_storing, 1)
  125. def test_session_fallback_only(self):
  126. """
  127. Large messages, none of which fit in a cookie, are stored in the
  128. SessionBackend (and nothing is stored in the CookieBackend).
  129. """
  130. storage = self.get_storage()
  131. response = self.get_response()
  132. # Generate the same (tested) content every time that does not get run
  133. # through zlib compression.
  134. random.seed(42)
  135. storage.add(constants.INFO, get_random_string(5000))
  136. storage.update(response)
  137. cookie_storing = self.stored_cookie_messages_count(storage, response)
  138. self.assertEqual(cookie_storing, 0)
  139. session_storing = self.stored_session_messages_count(storage, response)
  140. self.assertEqual(session_storing, 1)