synapse-core 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
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