eventsourcing 9.3.2__py3-none-any.whl → 9.3.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of eventsourcing might be problematic. Click here for more details.

Files changed (129) hide show
  1. eventsourcing/postgres.py +2 -1
  2. eventsourcing/system.py +3 -1
  3. {eventsourcing-9.3.2.dist-info → eventsourcing-9.3.4.dist-info}/METADATA +3 -8
  4. eventsourcing-9.3.4.dist-info/RECORD +24 -0
  5. eventsourcing/examples/__init__.py +0 -0
  6. eventsourcing/examples/aggregate1/__init__.py +0 -0
  7. eventsourcing/examples/aggregate1/application.py +0 -27
  8. eventsourcing/examples/aggregate1/domainmodel.py +0 -16
  9. eventsourcing/examples/aggregate1/test_application.py +0 -37
  10. eventsourcing/examples/aggregate2/__init__.py +0 -0
  11. eventsourcing/examples/aggregate2/application.py +0 -27
  12. eventsourcing/examples/aggregate2/domainmodel.py +0 -22
  13. eventsourcing/examples/aggregate2/test_application.py +0 -37
  14. eventsourcing/examples/aggregate3/__init__.py +0 -0
  15. eventsourcing/examples/aggregate3/application.py +0 -27
  16. eventsourcing/examples/aggregate3/domainmodel.py +0 -38
  17. eventsourcing/examples/aggregate3/test_application.py +0 -37
  18. eventsourcing/examples/aggregate4/__init__.py +0 -0
  19. eventsourcing/examples/aggregate4/application.py +0 -27
  20. eventsourcing/examples/aggregate4/domainmodel.py +0 -114
  21. eventsourcing/examples/aggregate4/test_application.py +0 -38
  22. eventsourcing/examples/aggregate5/__init__.py +0 -0
  23. eventsourcing/examples/aggregate5/application.py +0 -27
  24. eventsourcing/examples/aggregate5/domainmodel.py +0 -131
  25. eventsourcing/examples/aggregate5/test_application.py +0 -38
  26. eventsourcing/examples/aggregate6/__init__.py +0 -0
  27. eventsourcing/examples/aggregate6/application.py +0 -30
  28. eventsourcing/examples/aggregate6/domainmodel.py +0 -123
  29. eventsourcing/examples/aggregate6/test_application.py +0 -38
  30. eventsourcing/examples/aggregate6a/__init__.py +0 -0
  31. eventsourcing/examples/aggregate6a/application.py +0 -40
  32. eventsourcing/examples/aggregate6a/domainmodel.py +0 -149
  33. eventsourcing/examples/aggregate6a/test_application.py +0 -45
  34. eventsourcing/examples/aggregate7/__init__.py +0 -0
  35. eventsourcing/examples/aggregate7/application.py +0 -48
  36. eventsourcing/examples/aggregate7/domainmodel.py +0 -144
  37. eventsourcing/examples/aggregate7/persistence.py +0 -57
  38. eventsourcing/examples/aggregate7/test_application.py +0 -38
  39. eventsourcing/examples/aggregate7/test_compression_and_encryption.py +0 -45
  40. eventsourcing/examples/aggregate7/test_snapshotting_intervals.py +0 -67
  41. eventsourcing/examples/aggregate7a/__init__.py +0 -0
  42. eventsourcing/examples/aggregate7a/application.py +0 -56
  43. eventsourcing/examples/aggregate7a/domainmodel.py +0 -170
  44. eventsourcing/examples/aggregate7a/test_application.py +0 -46
  45. eventsourcing/examples/aggregate7a/test_compression_and_encryption.py +0 -45
  46. eventsourcing/examples/aggregate8/__init__.py +0 -0
  47. eventsourcing/examples/aggregate8/application.py +0 -47
  48. eventsourcing/examples/aggregate8/domainmodel.py +0 -65
  49. eventsourcing/examples/aggregate8/persistence.py +0 -57
  50. eventsourcing/examples/aggregate8/test_application.py +0 -37
  51. eventsourcing/examples/aggregate8/test_compression_and_encryption.py +0 -44
  52. eventsourcing/examples/aggregate8/test_snapshotting_intervals.py +0 -38
  53. eventsourcing/examples/bankaccounts/__init__.py +0 -0
  54. eventsourcing/examples/bankaccounts/application.py +0 -70
  55. eventsourcing/examples/bankaccounts/domainmodel.py +0 -56
  56. eventsourcing/examples/bankaccounts/test.py +0 -173
  57. eventsourcing/examples/cargoshipping/__init__.py +0 -0
  58. eventsourcing/examples/cargoshipping/application.py +0 -126
  59. eventsourcing/examples/cargoshipping/domainmodel.py +0 -330
  60. eventsourcing/examples/cargoshipping/interface.py +0 -143
  61. eventsourcing/examples/cargoshipping/test.py +0 -231
  62. eventsourcing/examples/contentmanagement/__init__.py +0 -0
  63. eventsourcing/examples/contentmanagement/application.py +0 -118
  64. eventsourcing/examples/contentmanagement/domainmodel.py +0 -69
  65. eventsourcing/examples/contentmanagement/test.py +0 -180
  66. eventsourcing/examples/contentmanagement/utils.py +0 -26
  67. eventsourcing/examples/contentmanagementsystem/__init__.py +0 -0
  68. eventsourcing/examples/contentmanagementsystem/application.py +0 -54
  69. eventsourcing/examples/contentmanagementsystem/postgres.py +0 -17
  70. eventsourcing/examples/contentmanagementsystem/sqlite.py +0 -17
  71. eventsourcing/examples/contentmanagementsystem/system.py +0 -14
  72. eventsourcing/examples/contentmanagementsystem/test_system.py +0 -180
  73. eventsourcing/examples/searchablecontent/__init__.py +0 -0
  74. eventsourcing/examples/searchablecontent/application.py +0 -45
  75. eventsourcing/examples/searchablecontent/persistence.py +0 -23
  76. eventsourcing/examples/searchablecontent/postgres.py +0 -118
  77. eventsourcing/examples/searchablecontent/sqlite.py +0 -136
  78. eventsourcing/examples/searchablecontent/test_application.py +0 -110
  79. eventsourcing/examples/searchablecontent/test_recorder.py +0 -68
  80. eventsourcing/examples/searchabletimestamps/__init__.py +0 -0
  81. eventsourcing/examples/searchabletimestamps/application.py +0 -32
  82. eventsourcing/examples/searchabletimestamps/persistence.py +0 -20
  83. eventsourcing/examples/searchabletimestamps/postgres.py +0 -110
  84. eventsourcing/examples/searchabletimestamps/sqlite.py +0 -99
  85. eventsourcing/examples/searchabletimestamps/test_searchabletimestamps.py +0 -94
  86. eventsourcing/examples/test_invoice.py +0 -176
  87. eventsourcing/examples/test_parking_lot.py +0 -206
  88. eventsourcing/tests/application_tests/__init__.py +0 -0
  89. eventsourcing/tests/application_tests/test_application_with_automatic_snapshotting.py +0 -55
  90. eventsourcing/tests/application_tests/test_application_with_popo.py +0 -22
  91. eventsourcing/tests/application_tests/test_application_with_postgres.py +0 -75
  92. eventsourcing/tests/application_tests/test_application_with_sqlite.py +0 -72
  93. eventsourcing/tests/application_tests/test_cache.py +0 -134
  94. eventsourcing/tests/application_tests/test_event_sourced_log.py +0 -162
  95. eventsourcing/tests/application_tests/test_notificationlog.py +0 -232
  96. eventsourcing/tests/application_tests/test_notificationlogreader.py +0 -126
  97. eventsourcing/tests/application_tests/test_processapplication.py +0 -110
  98. eventsourcing/tests/application_tests/test_processingpolicy.py +0 -109
  99. eventsourcing/tests/application_tests/test_repository.py +0 -504
  100. eventsourcing/tests/application_tests/test_snapshotting.py +0 -68
  101. eventsourcing/tests/application_tests/test_upcasting.py +0 -459
  102. eventsourcing/tests/docs_tests/__init__.py +0 -0
  103. eventsourcing/tests/docs_tests/test_docs.py +0 -293
  104. eventsourcing/tests/domain_tests/__init__.py +0 -0
  105. eventsourcing/tests/domain_tests/test_aggregate.py +0 -1200
  106. eventsourcing/tests/domain_tests/test_aggregate_decorators.py +0 -1604
  107. eventsourcing/tests/domain_tests/test_domainevent.py +0 -80
  108. eventsourcing/tests/interface_tests/__init__.py +0 -0
  109. eventsourcing/tests/interface_tests/test_remotenotificationlog.py +0 -258
  110. eventsourcing/tests/persistence_tests/__init__.py +0 -0
  111. eventsourcing/tests/persistence_tests/test_aes.py +0 -93
  112. eventsourcing/tests/persistence_tests/test_connection_pool.py +0 -722
  113. eventsourcing/tests/persistence_tests/test_eventstore.py +0 -72
  114. eventsourcing/tests/persistence_tests/test_infrastructure_factory.py +0 -21
  115. eventsourcing/tests/persistence_tests/test_mapper.py +0 -113
  116. eventsourcing/tests/persistence_tests/test_noninterleaving_notification_ids.py +0 -69
  117. eventsourcing/tests/persistence_tests/test_popo.py +0 -124
  118. eventsourcing/tests/persistence_tests/test_postgres.py +0 -1119
  119. eventsourcing/tests/persistence_tests/test_sqlite.py +0 -348
  120. eventsourcing/tests/persistence_tests/test_transcoder.py +0 -44
  121. eventsourcing/tests/system_tests/__init__.py +0 -0
  122. eventsourcing/tests/system_tests/test_runner.py +0 -935
  123. eventsourcing/tests/system_tests/test_system.py +0 -284
  124. eventsourcing/tests/utils_tests/__init__.py +0 -0
  125. eventsourcing/tests/utils_tests/test_utils.py +0 -226
  126. eventsourcing-9.3.2.dist-info/RECORD +0 -145
  127. {eventsourcing-9.3.2.dist-info → eventsourcing-9.3.4.dist-info}/AUTHORS +0 -0
  128. {eventsourcing-9.3.2.dist-info → eventsourcing-9.3.4.dist-info}/LICENSE +0 -0
  129. {eventsourcing-9.3.2.dist-info → eventsourcing-9.3.4.dist-info}/WHEEL +0 -0
