synapse-core 0.1.2

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.
Files changed (155) hide show
  1. data/lib/synapse.rb +351 -0
  2. data/lib/synapse/command/command_bus.rb +45 -0
  3. data/lib/synapse/command/command_callback.rb +18 -0
  4. data/lib/synapse/command/command_filter.rb +17 -0
  5. data/lib/synapse/command/command_handler.rb +13 -0
  6. data/lib/synapse/command/dispatch_interceptor.rb +16 -0
  7. data/lib/synapse/command/duplication.rb +43 -0
  8. data/lib/synapse/command/errors.rb +27 -0
  9. data/lib/synapse/command/filters/validation.rb +32 -0
  10. data/lib/synapse/command/gateway.rb +34 -0
  11. data/lib/synapse/command/interceptor_chain.rb +31 -0
  12. data/lib/synapse/command/interceptors/serialization.rb +35 -0
  13. data/lib/synapse/command/message.rb +19 -0
  14. data/lib/synapse/command/rollback_policy.rb +22 -0
  15. data/lib/synapse/command/simple_command_bus.rb +138 -0
  16. data/lib/synapse/command/wiring.rb +47 -0
  17. data/lib/synapse/domain/aggregate_root.rb +121 -0
  18. data/lib/synapse/domain/event_container.rb +127 -0
  19. data/lib/synapse/domain/message.rb +82 -0
  20. data/lib/synapse/domain/message_builder.rb +34 -0
  21. data/lib/synapse/domain/stream.rb +108 -0
  22. data/lib/synapse/duplication.rb +60 -0
  23. data/lib/synapse/errors.rb +13 -0
  24. data/lib/synapse/event_bus/event_bus.rb +40 -0
  25. data/lib/synapse/event_bus/event_listener.rb +16 -0
  26. data/lib/synapse/event_bus/event_listener_proxy.rb +12 -0
  27. data/lib/synapse/event_bus/simple_event_bus.rb +69 -0
  28. data/lib/synapse/event_bus/wiring.rb +23 -0
  29. data/lib/synapse/event_sourcing/aggregate_factory.rb +69 -0
  30. data/lib/synapse/event_sourcing/aggregate_root.rb +104 -0
  31. data/lib/synapse/event_sourcing/conflict_resolver.rb +80 -0
  32. data/lib/synapse/event_sourcing/entity.rb +64 -0
  33. data/lib/synapse/event_sourcing/member.rb +72 -0
  34. data/lib/synapse/event_sourcing/repository.rb +119 -0
  35. data/lib/synapse/event_sourcing/snapshot/count_stream.rb +86 -0
  36. data/lib/synapse/event_sourcing/snapshot/count_trigger.rb +91 -0
  37. data/lib/synapse/event_sourcing/snapshot/taker.rb +73 -0
  38. data/lib/synapse/event_sourcing/storage_listener.rb +34 -0
  39. data/lib/synapse/event_sourcing/stream_decorator.rb +25 -0
  40. data/lib/synapse/event_store/errors.rb +16 -0
  41. data/lib/synapse/event_store/event_store.rb +43 -0
  42. data/lib/synapse/event_store/in_memory.rb +59 -0
  43. data/lib/synapse/event_store/mongo/cursor_event_stream.rb +63 -0
  44. data/lib/synapse/event_store/mongo/event_store.rb +86 -0
  45. data/lib/synapse/event_store/mongo/per_commit_strategy.rb +253 -0
  46. data/lib/synapse/event_store/mongo/per_event_strategy.rb +143 -0
  47. data/lib/synapse/event_store/mongo/storage_strategy.rb +113 -0
  48. data/lib/synapse/event_store/mongo/template.rb +73 -0
  49. data/lib/synapse/identifier.rb +23 -0
  50. data/lib/synapse/message.rb +101 -0
  51. data/lib/synapse/message_builder.rb +38 -0
  52. data/lib/synapse/process_manager/correlation.rb +32 -0
  53. data/lib/synapse/process_manager/correlation_resolver.rb +14 -0
  54. data/lib/synapse/process_manager/correlation_set.rb +58 -0
  55. data/lib/synapse/process_manager/process.rb +71 -0
  56. data/lib/synapse/repository/errors.rb +26 -0
  57. data/lib/synapse/repository/lock_manager.rb +40 -0
  58. data/lib/synapse/repository/locking.rb +97 -0
  59. data/lib/synapse/repository/pessimistic_lock_manager.rb +61 -0
  60. data/lib/synapse/repository/repository.rb +109 -0
  61. data/lib/synapse/serialization/converter.rb +39 -0
  62. data/lib/synapse/serialization/converter/chain.rb +45 -0
  63. data/lib/synapse/serialization/converter/factory.rb +68 -0
  64. data/lib/synapse/serialization/converter/identity.rb +29 -0
  65. data/lib/synapse/serialization/converter/json.rb +31 -0
  66. data/lib/synapse/serialization/converter/ox.rb +31 -0
  67. data/lib/synapse/serialization/errors.rb +12 -0
  68. data/lib/synapse/serialization/lazy_object.rb +61 -0
  69. data/lib/synapse/serialization/message/data.rb +25 -0
  70. data/lib/synapse/serialization/message/metadata.rb +13 -0
  71. data/lib/synapse/serialization/message/serialization_aware.rb +17 -0
  72. data/lib/synapse/serialization/message/serialization_aware_message.rb +66 -0
  73. data/lib/synapse/serialization/message/serialized_message.rb +201 -0
  74. data/lib/synapse/serialization/message/serialized_message_builder.rb +64 -0
  75. data/lib/synapse/serialization/message/serialized_object_cache.rb +50 -0
  76. data/lib/synapse/serialization/message/serializer.rb +47 -0
  77. data/lib/synapse/serialization/revision_resolver.rb +30 -0
  78. data/lib/synapse/serialization/serialized_object.rb +37 -0
  79. data/lib/synapse/serialization/serialized_type.rb +31 -0
  80. data/lib/synapse/serialization/serializer.rb +98 -0
  81. data/lib/synapse/serialization/serializer/marshal.rb +32 -0
  82. data/lib/synapse/serialization/serializer/oj.rb +34 -0
  83. data/lib/synapse/serialization/serializer/ox.rb +31 -0
  84. data/lib/synapse/uow/factory.rb +28 -0
  85. data/lib/synapse/uow/listener.rb +79 -0
  86. data/lib/synapse/uow/listener_collection.rb +93 -0
  87. data/lib/synapse/uow/nesting.rb +262 -0
  88. data/lib/synapse/uow/provider.rb +71 -0
  89. data/lib/synapse/uow/storage_listener.rb +14 -0
  90. data/lib/synapse/uow/transaction_manager.rb +27 -0
  91. data/lib/synapse/uow/uow.rb +178 -0
  92. data/lib/synapse/upcasting/chain.rb +78 -0
  93. data/lib/synapse/upcasting/context.rb +58 -0
  94. data/lib/synapse/upcasting/data.rb +30 -0
  95. data/lib/synapse/upcasting/single_upcaster.rb +57 -0
  96. data/lib/synapse/upcasting/upcaster.rb +55 -0
  97. data/lib/synapse/version.rb +3 -0
  98. data/lib/synapse/wiring/message_wiring.rb +41 -0
  99. data/lib/synapse/wiring/wire.rb +55 -0
  100. data/lib/synapse/wiring/wire_registry.rb +61 -0
  101. data/test/command/duplication_test.rb +54 -0
  102. data/test/command/gateway_test.rb +25 -0
  103. data/test/command/interceptor_chain_test.rb +26 -0
  104. data/test/command/serialization_test.rb +37 -0
  105. data/test/command/simple_command_bus_test.rb +141 -0
  106. data/test/command/validation_test.rb +42 -0
  107. data/test/command/wiring_test.rb +73 -0
  108. data/test/domain/aggregate_root_test.rb +57 -0
  109. data/test/domain/fixtures.rb +31 -0
  110. data/test/domain/message_test.rb +61 -0
  111. data/test/domain/stream_test.rb +35 -0
  112. data/test/duplication_test.rb +40 -0
  113. data/test/event_bus/wiring_test.rb +46 -0
  114. data/test/event_sourcing/aggregate_factory_test.rb +28 -0
  115. data/test/event_sourcing/aggregate_root_test.rb +76 -0
  116. data/test/event_sourcing/entity_test.rb +34 -0
  117. data/test/event_sourcing/fixtures.rb +85 -0
  118. data/test/event_sourcing/repository_test.rb +102 -0
  119. data/test/event_sourcing/snapshot/aggregate_taker_test.rb +39 -0
  120. data/test/event_sourcing/snapshot/deferred_taker_test.rb +19 -0
  121. data/test/event_sourcing/snapshot/integration_test.rb +65 -0
  122. data/test/event_sourcing/storage_listener_test.rb +77 -0
  123. data/test/event_store/in_memory_test.rb +47 -0
  124. data/test/process_manager/correlation_set_test.rb +49 -0
  125. data/test/process_manager/correlation_test.rb +24 -0
  126. data/test/process_manager/process_test.rb +52 -0
  127. data/test/repository/locking_test.rb +101 -0
  128. data/test/serialization/converter/factory_test.rb +33 -0
  129. data/test/serialization/converter/identity_test.rb +17 -0
  130. data/test/serialization/converter/json_test.rb +31 -0
  131. data/test/serialization/converter/ox_test.rb +40 -0
  132. data/test/serialization/fixtures.rb +17 -0
  133. data/test/serialization/lazy_object_test.rb +32 -0
  134. data/test/serialization/message/metadata_test.rb +19 -0
  135. data/test/serialization/message/serialization_aware_message_test.rb +88 -0
  136. data/test/serialization/message/serialized_message_builder_test.rb +41 -0
  137. data/test/serialization/message/serialized_message_test.rb +140 -0
  138. data/test/serialization/message/serializer_test.rb +50 -0
  139. data/test/serialization/revision_resolver_test.rb +12 -0
  140. data/test/serialization/serialized_object_test.rb +36 -0
  141. data/test/serialization/serialized_type_test.rb +27 -0
  142. data/test/serialization/serializer/marshal_test.rb +22 -0
  143. data/test/serialization/serializer/oj_test.rb +24 -0
  144. data/test/serialization/serializer/ox_test.rb +36 -0
  145. data/test/serialization/serializer_test.rb +20 -0
  146. data/test/test_helper.rb +19 -0
  147. data/test/uow/factory_test.rb +23 -0
  148. data/test/uow/outer_commit_listener_test.rb +50 -0
  149. data/test/uow/provider_test.rb +70 -0
  150. data/test/uow/uow_test.rb +337 -0
  151. data/test/upcasting/chain_test.rb +29 -0
  152. data/test/upcasting/fixtures.rb +66 -0
  153. data/test/wiring/wire_registry_test.rb +60 -0
  154. data/test/wiring/wire_test.rb +51 -0
  155. metadata +263 -0
