test_controller.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. # Copyright © 2023 Ingram Micro Inc. All rights reserved.
  2. import pytest
  3. from django.conf import settings
  4. from django.utils.timezone import now
  5. from dj_cqrs.constants import SignalType
  6. from dj_cqrs.controller.consumer import consume, route_signal_to_replica_model
  7. from dj_cqrs.controller.producer import produce
  8. from dj_cqrs.dataclasses import TransportPayload
  9. from tests.dj_replica.models import AbstractModel, OnlyDirectSyncModel
  10. def test_producer(mocker):
  11. transport_mock = mocker.patch('tests.dj.transport.TransportStub.produce')
  12. produce(TransportPayload('a', 'b', {}, 'c', previous_data={'e': 'f'}))
  13. assert transport_mock.call_count == 1
  14. assert transport_mock.call_args[0][0].to_dict() == {
  15. 'signal_type': 'a',
  16. 'cqrs_id': 'b',
  17. 'instance_data': {},
  18. 'instance_pk': 'c',
  19. 'previous_data': {'e': 'f'},
  20. 'correlation_id': None,
  21. 'expires': None,
  22. 'retries': 0,
  23. 'meta': None,
  24. }
  25. def test_consumer(mocker):
  26. factory_mock = mocker.patch('dj_cqrs.controller.consumer.route_signal_to_replica_model')
  27. consume(TransportPayload('a', 'b', {}, 'c', previous_data={'e': 'f'}, queue='xyz'))
  28. factory_mock.assert_called_once_with(
  29. 'a',
  30. 'b',
  31. {},
  32. previous_data={'e': 'f'},
  33. meta=None,
  34. queue='xyz',
  35. )
  36. def test_changed_payload_data_during_consume(mocker):
  37. def change_data(*args, **kwargs):
  38. instance_data = args[2]
  39. instance_data['instance_key'] = 'changed instance'
  40. kwargs['previous_data']['previous_key'] = 'changed previous'
  41. factory_mock = mocker.patch(
  42. 'dj_cqrs.controller.consumer.route_signal_to_replica_model',
  43. side_effect=change_data,
  44. )
  45. payload = TransportPayload(
  46. SignalType.SAVE,
  47. cqrs_id='b',
  48. instance_data={'instance_key': 'initial instance'},
  49. instance_pk='c',
  50. previous_data={'previous_key': 'initial previous'},
  51. )
  52. consume(payload)
  53. assert factory_mock.call_count == 1
  54. assert payload.instance_data == {'instance_key': 'initial instance'}
  55. assert payload.previous_data == {'previous_key': 'initial previous'}
  56. @pytest.mark.django_db(transaction=True)
  57. def test_route_signal_to_replica_model_integrity_error(caplog):
  58. instance_data = {
  59. 'id': 10,
  60. 'author': {
  61. 'id': 100,
  62. },
  63. 'cqrs_revision': 0,
  64. 'cqrs_updated': now(),
  65. }
  66. instance = route_signal_to_replica_model(SignalType.SAVE, 'article', instance_data)
  67. assert not instance
  68. errors = {
  69. 'sqlite': 'FOREIGN KEY constraint failed',
  70. 'postgres': (
  71. 'insert or update on table "dj_replica_article" violates foreign key constraint'
  72. ),
  73. 'mysql': 'Cannot add or update a child row: a foreign key constraint',
  74. }
  75. assert errors[settings.DB_ENGINE] in caplog.text
  76. def test_route_signal_to_replica_model_without_db():
  77. with pytest.raises(NotImplementedError):
  78. route_signal_to_replica_model(SignalType.SAVE, 'no_db', {})
  79. @pytest.mark.parametrize('queue', ('abc', None))
  80. def test_route_signal_to_replica_with_only_direct_syncs(queue):
  81. assert (
  82. route_signal_to_replica_model(
  83. signal_type=SignalType.SYNC,
  84. cqrs_id=OnlyDirectSyncModel.CQRS_ID,
  85. instance_data={},
  86. queue=queue,
  87. )
  88. is True
  89. )
  90. @pytest.mark.django_db
  91. @pytest.mark.parametrize('data, pk_repr', (({}, 'None'), ({'id': '123'}, '123')))
  92. def test_route_signal_to_replica_exception(data, pk_repr, caplog):
  93. assert (
  94. route_signal_to_replica_model(
  95. signal_type=SignalType.SAVE,
  96. cqrs_id=AbstractModel.CQRS_ID,
  97. instance_data=data,
  98. )
  99. is None
  100. )
  101. assert 'pk = {pk}'.format(pk=pk_repr) in caplog.text