eventsourcing 9.2.22__py3-none-any.whl → 9.3.0__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.
- eventsourcing/__init__.py +1 -1
- eventsourcing/application.py +116 -135
- eventsourcing/cipher.py +15 -12
- eventsourcing/dispatch.py +31 -91
- eventsourcing/domain.py +220 -226
- eventsourcing/examples/__init__.py +0 -0
- eventsourcing/examples/aggregate1/__init__.py +0 -0
- eventsourcing/examples/aggregate1/application.py +27 -0
- eventsourcing/examples/aggregate1/domainmodel.py +16 -0
- eventsourcing/examples/aggregate1/test_application.py +37 -0
- eventsourcing/examples/aggregate2/__init__.py +0 -0
- eventsourcing/examples/aggregate2/application.py +27 -0
- eventsourcing/examples/aggregate2/domainmodel.py +22 -0
- eventsourcing/examples/aggregate2/test_application.py +37 -0
- eventsourcing/examples/aggregate3/__init__.py +0 -0
- eventsourcing/examples/aggregate3/application.py +27 -0
- eventsourcing/examples/aggregate3/domainmodel.py +38 -0
- eventsourcing/examples/aggregate3/test_application.py +37 -0
- eventsourcing/examples/aggregate4/__init__.py +0 -0
- eventsourcing/examples/aggregate4/application.py +27 -0
- eventsourcing/examples/aggregate4/domainmodel.py +114 -0
- eventsourcing/examples/aggregate4/test_application.py +38 -0
- eventsourcing/examples/aggregate5/__init__.py +0 -0
- eventsourcing/examples/aggregate5/application.py +27 -0
- eventsourcing/examples/aggregate5/domainmodel.py +131 -0
- eventsourcing/examples/aggregate5/test_application.py +38 -0
- eventsourcing/examples/aggregate6/__init__.py +0 -0
- eventsourcing/examples/aggregate6/application.py +30 -0
- eventsourcing/examples/aggregate6/domainmodel.py +123 -0
- eventsourcing/examples/aggregate6/test_application.py +38 -0
- eventsourcing/examples/aggregate6a/__init__.py +0 -0
- eventsourcing/examples/aggregate6a/application.py +40 -0
- eventsourcing/examples/aggregate6a/domainmodel.py +149 -0
- eventsourcing/examples/aggregate6a/test_application.py +45 -0
- eventsourcing/examples/aggregate7/__init__.py +0 -0
- eventsourcing/examples/aggregate7/application.py +48 -0
- eventsourcing/examples/aggregate7/domainmodel.py +144 -0
- eventsourcing/examples/aggregate7/persistence.py +57 -0
- eventsourcing/examples/aggregate7/test_application.py +38 -0
- eventsourcing/examples/aggregate7/test_compression_and_encryption.py +45 -0
- eventsourcing/examples/aggregate7/test_snapshotting_intervals.py +67 -0
- eventsourcing/examples/aggregate7a/__init__.py +0 -0
- eventsourcing/examples/aggregate7a/application.py +56 -0
- eventsourcing/examples/aggregate7a/domainmodel.py +170 -0
- eventsourcing/examples/aggregate7a/test_application.py +46 -0
- eventsourcing/examples/aggregate7a/test_compression_and_encryption.py +45 -0
- eventsourcing/examples/aggregate8/__init__.py +0 -0
- eventsourcing/examples/aggregate8/application.py +47 -0
- eventsourcing/examples/aggregate8/domainmodel.py +65 -0
- eventsourcing/examples/aggregate8/persistence.py +57 -0
- eventsourcing/examples/aggregate8/test_application.py +37 -0
- eventsourcing/examples/aggregate8/test_compression_and_encryption.py +44 -0
- eventsourcing/examples/aggregate8/test_snapshotting_intervals.py +38 -0
- eventsourcing/examples/bankaccounts/__init__.py +0 -0
- eventsourcing/examples/bankaccounts/application.py +70 -0
- eventsourcing/examples/bankaccounts/domainmodel.py +56 -0
- eventsourcing/examples/bankaccounts/test.py +173 -0
- eventsourcing/examples/cargoshipping/__init__.py +0 -0
- eventsourcing/examples/cargoshipping/application.py +126 -0
- eventsourcing/examples/cargoshipping/domainmodel.py +330 -0
- eventsourcing/examples/cargoshipping/interface.py +143 -0
- eventsourcing/examples/cargoshipping/test.py +231 -0
- eventsourcing/examples/contentmanagement/__init__.py +0 -0
- eventsourcing/examples/contentmanagement/application.py +118 -0
- eventsourcing/examples/contentmanagement/domainmodel.py +69 -0
- eventsourcing/examples/contentmanagement/test.py +180 -0
- eventsourcing/examples/contentmanagement/utils.py +26 -0
- eventsourcing/examples/contentmanagementsystem/__init__.py +0 -0
- eventsourcing/examples/contentmanagementsystem/application.py +54 -0
- eventsourcing/examples/contentmanagementsystem/postgres.py +17 -0
- eventsourcing/examples/contentmanagementsystem/sqlite.py +17 -0
- eventsourcing/examples/contentmanagementsystem/system.py +14 -0
- eventsourcing/examples/contentmanagementsystem/test_system.py +180 -0
- eventsourcing/examples/searchablecontent/__init__.py +0 -0
- eventsourcing/examples/searchablecontent/application.py +45 -0
- eventsourcing/examples/searchablecontent/persistence.py +23 -0
- eventsourcing/examples/searchablecontent/postgres.py +118 -0
- eventsourcing/examples/searchablecontent/sqlite.py +136 -0
- eventsourcing/examples/searchablecontent/test_application.py +110 -0
- eventsourcing/examples/searchablecontent/test_recorder.py +68 -0
- eventsourcing/examples/searchabletimestamps/__init__.py +0 -0
- eventsourcing/examples/searchabletimestamps/application.py +32 -0
- eventsourcing/examples/searchabletimestamps/persistence.py +20 -0
- eventsourcing/examples/searchabletimestamps/postgres.py +110 -0
- eventsourcing/examples/searchabletimestamps/sqlite.py +99 -0
- eventsourcing/examples/searchabletimestamps/test_searchabletimestamps.py +94 -0
- eventsourcing/examples/test_invoice.py +176 -0
- eventsourcing/examples/test_parking_lot.py +206 -0
- eventsourcing/interface.py +2 -2
- eventsourcing/persistence.py +85 -81
- eventsourcing/popo.py +30 -31
- eventsourcing/postgres.py +379 -590
- eventsourcing/sqlite.py +91 -99
- eventsourcing/system.py +52 -57
- eventsourcing/tests/application.py +20 -32
- eventsourcing/tests/application_tests/__init__.py +0 -0
- eventsourcing/tests/application_tests/test_application_with_automatic_snapshotting.py +55 -0
- eventsourcing/tests/application_tests/test_application_with_popo.py +22 -0
- eventsourcing/tests/application_tests/test_application_with_postgres.py +75 -0
- eventsourcing/tests/application_tests/test_application_with_sqlite.py +72 -0
- eventsourcing/tests/application_tests/test_cache.py +134 -0
- eventsourcing/tests/application_tests/test_event_sourced_log.py +162 -0
- eventsourcing/tests/application_tests/test_notificationlog.py +232 -0
- eventsourcing/tests/application_tests/test_notificationlogreader.py +126 -0
- eventsourcing/tests/application_tests/test_processapplication.py +110 -0
- eventsourcing/tests/application_tests/test_processingpolicy.py +109 -0
- eventsourcing/tests/application_tests/test_repository.py +504 -0
- eventsourcing/tests/application_tests/test_snapshotting.py +68 -0
- eventsourcing/tests/application_tests/test_upcasting.py +459 -0
- eventsourcing/tests/docs_tests/__init__.py +0 -0
- eventsourcing/tests/docs_tests/test_docs.py +293 -0
- eventsourcing/tests/domain.py +1 -1
- eventsourcing/tests/domain_tests/__init__.py +0 -0
- eventsourcing/tests/domain_tests/test_aggregate.py +1180 -0
- eventsourcing/tests/domain_tests/test_aggregate_decorators.py +1604 -0
- eventsourcing/tests/domain_tests/test_domainevent.py +80 -0
- eventsourcing/tests/interface_tests/__init__.py +0 -0
- eventsourcing/tests/interface_tests/test_remotenotificationlog.py +258 -0
- eventsourcing/tests/persistence.py +52 -50
- eventsourcing/tests/persistence_tests/__init__.py +0 -0
- eventsourcing/tests/persistence_tests/test_aes.py +93 -0
- eventsourcing/tests/persistence_tests/test_connection_pool.py +722 -0
- eventsourcing/tests/persistence_tests/test_eventstore.py +72 -0
- eventsourcing/tests/persistence_tests/test_infrastructure_factory.py +21 -0
- eventsourcing/tests/persistence_tests/test_mapper.py +113 -0
- eventsourcing/tests/persistence_tests/test_noninterleaving_notification_ids.py +69 -0
- eventsourcing/tests/persistence_tests/test_popo.py +124 -0
- eventsourcing/tests/persistence_tests/test_postgres.py +1119 -0
- eventsourcing/tests/persistence_tests/test_sqlite.py +348 -0
- eventsourcing/tests/persistence_tests/test_transcoder.py +44 -0
- eventsourcing/tests/postgres_utils.py +7 -7
- eventsourcing/tests/system_tests/__init__.py +0 -0
- eventsourcing/tests/system_tests/test_runner.py +935 -0
- eventsourcing/tests/system_tests/test_system.py +284 -0
- eventsourcing/tests/utils_tests/__init__.py +0 -0
- eventsourcing/tests/utils_tests/test_utils.py +226 -0
- eventsourcing/utils.py +47 -50
- {eventsourcing-9.2.22.dist-info → eventsourcing-9.3.0.dist-info}/METADATA +29 -79
- eventsourcing-9.3.0.dist-info/RECORD +145 -0
- {eventsourcing-9.2.22.dist-info → eventsourcing-9.3.0.dist-info}/WHEEL +1 -2
- eventsourcing-9.2.22.dist-info/RECORD +0 -25
- eventsourcing-9.2.22.dist-info/top_level.txt +0 -1
- {eventsourcing-9.2.22.dist-info → eventsourcing-9.3.0.dist-info}/AUTHORS +0 -0
- {eventsourcing-9.2.22.dist-info → eventsourcing-9.3.0.dist-info}/LICENSE +0 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
from decimal import Decimal
|
|
2
|
+
from unittest.case import TestCase
|
|
3
|
+
|
|
4
|
+
from eventsourcing.persistence import (
|
|
5
|
+
DatetimeAsISO,
|
|
6
|
+
DecimalAsStr,
|
|
7
|
+
EventStore,
|
|
8
|
+
JSONTranscoder,
|
|
9
|
+
Mapper,
|
|
10
|
+
UUIDAsHex,
|
|
11
|
+
)
|
|
12
|
+
from eventsourcing.sqlite import SQLiteAggregateRecorder, SQLiteDatastore
|
|
13
|
+
from eventsourcing.tests.application import EmailAddressAsStr
|
|
14
|
+
from eventsourcing.tests.domain import BankAccount
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class TestEventStore(TestCase):
|
|
18
|
+
def test(self):
|
|
19
|
+
# Open an account.
|
|
20
|
+
account = BankAccount.open(
|
|
21
|
+
full_name="Alice",
|
|
22
|
+
email_address="alice@example.com",
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
# Credit the account.
|
|
26
|
+
account.append_transaction(Decimal("10.00"))
|
|
27
|
+
account.append_transaction(Decimal("25.00"))
|
|
28
|
+
account.append_transaction(Decimal("30.00"))
|
|
29
|
+
|
|
30
|
+
# Collect pending events.
|
|
31
|
+
pending = account.collect_events()
|
|
32
|
+
|
|
33
|
+
# Construct event store.
|
|
34
|
+
transcoder = JSONTranscoder()
|
|
35
|
+
transcoder.register(UUIDAsHex())
|
|
36
|
+
transcoder.register(DecimalAsStr())
|
|
37
|
+
transcoder.register(DatetimeAsISO())
|
|
38
|
+
transcoder.register(EmailAddressAsStr())
|
|
39
|
+
recorder = SQLiteAggregateRecorder(SQLiteDatastore(":memory:"))
|
|
40
|
+
event_store = EventStore(
|
|
41
|
+
mapper=Mapper(transcoder),
|
|
42
|
+
recorder=recorder,
|
|
43
|
+
)
|
|
44
|
+
recorder.create_table()
|
|
45
|
+
|
|
46
|
+
# Get last event.
|
|
47
|
+
stored_events = event_store.get(account.id, desc=True, limit=1)
|
|
48
|
+
self.assertEqual(list(stored_events), [])
|
|
49
|
+
|
|
50
|
+
# Store pending events.
|
|
51
|
+
event_store.put(pending)
|
|
52
|
+
|
|
53
|
+
# Get domain events.
|
|
54
|
+
domain_events = event_store.get(account.id)
|
|
55
|
+
|
|
56
|
+
# Reconstruct the bank account.
|
|
57
|
+
copy = None
|
|
58
|
+
for domain_event in domain_events:
|
|
59
|
+
copy = domain_event.mutate(copy)
|
|
60
|
+
|
|
61
|
+
# Check copy has correct attribute values.
|
|
62
|
+
self.assertEqual(copy.id, account.id)
|
|
63
|
+
self.assertEqual(copy.balance, Decimal("65.00"))
|
|
64
|
+
|
|
65
|
+
# Get last event.
|
|
66
|
+
events = event_store.get(account.id, desc=True, limit=1)
|
|
67
|
+
events = list(events)
|
|
68
|
+
self.assertEqual(len(events), 1)
|
|
69
|
+
last_event = events[0]
|
|
70
|
+
|
|
71
|
+
self.assertEqual(last_event.originator_id, account.id)
|
|
72
|
+
assert type(last_event) is BankAccount.TransactionAppended
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from unittest.case import TestCase
|
|
2
|
+
|
|
3
|
+
from eventsourcing.persistence import InfrastructureFactory
|
|
4
|
+
from eventsourcing.utils import Environment, get_topic
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class TestInfrastructureFactoryErrors(TestCase):
|
|
8
|
+
def test_construct_raises_exception(self):
|
|
9
|
+
with self.assertRaises(EnvironmentError):
|
|
10
|
+
InfrastructureFactory.construct(
|
|
11
|
+
Environment(
|
|
12
|
+
env={InfrastructureFactory.PERSISTENCE_MODULE: "invalid topic"}
|
|
13
|
+
)
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
with self.assertRaises(AssertionError):
|
|
17
|
+
InfrastructureFactory.construct(
|
|
18
|
+
Environment(
|
|
19
|
+
env={InfrastructureFactory.PERSISTENCE_MODULE: get_topic(object)}
|
|
20
|
+
)
|
|
21
|
+
)
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import warnings
|
|
2
|
+
from decimal import Decimal
|
|
3
|
+
from unittest.case import TestCase
|
|
4
|
+
from uuid import uuid4
|
|
5
|
+
|
|
6
|
+
from eventsourcing.cipher import AESCipher
|
|
7
|
+
from eventsourcing.compressor import ZlibCompressor
|
|
8
|
+
from eventsourcing.domain import AggregateEvent
|
|
9
|
+
from eventsourcing.persistence import (
|
|
10
|
+
DatetimeAsISO,
|
|
11
|
+
DecimalAsStr,
|
|
12
|
+
JSONTranscoder,
|
|
13
|
+
Mapper,
|
|
14
|
+
UUIDAsHex,
|
|
15
|
+
)
|
|
16
|
+
from eventsourcing.tests.domain import BankAccount
|
|
17
|
+
from eventsourcing.utils import Environment
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class TestMapper(TestCase):
|
|
21
|
+
def test(self):
|
|
22
|
+
# Construct transcoder.
|
|
23
|
+
transcoder = JSONTranscoder()
|
|
24
|
+
transcoder.register(UUIDAsHex())
|
|
25
|
+
transcoder.register(DecimalAsStr())
|
|
26
|
+
transcoder.register(DatetimeAsISO())
|
|
27
|
+
|
|
28
|
+
# Construct cipher.
|
|
29
|
+
environment = Environment()
|
|
30
|
+
environment[AESCipher.CIPHER_KEY] = AESCipher.create_key(16)
|
|
31
|
+
cipher = AESCipher(environment)
|
|
32
|
+
|
|
33
|
+
# Construct compressor.
|
|
34
|
+
compressor = ZlibCompressor()
|
|
35
|
+
|
|
36
|
+
# Construct mapper with cipher.
|
|
37
|
+
mapper = Mapper(transcoder=transcoder, cipher=cipher)
|
|
38
|
+
|
|
39
|
+
# Create a domain event.
|
|
40
|
+
domain_event = BankAccount.TransactionAppended(
|
|
41
|
+
originator_id=uuid4(),
|
|
42
|
+
originator_version=123456,
|
|
43
|
+
timestamp=BankAccount.TransactionAppended.create_timestamp(),
|
|
44
|
+
amount=Decimal("10.00"),
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
# Map to stored event.
|
|
48
|
+
stored_event = mapper.to_stored_event(domain_event)
|
|
49
|
+
|
|
50
|
+
# Map to domain event.
|
|
51
|
+
copy = mapper.to_domain_event(stored_event)
|
|
52
|
+
|
|
53
|
+
# Check values are not visible.
|
|
54
|
+
self.assertNotIn("Alice", str(stored_event.state))
|
|
55
|
+
|
|
56
|
+
# Check decrypted copy has correct values.
|
|
57
|
+
self.assertEqual(copy.originator_id, domain_event.originator_id)
|
|
58
|
+
self.assertEqual(copy.originator_version, domain_event.originator_version)
|
|
59
|
+
self.assertEqual(copy.timestamp, domain_event.timestamp)
|
|
60
|
+
self.assertEqual(copy.originator_version, domain_event.originator_version)
|
|
61
|
+
|
|
62
|
+
self.assertEqual(len(stored_event.state), 162)
|
|
63
|
+
|
|
64
|
+
# Construct mapper with cipher and compressor.
|
|
65
|
+
mapper = Mapper(
|
|
66
|
+
transcoder=transcoder,
|
|
67
|
+
cipher=cipher,
|
|
68
|
+
compressor=compressor,
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
# Map to stored event.
|
|
72
|
+
stored_event = mapper.to_stored_event(domain_event)
|
|
73
|
+
|
|
74
|
+
# Map to domain event.
|
|
75
|
+
copy = mapper.to_domain_event(stored_event)
|
|
76
|
+
|
|
77
|
+
# Check decompressed copy has correct values.
|
|
78
|
+
self.assertEqual(copy.originator_id, domain_event.originator_id)
|
|
79
|
+
self.assertEqual(copy.originator_version, domain_event.originator_version)
|
|
80
|
+
|
|
81
|
+
self.assertIn(len(stored_event.state), range(129, 143))
|
|
82
|
+
|
|
83
|
+
def test_from_domain_event_gives_deprecated_warning(self):
|
|
84
|
+
# Construct transcoder.
|
|
85
|
+
transcoder = JSONTranscoder()
|
|
86
|
+
transcoder.register(UUIDAsHex())
|
|
87
|
+
transcoder.register(DatetimeAsISO())
|
|
88
|
+
|
|
89
|
+
# Construct mapper with cipher.
|
|
90
|
+
mapper = Mapper(transcoder=transcoder)
|
|
91
|
+
|
|
92
|
+
# Create a domain event.
|
|
93
|
+
domain_event = AggregateEvent(
|
|
94
|
+
originator_id=uuid4(),
|
|
95
|
+
originator_version=123456,
|
|
96
|
+
timestamp=AggregateEvent.create_timestamp(),
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
# Verify deprecation warning.
|
|
100
|
+
with warnings.catch_warnings(record=True) as w:
|
|
101
|
+
stored_event = mapper.from_domain_event(domain_event)
|
|
102
|
+
|
|
103
|
+
self.assertEqual(len(w), 1)
|
|
104
|
+
self.assertIs(w[-1].category, DeprecationWarning)
|
|
105
|
+
self.assertEqual(
|
|
106
|
+
"'from_domain_event()' is deprecated, use 'to_stored_event()' instead",
|
|
107
|
+
w[-1].message.args[0],
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
self.assertEqual(stored_event.originator_id, domain_event.originator_id)
|
|
111
|
+
self.assertEqual(
|
|
112
|
+
stored_event.originator_version, domain_event.originator_version
|
|
113
|
+
)
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
from eventsourcing.persistence import ApplicationRecorder
|
|
2
|
+
from eventsourcing.popo import POPOApplicationRecorder
|
|
3
|
+
from eventsourcing.postgres import PostgresApplicationRecorder, PostgresDatastore
|
|
4
|
+
from eventsourcing.sqlite import SQLiteApplicationRecorder, SQLiteDatastore
|
|
5
|
+
from eventsourcing.tests.persistence import (
|
|
6
|
+
NonInterleavingNotificationIDsBaseCase,
|
|
7
|
+
tmpfile_uris,
|
|
8
|
+
)
|
|
9
|
+
from eventsourcing.tests.postgres_utils import drop_postgres_table
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class TestNonInterleavingPOPO(NonInterleavingNotificationIDsBaseCase):
|
|
13
|
+
insert_num = 10000
|
|
14
|
+
|
|
15
|
+
def create_recorder(self) -> ApplicationRecorder:
|
|
16
|
+
return POPOApplicationRecorder()
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class TestNonInterleavingSQLiteInMemory(NonInterleavingNotificationIDsBaseCase):
|
|
20
|
+
insert_num = 10000
|
|
21
|
+
|
|
22
|
+
def create_recorder(self) -> ApplicationRecorder:
|
|
23
|
+
recorder = SQLiteApplicationRecorder(
|
|
24
|
+
SQLiteDatastore(db_name="file::memory:?cache=shared")
|
|
25
|
+
)
|
|
26
|
+
recorder.create_table()
|
|
27
|
+
return recorder
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class TestNonInterleavingSQLiteFileDB(NonInterleavingNotificationIDsBaseCase):
|
|
31
|
+
insert_num = 10000
|
|
32
|
+
|
|
33
|
+
def create_recorder(self) -> ApplicationRecorder:
|
|
34
|
+
self.uris = tmpfile_uris()
|
|
35
|
+
self.db_uri = next(self.uris)
|
|
36
|
+
|
|
37
|
+
recorder = SQLiteApplicationRecorder(SQLiteDatastore(db_name=self.db_uri))
|
|
38
|
+
recorder.create_table()
|
|
39
|
+
return recorder
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class TestNonInterleavingPostgres(NonInterleavingNotificationIDsBaseCase):
|
|
43
|
+
insert_num = 100
|
|
44
|
+
|
|
45
|
+
def setUp(self) -> None:
|
|
46
|
+
self.datastore = PostgresDatastore(
|
|
47
|
+
"eventsourcing",
|
|
48
|
+
"127.0.0.1",
|
|
49
|
+
"5432",
|
|
50
|
+
"eventsourcing",
|
|
51
|
+
"eventsourcing",
|
|
52
|
+
)
|
|
53
|
+
self.drop_table()
|
|
54
|
+
|
|
55
|
+
def tearDown(self) -> None:
|
|
56
|
+
self.drop_table()
|
|
57
|
+
|
|
58
|
+
def drop_table(self):
|
|
59
|
+
drop_postgres_table(self.datastore, "stored_events")
|
|
60
|
+
|
|
61
|
+
def create_recorder(self) -> ApplicationRecorder:
|
|
62
|
+
self.uris = tmpfile_uris()
|
|
63
|
+
self.db_uri = next(self.uris)
|
|
64
|
+
recorder = PostgresApplicationRecorder(self.datastore)
|
|
65
|
+
recorder.create_table()
|
|
66
|
+
return recorder
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
del NonInterleavingNotificationIDsBaseCase
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
from uuid import uuid4
|
|
2
|
+
|
|
3
|
+
from eventsourcing.persistence import StoredEvent, Tracking
|
|
4
|
+
from eventsourcing.popo import (
|
|
5
|
+
Factory,
|
|
6
|
+
POPOAggregateRecorder,
|
|
7
|
+
POPOApplicationRecorder,
|
|
8
|
+
POPOProcessRecorder,
|
|
9
|
+
)
|
|
10
|
+
from eventsourcing.tests.persistence import (
|
|
11
|
+
AggregateRecorderTestCase,
|
|
12
|
+
ApplicationRecorderTestCase,
|
|
13
|
+
InfrastructureFactoryTestCase,
|
|
14
|
+
ProcessRecorderTestCase,
|
|
15
|
+
)
|
|
16
|
+
from eventsourcing.utils import Environment
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class TestPOPOAggregateRecorder(AggregateRecorderTestCase):
|
|
20
|
+
def create_recorder(self):
|
|
21
|
+
return POPOAggregateRecorder()
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class TestPOPOApplicationRecorder(ApplicationRecorderTestCase):
|
|
25
|
+
def create_recorder(self):
|
|
26
|
+
return POPOApplicationRecorder()
|
|
27
|
+
|
|
28
|
+
def test_insert_select(self) -> None:
|
|
29
|
+
super().test_insert_select()
|
|
30
|
+
|
|
31
|
+
# Check select_notifications() does not use negative indexes.
|
|
32
|
+
|
|
33
|
+
# Construct the recorder.
|
|
34
|
+
recorder = self.create_recorder()
|
|
35
|
+
|
|
36
|
+
# Write two stored events.
|
|
37
|
+
stored_event1 = StoredEvent(
|
|
38
|
+
originator_id=uuid4(),
|
|
39
|
+
originator_version=self.INITIAL_VERSION,
|
|
40
|
+
topic="topic1",
|
|
41
|
+
state=b"state1",
|
|
42
|
+
)
|
|
43
|
+
stored_event2 = StoredEvent(
|
|
44
|
+
originator_id=uuid4(),
|
|
45
|
+
originator_version=self.INITIAL_VERSION,
|
|
46
|
+
topic="topic2",
|
|
47
|
+
state=b"state2",
|
|
48
|
+
)
|
|
49
|
+
recorder.insert_events([stored_event1, stored_event2])
|
|
50
|
+
|
|
51
|
+
# This was returning 3.
|
|
52
|
+
self.assertEqual(len(recorder.select_notifications(0, 10)), 2)
|
|
53
|
+
|
|
54
|
+
# This was returning 4.
|
|
55
|
+
self.assertEqual(len(recorder.select_notifications(-1, 10)), 2)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class TestPOPOProcessRecorder(ProcessRecorderTestCase):
|
|
59
|
+
def create_recorder(self):
|
|
60
|
+
return POPOProcessRecorder()
|
|
61
|
+
|
|
62
|
+
def test_performance(self):
|
|
63
|
+
super().test_performance()
|
|
64
|
+
|
|
65
|
+
def test_max_doesnt_increase_when_lower_inserted_later(self) -> None:
|
|
66
|
+
# Construct the recorder.
|
|
67
|
+
recorder = self.create_recorder()
|
|
68
|
+
|
|
69
|
+
tracking1 = Tracking(
|
|
70
|
+
application_name="upstream_app",
|
|
71
|
+
notification_id=1,
|
|
72
|
+
)
|
|
73
|
+
tracking2 = Tracking(
|
|
74
|
+
application_name="upstream_app",
|
|
75
|
+
notification_id=2,
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
# Insert tracking info.
|
|
79
|
+
recorder.insert_events(
|
|
80
|
+
stored_events=[],
|
|
81
|
+
tracking=tracking2,
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
# Get current position.
|
|
85
|
+
self.assertEqual(
|
|
86
|
+
recorder.max_tracking_id("upstream_app"),
|
|
87
|
+
2,
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
# Insert tracking info.
|
|
91
|
+
recorder.insert_events(
|
|
92
|
+
stored_events=[],
|
|
93
|
+
tracking=tracking1,
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
# Get current position.
|
|
97
|
+
self.assertEqual(
|
|
98
|
+
recorder.max_tracking_id("upstream_app"),
|
|
99
|
+
2,
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
class TestPOPOInfrastructureFactory(InfrastructureFactoryTestCase):
|
|
104
|
+
def setUp(self) -> None:
|
|
105
|
+
self.env = Environment("TestCase")
|
|
106
|
+
super().setUp()
|
|
107
|
+
|
|
108
|
+
def expected_factory_class(self):
|
|
109
|
+
return Factory
|
|
110
|
+
|
|
111
|
+
def expected_aggregate_recorder_class(self):
|
|
112
|
+
return POPOAggregateRecorder
|
|
113
|
+
|
|
114
|
+
def expected_application_recorder_class(self):
|
|
115
|
+
return POPOApplicationRecorder
|
|
116
|
+
|
|
117
|
+
def expected_process_recorder_class(self):
|
|
118
|
+
return POPOProcessRecorder
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
del AggregateRecorderTestCase
|
|
122
|
+
del ApplicationRecorderTestCase
|
|
123
|
+
del ProcessRecorderTestCase
|
|
124
|
+
del InfrastructureFactoryTestCase
|