@@ -1,162 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from typing import TYPE_CHECKING
4
- from unittest import TestCase
5
- from uuid import NAMESPACE_URL, UUID, uuid4, uuid5
6
-
7
- from eventsourcing.application import Application, EventSourcedLog
8
- from eventsourcing.domain import Aggregate, DomainEvent
9
- from eventsourcing.persistence import (
10
- DatetimeAsISO,
11
- DecimalAsStr,
12
- EventStore,
13
- JSONTranscoder,
14
- Mapper,
15
- UUIDAsHex,
16
- )
17
- from eventsourcing.popo import POPOAggregateRecorder
18
-
19
- if TYPE_CHECKING: # pragma: nocover
20
- from eventsourcing.utils import EnvType
21
-
22
-
23
- class TestEventSourcedLog(TestCase):
24
- def test_logging_aggregate_ids(self) -> None:
25
- class LoggedID(DomainEvent):
26
- aggregate_id: UUID
27
-
28
- transcoder = JSONTranscoder()
29
- transcoder.register(UUIDAsHex())
30
- transcoder.register(DecimalAsStr())
31
- transcoder.register(DatetimeAsISO())
32
-
33
- event_recorder = POPOAggregateRecorder()
34
- event_store = EventStore(
35
- mapper=Mapper(transcoder=transcoder),
36
- recorder=event_recorder,
37
- )
38
-
39
- log: EventSourcedLog[LoggedID] = EventSourcedLog(
40
- events=event_store,
41
- originator_id=uuid5(NAMESPACE_URL, "/aggregates"),
42
- logged_cls=LoggedID,
43
- )
44
- id1 = uuid4()
45
- id2 = uuid4()
46
- id3 = uuid4()
47
-
48
- self.assertEqual(log.get_first(), None)
49
- self.assertEqual(log.get_last(), None)
50
- logged = log.trigger_event(aggregate_id=id1)
51
- event_store.put([logged])
52
- first = log.get_first()
53
- assert first
54
- self.assertEqual(first.aggregate_id, id1)
55
- last = log.get_last()
56
- assert last
57
- self.assertEqual(last.aggregate_id, id1)
58
- logged = log.trigger_event(aggregate_id=id2)
59
- event_store.put([logged])
60
- last = log.get_last()
61
- assert last
62
- self.assertEqual(last.aggregate_id, id2)
63
- logged = log.trigger_event(aggregate_id=id3, next_originator_version=3)
64
- event_store.put([logged])
65
- last = log.get_last()
66
- assert last
67
- self.assertEqual(last.aggregate_id, id3)
68
- first = log.get_first()
69
- assert first
70
- self.assertEqual(first.aggregate_id, id1)
71
-
72
- ids = [e.aggregate_id for e in log.get()]
73
- self.assertEqual(ids, [id1, id2, id3])
74
-
75
- ids = [e.aggregate_id for e in log.get(gt=1)]
76
- self.assertEqual(ids, [id2, id3])
77
-
78
- ids = [e.aggregate_id for e in log.get(lte=2)]
79
- self.assertEqual(ids, [id1, id2])
80
-
81
- ids = [e.aggregate_id for e in log.get(limit=1)]
82
- self.assertEqual(ids, [id1])
83
-
84
- ids = [e.aggregate_id for e in log.get(desc=True)]
85
- self.assertEqual(ids, [id3, id2, id1])
86
-
87
- def test_with_application(self) -> None:
88
- class LoggedID(DomainEvent):
89
- aggregate_id: UUID
90
-
91
- class MyApplication(Application):
92
- def __init__(self, env: EnvType | None = None) -> None:
93
- super().__init__(env=env)
94
- self.aggregate_log = EventSourcedLog(
95
- events=self.events,
96
- originator_id=uuid5(NAMESPACE_URL, "/aggregates"),
97
- logged_cls=LoggedID,
98
- )
99
-
100
- def create_aggregate(self) -> UUID:
101
- aggregate = Aggregate()
102
- logged_id = self.aggregate_log.trigger_event(aggregate_id=aggregate.id)
103
- self.save(aggregate, logged_id)
104
- return aggregate.id
105
-
106
- app = MyApplication()
107
-
108
- self.assertEqual(app.aggregate_log.get_last(), None)
109
-
110
- aggregate1_id = app.create_aggregate()
111
- last = app.aggregate_log.get_last()
112
- assert last
113
- self.assertEqual(last.aggregate_id, aggregate1_id)
114
-
115
- aggregate2_id = app.create_aggregate()
116
- last = app.aggregate_log.get_last()
117
- assert last
118
- self.assertEqual(last.aggregate_id, aggregate2_id)
119
-
120
- aggregate_ids = [i.aggregate_id for i in app.aggregate_log.get()]
121
- self.assertEqual(aggregate_ids, [aggregate1_id, aggregate2_id])
122
-
123
- def test_subclasses(self) -> None:
124
- transcoder = JSONTranscoder()
125
- transcoder.register(UUIDAsHex())
126
- transcoder.register(DecimalAsStr())
127
- transcoder.register(DatetimeAsISO())
128
-
129
- event_recorder = POPOAggregateRecorder()
130
- event_store = EventStore(
131
- mapper=Mapper(transcoder=transcoder),
132
- recorder=event_recorder,
133
- )
134
-
135
- class TransactionLogEvent(DomainEvent):
136
- pass
137
-
138
- class AccountCredited(TransactionLogEvent):
139
- pass
140
-
141
- class AccountDebited(TransactionLogEvent):
142
- pass
143
-
144
- # Subclass EventSourcedLog.
145
- class TransactionLog(EventSourcedLog[TransactionLogEvent]):
146
- def account_credited(self) -> AccountCredited:
147
- return self._trigger_event(logged_cls=AccountCredited)
148
-
149
- def account_debited(self) -> AccountDebited:
150
- return self._trigger_event(logged_cls=AccountDebited)
151
-
152
- transaction_log = TransactionLog(
153
- events=event_store,
154
- originator_id=uuid5(NAMESPACE_URL, "/aggregates"),
155
- logged_cls=TransactionLogEvent,
156
- )
157
-
158
- account_credited = transaction_log.account_credited()
159
- self.assertIsInstance(account_credited, AccountCredited)
160
-
161
- account_debited = transaction_log.account_debited()
162
- self.assertIsInstance(account_debited, AccountDebited)
@@ -1,232 +0,0 @@
1
- from unittest.case import TestCase
2
- from uuid import uuid4
3
-
4
- from eventsourcing.application import LocalNotificationLog
5
- from eventsourcing.persistence import StoredEvent
6
- from eventsourcing.sqlite import SQLiteApplicationRecorder, SQLiteDatastore
7
-
8
-
9
- class TestNotificationLog(TestCase):
10
- def test_get_section(self):
11
- recorder = SQLiteApplicationRecorder(SQLiteDatastore(":memory:"))
12
- recorder.create_table()
13
-
14
- # Construct notification log.
15
- notification_log = LocalNotificationLog(recorder, section_size=5)
16
-
17
- # Get the "current" section of log.
18
- section = notification_log["1,10"]
19
- self.assertEqual(len(section.items), 0) # event notifications
20
- self.assertEqual(section.id, None)
21
- self.assertEqual(section.next_id, None)
22
-
23
- # Write 5 events.
24
- originator_id = uuid4()
25
- for i in range(5):
26
- stored_event = StoredEvent(
27
- originator_id=originator_id,
28
- originator_version=i,
29
- topic="topic",
30
- state=b"state",
31
- )
32
- recorder.insert_events([stored_event])
33
-
34
- # Get the "head" section of log.
35
- section = notification_log["1,10"]
36
- self.assertEqual(len(section.items), 5) # event notifications
37
- self.assertEqual(section.items[0].id, 1)
38
- self.assertEqual(section.items[1].id, 2)
39
- self.assertEqual(section.items[2].id, 3)
40
- self.assertEqual(section.items[3].id, 4)
41
- self.assertEqual(section.items[4].id, 5)
42
- self.assertEqual(section.id, "1,5")
43
- self.assertEqual(section.next_id, "6,10")
44
-
45
- # Get the "1,5" section of log.
46
- section = notification_log["1,5"]
47
- self.assertEqual(len(section.items), 5) # event notifications
48
- self.assertEqual(section.items[0].id, 1)
49
- self.assertEqual(section.items[1].id, 2)
50
- self.assertEqual(section.items[2].id, 3)
51
- self.assertEqual(section.items[3].id, 4)
52
- self.assertEqual(section.items[4].id, 5)
53
- self.assertEqual(section.id, "1,5")
54
- self.assertEqual(section.next_id, "6,10")
55
-
56
- # Get the next section of log.
57
- section = notification_log["6,10"]
58
- self.assertEqual(len(section.items), 0) # event notifications
59
- self.assertEqual(section.id, None)
60
- self.assertEqual(section.next_id, None)
61
-
62
- # Write 4 events.
63
- originator_id = uuid4()
64
- for i in range(4):
65
- stored_event = StoredEvent(
66
- originator_id=originator_id,
67
- originator_version=i,
68
- topic="topic",
69
- state=b"state",
70
- )
71
- recorder.insert_events([stored_event])
72
-
73
- # Get the next section of log.
74
- section = notification_log["6,10"]
75
- self.assertEqual(len(section.items), 4) # event notifications
76
- self.assertEqual(section.items[0].id, 6)
77
- self.assertEqual(section.items[1].id, 7)
78
- self.assertEqual(section.items[2].id, 8)
79
- self.assertEqual(section.items[3].id, 9)
80
- self.assertEqual(section.id, "6,9")
81
- self.assertEqual(section.next_id, None)
82
-
83
- # Start at non-regular section start.
84
- section = notification_log["3,7"]
85
- self.assertEqual(len(section.items), 5) # event notifications
86
- self.assertEqual(section.items[0].id, 3)
87
- self.assertEqual(section.items[1].id, 4)
88
- self.assertEqual(section.items[2].id, 5)
89
- self.assertEqual(section.items[3].id, 6)
90
- self.assertEqual(section.items[4].id, 7)
91
- self.assertEqual(section.id, "3,7")
92
- self.assertEqual(section.next_id, "8,12")
93
-
94
- # Notification log limits section size.
95
- section = notification_log["3,10"]
96
- self.assertEqual(len(section.items), 5) # event notifications
97
- self.assertEqual(section.items[0].id, 3)
98
- self.assertEqual(section.items[1].id, 4)
99
- self.assertEqual(section.items[2].id, 5)
100
- self.assertEqual(section.items[3].id, 6)
101
- self.assertEqual(section.items[4].id, 7)
102
- self.assertEqual(section.id, "3,7")
103
- self.assertEqual(section.next_id, "8,12")
104
-
105
- # Reader limits section size.
106
- section = notification_log["3,4"]
107
- self.assertEqual(len(section.items), 2) # event notifications
108
- self.assertEqual(section.items[0].id, 3)
109
- self.assertEqual(section.items[1].id, 4)
110
- self.assertEqual(section.id, "3,4")
111
- self.assertEqual(section.next_id, "5,6")
112
-
113
- # Meaningless section ID.
114
- section = notification_log["3,2"]
115
- self.assertEqual(len(section.items), 0) # event notifications
116
- self.assertEqual(section.id, None)
117
- self.assertEqual(section.next_id, None)
118
-
119
- # # Numbers below 1.
120
- # section = notification_log["-3,0"]
121
- # self.assertEqual(
122
- # len(section.items), 4
123
- # ) # event notifications
124
- # self.assertEqual(section.items[0].id, 6)
125
- # self.assertEqual(section.items[1].id, 7)
126
- # self.assertEqual(section.items[2].id, 8)
127
- # self.assertEqual(section.items[3].id, 9)
128
- # self.assertEqual(section.section_id, "6,9")
129
- # self.assertEqual(section.next_id, None)
130
- #
131
- # section = notification_log["-4,0"]
132
- # self.assertEqual(
133
- # len(section.items), 5
134
- # ) # event notifications
135
- # self.assertEqual(section.items[0].id, 5)
136
- # self.assertEqual(section.items[1].id, 6)
137
- # self.assertEqual(section.items[2].id, 7)
138
- # self.assertEqual(section.items[3].id, 8)
139
- # self.assertEqual(section.items[4].id, 9)
140
- # self.assertEqual(section.section_id, "5,9")
141
- # self.assertEqual(section.next_id, "10,14")
142
- #
143
- # section = notification_log["-4,-1"]
144
- # self.assertEqual(
145
- # len(section.items), 4
146
- # ) # event notifications
147
- # self.assertEqual(section.items[0].id, 5)
148
- # self.assertEqual(section.items[1].id, 6)
149
- # self.assertEqual(section.items[2].id, 7)
150
- # self.assertEqual(section.items[3].id, 8)
151
- # self.assertEqual(section.section_id, "5,8")
152
- # self.assertEqual(section.next_id, "9,12")
153
-
154
- def test_select(self):
155
- recorder = SQLiteApplicationRecorder(SQLiteDatastore(":memory:"))
156
- recorder.create_table()
157
-
158
- # Construct notification log.
159
- notification_log = LocalNotificationLog(recorder, section_size=10)
160
-
161
- # Select start 1, limit 10
162
- notifications = notification_log.select(1, 10)
163
- self.assertEqual(len(notifications), 0)
164
-
165
- # Write 5 events.
166
- originator_id = uuid4()
167
- for i in range(5):
168
- stored_event = StoredEvent(
169
- originator_id=originator_id,
170
- originator_version=i,
171
- topic="topic",
172
- state=b"state",
173
- )
174
- recorder.insert_events([stored_event])
175
-
176
- # Select start 1, limit 10
177
- notifications = notification_log.select(1, 5)
178
- self.assertEqual(len(notifications), 5)
179
- self.assertEqual(notifications[0].id, 1)
180
- self.assertEqual(notifications[1].id, 2)
181
- self.assertEqual(notifications[2].id, 3)
182
- self.assertEqual(notifications[3].id, 4)
183
- self.assertEqual(notifications[4].id, 5)
184
-
185
- # Select start 1, limit 10
186
- notifications = notification_log.select(1, 5)
187
- self.assertEqual(len(notifications), 5)
188
- self.assertEqual(notifications[0].id, 1)
189
- self.assertEqual(notifications[1].id, 2)
190
- self.assertEqual(notifications[2].id, 3)
191
- self.assertEqual(notifications[3].id, 4)
192
- self.assertEqual(notifications[4].id, 5)
193
-
194
- # Select start 6, limit 5
195
- notifications = notification_log.select(6, 5)
196
- self.assertEqual(len(notifications), 0)
197
-
198
- # Write 4 events.
199
- originator_id = uuid4()
200
- for i in range(4):
201
- stored_event = StoredEvent(
202
- originator_id=originator_id,
203
- originator_version=i,
204
- topic="topic",
205
- state=b"state",
206
- )
207
- recorder.insert_events([stored_event])
208
-
209
- # Select start 6, limit 5
210
- notifications = notification_log.select(6, 5)
211
- self.assertEqual(len(notifications), 4) # event notifications
212
- self.assertEqual(notifications[0].id, 6)
213
- self.assertEqual(notifications[1].id, 7)
214
- self.assertEqual(notifications[2].id, 8)
215
- self.assertEqual(notifications[3].id, 9)
216
-
217
- # Select start 3, limit 5
218
- notifications = notification_log.select(3, 5)
219
- self.assertEqual(len(notifications), 5) # event notifications
220
- self.assertEqual(notifications[0].id, 3)
221
- self.assertEqual(notifications[1].id, 4)
222
- self.assertEqual(notifications[2].id, 5)
223
- self.assertEqual(notifications[3].id, 6)
224
- self.assertEqual(notifications[4].id, 7)
225
-
226
- # Notification log limits limit.
227
- # Select start 1, limit 20
228
- with self.assertRaises(ValueError) as cm:
229
- notification_log.select(1, 20)
230
- self.assertEqual(
231
- cm.exception.args[0], "Requested limit 20 greater than section size 10"
232
- )
@@ -1,126 +0,0 @@
1
- from itertools import chain
2
- from unittest.case import TestCase
3
- from uuid import uuid4
4
-
5
- from eventsourcing.application import LocalNotificationLog
6
- from eventsourcing.persistence import StoredEvent
7
- from eventsourcing.sqlite import SQLiteDatastore, SQLiteProcessRecorder
8
- from eventsourcing.system import NotificationLogReader
9
-
10
-
11
- class TestNotificationLogReader(TestCase):
12
- def test_read(self):
13
- recorder = SQLiteProcessRecorder(SQLiteDatastore(":memory:"))
14
- recorder.create_table()
15
-
16
- # Construct notification log.
17
- notification_log = LocalNotificationLog(recorder, section_size=5)
18
- reader = NotificationLogReader(notification_log, section_size=10)
19
- notifications = list(reader.read(start=1))
20
- self.assertEqual(len(notifications), 0)
21
-
22
- # Write 5 events.
23
- originator_id = uuid4()
24
- for i in range(5):
25
- stored_event = StoredEvent(
26
- originator_id=originator_id,
27
- originator_version=i,
28
- topic="topic",
29
- state=b"state",
30
- )
31
- recorder.insert_events(
32
- [stored_event],
33
- )
34
-
35
- notifications = list(reader.read(start=1))
36
- self.assertEqual(len(notifications), 5)
37
-
38
- # Write 4 events.
39
- originator_id = uuid4()
40
- for i in range(4):
41
- stored_event = StoredEvent(
42
- originator_id=originator_id,
43
- originator_version=i,
44
- topic="topic",
45
- state=b"state",
46
- )
47
- recorder.insert_events([stored_event])
48
-
49
- notifications = list(reader.read(start=1))
50
- self.assertEqual(len(notifications), 9)
51
-
52
- notifications = list(reader.read(start=2))
53
- self.assertEqual(len(notifications), 8)
54
-
55
- notifications = list(reader.read(start=3))
56
- self.assertEqual(len(notifications), 7)
57
-
58
- notifications = list(reader.read(start=4))
59
- self.assertEqual(len(notifications), 6)
60
-
61
- notifications = list(reader.read(start=8))
62
- self.assertEqual(len(notifications), 2)
63
-
64
- notifications = list(reader.read(start=9))
65
- self.assertEqual(len(notifications), 1)
66
-
67
- notifications = list(reader.read(start=10))
68
- self.assertEqual(len(notifications), 0)
69
-
70
- def test_select(self):
71
- recorder = SQLiteProcessRecorder(SQLiteDatastore(":memory:"))
72
- recorder.create_table()
73
-
74
- # Construct notification log.
75
- notification_log = LocalNotificationLog(recorder, section_size=5)
76
- reader = NotificationLogReader(notification_log, section_size=5)
77
- notifications = list(chain(*reader.select(start=1)))
78
- self.assertEqual(len(notifications), 0)
79
-
80
- # Write 5 events.
81
- originator_id = uuid4()
82
- for i in range(5):
83
- stored_event = StoredEvent(
84
- originator_id=originator_id,
85
- originator_version=i,
86
- topic="topic",
87
- state=b"state",
88
- )
89
- recorder.insert_events(
90
- [stored_event],
91
- )
92
-
93
- notifications = list(chain(*reader.select(start=1)))
94
- self.assertEqual(len(notifications), 5)
95
-
96
- # Write 4 events.
97
- originator_id = uuid4()
98
- for i in range(4):
99
- stored_event = StoredEvent(
100
- originator_id=originator_id,
101
- originator_version=i,
102
- topic="topic",
103
- state=b"state",
104
- )
105
- recorder.insert_events([stored_event])
106
-
107
- notifications = list(chain(*reader.select(start=1)))
108
- self.assertEqual(len(notifications), 9)
109
-
110
- notifications = list(chain(*reader.select(start=2)))
111
- self.assertEqual(len(notifications), 8)
112
-
113
- notifications = list(chain(*reader.select(start=3)))
114
- self.assertEqual(len(notifications), 7)
115
-
116
- notifications = list(chain(*reader.select(start=4)))
117
- self.assertEqual(len(notifications), 6)
118
-
119
- notifications = list(chain(*reader.select(start=8)))
120
- self.assertEqual(len(notifications), 2)
121
-
122
- notifications = list(chain(*reader.select(start=9)))
123
- self.assertEqual(len(notifications), 1)
124
-
125
- notifications = list(chain(*reader.select(start=10)))
126
- self.assertEqual(len(notifications), 0)
@@ -1,110 +0,0 @@
1
- from unittest.case import TestCase
2
-
3
- from eventsourcing.application import RecordingEvent
4
- from eventsourcing.dispatch import singledispatchmethod
5
- from eventsourcing.domain import AggregateEvent
6
- from eventsourcing.persistence import Transcoder
7
- from eventsourcing.system import (
8
- Follower,
9
- Leader,
10
- ProcessApplication,
11
- ProcessingEvent,
12
- RecordingEventReceiver,
13
- )
14
- from eventsourcing.tests.application import BankAccounts, EmailAddressAsStr
15
- from eventsourcing.tests.application_tests.test_processingpolicy import (
16
- EmailNotification,
17
- )
18
- from eventsourcing.tests.domain import BankAccount
19
-
20
-
21
- class TestProcessApplication(TestCase):
22
- def test_pull_and_process(self):
23
- leader_cls = type(
24
- BankAccounts.__name__,
25
- (BankAccounts, Leader),
26
- {},
27
- )
28
-
29
- accounts = leader_cls()
30
- email_process = EmailProcess()
31
- email_process.follow(
32
- accounts.name,
33
- accounts.notification_log,
34
- )
35
-
36
- section = email_process.notification_log["1,5"]
37
- self.assertEqual(len(section.items), 0)
38
-
39
- accounts.open_account("Alice", "alice@example.com")
40
-
41
- email_process.pull_and_process(BankAccounts.name)
42
-
43
- section = email_process.notification_log["1,5"]
44
- self.assertEqual(len(section.items), 1)
45
-
46
- # Check we have processed the first event.
47
- self.assertEqual(email_process.recorder.max_tracking_id(BankAccounts.name), 1)
48
-
49
- # Check reprocessing first event changes nothing (swallows IntegrityError).
50
- email_process.pull_and_process(BankAccounts.name, start=1)
51
- self.assertEqual(email_process.recorder.max_tracking_id(BankAccounts.name), 1)
52
-
53
- # Check we can continue from the next position.
54
- email_process.pull_and_process(BankAccounts.name, start=2)
55
-
56
- # Check we haven't actually processed anything further.
57
- self.assertEqual(email_process.recorder.max_tracking_id(BankAccounts.name), 1)
58
- section = email_process.notification_log["1,5"]
59
- self.assertEqual(len(section.items), 1)
60
-
61
- # Subscribe for notifications.
62
- accounts.lead(PromptForwarder(email_process))
63
-
64
- # Create another notification.
65
- accounts.open_account("Bob", "bob@example.com")
66
-
67
- # Check we have processed the next notification.
68
- section = email_process.notification_log["1,5"]
69
- self.assertEqual(len(section.items), 2)
70
-
71
- # Check we have actually processed the second event.
72
- self.assertEqual(email_process.recorder.max_tracking_id(BankAccounts.name), 2)
73
-
74
-
75
- class EmailProcess(ProcessApplication):
76
- def register_transcodings(self, transcoder: Transcoder) -> None:
77
- super().register_transcodings(transcoder)
78
- transcoder.register(EmailAddressAsStr())
79
-
80
- @singledispatchmethod
81
- def policy(
82
- self,
83
- domain_event: AggregateEvent,
84
- processing_event: ProcessingEvent,
85
- ):
86
- """Default policy"""
87
-
88
- @policy.register
89
- def _(
90
- self,
91
- domain_event: BankAccount.Opened,
92
- processing_event: ProcessingEvent,
93
- ):
94
- notification = EmailNotification.create(
95
- to=domain_event.email_address,
96
- subject="Your New Account",
97
- message=f"Dear {domain_event.full_name}, ...",
98
- )
99
- processing_event.collect_events(notification)
100
-
101
-
102
- class PromptForwarder(RecordingEventReceiver):
103
- def __init__(self, application: Follower):
104
- self.application = application
105
-
106
- def receive_recording_event(self, recording_event: RecordingEvent) -> None:
107
- self.application.pull_and_process(
108
- leader_name=recording_event.application_name,
109
- start=recording_event.recordings[0].notification.id,
110
- )