synapse-core 0.4.0 → 0.5.1
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.
- data/lib/synapse/command/async_command_bus.rb +41 -0
- data/lib/synapse/command/command_callback.rb +49 -2
- data/lib/synapse/command/command_handler.rb +2 -0
- data/lib/synapse/command/filters/validation.rb +2 -2
- data/lib/synapse/command/gateway/interval_retry_scheduler.rb +75 -0
- data/lib/synapse/command/gateway/retry_scheduler.rb +26 -0
- data/lib/synapse/command/gateway/retrying_callback.rb +46 -0
- data/lib/synapse/command/gateway.rb +56 -11
- data/lib/synapse/command/interceptor_chain.rb +2 -2
- data/lib/synapse/command/interceptors/serialization.rb +2 -2
- data/lib/synapse/command/message.rb +16 -0
- data/lib/synapse/command/simple_command_bus.rb +6 -2
- data/lib/synapse/command/wiring.rb +3 -3
- data/lib/synapse/command.rb +7 -1
- data/lib/synapse/common/concurrency/identifier_lock.rb +2 -17
- data/lib/synapse/common/concurrency/public_lock.rb +8 -9
- data/lib/synapse/common/errors.rb +1 -1
- data/lib/synapse/common/message.rb +2 -6
- data/lib/synapse/common.rb +9 -0
- data/lib/synapse/configuration/component/command_bus/async_command_bus.rb +41 -0
- data/lib/synapse/configuration/component/command_bus/gateway.rb +38 -0
- data/lib/synapse/configuration/component/command_bus/simple_command_bus.rb +81 -0
- data/lib/synapse/configuration/component/command_bus.rb +35 -0
- data/lib/synapse/configuration/component/event_bus/simple_event_bus.rb +41 -0
- data/lib/synapse/configuration/component/event_bus.rb +15 -0
- data/lib/synapse/configuration/component/event_sourcing/repository.rb +62 -0
- data/lib/synapse/configuration/component/event_sourcing.rb +15 -0
- data/lib/synapse/configuration/component/repository/locking_repository.rb +85 -0
- data/lib/synapse/configuration/component/repository/simple_repository.rb +31 -0
- data/lib/synapse/configuration/component/repository.rb +15 -0
- data/lib/synapse/configuration/component/serialization/converter_factory.rb +50 -0
- data/lib/synapse/configuration/component/serialization/serializer.rb +90 -0
- data/lib/synapse/configuration/component/serialization.rb +25 -0
- data/lib/synapse/configuration/component/uow/unit_factory.rb +51 -0
- data/lib/synapse/configuration/component/uow.rb +22 -0
- data/lib/synapse/configuration/component/upcasting/upcaster_chain.rb +61 -0
- data/lib/synapse/configuration/component/upcasting.rb +15 -0
- data/lib/synapse/configuration/container.rb +80 -0
- data/lib/synapse/configuration/container_builder.rb +108 -0
- data/lib/synapse/configuration/definition.rb +31 -0
- data/lib/synapse/configuration/definition_builder.rb +138 -0
- data/lib/synapse/configuration/dependent.rb +31 -0
- data/lib/synapse/configuration/ext.rb +35 -0
- data/lib/synapse/configuration.rb +32 -0
- data/lib/synapse/domain/aggregate_root.rb +25 -26
- data/lib/synapse/domain/event_container.rb +5 -5
- data/lib/synapse/domain/message.rb +16 -0
- data/lib/synapse/event_bus/event_listener.rb +2 -0
- data/lib/synapse/event_bus/event_publisher.rb +19 -0
- data/lib/synapse/event_bus/simple_event_bus.rb +21 -30
- data/lib/synapse/event_bus/wiring.rb +5 -4
- data/lib/synapse/event_bus.rb +1 -1
- data/lib/synapse/event_sourcing/aggregate_root.rb +6 -4
- data/lib/synapse/process_manager/container_resource_injector.rb +18 -0
- data/lib/synapse/process_manager/pessimistic_lock_manager.rb +1 -1
- data/lib/synapse/process_manager/process.rb +4 -0
- data/lib/synapse/process_manager/process_factory.rb +3 -3
- data/lib/synapse/process_manager/repository/in_memory.rb +1 -1
- data/lib/synapse/process_manager/wiring/process.rb +6 -6
- data/lib/synapse/process_manager/wiring/process_manager.rb +8 -8
- data/lib/synapse/process_manager.rb +2 -0
- data/lib/synapse/repository/locking.rb +5 -3
- data/lib/synapse/repository/optimistic_lock_manager.rb +2 -7
- data/lib/synapse/repository/pessimistic_lock_manager.rb +3 -3
- data/lib/synapse/repository/repository.rb +2 -2
- data/lib/synapse/repository/simple_repository.rb +69 -0
- data/lib/synapse/repository.rb +1 -0
- data/lib/synapse/serialization/converter/chain.rb +2 -2
- data/lib/synapse/serialization/converter_factory.rb +2 -2
- data/lib/synapse/serialization/lazy_object.rb +2 -2
- data/lib/synapse/serialization/message/serialization_aware_message.rb +3 -3
- data/lib/synapse/serialization/message/serialized_message.rb +6 -10
- data/lib/synapse/serialization/message/serialized_message_builder.rb +4 -4
- data/lib/synapse/serialization/message/serialized_object_cache.rb +2 -2
- data/lib/synapse/serialization/message/serializer.rb +2 -2
- data/lib/synapse/serialization/revision_resolver.rb +3 -3
- data/lib/synapse/serialization/serialized_object.rb +2 -2
- data/lib/synapse/serialization/serialized_type.rb +2 -2
- data/lib/synapse/serialization/serializer/attribute.rb +2 -2
- data/lib/synapse/serialization/serializer/marshal.rb +2 -2
- data/lib/synapse/serialization/serializer/oj.rb +2 -2
- data/lib/synapse/serialization/serializer/ox.rb +2 -2
- data/lib/synapse/serialization/serializer.rb +2 -2
- data/lib/synapse/uow/factory.rb +2 -2
- data/lib/synapse/uow/listener_collection.rb +2 -2
- data/lib/synapse/uow/nesting.rb +9 -2
- data/lib/synapse/uow/provider.rb +2 -2
- data/lib/synapse/uow/uow.rb +8 -2
- data/lib/synapse/upcasting/{chain.rb → upcaster_chain.rb} +0 -0
- data/lib/synapse/upcasting.rb +1 -1
- data/lib/synapse/version.rb +1 -1
- data/lib/synapse/wiring/message_wiring.rb +31 -0
- data/lib/synapse.rb +2 -14
- data/test/auditing/data_provider_test.rb +2 -2
- data/test/auditing/dispatch_interceptor_test.rb +1 -1
- data/test/auditing/unit_listener_test.rb +3 -3
- data/test/command/async_command_bus_test.rb +49 -0
- data/test/command/duplication_test.rb +2 -2
- data/test/command/gateway/interval_retry_scheduler_test.rb +42 -0
- data/test/command/gateway/retrying_callback_test.rb +57 -0
- data/test/command/gateway_test.rb +41 -7
- data/test/command/interceptor_chain_test.rb +1 -1
- data/test/command/message_test.rb +17 -0
- data/test/command/serialization_test.rb +2 -2
- data/test/command/simple_command_bus_test.rb +7 -7
- data/test/command/validation_test.rb +3 -3
- data/test/command/wiring_test.rb +3 -3
- data/test/common/concurrency/identifier_lock_test.rb +2 -13
- data/test/common/concurrency/public_lock_test.rb +6 -6
- data/test/{duplication_test.rb → common/duplication_test.rb} +3 -3
- data/test/configuration/component/command_bus/async_command_bus_test.rb +36 -0
- data/test/configuration/component/command_bus/simple_command_bus_test.rb +57 -0
- data/test/configuration/component/event_bus/simple_event_bus_test.rb +58 -0
- data/test/configuration/component/serialization/converter_factory_test.rb +48 -0
- data/test/configuration/component/serialization/serializer_test.rb +78 -0
- data/test/configuration/component/uow/unit_factory_test.rb +46 -0
- data/test/configuration/container_builder_test.rb +47 -0
- data/test/configuration/container_test.rb +88 -0
- data/test/configuration/definition_builder_test.rb +126 -0
- data/test/configuration/definition_test.rb +41 -0
- data/test/configuration/dependent_test.rb +30 -0
- data/test/configuration/ext_test.rb +19 -0
- data/test/configuration/fixtures/dependent.rb +10 -0
- data/test/domain/aggregate_root_test.rb +5 -5
- data/test/domain/message_test.rb +15 -3
- data/test/domain/stream_test.rb +2 -2
- data/test/event_bus/publisher_test.rb +29 -0
- data/test/event_bus/wiring_test.rb +1 -1
- data/test/event_sourcing/aggregate_factory_test.rb +12 -6
- data/test/event_sourcing/aggregate_root_test.rb +4 -4
- data/test/event_sourcing/entity_test.rb +10 -9
- data/test/event_sourcing/repository_test.rb +6 -6
- data/test/event_sourcing/storage_listener_test.rb +8 -4
- data/test/event_store/in_memory_test.rb +3 -3
- data/test/process_manager/container_resource_injector_test.rb +19 -0
- data/test/process_manager/correlation_set_test.rb +2 -2
- data/test/process_manager/correlation_test.rb +2 -2
- data/test/process_manager/in_memory_test.rb +3 -3
- data/test/process_manager/process_factory_test.rb +2 -2
- data/test/process_manager/process_test.rb +3 -3
- data/test/process_manager/simple_process_manager_test.rb +5 -5
- data/test/process_manager/wiring/process_manager_test.rb +4 -4
- data/test/process_manager/wiring/process_test.rb +2 -2
- data/test/repository/locking_test.rb +4 -4
- data/test/repository/optimistic_test.rb +2 -2
- data/test/repository/pessimistic_test.rb +1 -1
- data/test/repository/simple_repository_test.rb +79 -0
- data/test/support/countdown_latch.rb +18 -0
- data/test/test_helper.rb +6 -3
- data/test/upcasting/data_test.rb +31 -0
- metadata +84 -25
- data/lib/synapse/event_bus/event_listener_proxy.rb +0 -12
- data/lib/synapse/partitioning/memory_queue_reader.rb +0 -31
- data/lib/synapse/partitioning/memory_queue_writer.rb +0 -19
- data/lib/synapse/partitioning/message_receipt.rb +0 -25
- data/lib/synapse/partitioning/packing/json_packer.rb +0 -93
- data/lib/synapse/partitioning/packing/json_unpacker.rb +0 -83
- data/lib/synapse/partitioning/packing.rb +0 -27
- data/lib/synapse/partitioning/queue_reader.rb +0 -32
- data/lib/synapse/partitioning/queue_writer.rb +0 -17
- data/lib/synapse/partitioning.rb +0 -18
- data/test/partitioning/memory_test.rb +0 -34
- data/test/partitioning/packing/json_test.rb +0 -62
data/lib/synapse/uow/factory.rb
CHANGED
data/lib/synapse/uow/nesting.rb
CHANGED
@@ -26,6 +26,7 @@ module Synapse
|
|
26
26
|
# resources it acquired. The effectively means that a rollback is done if the unit of work
|
27
27
|
# failed to commit.
|
28
28
|
#
|
29
|
+
# @api public
|
29
30
|
# @raise [RuntimeError] If unit of work hasn't been started yet
|
30
31
|
# @return [undefined]
|
31
32
|
def commit
|
@@ -61,6 +62,7 @@ module Synapse
|
|
61
62
|
# Any buffered events and registered aggregates are discarded and any registered unit of work
|
62
63
|
# listeners are notified of the rollback.
|
63
64
|
#
|
65
|
+
# @api public
|
64
66
|
# @param [Error] cause
|
65
67
|
# @return [undefined]
|
66
68
|
def rollback(cause = nil)
|
@@ -79,6 +81,7 @@ module Synapse
|
|
79
81
|
|
80
82
|
# Starts the unit of work, preparing it for aggregate registration
|
81
83
|
#
|
84
|
+
# @api public
|
82
85
|
# @raise [RuntimeError] If unit of work has already been started
|
83
86
|
# @return [undefined]
|
84
87
|
def start
|
@@ -105,6 +108,8 @@ module Synapse
|
|
105
108
|
end
|
106
109
|
|
107
110
|
# Returns true if this unit of work has been started
|
111
|
+
#
|
112
|
+
# @api public
|
108
113
|
# @return [Boolean]
|
109
114
|
def started?
|
110
115
|
@started
|
@@ -224,6 +229,8 @@ module Synapse
|
|
224
229
|
|
225
230
|
# Listener that allows a nested unit of work to properly operate within in a unit of
|
226
231
|
# work that is not aware of nesting
|
232
|
+
#
|
233
|
+
# @api private
|
227
234
|
class OuterCommitUnitOfWorkListener < UnitOfWorkListener
|
228
235
|
# @param [UnitOfWork] inner_unit
|
229
236
|
# @param [UnitOfWorkProvider] provider
|
@@ -257,6 +264,6 @@ module Synapse
|
|
257
264
|
def on_cleanup(outer_unit)
|
258
265
|
@inner_unit.perform_cleanup
|
259
266
|
end
|
260
|
-
end
|
261
|
-
end
|
267
|
+
end # NestableUnitOfWork
|
268
|
+
end # UnitOfWork
|
262
269
|
end
|
data/lib/synapse/uow/provider.rb
CHANGED
data/lib/synapse/uow/uow.rb
CHANGED
@@ -13,6 +13,8 @@ module Synapse
|
|
13
13
|
end
|
14
14
|
|
15
15
|
# Returns true if this unit of work is bound to a transaction
|
16
|
+
#
|
17
|
+
# @api public
|
16
18
|
# @return [Boolean]
|
17
19
|
def transactional?
|
18
20
|
!!@transaction_manager
|
@@ -20,6 +22,7 @@ module Synapse
|
|
20
22
|
|
21
23
|
# Registers a listener that is notified of state changes in this unit of work
|
22
24
|
#
|
25
|
+
# @api public
|
23
26
|
# @param [UnitOfWorkListener] listener
|
24
27
|
# @return [undefined]
|
25
28
|
def register_listener(listener)
|
@@ -38,6 +41,7 @@ module Synapse
|
|
38
41
|
# and with the same identifier, that aggregate will be returned instead of the given
|
39
42
|
# aggregate.
|
40
43
|
#
|
44
|
+
# @api public
|
41
45
|
# @param [AggregateRoot] aggregate
|
42
46
|
# @param [EventBus] event_bus
|
43
47
|
# @param [StorageListener] storage_listener
|
@@ -60,6 +64,7 @@ module Synapse
|
|
60
64
|
# Buffers an event for publication to the given event bus until this unit of work is
|
61
65
|
# committed
|
62
66
|
#
|
67
|
+
# @api public
|
63
68
|
# @param [EventMessage] event
|
64
69
|
# @param [EventBus] event_bus
|
65
70
|
# @return [EventMessage] The event that will be published to the event bus
|
@@ -78,6 +83,7 @@ module Synapse
|
|
78
83
|
|
79
84
|
# Sets the transaction manager that will be used by this unit of work
|
80
85
|
#
|
86
|
+
# @api public
|
81
87
|
# @raise [RuntimeError] If unit of work has been started
|
82
88
|
# @param [TransactionManager] transaction_manager
|
83
89
|
# @return [undefined]
|
@@ -173,6 +179,6 @@ module Synapse
|
|
173
179
|
end
|
174
180
|
end
|
175
181
|
end
|
176
|
-
end
|
177
|
-
end
|
182
|
+
end # UnitOfWork
|
183
|
+
end # UnitOfWork
|
178
184
|
end
|
File without changes
|
data/lib/synapse/upcasting.rb
CHANGED
data/lib/synapse/version.rb
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
module Synapse
|
2
2
|
module Wiring
|
3
3
|
# Base mixin that make it easier to wire handlers to their respective types
|
4
|
+
#
|
5
|
+
# It is recommended to use mixins more specific to the component being implemented, like
|
6
|
+
# wiring command handlers, event listeners, event-sourced members, or processes.
|
7
|
+
#
|
4
8
|
# @abstract
|
5
9
|
module MessageWiring
|
6
10
|
extend ActiveSupport::Concern
|
@@ -14,6 +18,33 @@ module Synapse
|
|
14
18
|
end
|
15
19
|
|
16
20
|
module ClassMethods
|
21
|
+
# Wires a message handler to messages with payload of the given type
|
22
|
+
#
|
23
|
+
# @example
|
24
|
+
# wire CashWithdrawnEvent do |event|
|
25
|
+
# # do something with the event
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# @example
|
29
|
+
# wire CashWithdrawnEvent :to => :on_withdraw
|
30
|
+
#
|
31
|
+
# def on_withdraw(event)
|
32
|
+
# # do something with the event
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
# Certain components that use message handling have different options that can be set
|
36
|
+
# on wires, like wiring processes.
|
37
|
+
#
|
38
|
+
# @example
|
39
|
+
# wire SellTransactionStartedEvent, :start => true, :correlate => :transaction_id do
|
40
|
+
# # do something with the event
|
41
|
+
# end
|
42
|
+
#
|
43
|
+
# @api public
|
44
|
+
# @param [Class] type
|
45
|
+
# @param [Object...] args
|
46
|
+
# @param [Proc] block
|
47
|
+
# @return [undefined]
|
17
48
|
def wire(type, *args, &block)
|
18
49
|
options = args.extract_options!
|
19
50
|
|
data/lib/synapse.rb
CHANGED
@@ -3,24 +3,12 @@ require 'active_support/core_ext'
|
|
3
3
|
require 'logging'
|
4
4
|
require 'set'
|
5
5
|
|
6
|
+
require 'synapse/common'
|
6
7
|
require 'synapse/version'
|
7
8
|
|
8
|
-
require 'synapse/common/errors'
|
9
|
-
require 'synapse/common/identifier'
|
10
|
-
require 'synapse/common/message'
|
11
|
-
require 'synapse/common/message_builder'
|
12
|
-
|
13
|
-
require 'synapse/common/concurrency/identifier_lock'
|
14
|
-
require 'synapse/common/concurrency/public_lock'
|
15
|
-
|
16
9
|
module Synapse
|
17
10
|
extend ActiveSupport::Autoload
|
18
11
|
|
19
|
-
autoload_at 'synapse/common/duplication' do
|
20
|
-
autoload :DuplicationError
|
21
|
-
autoload :DuplicationRecorder
|
22
|
-
end
|
23
|
-
|
24
12
|
eager_autoload do
|
25
13
|
# Common components
|
26
14
|
autoload :Command
|
@@ -34,9 +22,9 @@ module Synapse
|
|
34
22
|
|
35
23
|
# Optional components
|
36
24
|
autoload :Auditing
|
25
|
+
autoload :Configuration
|
37
26
|
autoload :EventSourcing
|
38
27
|
autoload :EventStore
|
39
|
-
autoload :Partitioning
|
40
28
|
autoload :ProcessManager
|
41
29
|
autoload :Upcasting
|
42
30
|
end
|
@@ -4,7 +4,7 @@ module Synapse
|
|
4
4
|
module Auditing
|
5
5
|
|
6
6
|
class CommandMetadataProviderTest < Test::Unit::TestCase
|
7
|
-
|
7
|
+
should 'provide the metadata from a command for auditing' do
|
8
8
|
data = { foo: 0 }
|
9
9
|
|
10
10
|
provider = CommandMetadataProvider.new
|
@@ -17,7 +17,7 @@ module Synapse
|
|
17
17
|
end
|
18
18
|
|
19
19
|
class CorrelationDataProviderTest < Test::Unit::TestCase
|
20
|
-
|
20
|
+
should 'provide the identifier of a command for auditing' do
|
21
21
|
provider = CorrelationDataProvider.new
|
22
22
|
command = Command::CommandMessage.build
|
23
23
|
|
@@ -4,7 +4,7 @@ module Synapse
|
|
4
4
|
module Auditing
|
5
5
|
|
6
6
|
class AuditingUnitOfWorkListenerTest < Test::Unit::TestCase
|
7
|
-
|
7
|
+
should 'supplement events with auditing data' do
|
8
8
|
data_provider_a = Object.new
|
9
9
|
data_provider_b = Object.new
|
10
10
|
|
@@ -30,7 +30,7 @@ module Synapse
|
|
30
30
|
assert listener.recorded_events.include? event
|
31
31
|
end
|
32
32
|
|
33
|
-
|
33
|
+
should 'notify the audit logger of success after the unit of work is committed' do
|
34
34
|
logger = Object.new
|
35
35
|
|
36
36
|
command = Object.new
|
@@ -48,7 +48,7 @@ module Synapse
|
|
48
48
|
listener.after_commit Object.new
|
49
49
|
end
|
50
50
|
|
51
|
-
|
51
|
+
should 'notify the audit logger of failure when a unit of work is rolled back' do
|
52
52
|
logger = Object.new
|
53
53
|
|
54
54
|
command = Object.new
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'support/countdown_latch'
|
3
|
+
|
4
|
+
module Synapse
|
5
|
+
module Command
|
6
|
+
class AsynchronousCommandBusTest < Test::Unit::TestCase
|
7
|
+
def setup
|
8
|
+
unit_provider = UnitOfWork::UnitOfWorkProvider.new
|
9
|
+
unit_factory = UnitOfWork::UnitOfWorkFactory.new unit_provider
|
10
|
+
|
11
|
+
@bus = AsynchronousCommandBus.new unit_factory
|
12
|
+
@bus.thread_pool = Thread.pool 2
|
13
|
+
end
|
14
|
+
|
15
|
+
should 'be able to dispatch commands asynchronously using a thread pool' do
|
16
|
+
x = 5 # Number of commands to dispatch
|
17
|
+
|
18
|
+
command = CommandMessage.as_message TestCommand.new
|
19
|
+
handler = TestAsyncHandler.new x
|
20
|
+
|
21
|
+
@bus.subscribe TestCommand, handler
|
22
|
+
|
23
|
+
x.times do
|
24
|
+
@bus.dispatch command
|
25
|
+
end
|
26
|
+
|
27
|
+
wait_until do
|
28
|
+
handler.latch.count == 0
|
29
|
+
end
|
30
|
+
|
31
|
+
@bus.shutdown
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class TestAsyncHandler
|
36
|
+
attr_reader :latch
|
37
|
+
|
38
|
+
def initialize(x)
|
39
|
+
@latch = CountdownLatch.new x
|
40
|
+
end
|
41
|
+
|
42
|
+
def handle(command, unit)
|
43
|
+
@latch.countdown!
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class TestCommand; end
|
48
|
+
end
|
49
|
+
end
|
@@ -3,7 +3,7 @@ require 'test_helper'
|
|
3
3
|
module Synapse
|
4
4
|
module Command
|
5
5
|
class DuplicationFilterTest < Test::Unit::TestCase
|
6
|
-
|
6
|
+
should 'record commands so that duplication can be detected' do
|
7
7
|
recorder = DuplicationRecorder.new
|
8
8
|
filter = DuplicationFilter.new recorder
|
9
9
|
|
@@ -17,7 +17,7 @@ module Synapse
|
|
17
17
|
end
|
18
18
|
|
19
19
|
class DuplicationCleanupInterceptorTest < Test::Unit::TestCase
|
20
|
-
|
20
|
+
should 'forget recorded commands only if a transient error occurs' do
|
21
21
|
recorder = DuplicationRecorder.new
|
22
22
|
interceptor = DuplicationCleanupInterceptor.new recorder
|
23
23
|
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'eventmachine'
|
3
|
+
|
4
|
+
module Synapse
|
5
|
+
module Command
|
6
|
+
class IntervalRetrySchedulerTest < Test::Unit::TestCase
|
7
|
+
|
8
|
+
def setup
|
9
|
+
@maxRetries = 3
|
10
|
+
|
11
|
+
@scheduler = IntervalRetryScheduler.new 5.0, @maxRetries
|
12
|
+
@command = CommandMessage.as_message Object.new
|
13
|
+
@dispatcher = proc {}
|
14
|
+
end
|
15
|
+
|
16
|
+
should 'schedule up until the max number of retries' do
|
17
|
+
failures = []
|
18
|
+
|
19
|
+
mock(EventMachine).add_timer(5.0, &@dispatcher).times(@maxRetries)
|
20
|
+
|
21
|
+
@maxRetries.times do
|
22
|
+
failures.push RuntimeError.new
|
23
|
+
assert @scheduler.schedule @command, failures, @dispatcher
|
24
|
+
end
|
25
|
+
|
26
|
+
failures.push RuntimeError.new
|
27
|
+
refute @scheduler.schedule @command, failures, @dispatcher
|
28
|
+
end
|
29
|
+
|
30
|
+
should 'not schedule if failure was explicitly non-transient' do
|
31
|
+
failure = CommandValidationError.new
|
32
|
+
refute @scheduler.schedule @command, [failure], @dispatcher
|
33
|
+
end
|
34
|
+
|
35
|
+
should 'not schedule if cause of failure was explicitly non-transient' do
|
36
|
+
failure = CommandExecutionError.new NonTransientError.new
|
37
|
+
refute @scheduler.schedule @command, [failure], @dispatcher
|
38
|
+
end
|
39
|
+
|
40
|
+
end # IntervalRetrySchedulerTest
|
41
|
+
end # Command
|
42
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Synapse
|
4
|
+
module Command
|
5
|
+
class RetryingCallbackTest < Test::Unit::TestCase
|
6
|
+
|
7
|
+
def setup
|
8
|
+
@command = CommandMessage.as_message Object.new
|
9
|
+
@delegate = Object.new
|
10
|
+
@retry_scheduler = Object.new
|
11
|
+
@command_bus = Object.new
|
12
|
+
|
13
|
+
@callback = RetryingCallback.new @delegate, @command, @retry_scheduler, @command_bus
|
14
|
+
end
|
15
|
+
|
16
|
+
should 'notify delegate of a successful dispatch' do
|
17
|
+
result = Object.new
|
18
|
+
|
19
|
+
mock(@delegate).on_success(result)
|
20
|
+
@callback.on_success result
|
21
|
+
end
|
22
|
+
|
23
|
+
should 'not notify delegate of a failed dispatch when rescheduling' do
|
24
|
+
failures = [RuntimeError.new]
|
25
|
+
|
26
|
+
mock(@command_bus).dispatch_with_callback(@command, @callback)
|
27
|
+
|
28
|
+
mock(@retry_scheduler).schedule(@command, failures, is_a(Proc)) do |_, _, dispatcher|
|
29
|
+
dispatcher.call
|
30
|
+
true
|
31
|
+
end
|
32
|
+
|
33
|
+
@callback.on_failure failures.last
|
34
|
+
end
|
35
|
+
|
36
|
+
should 'notify delegate of a failed dispatch when not rescheduling' do
|
37
|
+
failures = [RuntimeError.new]
|
38
|
+
|
39
|
+
mock(@retry_scheduler).schedule(@command, failures, is_a(Proc)) do
|
40
|
+
false
|
41
|
+
end
|
42
|
+
mock(@delegate).on_failure(failures.last)
|
43
|
+
|
44
|
+
@callback.on_failure failures.last
|
45
|
+
end
|
46
|
+
|
47
|
+
should 'notify delegate of a failed dispatch on an unchecked exception' do
|
48
|
+
failure = ThreadError.new
|
49
|
+
|
50
|
+
mock(@delegate).on_failure(failure)
|
51
|
+
|
52
|
+
@callback.on_failure failure
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -4,20 +4,54 @@ module Synapse
|
|
4
4
|
module Command
|
5
5
|
|
6
6
|
class CommandGatewayTest < Test::Unit::TestCase
|
7
|
-
def
|
8
|
-
command_bus = Object.new
|
9
|
-
gateway = CommandGateway.new command_bus
|
7
|
+
def setup
|
8
|
+
@command_bus = Object.new
|
9
|
+
@gateway = CommandGateway.new @command_bus
|
10
|
+
end
|
10
11
|
|
12
|
+
should 'wrap bare command objects in command messages before dispatch' do
|
11
13
|
command = Object.new
|
12
14
|
command_message = CommandMessage.build do |builder|
|
13
15
|
builder.payload = command
|
14
16
|
end
|
15
17
|
|
16
|
-
mock(command_bus).
|
17
|
-
mock(command_bus).
|
18
|
+
mock(@command_bus).dispatch_with_callback(is_a(CommandMessage), anything).ordered
|
19
|
+
mock(@command_bus).dispatch_with_callback(command_message, anything).ordered
|
20
|
+
|
21
|
+
@gateway.send command
|
22
|
+
@gateway.send command_message
|
23
|
+
end
|
24
|
+
|
25
|
+
should 'wrap callback in RetryingCallback if RetryScheduler' do
|
26
|
+
@gateway.retry_scheduler = IntervalRetryScheduler.new 3, 3
|
27
|
+
|
28
|
+
command = Object.new
|
29
|
+
callback = CommandCallback.new
|
30
|
+
|
31
|
+
mock(@command_bus).dispatch_with_callback(is_a(CommandMessage), is_a(RetryingCallback))
|
32
|
+
|
33
|
+
@gateway.send_with_callback command, callback
|
34
|
+
end
|
35
|
+
|
36
|
+
should 'send a command and wait for it to be dispatched' do
|
37
|
+
@gateway.retry_scheduler = IntervalRetryScheduler.new 3, 3
|
38
|
+
|
39
|
+
command = Object.new
|
40
|
+
result = Object.new
|
41
|
+
|
42
|
+
mock(@command_bus).dispatch_with_callback(is_a(CommandMessage), is_a(RetryingCallback)) do |message, callback|
|
43
|
+
callback.on_success result
|
44
|
+
end
|
45
|
+
|
46
|
+
received_result = nil
|
47
|
+
|
48
|
+
Thread.new do
|
49
|
+
received_result = @gateway.send_and_wait(command)
|
50
|
+
end
|
18
51
|
|
19
|
-
|
20
|
-
|
52
|
+
wait_until do
|
53
|
+
received_result.equal? result
|
54
|
+
end
|
21
55
|
end
|
22
56
|
end
|
23
57
|
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Synapse
|
4
|
+
module Command
|
5
|
+
class CommandMessageTest < Test::Unit::TestCase
|
6
|
+
should 'not wrap objects that are already command messages' do
|
7
|
+
command = Object.new
|
8
|
+
command_message = CommandMessage.build
|
9
|
+
|
10
|
+
assert_same command_message, CommandMessage.as_message(command_message)
|
11
|
+
|
12
|
+
wrapped = CommandMessage.as_message(command)
|
13
|
+
assert_same command, wrapped.payload
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -4,7 +4,7 @@ module Synapse
|
|
4
4
|
module Command
|
5
5
|
|
6
6
|
class SerializationOptimizingInterceptorTest < Test::Unit::TestCase
|
7
|
-
|
7
|
+
should 'register a serialization optimizing listener to the current unit of work' do
|
8
8
|
interceptor = SerializationOptimizingInterceptor.new
|
9
9
|
|
10
10
|
command = CommandMessage.build
|
@@ -19,7 +19,7 @@ module Synapse
|
|
19
19
|
end
|
20
20
|
|
21
21
|
class SerializationOptimizingListenerTest < Test::Unit::TestCase
|
22
|
-
|
22
|
+
should 'wrap event messages with serialization aware event messages' do
|
23
23
|
listener = SerializationOptimizingListener.new
|
24
24
|
unit = Object.new
|
25
25
|
|
@@ -15,7 +15,7 @@ module Synapse
|
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
-
|
18
|
+
should 'dispatch a command message to its registered handler' do
|
19
19
|
handler = Object.new
|
20
20
|
command = CommandMessage.build do |m|
|
21
21
|
m.payload = TestCommand.new
|
@@ -28,7 +28,7 @@ module Synapse
|
|
28
28
|
@command_bus.dispatch command
|
29
29
|
end
|
30
30
|
|
31
|
-
|
31
|
+
should 'invoke a callback with the return value from a command handler' do
|
32
32
|
handler = Object.new
|
33
33
|
callback = Object.new
|
34
34
|
command = CommandMessage.build do |m|
|
@@ -47,7 +47,7 @@ module Synapse
|
|
47
47
|
@command_bus.dispatch_with_callback command, callback
|
48
48
|
end
|
49
49
|
|
50
|
-
|
50
|
+
should 'raise an exception when a dispatched command has no registered handler' do
|
51
51
|
command = CommandMessage.build do |m|
|
52
52
|
m.payload = TestCommand.new
|
53
53
|
end
|
@@ -58,7 +58,7 @@ module Synapse
|
|
58
58
|
@command_bus.dispatch_with_callback command, callback
|
59
59
|
end
|
60
60
|
|
61
|
-
|
61
|
+
should 'roll back the current unit of work if the command handler raises an exception' do
|
62
62
|
handler = Object.new
|
63
63
|
command = CommandMessage.build do |m|
|
64
64
|
m.payload = TestCommand.new
|
@@ -81,7 +81,7 @@ module Synapse
|
|
81
81
|
@command_bus.dispatch_with_callback command, callback
|
82
82
|
end
|
83
83
|
|
84
|
-
|
84
|
+
should 'commit the current unit of work if the command handler raises an exception' do
|
85
85
|
handler = Object.new
|
86
86
|
command = CommandMessage.build do |m|
|
87
87
|
m.payload = TestCommand.new
|
@@ -108,7 +108,7 @@ module Synapse
|
|
108
108
|
@command_bus.dispatch_with_callback command, callback
|
109
109
|
end
|
110
110
|
|
111
|
-
|
111
|
+
should 'log when a subscribed handler is replaced' do
|
112
112
|
handler = Object.new
|
113
113
|
|
114
114
|
mock(@logger).debug(anything).ordered
|
@@ -118,7 +118,7 @@ module Synapse
|
|
118
118
|
@command_bus.subscribe TestCommand, handler
|
119
119
|
end
|
120
120
|
|
121
|
-
|
121
|
+
should 'log when a handler is unsubscribed' do
|
122
122
|
handler_a = Object.new
|
123
123
|
handler_b = Object.new
|
124
124
|
|
@@ -5,16 +5,16 @@ module Synapse
|
|
5
5
|
module Command
|
6
6
|
|
7
7
|
class ActiveModelValidationFilterTest < Test::Unit::TestCase
|
8
|
-
|
8
|
+
should 'continue if payload of a command message is valid' do
|
9
9
|
message = CommandMessage.build do |m|
|
10
|
-
m.payload = CreatePersonCommand.new 'River'
|
10
|
+
m.payload = CreatePersonCommand.new 'River Tam'
|
11
11
|
end
|
12
12
|
|
13
13
|
filter = ActiveModelValidationFilter.new
|
14
14
|
filter.filter message
|
15
15
|
end
|
16
16
|
|
17
|
-
|
17
|
+
should 'raise an exception if payload of a command message is invalid' do
|
18
18
|
message = CommandMessage.build do |m|
|
19
19
|
m.payload = CreatePersonCommand.new nil
|
20
20
|
end
|