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.
- data/lib/synapse.rb +351 -0
- data/lib/synapse/command/command_bus.rb +45 -0
- data/lib/synapse/command/command_callback.rb +18 -0
- data/lib/synapse/command/command_filter.rb +17 -0
- data/lib/synapse/command/command_handler.rb +13 -0
- data/lib/synapse/command/dispatch_interceptor.rb +16 -0
- data/lib/synapse/command/duplication.rb +43 -0
- data/lib/synapse/command/errors.rb +27 -0
- data/lib/synapse/command/filters/validation.rb +32 -0
- data/lib/synapse/command/gateway.rb +34 -0
- data/lib/synapse/command/interceptor_chain.rb +31 -0
- data/lib/synapse/command/interceptors/serialization.rb +35 -0
- data/lib/synapse/command/message.rb +19 -0
- data/lib/synapse/command/rollback_policy.rb +22 -0
- data/lib/synapse/command/simple_command_bus.rb +138 -0
- data/lib/synapse/command/wiring.rb +47 -0
- data/lib/synapse/domain/aggregate_root.rb +121 -0
- data/lib/synapse/domain/event_container.rb +127 -0
- data/lib/synapse/domain/message.rb +82 -0
- data/lib/synapse/domain/message_builder.rb +34 -0
- data/lib/synapse/domain/stream.rb +108 -0
- data/lib/synapse/duplication.rb +60 -0
- data/lib/synapse/errors.rb +13 -0
- data/lib/synapse/event_bus/event_bus.rb +40 -0
- data/lib/synapse/event_bus/event_listener.rb +16 -0
- data/lib/synapse/event_bus/event_listener_proxy.rb +12 -0
- data/lib/synapse/event_bus/simple_event_bus.rb +69 -0
- data/lib/synapse/event_bus/wiring.rb +23 -0
- data/lib/synapse/event_sourcing/aggregate_factory.rb +69 -0
- data/lib/synapse/event_sourcing/aggregate_root.rb +104 -0
- data/lib/synapse/event_sourcing/conflict_resolver.rb +80 -0
- data/lib/synapse/event_sourcing/entity.rb +64 -0
- data/lib/synapse/event_sourcing/member.rb +72 -0
- data/lib/synapse/event_sourcing/repository.rb +119 -0
- data/lib/synapse/event_sourcing/snapshot/count_stream.rb +86 -0
- data/lib/synapse/event_sourcing/snapshot/count_trigger.rb +91 -0
- data/lib/synapse/event_sourcing/snapshot/taker.rb +73 -0
- data/lib/synapse/event_sourcing/storage_listener.rb +34 -0
- data/lib/synapse/event_sourcing/stream_decorator.rb +25 -0
- data/lib/synapse/event_store/errors.rb +16 -0
- data/lib/synapse/event_store/event_store.rb +43 -0
- data/lib/synapse/event_store/in_memory.rb +59 -0
- data/lib/synapse/event_store/mongo/cursor_event_stream.rb +63 -0
- data/lib/synapse/event_store/mongo/event_store.rb +86 -0
- data/lib/synapse/event_store/mongo/per_commit_strategy.rb +253 -0
- data/lib/synapse/event_store/mongo/per_event_strategy.rb +143 -0
- data/lib/synapse/event_store/mongo/storage_strategy.rb +113 -0
- data/lib/synapse/event_store/mongo/template.rb +73 -0
- data/lib/synapse/identifier.rb +23 -0
- data/lib/synapse/message.rb +101 -0
- data/lib/synapse/message_builder.rb +38 -0
- data/lib/synapse/process_manager/correlation.rb +32 -0
- data/lib/synapse/process_manager/correlation_resolver.rb +14 -0
- data/lib/synapse/process_manager/correlation_set.rb +58 -0
- data/lib/synapse/process_manager/process.rb +71 -0
- data/lib/synapse/repository/errors.rb +26 -0
- data/lib/synapse/repository/lock_manager.rb +40 -0
- data/lib/synapse/repository/locking.rb +97 -0
- data/lib/synapse/repository/pessimistic_lock_manager.rb +61 -0
- data/lib/synapse/repository/repository.rb +109 -0
- data/lib/synapse/serialization/converter.rb +39 -0
- data/lib/synapse/serialization/converter/chain.rb +45 -0
- data/lib/synapse/serialization/converter/factory.rb +68 -0
- data/lib/synapse/serialization/converter/identity.rb +29 -0
- data/lib/synapse/serialization/converter/json.rb +31 -0
- data/lib/synapse/serialization/converter/ox.rb +31 -0
- data/lib/synapse/serialization/errors.rb +12 -0
- data/lib/synapse/serialization/lazy_object.rb +61 -0
- data/lib/synapse/serialization/message/data.rb +25 -0
- data/lib/synapse/serialization/message/metadata.rb +13 -0
- data/lib/synapse/serialization/message/serialization_aware.rb +17 -0
- data/lib/synapse/serialization/message/serialization_aware_message.rb +66 -0
- data/lib/synapse/serialization/message/serialized_message.rb +201 -0
- data/lib/synapse/serialization/message/serialized_message_builder.rb +64 -0
- data/lib/synapse/serialization/message/serialized_object_cache.rb +50 -0
- data/lib/synapse/serialization/message/serializer.rb +47 -0
- data/lib/synapse/serialization/revision_resolver.rb +30 -0
- data/lib/synapse/serialization/serialized_object.rb +37 -0
- data/lib/synapse/serialization/serialized_type.rb +31 -0
- data/lib/synapse/serialization/serializer.rb +98 -0
- data/lib/synapse/serialization/serializer/marshal.rb +32 -0
- data/lib/synapse/serialization/serializer/oj.rb +34 -0
- data/lib/synapse/serialization/serializer/ox.rb +31 -0
- data/lib/synapse/uow/factory.rb +28 -0
- data/lib/synapse/uow/listener.rb +79 -0
- data/lib/synapse/uow/listener_collection.rb +93 -0
- data/lib/synapse/uow/nesting.rb +262 -0
- data/lib/synapse/uow/provider.rb +71 -0
- data/lib/synapse/uow/storage_listener.rb +14 -0
- data/lib/synapse/uow/transaction_manager.rb +27 -0
- data/lib/synapse/uow/uow.rb +178 -0
- data/lib/synapse/upcasting/chain.rb +78 -0
- data/lib/synapse/upcasting/context.rb +58 -0
- data/lib/synapse/upcasting/data.rb +30 -0
- data/lib/synapse/upcasting/single_upcaster.rb +57 -0
- data/lib/synapse/upcasting/upcaster.rb +55 -0
- data/lib/synapse/version.rb +3 -0
- data/lib/synapse/wiring/message_wiring.rb +41 -0
- data/lib/synapse/wiring/wire.rb +55 -0
- data/lib/synapse/wiring/wire_registry.rb +61 -0
- data/test/command/duplication_test.rb +54 -0
- data/test/command/gateway_test.rb +25 -0
- data/test/command/interceptor_chain_test.rb +26 -0
- data/test/command/serialization_test.rb +37 -0
- data/test/command/simple_command_bus_test.rb +141 -0
- data/test/command/validation_test.rb +42 -0
- data/test/command/wiring_test.rb +73 -0
- data/test/domain/aggregate_root_test.rb +57 -0
- data/test/domain/fixtures.rb +31 -0
- data/test/domain/message_test.rb +61 -0
- data/test/domain/stream_test.rb +35 -0
- data/test/duplication_test.rb +40 -0
- data/test/event_bus/wiring_test.rb +46 -0
- data/test/event_sourcing/aggregate_factory_test.rb +28 -0
- data/test/event_sourcing/aggregate_root_test.rb +76 -0
- data/test/event_sourcing/entity_test.rb +34 -0
- data/test/event_sourcing/fixtures.rb +85 -0
- data/test/event_sourcing/repository_test.rb +102 -0
- data/test/event_sourcing/snapshot/aggregate_taker_test.rb +39 -0
- data/test/event_sourcing/snapshot/deferred_taker_test.rb +19 -0
- data/test/event_sourcing/snapshot/integration_test.rb +65 -0
- data/test/event_sourcing/storage_listener_test.rb +77 -0
- data/test/event_store/in_memory_test.rb +47 -0
- data/test/process_manager/correlation_set_test.rb +49 -0
- data/test/process_manager/correlation_test.rb +24 -0
- data/test/process_manager/process_test.rb +52 -0
- data/test/repository/locking_test.rb +101 -0
- data/test/serialization/converter/factory_test.rb +33 -0
- data/test/serialization/converter/identity_test.rb +17 -0
- data/test/serialization/converter/json_test.rb +31 -0
- data/test/serialization/converter/ox_test.rb +40 -0
- data/test/serialization/fixtures.rb +17 -0
- data/test/serialization/lazy_object_test.rb +32 -0
- data/test/serialization/message/metadata_test.rb +19 -0
- data/test/serialization/message/serialization_aware_message_test.rb +88 -0
- data/test/serialization/message/serialized_message_builder_test.rb +41 -0
- data/test/serialization/message/serialized_message_test.rb +140 -0
- data/test/serialization/message/serializer_test.rb +50 -0
- data/test/serialization/revision_resolver_test.rb +12 -0
- data/test/serialization/serialized_object_test.rb +36 -0
- data/test/serialization/serialized_type_test.rb +27 -0
- data/test/serialization/serializer/marshal_test.rb +22 -0
- data/test/serialization/serializer/oj_test.rb +24 -0
- data/test/serialization/serializer/ox_test.rb +36 -0
- data/test/serialization/serializer_test.rb +20 -0
- data/test/test_helper.rb +19 -0
- data/test/uow/factory_test.rb +23 -0
- data/test/uow/outer_commit_listener_test.rb +50 -0
- data/test/uow/provider_test.rb +70 -0
- data/test/uow/uow_test.rb +337 -0
- data/test/upcasting/chain_test.rb +29 -0
- data/test/upcasting/fixtures.rb +66 -0
- data/test/wiring/wire_registry_test.rb +60 -0
- data/test/wiring/wire_test.rb +51 -0
- 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
|
data/test/test_helper.rb
ADDED
|
@@ -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
|