test_validation.py 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. # Copyright © 2023 Ingram Micro Inc. All rights reserved.
  2. from unittest.mock import MagicMock
  3. import pytest
  4. from dj_cqrs._validation import validate_settings
  5. def test_full_configuration():
  6. def f(*a, **kw):
  7. pass
  8. settings = MagicMock(
  9. CQRS={
  10. 'queue': 'start',
  11. 'transport': 'dj_cqrs.transport.rabbit_mq.RabbitMQTransport',
  12. 'host': 'host',
  13. 'port': 1234,
  14. 'user': 'user',
  15. 'password': 'pswd',
  16. 'master': {
  17. 'CQRS_AUTO_UPDATE_FIELDS': True,
  18. 'CQRS_MESSAGE_TTL': 10,
  19. 'correlation_function': f,
  20. 'meta_function': f,
  21. },
  22. 'replica': {
  23. 'CQRS_MAX_RETRIES': 5,
  24. 'CQRS_RETRY_DELAY': 4,
  25. 'delay_queue_max_size': 2,
  26. },
  27. },
  28. )
  29. validate_settings(settings)
  30. def test_configuration_does_not_exist():
  31. with pytest.raises(AssertionError) as e:
  32. validate_settings({})
  33. assert str(e.value) == 'CQRS configuration must be set in Django project settings.'
  34. @pytest.mark.parametrize('value', ([], 'settings'))
  35. def test_configuration_has_wrong_type(value):
  36. with pytest.raises(AssertionError) as e:
  37. validate_settings(MagicMock(CQRS=value))
  38. assert str(e.value) == 'CQRS configuration must be dict.'
  39. def test_transport_is_not_set():
  40. with pytest.raises(AssertionError) as e:
  41. validate_settings(MagicMock(CQRS={}))
  42. assert str(e.value) == 'CQRS transport is not set.'
  43. def test_transport_is_not_importable():
  44. with pytest.raises(ImportError):
  45. validate_settings(MagicMock(CQRS={'transport': 'abc'}))
  46. def test_transport_has_wrong_inheritance():
  47. with pytest.raises(AssertionError) as e:
  48. validate_settings(MagicMock(CQRS={'transport': 'dj_cqrs.dataclasses.TransportPayload'}))
  49. assert str(e.value) == (
  50. 'CQRS transport must be inherited from `dj_cqrs.transport.BaseTransport`.'
  51. )
  52. @pytest.fixture
  53. def cqrs_settings():
  54. return MagicMock(
  55. CQRS={
  56. 'transport': 'dj_cqrs.transport.mock.TransportMock',
  57. 'queue': 'replica',
  58. },
  59. )
  60. def test_master_configuration_not_set(cqrs_settings):
  61. validate_settings(cqrs_settings)
  62. assert cqrs_settings.CQRS['master'] == {
  63. 'CQRS_AUTO_UPDATE_FIELDS': False,
  64. 'CQRS_MESSAGE_TTL': 86400,
  65. 'correlation_function': None,
  66. 'meta_function': None,
  67. }
  68. @pytest.mark.parametrize('value', ([], 'settings', None))
  69. def test_master_configuration_has_wrong_type(cqrs_settings, value):
  70. cqrs_settings.CQRS['master'] = value
  71. with pytest.raises(AssertionError) as e:
  72. validate_settings(cqrs_settings)
  73. assert str(e.value) == 'CQRS master configuration must be dict.'
  74. def test_master_configuration_is_empty(cqrs_settings):
  75. cqrs_settings.CQRS['master'] = {}
  76. validate_settings(cqrs_settings)
  77. assert cqrs_settings.CQRS['master'] == {
  78. 'CQRS_AUTO_UPDATE_FIELDS': False,
  79. 'CQRS_MESSAGE_TTL': 86400,
  80. 'correlation_function': None,
  81. 'meta_function': None,
  82. }
  83. @pytest.mark.parametrize('value', (None, 'true', 1))
  84. def test_master_auto_update_fields_has_wrong_type(cqrs_settings, value):
  85. cqrs_settings.CQRS['master'] = {'CQRS_AUTO_UPDATE_FIELDS': value}
  86. with pytest.raises(AssertionError) as e:
  87. validate_settings(cqrs_settings)
  88. assert str(e.value) == 'CQRS master CQRS_AUTO_UPDATE_FIELDS must be bool.'
  89. def test_master_message_ttl_is_none(cqrs_settings):
  90. cqrs_settings.CQRS['master'] = {
  91. 'CQRS_AUTO_UPDATE_FIELDS': True,
  92. 'CQRS_MESSAGE_TTL': None,
  93. }
  94. validate_settings(cqrs_settings)
  95. assert cqrs_settings.CQRS['master'] == {
  96. 'CQRS_AUTO_UPDATE_FIELDS': True,
  97. 'CQRS_MESSAGE_TTL': None,
  98. 'correlation_function': None,
  99. 'meta_function': None,
  100. }
  101. @pytest.mark.parametrize('value', ({}, 1.23, -2, 0))
  102. def test_master_message_ttl_has_wrong_type_or_invalid_value(value, cqrs_settings, caplog):
  103. cqrs_settings.CQRS['master'] = {'CQRS_MESSAGE_TTL': value}
  104. validate_settings(cqrs_settings)
  105. assert cqrs_settings.CQRS['master'] == {
  106. 'CQRS_AUTO_UPDATE_FIELDS': False,
  107. 'CQRS_MESSAGE_TTL': 86400,
  108. 'correlation_function': None,
  109. 'meta_function': None,
  110. }
  111. assert caplog.record_tuples
  112. def test_master_correlation_func_is_not_callable(cqrs_settings):
  113. cqrs_settings.CQRS['master'] = {'correlation_function': 'x'}
  114. with pytest.raises(AssertionError) as e:
  115. validate_settings(cqrs_settings)
  116. assert str(e.value) == 'CQRS master correlation_function must be callable.'
  117. def test_master_correlation_func_is_callable(cqrs_settings):
  118. cqrs_settings.CQRS['master'] = {'correlation_function': lambda: 1}
  119. validate_settings(cqrs_settings)
  120. assert cqrs_settings.CQRS['master']['correlation_function']() == 1
  121. def test_master_meta_func_is_func_from_string(cqrs_settings):
  122. cqrs_settings.CQRS['master'] = {'meta_function': 'tests.utils.db_error'}
  123. validate_settings(cqrs_settings)
  124. assert callable(cqrs_settings.CQRS['master']['meta_function'])
  125. def test_master_meta_func_is_func(cqrs_settings):
  126. cqrs_settings.CQRS['master'] = {'meta_function': lambda **kw: 1}
  127. validate_settings(cqrs_settings)
  128. assert cqrs_settings.CQRS['master']['meta_function']() == 1
  129. def test_master_meta_func_is_non_importable_from_string(cqrs_settings):
  130. cqrs_settings.CQRS['master'] = {'meta_function': 'random.stuff'}
  131. with pytest.raises(AssertionError) as e:
  132. validate_settings(cqrs_settings)
  133. assert str(e.value) == 'CQRS master meta_function import error.'
  134. @pytest.mark.parametrize('f', ('dj_cqrs.dataclasses.TransportPayload', 5))
  135. def test_master_meta_func_is_not_func(cqrs_settings, f):
  136. cqrs_settings.CQRS['master'] = {'meta_function': f}
  137. with pytest.raises(AssertionError) as e:
  138. validate_settings(cqrs_settings)
  139. assert str(e.value) == 'CQRS master meta_function must be function.'
  140. @pytest.mark.parametrize('f', ('dj_cqrs.utils.get_message_expiration_dt', lambda: 1))
  141. def test_master_meta_func_must_support_kwargs(cqrs_settings, f):
  142. cqrs_settings.CQRS['master'] = {'meta_function': f}
  143. with pytest.raises(AssertionError) as e:
  144. validate_settings(cqrs_settings)
  145. assert str(e.value) == 'CQRS master meta_function must support **kwargs.'
  146. def test_replica_configuration_not_set(cqrs_settings):
  147. validate_settings(cqrs_settings)
  148. assert cqrs_settings.CQRS['replica'] == {
  149. 'CQRS_MAX_RETRIES': 30,
  150. 'CQRS_RETRY_DELAY': 2,
  151. 'delay_queue_max_size': 1000,
  152. }
  153. @pytest.mark.parametrize('value', ([], 'settings', None))
  154. def test_replica_configuration_has_wrong_type(cqrs_settings, value):
  155. cqrs_settings.CQRS['replica'] = value
  156. with pytest.raises(AssertionError) as e:
  157. validate_settings(cqrs_settings)
  158. assert str(e.value) == 'CQRS replica configuration must be dict.'
  159. def test_replica_configuration_is_empty(cqrs_settings):
  160. cqrs_settings.CQRS['replica'] = {}
  161. validate_settings(cqrs_settings)
  162. assert cqrs_settings.CQRS['replica'] == {
  163. 'CQRS_MAX_RETRIES': 30,
  164. 'CQRS_RETRY_DELAY': 2,
  165. 'delay_queue_max_size': 1000,
  166. }
  167. def test_replica_max_retries_is_none(cqrs_settings):
  168. cqrs_settings.CQRS['replica'] = {'CQRS_MAX_RETRIES': None}
  169. validate_settings(cqrs_settings)
  170. assert cqrs_settings.CQRS['replica']['CQRS_MAX_RETRIES'] is None
  171. @pytest.mark.parametrize('value', ({}, 1.23, -2))
  172. def test_replica_max_retries_has_wrong_type_or_invalid_value(value, cqrs_settings, caplog):
  173. cqrs_settings.CQRS['replica'] = {
  174. 'CQRS_MAX_RETRIES': value,
  175. 'CQRS_RETRY_DELAY': 10,
  176. 'delay_queue_max_size': value,
  177. }
  178. validate_settings(cqrs_settings)
  179. assert cqrs_settings.CQRS['replica'] == {
  180. 'CQRS_MAX_RETRIES': 30,
  181. 'CQRS_RETRY_DELAY': 10,
  182. 'delay_queue_max_size': 1000,
  183. }
  184. assert caplog.record_tuples
  185. def test_replica_retry_delay_is_none(cqrs_settings):
  186. cqrs_settings.CQRS['replica'] = {'CQRS_RETRY_DELAY': None}
  187. validate_settings(cqrs_settings)
  188. assert cqrs_settings.CQRS['replica']['CQRS_RETRY_DELAY'] == 2
  189. @pytest.mark.parametrize('value', ({}, 1.23, -2))
  190. def test_replica_retry_delay_has_wrong_type_or_invalid_value(value, cqrs_settings, caplog):
  191. cqrs_settings.CQRS['replica'] = {
  192. 'CQRS_MAX_RETRIES': 0,
  193. 'CQRS_RETRY_DELAY': value,
  194. 'delay_queue_max_size': 1,
  195. }
  196. validate_settings(cqrs_settings)
  197. assert cqrs_settings.CQRS['replica'] == {
  198. 'CQRS_MAX_RETRIES': 0,
  199. 'CQRS_RETRY_DELAY': 2,
  200. 'delay_queue_max_size': 1,
  201. }
  202. assert caplog.record_tuples
  203. def test_replica_delay_queue_max_size_is_none(cqrs_settings):
  204. cqrs_settings.CQRS['replica'] = {'delay_queue_max_size': None}
  205. validate_settings(cqrs_settings)
  206. assert cqrs_settings.CQRS['replica']['delay_queue_max_size'] is None
  207. @pytest.mark.parametrize('value', ({}, 1.23, -2))
  208. def test_replica_delay_queue_max_size_has_wrong_type_or_invalid_value(value, cqrs_settings, caplog):
  209. cqrs_settings.CQRS['replica'] = {
  210. 'CQRS_RETRY_DELAY': 0,
  211. 'delay_queue_max_size': value,
  212. }
  213. validate_settings(cqrs_settings)
  214. assert cqrs_settings.CQRS['replica'] == {
  215. 'CQRS_MAX_RETRIES': 30,
  216. 'CQRS_RETRY_DELAY': 0,
  217. 'delay_queue_max_size': 1000,
  218. }
  219. assert caplog.record_tuples
  220. def test_replica_delay_queue_max_size_deprecated_parameter(cqrs_settings):
  221. cqrs_settings.CQRS['replica'] = {'delay_queue_max_size': 200}
  222. validate_settings(cqrs_settings)
  223. assert cqrs_settings.CQRS['replica']['delay_queue_max_size'] == 200