@@ -0,0 +1,50 @@
1
+ require 'test_helper'
2
+
3
+ module Synapse
4
+ module Serialization
5
+ class MessageSerializerTest < Test::Unit::TestCase
6
+ def test_serialize
7
+ delegate = Object.new
8
+ serializer = MessageSerializer.new delegate
9
+
10
+ metadata = Hash.new
11
+ payload = Object.new
12
+
13
+ m = MessageBuilder.build do |b|
14
+ b.metadata = metadata
15
+ b.payload = payload
16
+ end
17
+
18
+ serialized_metadata = Object.new
19
+ serialized_payload = Object.new
20
+
21
+ mock(delegate).serialize(metadata, String) do
22
+ serialized_metadata
23
+ end
24
+ mock(delegate).serialize(payload, String) do
25
+ serialized_payload
26
+ end
27
+
28
+ assert_equal serialized_metadata, serializer.serialize_metadata(m, String)
29
+ assert_equal serialized_payload, serializer.serialize_payload(m, String)
30
+ end
31
+
32
+ def test_serialization_aware
33
+ delegate = Object.new
34
+ serializer = MessageSerializer.new delegate
35
+
36
+ stub_class = Class.new do
37
+ include SerializationAware
38
+ end
39
+
40
+ stub = stub_class.new
41
+
42
+ mock(stub).serialize_metadata(delegate, String)
43
+ mock(stub).serialize_payload(delegate, String)
44
+
45
+ serializer.serialize_metadata(stub, String)
46
+ serializer.serialize_payload(stub, String)
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,12 @@
1
+ require 'test_helper'
2
+
3
+ module Synapse
4
+ module Serialization
5
+ class FixedRevisionResolverTest < Test::Unit::TestCase
6
+ def test_revision_of
7
+ resolver = FixedRevisionResolver.new 1
8
+ assert_equal '1', resolver.revision_of(Array)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,36 @@
1
+ require 'test_helper'
2
+
3
+ module Synapse
4
+ module Serialization
5
+ class SerializedObjectTest < Test::Unit::TestCase
6
+
7
+ def test_attributes
8
+ content = 'some content'
9
+ type = SerializedType.new 'SomeClass', '1'
10
+
11
+ object = SerializedObject.new content, content.class, type
12
+
13
+ assert_equal content, object.content
14
+ assert_equal content.class, object.content_type
15
+ assert_equal type, object.type
16
+ end
17
+
18
+ def test_object_equality
19
+ type_a = SerializedType.new 'SomeClass', '1'
20
+ type_b = SerializedType.new 'SomeClass', '2'
21
+
22
+ a = SerializedObject.new 'content', String, type_a
23
+ b = SerializedObject.new 'content', String, type_a
24
+ c = SerializedObject.new 'content', String, type_b
25
+ d = SerializedObject.new 'content_derp', String, type_a
26
+
27
+ assert_equal a, b
28
+ refute_equal a, c
29
+ refute_equal a, d
30
+
31
+ assert_equal a.hash, b.hash
32
+ end
33
+
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,27 @@
1
+ require 'test_helper'
2
+
3
+ module Synapse
4
+ module Serialization
5
+ class SerializedTypeTest < Test::Unit::TestCase
6
+
7
+ def test_attributes
8
+ type = SerializedType.new 'SomeClass', '1'
9
+
10
+ assert_equal 'SomeClass', type.name
11
+ assert_equal '1', type.revision
12
+ end
13
+
14
+ def test_object_equality
15
+ a = SerializedType.new 'SomeClass', '1'
16
+ b = SerializedType.new 'SomeClass', '1'
17
+ c = SerializedType.new 'SomeClass', '2'
18
+
19
+ assert_equal a, b
20
+ refute_equal a, c
21
+ assert_equal a.hash, b.hash
22
+ refute_equal a.hash, c.hash
23
+ end
24
+
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,22 @@
1
+ require 'test_helper'
2
+ require 'serialization/fixtures'
3
+
4
+ module Synapse
5
+ module Serialization
6
+
7
+ class MarshalSerializerTest < Test::Unit::TestCase
8
+
9
+ def test_serialize_deserialize
10
+ serializer = MarshalSerializer.new
11
+ event = TestEvent.new 'derp', 'herp'
12
+
13
+ serialized_obj = serializer.serialize event, String
14
+ deserialized = serializer.deserialize serialized_obj
15
+
16
+ assert_equal event, deserialized
17
+ end
18
+
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,24 @@
1
+ require 'test_helper'
2
+ require 'serialization/fixtures'
3
+
4
+ module Synapse
5
+ module Serialization
6
+
7
+ class OjSerializerTest < Test::Unit::TestCase
8
+ def setup
9
+ skip 'Oj not supported on JRuby' if defined? JRUBY_VERSION
10
+ end
11
+
12
+ def test_serialize_deserialize
13
+ serializer = OjSerializer.new
14
+ event = TestEvent.new 'derp', 'herp'
15
+
16
+ serialized_obj = serializer.serialize event, String
17
+ deserialized = serializer.deserialize serialized_obj
18
+
19
+ assert_equal event, deserialized
20
+ end
21
+ end
22
+
23
+ end
24
+ end
@@ -0,0 +1,36 @@
1
+ require 'test_helper'
2
+ require 'serialization/fixtures'
3
+
4
+ module Synapse
5
+ module Serialization
6
+
7
+ class OxSerializerTest < Test::Unit::TestCase
8
+ def setup
9
+ skip 'Ox not supported on JRuby' if defined? JRUBY_VERSION
10
+
11
+ @serializer = OxSerializer.new
12
+ end
13
+
14
+ def test_serialize_and_deserialize
15
+ event = TestEvent.new 'derp', 'herp'
16
+
17
+ serialized_obj = @serializer.serialize event, String
18
+ deserialized = @serializer.deserialize serialized_obj
19
+
20
+ assert_equal event, deserialized
21
+ end
22
+
23
+ def test_type_converison
24
+ type = SerializedType.new 'String', nil
25
+
26
+ assert_equal String, @serializer.class_for(type)
27
+ assert_equal type, @serializer.type_for(String)
28
+
29
+ assert_raise UnknownSerializedTypeError do
30
+ @serializer.class_for(SerializedType.new('NonExistentClass', nil))
31
+ end
32
+ end
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,20 @@
1
+ require 'test_helper'
2
+
3
+ module Synapse
4
+ module Serialization
5
+
6
+ class SerializerTest < Test::Unit::TestCase
7
+ def test_revision
8
+ revision = '123'
9
+
10
+ serializer = Serializer.new
11
+ serializer.revision_resolver = FixedRevisionResolver.new revision
12
+
13
+ type = serializer.type_for Object
14
+
15
+ assert_equal revision, type.revision
16
+ end
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,19 @@
1
+ if ENV['TRAVIS']
2
+ require 'coveralls'
3
+ Coveralls.wear!
4
+ else
5
+ require 'simplecov'
6
+ SimpleCov.start do
7
+ add_filter '/test/'
8
+ end
9
+ end
10
+
11
+ require 'pp'
12
+ require 'test/unit'
13
+ require 'rr'
14
+ require 'timecop'
15
+ require 'synapse'
16
+
17
+ class Test::Unit::TestCase
18
+ include RR::Adapters::TestUnit
19
+ end
@@ -0,0 +1,23 @@
1
+ require 'test_helper'
2
+
3
+ module Synapse
4
+ module UnitOfWork
5
+ class UnitOfWorkFactoryTest < Test::Unit::TestCase
6
+ def test_create
7
+ provider = UnitOfWorkProvider.new
8
+ txm = Object.new
9
+ factory = UnitOfWorkFactory.new provider
10
+ factory.transaction_manager = txm
11
+
12
+ mock(txm).start {
13
+ Object.new
14
+ }
15
+
16
+ uow = factory.create
17
+
18
+ assert uow.started?
19
+ assert uow.transactional?
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,50 @@
1
+ require 'test_helper'
2
+
3
+ module Synapse
4
+ module UnitOfWork
5
+ class OuterCommitUnitOfWorkListenerTest < Test::Unit::TestCase
6
+ def setup
7
+ @provider = Object.new
8
+ @outer_unit = Object.new
9
+ @inner_unit = Object.new
10
+ @listener = OuterCommitUnitOfWorkListener.new @inner_unit, @provider
11
+ end
12
+
13
+ def test_after_commit
14
+ mock(@inner_unit).perform_inner_commit
15
+ @listener.after_commit @outer_unit
16
+ end
17
+
18
+ def test_on_rollback
19
+ cause = TestError.new
20
+
21
+ mock(@provider).push(@inner_unit)
22
+ mock(@inner_unit).perform_rollback(cause)
23
+ mock(@provider).clear(@inner_unit)
24
+
25
+ @listener.on_rollback @outer_unit, cause
26
+ end
27
+
28
+ def test_on_rollback_handles_exception
29
+ cause = TestError.new
30
+
31
+ mock(@provider).push(@inner_unit)
32
+ mock(@inner_unit).perform_rollback(cause) {
33
+ raise TestError
34
+ }
35
+ mock(@provider).clear(@inner_unit)
36
+
37
+ assert_raises TestError do
38
+ @listener.on_rollback @outer_unit, cause
39
+ end
40
+ end
41
+
42
+ def test_on_cleanup
43
+ mock(@inner_unit).perform_cleanup
44
+ @listener.on_cleanup @outer_unit
45
+ end
46
+ end
47
+
48
+ class TestError < StandardError; end
49
+ end
50
+ end
@@ -0,0 +1,70 @@
1
+ require 'test_helper'
2
+
3
+ module Synapse
4
+ module UnitOfWork
5
+ class UnitOfWorkProviderTest < Test::Unit::TestCase
6
+ def setup
7
+ @provider = UnitOfWorkProvider.new
8
+ end
9
+
10
+ def test_clear
11
+ uow = UnitOfWork.new @provider
12
+ uow.start
13
+
14
+ assert @provider.started?
15
+ @provider.clear uow
16
+ refute @provider.started?
17
+ end
18
+
19
+ def test_clear_raises_mismatch
20
+ outer = UnitOfWork.new @provider
21
+ inner = UnitOfWork.new @provider
22
+
23
+ outer.start
24
+ inner.start
25
+
26
+ assert_raises ArgumentError do
27
+ @provider.clear outer
28
+ end
29
+ end
30
+
31
+ def test_commit
32
+ uow = UnitOfWork.new @provider
33
+ uow.start
34
+
35
+ @provider.commit
36
+
37
+ refute @provider.started?
38
+ refute uow.started?
39
+ end
40
+
41
+ def test_current
42
+ uow = UnitOfWork.new @provider
43
+
44
+ assert_raises RuntimeError do
45
+ @provider.current
46
+ end
47
+
48
+ uow.start
49
+
50
+ assert_same uow, @provider.current
51
+ end
52
+
53
+ def test_threading
54
+ t1 = Thread.new {
55
+ uow = UnitOfWork.new @provider
56
+ uow.start
57
+
58
+ @provider.started?
59
+ }.join
60
+
61
+ t2 = Thread.new {
62
+ @provider.started?
63
+ }.join
64
+
65
+ assert t1.value
66
+ refute t2.value
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,337 @@
1
+ require 'test_helper'
2
+
3
+ module Synapse
4
+ module UnitOfWork
5
+ class UnitOfWorkTest < Test::Unit::TestCase
6
+ def setup
7
+ @provider = UnitOfWorkProvider.new
8
+ @uow = UnitOfWork.new @provider
9
+ end
10
+
11
+ def teardown
12
+ if @provider.started?
13
+ raise 'Unit of work was not properly cleared from the provider'
14
+ end
15
+ end
16
+
17
+ def test_start_raises
18
+ @uow.start
19
+
20
+ assert_raises RuntimeError do
21
+ @uow.start
22
+ end
23
+
24
+ @uow.rollback
25
+ end
26
+
27
+ def test_commit_raises_if_not_started
28
+ assert_raises RuntimeError do
29
+ @uow.commit
30
+ end
31
+ end
32
+
33
+ def test_similar_aggregates
34
+ aggregate_a = TestAggregateA.new 1
35
+ aggregate_b = TestAggregateB.new 2
36
+ aggregate_c = TestAggregateB.new 3
37
+ aggregate_d = TestAggregateB.new 3
38
+
39
+ event_bus = Object.new
40
+ storage_listener = Object.new
41
+
42
+ assert_same aggregate_a, @uow.register_aggregate(aggregate_a, event_bus, storage_listener)
43
+ assert_same aggregate_b, @uow.register_aggregate(aggregate_b, event_bus, storage_listener)
44
+ assert_same aggregate_c, @uow.register_aggregate(aggregate_c, event_bus, storage_listener)
45
+ assert_same aggregate_c, @uow.register_aggregate(aggregate_d, event_bus, storage_listener)
46
+ end
47
+
48
+ def test_tx_bound_uow_lifecycle
49
+ listener = UnitOfWorkListener.new
50
+
51
+ tx = Object.new
52
+ txm = Object.new
53
+ mock(txm).start {
54
+ tx
55
+ }
56
+
57
+ mock(listener).on_start(@uow).ordered
58
+ mock(listener).on_prepare_commit(@uow, anything, anything).ordered
59
+ mock(listener).on_prepare_transaction_commit(@uow, tx).ordered
60
+ mock(txm).commit(tx).ordered
61
+ mock(listener).after_commit(@uow).ordered
62
+ mock(listener).on_cleanup(@uow).ordered
63
+
64
+ @uow.transaction_manager = txm
65
+ @uow.register_listener listener
66
+ @uow.start
67
+
68
+ @uow.commit
69
+ end
70
+
71
+ def test_tx_bound_uow_rollback_lifecycle
72
+ listener = UnitOfWorkListener.new
73
+
74
+ tx = Object.new
75
+ txm = Object.new
76
+ mock(txm).start {
77
+ tx
78
+ }
79
+
80
+ mock(listener).on_start(@uow).ordered
81
+ mock(txm).rollback(tx).ordered
82
+ mock(listener).on_rollback(@uow, nil).ordered
83
+ mock(listener).on_cleanup(@uow).ordered
84
+
85
+ @uow.transaction_manager = txm
86
+ @uow.register_listener listener
87
+ @uow.start
88
+
89
+ @uow.rollback
90
+ end
91
+
92
+ def test_uow_registers_listener_with_parent
93
+ outer_unit = Object.new
94
+ mock(outer_unit).register_listener(is_a(OuterCommitUnitOfWorkListener))
95
+ mock(outer_unit).rollback
96
+
97
+ @provider.push outer_unit
98
+
99
+ inner_unit = create_uow
100
+
101
+ inner_unit.rollback
102
+ outer_unit.rollback
103
+
104
+ @provider.clear outer_unit
105
+ end
106
+
107
+ def test_inner_rolled_back_with_outer
108
+ outer_unit = create_uow
109
+ inner_unit = create_uow
110
+
111
+ listener = UnitOfWorkListener.new
112
+ mock(listener).on_rollback(inner_unit, nil)
113
+
114
+ inner_unit.register_listener listener
115
+
116
+ inner_unit.commit
117
+ outer_unit.rollback
118
+ end
119
+
120
+ def test_inner_committed_with_outer
121
+ outer_unit = create_uow
122
+ inner_unit = create_uow
123
+
124
+ committed = false
125
+
126
+ listener = UnitOfWorkListener.new
127
+ mock(listener).after_commit(inner_unit) {
128
+ committed = true
129
+ }
130
+
131
+ inner_unit.register_listener listener
132
+ inner_unit.commit
133
+
134
+ refute committed, 'Inner unit was committed prematurely'
135
+
136
+ outer_unit.commit
137
+
138
+ assert committed, 'Inner unit should have been committed'
139
+ end
140
+
141
+ def test_unit_rollback_on_prepare_commit_error
142
+ cause = TestError.new
143
+ listener = UnitOfWorkListener.new
144
+
145
+ mock(listener).on_prepare_commit(@uow, anything, anything) {
146
+ raise cause
147
+ }
148
+ mock(listener).on_rollback(@uow, cause)
149
+ mock(listener).after_commit.never
150
+ mock(listener).on_cleanup(@uow)
151
+
152
+ @uow.register_listener listener
153
+ @uow.start
154
+
155
+ assert_raises TestError do
156
+ @uow.commit
157
+ end
158
+ end
159
+
160
+ def test_unit_rollback_on_store_aggregate_error
161
+ aggregate_root = Object.new
162
+ mock(aggregate_root).add_registration_listener
163
+ mock(aggregate_root).id
164
+
165
+ event_bus = Object.new
166
+ cause = TestError.new
167
+
168
+ storage_listener = Object.new
169
+ mock(storage_listener).store(aggregate_root) {
170
+ raise cause
171
+ }
172
+
173
+ listener = UnitOfWorkListener.new
174
+ mock(listener).on_prepare_commit(@uow, anything, anything)
175
+ mock(listener).on_rollback(@uow, cause)
176
+ mock(listener).after_commit.never
177
+ mock(listener).on_cleanup(@uow)
178
+
179
+ @uow.start
180
+ @uow.register_listener listener
181
+ @uow.register_aggregate aggregate_root, event_bus, storage_listener
182
+
183
+ assert_raises TestError do
184
+ @uow.commit
185
+ end
186
+ end
187
+
188
+ def test_unit_rollback_on_publish_error
189
+ cause = TestError.new
190
+ event = Object.new
191
+
192
+ event_bus = Object.new
193
+ mock(event_bus).publish([event]) {
194
+ raise cause
195
+ }
196
+
197
+ listener = UnitOfWorkListener.new
198
+ mock(listener).on_event_registered(@uow, event) {
199
+ event
200
+ }
201
+ mock(listener).after_commit.never
202
+
203
+ @uow.start
204
+ @uow.register_listener listener
205
+ @uow.publish_event event, event_bus
206
+
207
+ assert_raises TestError do
208
+ @uow.commit
209
+ end
210
+ end
211
+
212
+ def test_inner_cleanup_delayed_until_outer_cleanup_inner_commit
213
+ outer_listener = UnitOfWorkListener.new
214
+ inner_listener = UnitOfWorkListener.new
215
+
216
+ outer_unit = create_uow
217
+ inner_unit = create_uow
218
+
219
+ outer_unit.register_listener outer_listener
220
+ inner_unit.register_listener inner_listener
221
+
222
+ mock(inner_listener).after_commit(inner_unit).ordered
223
+ mock(outer_listener).after_commit(outer_unit).ordered
224
+ mock(inner_listener).on_cleanup(inner_unit).ordered
225
+ mock(outer_listener).on_cleanup(outer_unit).ordered
226
+
227
+ inner_unit.commit
228
+ outer_unit.commit
229
+ end
230
+
231
+ def test_inner_cleanup_delayed_until_outer_cleanup_inner_rollback
232
+ outer_listener = UnitOfWorkListener.new
233
+ inner_listener = UnitOfWorkListener.new
234
+
235
+ outer_unit = create_uow
236
+ inner_unit = create_uow
237
+
238
+ outer_unit.register_listener outer_listener
239
+ inner_unit.register_listener inner_listener
240
+
241
+ mock(inner_listener).on_rollback(inner_unit, nil).ordered
242
+ mock(outer_listener).after_commit(outer_unit).ordered
243
+ mock(inner_listener).on_cleanup(inner_unit).ordered
244
+ mock(outer_listener).on_cleanup(outer_unit).ordered
245
+
246
+ inner_unit.rollback
247
+ outer_unit.commit
248
+ end
249
+
250
+ def test_inner_cleanup_delayed_until_outer_cleanup_inner_commit_outer_rollback
251
+ outer_listener = UnitOfWorkListener.new
252
+ inner_listener = UnitOfWorkListener.new
253
+
254
+ outer_unit = create_uow
255
+ inner_unit = create_uow
256
+
257
+ outer_unit.register_listener outer_listener
258
+ inner_unit.register_listener inner_listener
259
+
260
+ mock(inner_listener).on_prepare_commit(inner_unit, anything, anything).ordered
261
+ mock(inner_listener).on_rollback(inner_unit, nil).ordered
262
+ mock(outer_listener).on_rollback(outer_unit, nil).ordered
263
+ mock(inner_listener).on_cleanup(inner_unit).ordered
264
+ mock(outer_listener).on_cleanup(outer_unit).ordered
265
+
266
+ inner_unit.commit
267
+ outer_unit.rollback
268
+ end
269
+
270
+ def test_set_txm_throws_if_started
271
+ @uow.start
272
+
273
+ assert_raises RuntimeError do
274
+ @uow.transaction_manager = Object.new
275
+ end
276
+
277
+ @uow.commit
278
+ end
279
+
280
+ def test_provider_not_changed_if_start_fails
281
+ txm = Object.new
282
+ mock(txm).start {
283
+ raise 'Something bad happened'
284
+ }
285
+
286
+ @uow.transaction_manager = txm
287
+
288
+ begin
289
+ @uow.start
290
+ rescue RuntimeError; end
291
+
292
+ refute @provider.started?
293
+ end
294
+
295
+ def test_events_continually_publish
296
+ @uow.start
297
+
298
+ event_bus = EventBus::SimpleEventBus.new
299
+
300
+ event_a = Domain::EventMessage.build
301
+ event_b = Domain::EventMessage.build
302
+
303
+ listener = Object.new
304
+ mock(listener).notify(event_a) {
305
+ @uow.publish_event event_b, event_bus
306
+ }
307
+ mock(listener).notify(event_b)
308
+
309
+ event_bus.subscribe listener
310
+
311
+ @uow.publish_event event_a, event_bus
312
+ @uow.commit
313
+ end
314
+
315
+ def create_uow
316
+ uow = UnitOfWork.new @provider
317
+ uow.start
318
+ uow
319
+ end
320
+ end
321
+
322
+ class TestError < StandardError; end
323
+
324
+ class TestAggregateA
325
+ include Domain::AggregateRoot
326
+ def initialize(id)
327
+ @id = id
328
+ end
329
+ end
330
+ class TestAggregateB
331
+ include Domain::AggregateRoot
332
+ def initialize(id)
333
+ @id = id
334
+ end
335
+ end
336
+ end
337
+ end