synapse-core 0.5.1 → 0.5.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/synapse.rb +1 -1
- data/lib/synapse/command.rb +1 -1
- data/lib/synapse/command/command_handler.rb +1 -1
- data/lib/synapse/command/mapping.rb +71 -0
- data/lib/synapse/command/message.rb +0 -16
- data/lib/synapse/command/simple_command_bus.rb +5 -2
- data/lib/synapse/common/message.rb +16 -0
- data/lib/synapse/configuration.rb +1 -18
- data/lib/synapse/configuration/component/command_bus.rb +7 -24
- data/lib/synapse/configuration/component/command_bus/simple_command_bus.rb +31 -7
- data/lib/synapse/configuration/component/event_bus.rb +3 -8
- data/lib/synapse/configuration/component/event_sourcing.rb +11 -8
- data/lib/synapse/configuration/component/event_sourcing/aggregate_snapshot_taker.rb +48 -0
- data/lib/synapse/configuration/component/event_sourcing/interval_snapshot_policy.rb +33 -0
- data/lib/synapse/configuration/component/event_sourcing/repository.rb +36 -1
- data/lib/synapse/configuration/component/repository.rb +4 -8
- data/lib/synapse/configuration/component/serialization.rb +5 -16
- data/lib/synapse/configuration/component/uow.rb +3 -8
- data/lib/synapse/configuration/component/upcasting.rb +3 -8
- data/lib/synapse/configuration/container_builder.rb +29 -2
- data/lib/synapse/configuration/definition_builder.rb +47 -23
- data/lib/synapse/domain/message.rb +0 -16
- data/lib/synapse/event_bus.rb +1 -1
- data/lib/synapse/event_bus/event_listener.rb +1 -1
- data/lib/synapse/event_bus/mapping.rb +47 -0
- data/lib/synapse/event_sourcing.rb +3 -2
- data/lib/synapse/event_sourcing/aggregate_factory.rb +4 -3
- data/lib/synapse/event_sourcing/aggregate_root.rb +17 -0
- data/lib/synapse/event_sourcing/conflict_resolver.rb +3 -0
- data/lib/synapse/event_sourcing/member.rb +34 -6
- data/lib/synapse/event_sourcing/repository.rb +17 -0
- data/lib/synapse/event_sourcing/snapshot/aggregate_taker.rb +38 -0
- data/lib/synapse/event_sourcing/snapshot/policy.rb +27 -0
- data/lib/synapse/event_sourcing/snapshot/taker.rb +2 -37
- data/lib/synapse/event_sourcing/snapshot/unit_listener.rb +26 -0
- data/lib/synapse/event_sourcing/stream_decorator.rb +8 -6
- data/lib/synapse/event_store/errors.rb +2 -2
- data/lib/synapse/mapping.rb +2 -0
- data/lib/synapse/mapping/mapper.rb +75 -0
- data/lib/synapse/{wiring/wire.rb → mapping/mapping.rb} +8 -8
- data/lib/synapse/process_manager.rb +2 -2
- data/lib/synapse/process_manager/mapping/process.rb +44 -0
- data/lib/synapse/process_manager/{wiring → mapping}/process_manager.rb +13 -13
- data/lib/synapse/process_manager/process.rb +3 -3
- data/lib/synapse/repository/locking.rb +14 -8
- data/lib/synapse/upcasting/upcaster_chain.rb +2 -2
- data/lib/synapse/version.rb +1 -1
- data/test/command/{wiring_test.rb → mapping_test.rb} +11 -11
- data/test/configuration/component/command_bus/simple_command_bus_test.rb +30 -0
- data/test/configuration/component/event_bus/simple_event_bus_test.rb +2 -2
- data/test/configuration/component/event_sourcing/repository_test.rb +71 -0
- data/test/configuration/component/repository/simple_repository_test.rb +35 -0
- data/test/configuration/component/upcasting/upcaster_chain_test.rb +29 -0
- data/test/configuration/container_builder_test.rb +4 -6
- data/test/event_bus/{wiring_test.rb → mapping_test.rb} +6 -6
- data/test/event_sourcing/aggregate_factory_test.rb +5 -1
- data/test/event_sourcing/aggregate_root_test.rb +1 -0
- data/test/event_sourcing/fixtures.rb +21 -21
- data/test/event_sourcing/repository_test.rb +10 -0
- data/test/event_sourcing/snapshot/aggregate_taker_test.rb +1 -1
- data/test/event_sourcing/snapshot/interval_policy_test.rb +24 -0
- data/test/process_manager/{wiring → mapping}/fixtures.rb +7 -8
- data/test/process_manager/{wiring → mapping}/process_manager_test.rb +6 -6
- data/test/process_manager/{wiring → mapping}/process_test.rb +3 -3
- data/test/serialization/converter/chain_test.rb +2 -2
- data/test/serialization/converter/factory_test.rb +2 -2
- data/test/serialization/converter/identity_test.rb +1 -1
- data/test/serialization/converter/json_test.rb +2 -2
- data/test/serialization/converter/ox_test.rb +2 -2
- data/test/serialization/lazy_object_test.rb +1 -1
- data/test/serialization/message/metadata_test.rb +1 -1
- data/test/serialization/message/serialization_aware_message_test.rb +5 -5
- data/test/serialization/message/serialized_message_builder_test.rb +1 -1
- data/test/serialization/message/serialized_message_test.rb +5 -5
- data/test/serialization/message/serializer_test.rb +2 -2
- data/test/serialization/revision_resolver_test.rb +1 -1
- data/test/serialization/serialized_object_test.rb +2 -2
- data/test/serialization/serialized_type_test.rb +2 -2
- data/test/serialization/serializer/marshal_test.rb +1 -1
- data/test/serialization/serializer/oj_test.rb +1 -1
- data/test/serialization/serializer/ox_test.rb +2 -2
- data/test/serialization/serializer_test.rb +1 -1
- data/test/uow/factory_test.rb +1 -1
- data/test/uow/outer_commit_listener_test.rb +4 -4
- data/test/uow/provider_test.rb +5 -5
- data/test/uow/uow_test.rb +19 -17
- data/test/upcasting/chain_test.rb +1 -1
- data/test/upcasting/data_test.rb +3 -1
- metadata +30 -37
- data/lib/synapse/command/wiring.rb +0 -47
- data/lib/synapse/event_bus/wiring.rb +0 -20
- data/lib/synapse/event_sourcing/snapshot/count_stream.rb +0 -86
- data/lib/synapse/event_sourcing/snapshot/count_trigger.rb +0 -91
- data/lib/synapse/process_manager/wiring/process.rb +0 -27
- data/lib/synapse/wiring.rb +0 -3
- data/lib/synapse/wiring/message_wiring.rb +0 -76
- data/lib/synapse/wiring/wire_registry.rb +0 -61
- data/test/event_sourcing/snapshot/integration_test.rb +0 -65
- data/test/wiring/wire_registry_test.rb +0 -60
- data/test/wiring/wire_test.rb +0 -51
@@ -1,47 +0,0 @@
|
|
1
|
-
module Synapse
|
2
|
-
module Command
|
3
|
-
# Mixin for a command handler that wishes to use the wiring DSL
|
4
|
-
module WiringCommandHandler
|
5
|
-
extend ActiveSupport::Concern
|
6
|
-
include CommandHandler
|
7
|
-
include Wiring::MessageWiring
|
8
|
-
|
9
|
-
included do
|
10
|
-
self.wire_registry = Wiring::WireRegistry.new false
|
11
|
-
end
|
12
|
-
|
13
|
-
# @param [CommandMessage] command
|
14
|
-
# @param [UnitOfWork] current_unit Current unit of work
|
15
|
-
# @return [Object] The result of handling the given command
|
16
|
-
def handle(command, current_unit)
|
17
|
-
wire = wire_registry.wire_for command.payload_type
|
18
|
-
|
19
|
-
unless wire
|
20
|
-
raise ArgumentError, 'Not capable of handling [%s] commands' % command.payload_type
|
21
|
-
end
|
22
|
-
|
23
|
-
invoke_wire command, wire
|
24
|
-
end
|
25
|
-
|
26
|
-
# Subscribes this handler to the given command bus for any types that have been wired
|
27
|
-
#
|
28
|
-
# @param [CommandBus] command_bus
|
29
|
-
# @return [undefined]
|
30
|
-
def subscribe(command_bus)
|
31
|
-
self.wire_registry.each_type do |type|
|
32
|
-
command_bus.subscribe type, self
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
# Unsubscribes this handler from the given command bus for any types that have been wired
|
37
|
-
#
|
38
|
-
# @param [CommandBus] command_bus
|
39
|
-
# @return [undefined]
|
40
|
-
def unsubscribe(command_bus)
|
41
|
-
self.wire_registry.each_type do |type|
|
42
|
-
command_bus.unsubscribe type, self
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end # WiringCommandHandler
|
46
|
-
end # Command
|
47
|
-
end
|
@@ -1,20 +0,0 @@
|
|
1
|
-
module Synapse
|
2
|
-
module EventBus
|
3
|
-
# Mixin for an event listener that wishes to use the wiring DSL
|
4
|
-
module WiringEventListener
|
5
|
-
extend ActiveSupport::Concern
|
6
|
-
include EventListener
|
7
|
-
include Wiring::MessageWiring
|
8
|
-
|
9
|
-
# @param [EventMessage] event
|
10
|
-
# @return [undefined]
|
11
|
-
def notify(event)
|
12
|
-
wire = wire_registry.wire_for event.payload_type
|
13
|
-
|
14
|
-
return unless wire
|
15
|
-
|
16
|
-
invoke_wire event, wire
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
@@ -1,86 +0,0 @@
|
|
1
|
-
module Synapse
|
2
|
-
module EventSourcing
|
3
|
-
# Event stream decorator that simply counts each event that is retrieved from a delegate stream
|
4
|
-
class CountingEventStream < Domain::DomainEventStream
|
5
|
-
extend Forwardable
|
6
|
-
|
7
|
-
# @param [DomainEventStream] delegate
|
8
|
-
# @param [Atomic] counter
|
9
|
-
# @return [undefined]
|
10
|
-
def initialize(delegate, counter)
|
11
|
-
@delegate = delegate
|
12
|
-
@counter = counter
|
13
|
-
end
|
14
|
-
|
15
|
-
# @return [DomainEventMessage]
|
16
|
-
def next_event
|
17
|
-
next_event = @delegate.next_event
|
18
|
-
|
19
|
-
@counter.update do |value|
|
20
|
-
value = value.next
|
21
|
-
end
|
22
|
-
|
23
|
-
next_event
|
24
|
-
end
|
25
|
-
|
26
|
-
# Delegate un-decorated domain event stream operations
|
27
|
-
def_delegators :@delegate, :end?, :peek
|
28
|
-
end
|
29
|
-
|
30
|
-
# Event stream decorator that counts each event retrieved from the delegate stream and
|
31
|
-
# registers a listener with the current unit of work that can trigger a snapshot after the
|
32
|
-
# unit of work has been cleaned up
|
33
|
-
class TriggeringEventStream < CountingEventStream
|
34
|
-
# @param [DomainEventStream] delegate
|
35
|
-
# @param [Atomic] counter
|
36
|
-
# @param [String] type_identifier
|
37
|
-
# @param [Object] aggregate_id
|
38
|
-
# @param [EventCountSnapshotTrigger] trigger
|
39
|
-
# @return [undefined]
|
40
|
-
def initialize(delegate, counter, type_identifier, aggregate_id, trigger)
|
41
|
-
super delegate, counter
|
42
|
-
|
43
|
-
@type_identifier = type_identifier
|
44
|
-
@aggregate_id = aggregate_id
|
45
|
-
@trigger = trigger
|
46
|
-
end
|
47
|
-
|
48
|
-
# @return [Boolean]
|
49
|
-
def end?
|
50
|
-
the_end = @delegate.end?
|
51
|
-
|
52
|
-
if the_end
|
53
|
-
listener = SnapshotUnitOfWorkListener.new @type_identifier, @aggregate_id, @counter, @trigger
|
54
|
-
|
55
|
-
unit = @trigger.unit_provider.current
|
56
|
-
unit.register_listener listener
|
57
|
-
|
58
|
-
@trigger.clear_counter @aggregate_id
|
59
|
-
end
|
60
|
-
|
61
|
-
the_end
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
# Unit of work listener that is used to trigger snapshots after a unit of work has been cleaned up
|
66
|
-
class SnapshotUnitOfWorkListener < UnitOfWork::UnitOfWorkListener
|
67
|
-
# @param [String] type_identifier
|
68
|
-
# @param [Object] aggregate_id
|
69
|
-
# @param [Atomic] counter
|
70
|
-
# @param [EventCountSnapshotTrigger] trigger
|
71
|
-
# @return [undefined]
|
72
|
-
def initialize(type_identifier, aggregate_id, counter, trigger)
|
73
|
-
@type_identifier = type_identifier
|
74
|
-
@aggregate_id = aggregate_id
|
75
|
-
@trigger = trigger
|
76
|
-
@counter = counter
|
77
|
-
end
|
78
|
-
|
79
|
-
# @param [UnitOfWork] unit
|
80
|
-
# @return [undefined]
|
81
|
-
def on_cleanup(unit)
|
82
|
-
@trigger.trigger_snapshot @type_identifier, @aggregate_id, @counter
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
@@ -1,91 +0,0 @@
|
|
1
|
-
require 'atomic'
|
2
|
-
|
3
|
-
module Synapse
|
4
|
-
module EventSourcing
|
5
|
-
# Snapshot trigger that counts the number of events between snapshots to decide when to
|
6
|
-
# schedule the next snapshot
|
7
|
-
class EventCountSnapshotTrigger < EventStreamDecorator
|
8
|
-
# Default threshold for a snapshot to be scheduled
|
9
|
-
# @return [Integer]
|
10
|
-
DEFAULT_THRESHOLD = 50
|
11
|
-
|
12
|
-
# @return [SnapshotTaker]
|
13
|
-
attr_reader :snapshot_taker
|
14
|
-
|
15
|
-
# @return [Integer] The number of events between snapshots
|
16
|
-
attr_accessor :threshold
|
17
|
-
|
18
|
-
# @return [UnitOfWorkProvider]
|
19
|
-
attr_reader :unit_provider
|
20
|
-
|
21
|
-
# @param [SnapshotTaker] snapshot_taker
|
22
|
-
# @param [UnitOfWorkProvider] unit_provider
|
23
|
-
# @return [undefined]
|
24
|
-
def initialize(snapshot_taker, unit_provider)
|
25
|
-
@counters = Hash.new
|
26
|
-
@lock = Mutex.new
|
27
|
-
@logger = Logging.logger[self.class]
|
28
|
-
@threshold = DEFAULT_THRESHOLD
|
29
|
-
|
30
|
-
@snapshot_taker = snapshot_taker
|
31
|
-
@unit_provider = unit_provider
|
32
|
-
end
|
33
|
-
|
34
|
-
# If the event threshold has been reached for the aggregate with the given identifier, this
|
35
|
-
# will cause a snapshot to be scheduled
|
36
|
-
#
|
37
|
-
# @param [String] type_identifier
|
38
|
-
# @param [Object] aggregate_id
|
39
|
-
# @param [Atomic] counter
|
40
|
-
# @return [undefined]
|
41
|
-
def trigger_snapshot(type_identifier, aggregate_id, counter)
|
42
|
-
if counter.value > @threshold
|
43
|
-
@logger.info 'Snapshot threshold reached for [%s] [%s]' % [type_identifier, aggregate_id]
|
44
|
-
|
45
|
-
@snapshot_taker.schedule_snapshot type_identifier, aggregate_id
|
46
|
-
counter.value = 1
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
# @param [String] type_identifier
|
51
|
-
# @param [Object] aggregate_id
|
52
|
-
# @param [DomainEventStream] stream
|
53
|
-
# @return [DomainEventStream]
|
54
|
-
def decorate_for_read(type_identifier, aggregate_id, stream)
|
55
|
-
CountingEventStream.new(stream, counter_for(aggregate_id))
|
56
|
-
end
|
57
|
-
|
58
|
-
# @param [String] type_identifier
|
59
|
-
# @param [AggregateRoot] aggregate
|
60
|
-
# @param [DomainEventStream] stream
|
61
|
-
# @return [DomainEventStream]
|
62
|
-
def decorate_for_append(type_identifier, aggregate, stream)
|
63
|
-
TriggeringEventStream.new(stream, counter_for(aggregate.id), type_identifier, aggregate.id, self)
|
64
|
-
end
|
65
|
-
|
66
|
-
# Returns the event counter for the aggregate with the given identifier
|
67
|
-
#
|
68
|
-
# @param [Object] aggregate_id
|
69
|
-
# @return [Atomic]
|
70
|
-
def counter_for(aggregate_id)
|
71
|
-
@lock.synchronize do
|
72
|
-
if @counters.has_key? aggregate_id
|
73
|
-
@counters.fetch aggregate_id
|
74
|
-
else
|
75
|
-
@counters.store aggregate_id, Atomic.new(0)
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
# Clears the event counter for the aggregate with the given identifier
|
81
|
-
#
|
82
|
-
# @param [Object] aggregate_id
|
83
|
-
# @return [undefined]
|
84
|
-
def clear_counter(aggregate_id)
|
85
|
-
@lock.synchronize do
|
86
|
-
@counters.delete aggregate_id
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|
@@ -1,27 +0,0 @@
|
|
1
|
-
module Synapse
|
2
|
-
module ProcessManager
|
3
|
-
# Process that has the wiring DSL built-in
|
4
|
-
#
|
5
|
-
# @example
|
6
|
-
# class OrderProcess < WiringProcess
|
7
|
-
# wire OrderCreatedEvent, correlate: :order_id, start: true, to: :on_create
|
8
|
-
# wire OrderFinishedEvent, correlate: :order_id, finish: true, to: :on_finish
|
9
|
-
# end
|
10
|
-
class WiringProcess < Process
|
11
|
-
include Wiring::MessageWiring
|
12
|
-
|
13
|
-
# @param [EventMessage] event
|
14
|
-
# @return [undefined]
|
15
|
-
def handle(event)
|
16
|
-
return unless @active
|
17
|
-
|
18
|
-
wire = wire_registry.wire_for event.payload_type
|
19
|
-
|
20
|
-
return unless wire
|
21
|
-
|
22
|
-
invoke_wire event, wire
|
23
|
-
finish if wire.options[:finish]
|
24
|
-
end
|
25
|
-
end # WiringProcess
|
26
|
-
end # ProcessManager
|
27
|
-
end
|
data/lib/synapse/wiring.rb
DELETED
@@ -1,76 +0,0 @@
|
|
1
|
-
module Synapse
|
2
|
-
module Wiring
|
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
|
-
#
|
8
|
-
# @abstract
|
9
|
-
module MessageWiring
|
10
|
-
extend ActiveSupport::Concern
|
11
|
-
|
12
|
-
included do
|
13
|
-
# @return [WireRegistry]
|
14
|
-
class_attribute :wire_registry
|
15
|
-
|
16
|
-
# By default, the wire registry allows duplicates
|
17
|
-
self.wire_registry = Wiring::WireRegistry.new true
|
18
|
-
end
|
19
|
-
|
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]
|
48
|
-
def wire(type, *args, &block)
|
49
|
-
options = args.extract_options!
|
50
|
-
|
51
|
-
to = options.delete :to
|
52
|
-
unless to
|
53
|
-
unless block
|
54
|
-
raise ArgumentError, 'Expected block or option :to'
|
55
|
-
end
|
56
|
-
|
57
|
-
to = block
|
58
|
-
end
|
59
|
-
|
60
|
-
wire = Wire.new type, options, to
|
61
|
-
|
62
|
-
self.wire_registry.register wire
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
protected
|
67
|
-
|
68
|
-
# @param [Message] message
|
69
|
-
# @param [Wire] wire
|
70
|
-
# @return [Object] Result of the handler invocation
|
71
|
-
def invoke_wire(message, wire)
|
72
|
-
wire.invoke self, message.payload
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
@@ -1,61 +0,0 @@
|
|
1
|
-
module Synapse
|
2
|
-
module Wiring
|
3
|
-
class WireRegistry
|
4
|
-
# @param [Boolean] duplicates_allowed
|
5
|
-
# @return [undefined]
|
6
|
-
def initialize(duplicates_allowed)
|
7
|
-
@duplicates_allowed = duplicates_allowed
|
8
|
-
@wires = Array.new
|
9
|
-
end
|
10
|
-
|
11
|
-
# Yields the type that each wire is registered for
|
12
|
-
#
|
13
|
-
# @yield [Class]
|
14
|
-
# @return [undefined]
|
15
|
-
def each_type
|
16
|
-
@wires.each do |wire|
|
17
|
-
yield wire.type
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
# @raise [DuplicateWireError] If duplicates aren't allowed and another wire exists that
|
22
|
-
# wires the exact same type as the given wire
|
23
|
-
# @param [Wire] wire
|
24
|
-
# @return [undefined]
|
25
|
-
def register(wire)
|
26
|
-
unless @duplicates_allowed
|
27
|
-
if @wires.include? wire
|
28
|
-
raise DuplicateWireError
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
@wires.push wire
|
33
|
-
@wires.sort!
|
34
|
-
end
|
35
|
-
|
36
|
-
# Retrieves the most specific wire for a given type, if any
|
37
|
-
#
|
38
|
-
# @param [Class] target_type
|
39
|
-
# @return [Wire]
|
40
|
-
def wire_for(target_type)
|
41
|
-
@wires.find do |wire|
|
42
|
-
wire.type >= target_type
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
# Retrieves any wires for a given type, regardless of specificity
|
47
|
-
#
|
48
|
-
# @param [Class] target_type
|
49
|
-
# @return [Array]
|
50
|
-
def wires_for(target_type)
|
51
|
-
@wires.find_all do |wire|
|
52
|
-
wire.type >= target_type
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
# Raised if a wire registry doesn't allow duplicates and an attempt is made to wire the same
|
58
|
-
# type to multiple handlers
|
59
|
-
class DuplicateWireError < NonTransientError; end
|
60
|
-
end
|
61
|
-
end
|
@@ -1,65 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
require 'event_sourcing/fixtures'
|
3
|
-
|
4
|
-
module Synapse
|
5
|
-
module EventSourcing
|
6
|
-
|
7
|
-
class SnapshotIntegrationTest < Test::Unit::TestCase
|
8
|
-
def test_integration
|
9
|
-
unit_provider = Object.new
|
10
|
-
unit = Object.new
|
11
|
-
|
12
|
-
mock(unit_provider).current do
|
13
|
-
unit
|
14
|
-
end
|
15
|
-
|
16
|
-
listener = nil
|
17
|
-
|
18
|
-
mock(unit).register_listener(is_a(SnapshotUnitOfWorkListener)) do |l|
|
19
|
-
listener = l
|
20
|
-
end
|
21
|
-
|
22
|
-
event_store = Object.new
|
23
|
-
|
24
|
-
aggregate_id = 123
|
25
|
-
type_identifier = Object.to_s
|
26
|
-
|
27
|
-
aggregate = Object.new
|
28
|
-
mock(aggregate).id.any_times do
|
29
|
-
aggregate_id
|
30
|
-
end
|
31
|
-
|
32
|
-
snapshot_taker = Object.new
|
33
|
-
snapshot_trigger = EventCountSnapshotTrigger.new snapshot_taker, unit_provider
|
34
|
-
snapshot_trigger.threshold = 5
|
35
|
-
|
36
|
-
read_stream = create_stream 3
|
37
|
-
append_stream = create_stream 3
|
38
|
-
|
39
|
-
decorated_read_stream = snapshot_trigger.decorate_for_read type_identifier, aggregate_id, read_stream
|
40
|
-
decorated_read_stream.to_a # Causes stream to iterate over all events
|
41
|
-
|
42
|
-
decorated_append_stream = snapshot_trigger.decorate_for_append type_identifier, aggregate, append_stream
|
43
|
-
decorated_append_stream.to_a # Ditto
|
44
|
-
|
45
|
-
# At this point, there is a snapshot unit of work listener added
|
46
|
-
# Let's "cleanup" the unit of work and check if the snapshot is triggered
|
47
|
-
|
48
|
-
mock(snapshot_taker).schedule_snapshot type_identifier, aggregate_id
|
49
|
-
|
50
|
-
listener.on_cleanup unit
|
51
|
-
end
|
52
|
-
|
53
|
-
def create_stream(size)
|
54
|
-
events = Array.new
|
55
|
-
|
56
|
-
size.times do
|
57
|
-
events.push Domain::DomainEventMessage.build
|
58
|
-
end
|
59
|
-
|
60
|
-
Domain::SimpleDomainEventStream.new events
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
end
|
65
|
-
end
|