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,54 @@
1
+ require 'test_helper'
2
+
3
+ module Synapse
4
+ module Command
5
+ class DuplicationFilterTest < Test::Unit::TestCase
6
+ def test_filter
7
+ recorder = DuplicationRecorder.new
8
+ filter = DuplicationFilter.new recorder
9
+
10
+ command = CommandMessage.build
11
+
12
+ result = filter.filter command
13
+
14
+ assert_same command, result
15
+ assert recorder.recorded? command
16
+ end
17
+ end
18
+
19
+ class DuplicationCleanupInterceptorTest < Test::Unit::TestCase
20
+ def test_intercept
21
+ recorder = DuplicationRecorder.new
22
+ interceptor = DuplicationCleanupInterceptor.new recorder
23
+
24
+ command = CommandMessage.build
25
+ unit = Object.new
26
+
27
+ chain = Object.new
28
+ mock(chain).proceed(command) do
29
+ raise TransientError
30
+ end
31
+
32
+ recorder.record command
33
+
34
+ assert_raise TransientError do
35
+ interceptor.intercept command, unit, chain
36
+ end
37
+
38
+ refute recorder.recorded? command
39
+
40
+ mock(chain).proceed(command) do
41
+ raise ArgumentError
42
+ end
43
+
44
+ recorder.record command
45
+
46
+ assert_raise ArgumentError do
47
+ interceptor.intercept command, unit, chain
48
+ end
49
+
50
+ assert recorder.recorded? command
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,25 @@
1
+ require 'test_helper'
2
+
3
+ module Synapse
4
+ module Command
5
+
6
+ class CommandGatewayTest < Test::Unit::TestCase
7
+ def test_send
8
+ command_bus = Object.new
9
+ gateway = CommandGateway.new command_bus
10
+
11
+ command = Object.new
12
+ command_message = CommandMessage.build do |builder|
13
+ builder.payload = command
14
+ end
15
+
16
+ mock(command_bus).dispatch(is_a(CommandMessage)).ordered
17
+ mock(command_bus).dispatch(command_message).ordered
18
+
19
+ gateway.send command
20
+ gateway.send command_message
21
+ end
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,26 @@
1
+ require 'test_helper'
2
+
3
+ module Synapse
4
+ module Command
5
+
6
+ class InterceptorChainTest < Test::Unit::TestCase
7
+ def test_proceed
8
+ unit = Object.new
9
+ interceptor = Object.new
10
+ interceptors = Array.new << interceptor
11
+ handler = Object.new
12
+
13
+ command = Object.new
14
+
15
+ chain = InterceptorChain.new unit, interceptors, handler
16
+
17
+ mock(interceptor).intercept(command, unit, chain).ordered
18
+ mock(handler).handle(command, unit).ordered
19
+
20
+ chain.proceed command
21
+ chain.proceed command
22
+ end
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,37 @@
1
+ require 'test_helper'
2
+
3
+ module Synapse
4
+ module Command
5
+
6
+ class SerializationOptimizingInterceptorTest < Test::Unit::TestCase
7
+ def test_intercept
8
+ interceptor = SerializationOptimizingInterceptor.new
9
+
10
+ command = CommandMessage.build
11
+ chain = Object.new
12
+ unit = Object.new
13
+
14
+ mock(chain).proceed(command)
15
+ mock(unit).register_listener(is_a(SerializationOptimizingListener))
16
+
17
+ interceptor.intercept(command, unit, chain)
18
+ end
19
+ end
20
+
21
+ class SerializationOptimizingListenerTest < Test::Unit::TestCase
22
+ def test_on_event_registered
23
+ listener = SerializationOptimizingListener.new
24
+ unit = Object.new
25
+
26
+ event = Domain::DomainEventMessage.build
27
+ decorated = listener.on_event_registered unit, event
28
+ assert decorated.is_a? Serialization::SerializationAwareDomainEventMessage
29
+
30
+ event = Domain::EventMessage.build
31
+ decorated = listener.on_event_registered unit, event
32
+ assert decorated.is_a? Serialization::SerializationAwareEventMessage
33
+ end
34
+ end
35
+
36
+ end
37
+ end
@@ -0,0 +1,141 @@
1
+ require 'test_helper'
2
+
3
+ module Synapse
4
+ module Command
5
+
6
+ class SimpleCommandBusTest < Test::Unit::TestCase
7
+ def setup
8
+ @unit_factory = Object.new
9
+ @unit = Object.new
10
+ @command_bus = SimpleCommandBus.new @unit_factory
11
+ @logger = Logging.logger[@command_bus.class]
12
+
13
+ mock(@unit_factory).create.any_times do
14
+ @unit
15
+ end
16
+ end
17
+
18
+ def test_dispatch
19
+ handler = Object.new
20
+ command = CommandMessage.build do |m|
21
+ m.payload = TestCommand.new
22
+ end
23
+
24
+ mock(handler).handle(command, @unit)
25
+ mock(@unit).commit
26
+
27
+ @command_bus.subscribe TestCommand, handler
28
+ @command_bus.dispatch command
29
+ end
30
+
31
+ def test_dispatch_result
32
+ handler = Object.new
33
+ callback = Object.new
34
+ command = CommandMessage.build do |m|
35
+ m.payload = TestCommand.new
36
+ end
37
+
38
+ result = 123
39
+
40
+ mock(handler).handle(command, @unit) do
41
+ result
42
+ end
43
+ mock(callback).on_success(result)
44
+ mock(@unit).commit
45
+
46
+ @command_bus.subscribe TestCommand, handler
47
+ @command_bus.dispatch_with_callback command, callback
48
+ end
49
+
50
+ def test_dispatch_no_handler
51
+ command = CommandMessage.build do |m|
52
+ m.payload = TestCommand.new
53
+ end
54
+
55
+ callback = Object.new
56
+ mock(callback).on_failure(is_a(NoHandlerError))
57
+
58
+ @command_bus.dispatch_with_callback command, callback
59
+ end
60
+
61
+ def test_dispatch_rollback_on_exception
62
+ handler = Object.new
63
+ command = CommandMessage.build do |m|
64
+ m.payload = TestCommand.new
65
+ end
66
+
67
+ exception = TypeError.new
68
+
69
+ mock(handler).handle(command, @unit) do
70
+ raise exception
71
+ end
72
+
73
+ mock(@logger).error(anything)
74
+ mock(@unit).rollback(exception)
75
+
76
+ @command_bus.subscribe TestCommand, handler
77
+
78
+ callback = Object.new
79
+ mock(callback).on_failure(is_a(CommandExecutionError))
80
+
81
+ @command_bus.dispatch_with_callback command, callback
82
+ end
83
+
84
+ def test_dispatch_commit_on_exception
85
+ handler = Object.new
86
+ command = CommandMessage.build do |m|
87
+ m.payload = TestCommand.new
88
+ end
89
+
90
+ exception = TypeError.new
91
+
92
+ mock(handler).handle(command, @unit) do
93
+ raise exception
94
+ end
95
+
96
+ rollback_policy = Object.new
97
+ mock(rollback_policy).should_rollback(exception) do
98
+ false
99
+ end
100
+ mock(@unit).commit
101
+
102
+ @command_bus.rollback_policy = rollback_policy
103
+ @command_bus.subscribe TestCommand, handler
104
+
105
+ callback = Object.new
106
+ mock(callback).on_failure(is_a(CommandExecutionError))
107
+
108
+ @command_bus.dispatch_with_callback command, callback
109
+ end
110
+
111
+ def test_subscribe
112
+ handler = Object.new
113
+
114
+ mock(@logger).debug(anything).ordered
115
+ mock(@logger).info(anything).ordered
116
+
117
+ @command_bus.subscribe TestCommand, handler
118
+ @command_bus.subscribe TestCommand, handler
119
+ end
120
+
121
+ def test_unsubscribe
122
+ handler_a = Object.new
123
+ handler_b = Object.new
124
+
125
+ mock(@logger).info(anything).ordered # not subscribed to anyone
126
+ mock(@logger).debug(anything).ordered # now subscribed
127
+ mock(@logger).info(anything).ordered # subscribed to different
128
+ mock(@logger).debug(anything).ordered # now unsubscribed
129
+
130
+ @command_bus.unsubscribe TestCommand, handler_a
131
+ @command_bus.subscribe TestCommand, handler_a
132
+ @command_bus.unsubscribe TestCommand, handler_b
133
+ @command_bus.unsubscribe TestCommand, handler_a
134
+ end
135
+ end
136
+
137
+ class TestCommand; end
138
+ class TestOtherCommand; end
139
+
140
+ end
141
+ end
@@ -0,0 +1,42 @@
1
+ require 'test_helper'
2
+ require 'active_model'
3
+
4
+ module Synapse
5
+ module Command
6
+
7
+ class ActiveModelValidationFilterTest < Test::Unit::TestCase
8
+ def test_filter
9
+ message = CommandMessage.build do |m|
10
+ m.payload = CreatePersonCommand.new 'River'
11
+ end
12
+
13
+ filter = ActiveModelValidationFilter.new
14
+ filter.filter message
15
+ end
16
+
17
+ def test_filter_fails
18
+ message = CommandMessage.build do |m|
19
+ m.payload = CreatePersonCommand.new nil
20
+ end
21
+
22
+ filter = ActiveModelValidationFilter.new
23
+ assert_raise ActiveModelValidationError do
24
+ filter.filter message
25
+ end
26
+ end
27
+ end
28
+
29
+ class CreatePersonCommand
30
+ include ActiveModel::Validations
31
+
32
+ attr_reader :name
33
+
34
+ validates :name, :presence => true
35
+
36
+ def initialize(name)
37
+ @name = name
38
+ end
39
+ end
40
+
41
+ end
42
+ end
@@ -0,0 +1,73 @@
1
+ require 'test_helper'
2
+
3
+ module Synapse
4
+ module Command
5
+
6
+ class WiringCommandHandlerTest < Test::Unit::TestCase
7
+ def test_handle
8
+ handler = ExampleWiringCommandHandler.new
9
+ unit = Object.new
10
+
11
+ command = CommandMessage.build do |builder|
12
+ builder.payload = TestCommand.new
13
+ end
14
+
15
+ handler.handle command, unit
16
+ assert handler.handled
17
+
18
+ command = CommandMessage.build do |builder|
19
+ builder.payload = TestSubCommand.new
20
+ end
21
+
22
+ handler.handle command, unit
23
+ assert handler.sub_handled
24
+
25
+ command = CommandMessage.build do |builder|
26
+ builder.payload = 5
27
+ end
28
+
29
+ assert_raise ArgumentError do
30
+ handler.handle command, unit
31
+ end
32
+ end
33
+
34
+ def test_subscribe
35
+ handler = ExampleWiringCommandHandler.new
36
+ bus = Object.new
37
+
38
+ mock(bus).subscribe(TestSubCommand, handler)
39
+ mock(bus).subscribe(TestCommand, handler)
40
+
41
+ handler.subscribe bus
42
+ end
43
+
44
+ def test_unsubscribe
45
+ handler = ExampleWiringCommandHandler.new
46
+ bus = Object.new
47
+
48
+ mock(bus).unsubscribe(TestSubCommand, handler)
49
+ mock(bus).unsubscribe(TestCommand, handler)
50
+
51
+ handler.unsubscribe bus
52
+ end
53
+ end
54
+
55
+ class TestCommand; end
56
+ class TestSubCommand; end
57
+
58
+ class ExampleWiringCommandHandler
59
+ include WiringCommandHandler
60
+
61
+ attr_accessor :handled, :sub_handled
62
+
63
+ wire TestCommand do |command|
64
+ @handled = true
65
+ end
66
+
67
+ wire TestSubCommand do |command|
68
+ @sub_handled = true
69
+ end
70
+ end
71
+
72
+ end
73
+ end
@@ -0,0 +1,57 @@
1
+ require 'test_helper'
2
+ require 'domain/fixtures'
3
+
4
+ module Synapse
5
+ module Domain
6
+ class AggregateRootTest < Test::Unit::TestCase
7
+
8
+ def setup
9
+ @person = Person.new 123, 'Fry'
10
+ end
11
+
12
+ def test_publish_events
13
+ assert_equal 0, @person.uncommitted_event_count
14
+
15
+ @person.change_name 'Leela'
16
+
17
+ events = Array.new
18
+
19
+ @person.add_registration_listener do |event|
20
+ events.push event
21
+ event
22
+ end
23
+
24
+ @person.change_name 'Bender'
25
+
26
+ assert_equal 2, @person.uncommitted_event_count
27
+ assert_equal events, @person.uncommitted_events.to_a
28
+ end
29
+
30
+ def test_mark_committed
31
+ @person.change_name 'Bender'
32
+ @person.mark_committed
33
+
34
+ assert_equal 0, @person.uncommitted_event_count
35
+ end
36
+
37
+ def test_mark_deleted
38
+ @person.delete
39
+
40
+ assert @person.deleted?
41
+ end
42
+
43
+ def test_identifier_not_initialized
44
+ p = Person.new nil, nil
45
+
46
+ assert_raise AggregateIdentifierNotInitializedError do
47
+ p.change_name 'Zoidberg'
48
+ end
49
+ end
50
+
51
+ def test_empty_uncommitted_events
52
+ assert @person.uncommitted_events.end?
53
+ end
54
+
55
+ end
56
+ end
57
+ end