euston-daemons 1.0.4-java → 1.1.0-java
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/Gemfile +3 -1
- data/Rakefile +2 -3
- data/euston-daemons.gemspec +61 -26
- data/lib/euston-daemons/command_processor_daemon/config/environment.rb +27 -18
- data/lib/euston-daemons/command_processor_daemon/lib/clients/command_handler.rb +37 -0
- data/lib/euston-daemons/command_processor_daemon/lib/command_handlers/retry_failed_message.rb +35 -0
- data/lib/euston-daemons/command_processor_daemon/lib/daemon.rb +11 -32
- data/lib/euston-daemons/command_processor_daemon/lib/mongo_models/failed_message.rb +34 -0
- data/lib/euston-daemons/command_processor_daemon/rake_task.rb +15 -13
- data/lib/euston-daemons/euston/daemon.rb +93 -0
- data/lib/euston-daemons/euston/daemon_client.rb +24 -0
- data/lib/euston-daemons/euston/daemon_component.rb +65 -0
- data/lib/euston-daemons/euston/daemon_environment.rb +54 -0
- data/lib/euston-daemons/event_processor_daemon/config/environment.rb +27 -16
- data/lib/euston-daemons/event_processor_daemon/lib/clients/event_handler.rb +42 -0
- data/lib/euston-daemons/event_processor_daemon/lib/daemon.rb +13 -60
- data/lib/euston-daemons/event_processor_daemon/lib/event_handlers/message_failure.rb +27 -0
- data/lib/euston-daemons/event_processor_daemon/rake_task.rb +18 -16
- data/lib/euston-daemons/message_buffer_daemon/config/environment.rb +39 -25
- data/lib/euston-daemons/message_buffer_daemon/lib/clients/command_buffer_cleanup.rb +9 -0
- data/lib/euston-daemons/message_buffer_daemon/lib/clients/command_buffer_publisher.rb +9 -0
- data/lib/euston-daemons/message_buffer_daemon/lib/clients/command_logger.rb +9 -0
- data/lib/euston-daemons/message_buffer_daemon/lib/clients/euston_exchange_accessors.rb +15 -0
- data/lib/euston-daemons/message_buffer_daemon/lib/clients/event_buffer_cleanup.rb +9 -0
- data/lib/euston-daemons/message_buffer_daemon/lib/clients/event_buffer_publisher.rb +9 -0
- data/lib/euston-daemons/message_buffer_daemon/lib/clients/event_logger.rb +9 -0
- data/lib/euston-daemons/message_buffer_daemon/lib/clients/event_store_dispatcher.rb +25 -0
- data/lib/euston-daemons/message_buffer_daemon/lib/clients/message_buffer_cleanup.rb +52 -0
- data/lib/euston-daemons/message_buffer_daemon/lib/clients/message_buffer_publisher.rb +37 -0
- data/lib/euston-daemons/message_buffer_daemon/lib/clients/message_logger.rb +45 -0
- data/lib/euston-daemons/message_buffer_daemon/lib/clients/mongo_model_accessors.rb +21 -0
- data/lib/euston-daemons/message_buffer_daemon/lib/daemon.rb +11 -42
- data/lib/euston-daemons/message_buffer_daemon/lib/mongo_models/command_buffer.rb +11 -0
- data/lib/euston-daemons/message_buffer_daemon/lib/mongo_models/command_log.rb +11 -0
- data/lib/euston-daemons/message_buffer_daemon/lib/mongo_models/event_buffer.rb +11 -0
- data/lib/euston-daemons/message_buffer_daemon/lib/mongo_models/event_log.rb +11 -0
- data/lib/euston-daemons/message_buffer_daemon/lib/mongo_models/message_buffer.rb +57 -0
- data/lib/euston-daemons/message_buffer_daemon/lib/{read_model → mongo_models}/message_log.rb +4 -11
- data/lib/euston-daemons/message_buffer_daemon/rake_task.rb +13 -11
- data/lib/euston-daemons/rake_task.rb +41 -65
- data/lib/euston-daemons/rake_tasks.rb +5 -5
- data/lib/euston-daemons/snapshot_daemon/lib/clients/snapshotter.rb +43 -0
- data/lib/euston-daemons/version.rb +1 -1
- data/lib/euston-daemons.rb +6 -1
- data/sample/Rakefile +63 -0
- data/sample/amqp_config.yml +14 -0
- data/sample/command_handlers.rb +17 -0
- data/sample/command_processor_daemon_config.yml +9 -0
- data/sample/event_handlers.rb +21 -0
- data/sample/event_processor_daemon_config.yml +8 -0
- data/sample/message_buffer_daemon_config.yml +8 -0
- data/sample/mongoid_config.yml +13 -0
- data/sample/pids/.placeholder +0 -0
- data/spec/daemons/command_buffer_publisher_spec.rb +110 -0
- data/spec/daemons/command_handler_spec.rb +48 -0
- data/spec/daemons/event_handler_spec.rb +55 -0
- data/spec/daemons/snapshot_client_spec.rb +98 -0
- data/spec/spec_helper.rb +77 -0
- data/spec/support/factories/commands.rb +16 -0
- data/spec/support/factories/commit.rb +7 -0
- data/spec/support/factories/event_message.rb +12 -0
- data/spec/support/factories/events.rb +8 -0
- data/spec/support/filters.rb +14 -0
- data/spec/support/sample_model/commands.rb +14 -0
- data/spec/support/sample_model/counter.rb +36 -0
- data/spec/support/sample_model/counter2.rb +46 -0
- data/spec/support/stub_retrying_subscription.rb +9 -0
- metadata +134 -67
- data/lib/euston-daemons/command_processor_daemon/lib/components/command_handler_component.rb +0 -56
- data/lib/euston-daemons/command_processor_daemon/lib/settings.rb +0 -22
- data/lib/euston-daemons/event_processor_daemon/lib/components/event_handler_component.rb +0 -58
- data/lib/euston-daemons/event_processor_daemon/lib/settings.rb +0 -26
- data/lib/euston-daemons/framework/basic_component.rb +0 -33
- data/lib/euston-daemons/framework/channel_thread.rb +0 -22
- data/lib/euston-daemons/framework/component_shutdown.rb +0 -22
- data/lib/euston-daemons/framework/daemon.rb +0 -27
- data/lib/euston-daemons/framework/handler_bindings_component.rb +0 -56
- data/lib/euston-daemons/framework/queue.rb +0 -71
- data/lib/euston-daemons/message_buffer_daemon/lib/components/buffer_component.rb +0 -73
- data/lib/euston-daemons/message_buffer_daemon/lib/components/event_store_component.rb +0 -52
- data/lib/euston-daemons/message_buffer_daemon/lib/message_logger.rb +0 -54
- data/lib/euston-daemons/message_buffer_daemon/lib/publisher.rb +0 -56
- data/lib/euston-daemons/message_buffer_daemon/lib/settings.rb +0 -14
- data/lib/euston-daemons/message_buffer_daemon/lib/subscriber.rb +0 -60
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
describe 'command buffer publisher client', :purge_event_store do
|
|
2
|
+
require 'euston-daemons/message_buffer_daemon/lib/clients/euston_exchange_accessors'
|
|
3
|
+
require 'euston-daemons/message_buffer_daemon/lib/clients/mongo_model_accessors'
|
|
4
|
+
require 'euston-daemons/message_buffer_daemon/lib/clients/message_buffer_publisher'
|
|
5
|
+
require 'euston-daemons/message_buffer_daemon/lib/clients/command_buffer_publisher'
|
|
6
|
+
require 'euston-daemons/message_buffer_daemon/lib/mongo_models/message_buffer'
|
|
7
|
+
require 'euston-daemons/message_buffer_daemon/lib/mongo_models/command_buffer'
|
|
8
|
+
|
|
9
|
+
let(:logger) { Euston::NullLogger.instance }
|
|
10
|
+
let(:channel) { double('channel').as_null_object }
|
|
11
|
+
let(:command) { Factory.build(:create_counter_command, :id => Uuid.generate).to_hash }
|
|
12
|
+
let(:exchange) { double('exchange').as_null_object }
|
|
13
|
+
let(:published) { [] }
|
|
14
|
+
let(:collection) { @event_store_database[buffer.name] }
|
|
15
|
+
let(:buffer) { Euston::MessageBufferDaemon::MongoModel::CommandBuffer.new @event_store_database }
|
|
16
|
+
let(:publisher) { Euston::MessageBufferDaemon::CommandBufferPublisher.new channel }
|
|
17
|
+
|
|
18
|
+
module Euston
|
|
19
|
+
class DaemonEnvironment
|
|
20
|
+
class << self
|
|
21
|
+
attr_accessor :event_store_mongodb
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
before do
|
|
27
|
+
Euston::DaemonEnvironment.event_store_mongodb = @event_store_database
|
|
28
|
+
channel.stub(:topic) { exchange }
|
|
29
|
+
exchange.stub(:name) { 'commands' }
|
|
30
|
+
exchange.stub(:publish) { |json, options| published << { :json => json, :options => options } }
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
context 'there are no commands in the buffer' do
|
|
34
|
+
describe 'command buffer size' do
|
|
35
|
+
subject { collection.count }
|
|
36
|
+
it { should == 0 }
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
context 'the publisher runs' do
|
|
40
|
+
before { publisher.run }
|
|
41
|
+
|
|
42
|
+
describe 'published commands' do
|
|
43
|
+
subject { published }
|
|
44
|
+
it { should be_empty }
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
context 'there is a due command' do
|
|
50
|
+
|
|
51
|
+
before do
|
|
52
|
+
buffer.buffer_new_message command
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
describe 'command buffer size' do
|
|
56
|
+
subject { collection.count }
|
|
57
|
+
it { should == 1 }
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
context 'the publisher runs' do
|
|
61
|
+
before { publisher.run }
|
|
62
|
+
|
|
63
|
+
describe 'published commands' do
|
|
64
|
+
subject { published }
|
|
65
|
+
it { should have(1).item }
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
describe 'published command' do
|
|
69
|
+
subject { published.first }
|
|
70
|
+
its([:json]) { should == command.to_json }
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
describe 'buffered command' do
|
|
74
|
+
subject { collection.find_one }
|
|
75
|
+
its(['next_attempt']) { should > Time.now.to_f + 2 }
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
context 'there is a command that is not yet due' do
|
|
81
|
+
before do
|
|
82
|
+
buffer.buffer_new_message command
|
|
83
|
+
collection.update({}, { '$set' => { 'next_attempt' => Time.now.to_f + 1000 } }, { :safe => true })
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
context 'the publisher runs' do
|
|
87
|
+
before { publisher.run }
|
|
88
|
+
|
|
89
|
+
describe 'published commands' do
|
|
90
|
+
subject { published }
|
|
91
|
+
it { should be_empty }
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
context 'a command is buffered for dispatch in the future' do
|
|
97
|
+
before do
|
|
98
|
+
buffer.buffer_new_message command, Time.now.to_f + 1000
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
context 'the publisher runs' do
|
|
102
|
+
before { publisher.run }
|
|
103
|
+
|
|
104
|
+
describe 'published commands' do
|
|
105
|
+
subject { published }
|
|
106
|
+
it { should be_empty }
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
describe 'command handler client', :purge_event_store, :purge_rabbitmq do
|
|
2
|
+
require 'euston-daemons/command_processor_daemon/lib/clients/command_handler'
|
|
3
|
+
|
|
4
|
+
let(:logger) { Euston::NullLogger.instance }
|
|
5
|
+
let(:handlers) { [] }
|
|
6
|
+
let(:subscription) { StubRetryingSubscription.new }
|
|
7
|
+
let(:client) { Euston::CommandProcessorDaemon::CommandHandler.new @channel, handlers, logger }
|
|
8
|
+
let(:aggregate) { Euston::Daemons::SampleModel::Counter2.new }
|
|
9
|
+
let(:saved_aggregates) { [] }
|
|
10
|
+
|
|
11
|
+
before do
|
|
12
|
+
Euston::RabbitMq::RetryingSubscription.stub(:new) { subscription }
|
|
13
|
+
Euston::Repository.stub(:find) { aggregate }
|
|
14
|
+
Euston::Repository.stub(:save) { |aggregate| saved_aggregates << aggregate }
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
context 'a message is received' do
|
|
18
|
+
before do
|
|
19
|
+
client.run
|
|
20
|
+
command = Factory.build(:create_counter_command, :id => Uuid.generate).to_hash
|
|
21
|
+
subscription.stub_message_receipt command
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
context 'the message is not explicitly handled by a command handler class' do
|
|
25
|
+
subject { saved_aggregates }
|
|
26
|
+
it { should_not be_empty }
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
context 'the message is explicitly handled by a command handler class' do
|
|
30
|
+
class CreateCounter
|
|
31
|
+
include Euston::CommandHandler
|
|
32
|
+
|
|
33
|
+
class << self
|
|
34
|
+
attr_accessor :was_called
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
version 1 do |headers, command|
|
|
38
|
+
self.class.was_called = true
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
let(:handlers) { [ Euston::RabbitMq::HandlerReference.new(Object, CreateCounter, :CreateCounter) ] }
|
|
43
|
+
|
|
44
|
+
subject { CreateCounter.was_called }
|
|
45
|
+
it { should be_true }
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
describe 'event handler client', :purge_event_store, :purge_rabbitmq do
|
|
2
|
+
require 'euston-daemons/event_processor_daemon/lib/clients/event_handler'
|
|
3
|
+
|
|
4
|
+
let(:logger) { Euston::NullLogger.instance }
|
|
5
|
+
let(:subscription) { StubRetryingSubscription.new }
|
|
6
|
+
let(:client) { Euston::EventProcessorDaemon::EventHandler.new @channel, reference, logger }
|
|
7
|
+
let(:aggregate) { Euston::Daemons::SampleModel::Counter2.new }
|
|
8
|
+
let(:saved_aggregates) { [] }
|
|
9
|
+
|
|
10
|
+
before do
|
|
11
|
+
Euston::RabbitMq::RetryingSubscription.stub(:new) { subscription }
|
|
12
|
+
Euston::Repository.stub(:find) { aggregate }
|
|
13
|
+
Euston::Repository.stub(:save) { |aggregate| saved_aggregates << aggregate }
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
context 'a message is received' do
|
|
17
|
+
before do
|
|
18
|
+
client.run
|
|
19
|
+
|
|
20
|
+
event = { :headers => { :id => Uuid.generate,
|
|
21
|
+
:type => :external_thing_happened,
|
|
22
|
+
:timestamp => Time.now.to_f,
|
|
23
|
+
:version => 1 },
|
|
24
|
+
:body => {} }
|
|
25
|
+
|
|
26
|
+
subscription.stub_message_receipt event
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
context 'the event handler is bound to an aggregate root' do
|
|
30
|
+
let(:reference) { Euston::RabbitMq::HandlerReference.new(Euston::Daemons::SampleModel, Euston::Daemons::SampleModel::Counter2, :Counter2) }
|
|
31
|
+
|
|
32
|
+
subject { saved_aggregates }
|
|
33
|
+
it { should_not be_empty }
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
context 'the message is explicitly handled by an event handler class' do
|
|
37
|
+
class ExternalThingHappenedListener
|
|
38
|
+
include Euston::EventHandler
|
|
39
|
+
|
|
40
|
+
class << self
|
|
41
|
+
attr_accessor :was_called
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
subscribes :external_thing_happened, do |headers, command|
|
|
45
|
+
self.class.was_called = true
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
let(:reference) { Euston::RabbitMq::HandlerReference.new(Object, ExternalThingHappenedListener, :ExternalThingHappenedListener) }
|
|
50
|
+
|
|
51
|
+
subject { ExternalThingHappenedListener.was_called }
|
|
52
|
+
it { should be_true }
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
describe 'snapshot client', :purge_event_store, :euston_event_store do
|
|
2
|
+
require 'euston-daemons/snapshot_daemon/lib/clients/snapshotter'
|
|
3
|
+
|
|
4
|
+
let(:logger) { Euston::NullLogger.instance }
|
|
5
|
+
let(:threshold) { 2 }
|
|
6
|
+
let(:snapshotter) { Euston::SnapshotDaemon::Snapshotter.new @event_store, threshold, logger }
|
|
7
|
+
let(:commands) { [] }
|
|
8
|
+
let(:counter_id) { Uuid.generate }
|
|
9
|
+
|
|
10
|
+
def publish_commands_then_take_snapshot commands
|
|
11
|
+
commands.each { |c| publish_command c }
|
|
12
|
+
sleep 0.25 # to allow the async stream head update to finish
|
|
13
|
+
snapshotter.run
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
before { publish_commands_then_take_snapshot commands }
|
|
17
|
+
|
|
18
|
+
context 'there are no streams' do
|
|
19
|
+
describe 'snapshots collection size' do
|
|
20
|
+
subject { @event_store_database['snapshots'].count }
|
|
21
|
+
it { should == 0 }
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
context 'there is a stream that is too small to snapshot' do
|
|
26
|
+
let(:commands) { [ Factory.build(:create_counter_command) ] }
|
|
27
|
+
|
|
28
|
+
describe 'snapshots collection size' do
|
|
29
|
+
subject { @event_store_database['snapshots'].count }
|
|
30
|
+
it { should == 0 }
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
context 'there is a stream that is large enough to snapshot' do
|
|
35
|
+
let(:commands) { [ Factory.build(:create_counter_command, :id => counter_id),
|
|
36
|
+
Factory.build(:increment_counter_command, :counter_id => counter_id, :amount => 1),
|
|
37
|
+
Factory.build(:increment_counter_command, :counter_id => counter_id, :amount => 2) ] }
|
|
38
|
+
|
|
39
|
+
describe 'snapshots collection size' do
|
|
40
|
+
subject { @event_store_database['snapshots'].count }
|
|
41
|
+
it { should == 1 }
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
describe 'snapshot' do
|
|
45
|
+
subject { @event_store.get_snapshot counter_id }
|
|
46
|
+
its(:headers) { should == { :version => 1 } }
|
|
47
|
+
its(:payload) { should == { :count => 3 } }
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
describe 'reloading from the snapshot' do
|
|
51
|
+
subject { Euston::Repository.find Euston::Daemons::SampleModel::Counter, counter_id }
|
|
52
|
+
its(:count) { should == 3 }
|
|
53
|
+
its(:snapshot_loaded) { should == { :count => 3 }}
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
context 'multiple snapshots taken over time' do
|
|
58
|
+
# let(:logger) { Logger.new(STDOUT) }
|
|
59
|
+
|
|
60
|
+
let(:commands) { [ Factory.build(:create_counter_command, :id => counter_id),
|
|
61
|
+
Factory.build(:increment_counter_command, :counter_id => counter_id, :amount => 1),
|
|
62
|
+
Factory.build(:increment_counter_command, :counter_id => counter_id, :amount => 2) ] }
|
|
63
|
+
let(:commands2) { [ Factory.build(:increment_counter_command, :counter_id => counter_id, :amount => 3),
|
|
64
|
+
Factory.build(:increment_counter_command, :counter_id => counter_id, :amount => 5),
|
|
65
|
+
Factory.build(:increment_counter_command, :counter_id => counter_id, :amount => 8) ] }
|
|
66
|
+
let(:commands3) { [ Factory.build(:increment_counter_command, :counter_id => counter_id, :amount => 13),
|
|
67
|
+
Factory.build(:increment_counter_command, :counter_id => counter_id, :amount => 21),
|
|
68
|
+
Factory.build(:increment_counter_command, :counter_id => counter_id, :amount => 34) ] }
|
|
69
|
+
|
|
70
|
+
before do
|
|
71
|
+
publish_commands_then_take_snapshot commands2
|
|
72
|
+
publish_commands_then_take_snapshot commands3
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
describe 'snapshots collection size' do
|
|
76
|
+
subject { @event_store_database['snapshots'].count }
|
|
77
|
+
it { should == 3 }
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
describe 'first snapshot' do
|
|
81
|
+
subject { @event_store.get_snapshot counter_id, 3 }
|
|
82
|
+
its(:headers) { should == { :version => 1 } }
|
|
83
|
+
its(:payload) { should == { :count => 3 } }
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
describe 'second snapshot' do
|
|
87
|
+
subject { @event_store.get_snapshot counter_id, 6 }
|
|
88
|
+
its(:headers) { should == { :version => 1 } }
|
|
89
|
+
its(:payload) { should == { :count => 19 } }
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
describe 'third snapshot' do
|
|
93
|
+
subject { @event_store.get_snapshot counter_id }
|
|
94
|
+
its(:headers) { should == { :version => 1 } }
|
|
95
|
+
its(:payload) { should == { :count => 87 } }
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
jruby = RUBY_PLATFORM.to_s == 'java'
|
|
2
|
+
|
|
3
|
+
require 'ap'
|
|
4
|
+
require 'rabbitmqadmin-cli'
|
|
5
|
+
require 'euston'
|
|
6
|
+
require 'euston-rabbitmq'
|
|
7
|
+
require 'euston-eventstore'
|
|
8
|
+
require 'euston-daemons'
|
|
9
|
+
require 'cranky'
|
|
10
|
+
require 'ffaker'
|
|
11
|
+
require 'mongo' unless jruby
|
|
12
|
+
require 'jmongo' if jruby
|
|
13
|
+
require 'safely'
|
|
14
|
+
|
|
15
|
+
specs_path = File.dirname __FILE__
|
|
16
|
+
require File.join specs_path, 'support', 'factories', 'event_message'
|
|
17
|
+
require File.join specs_path, 'support', 'factories', 'commit'
|
|
18
|
+
require File.join specs_path, 'support', 'factories', 'commands'
|
|
19
|
+
require File.join specs_path, 'support', 'filters'
|
|
20
|
+
require File.join specs_path, 'support', 'stub_retrying_subscription'
|
|
21
|
+
require File.join specs_path, 'support', 'sample_model', 'commands'
|
|
22
|
+
require File.join specs_path, 'support', 'sample_model', 'counter'
|
|
23
|
+
require File.join specs_path, 'support', 'sample_model', 'counter2'
|
|
24
|
+
|
|
25
|
+
Safely.configure do |config|
|
|
26
|
+
config.strategies = [ Safely::Strategy::Log ]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
amqp_config = { :host => 'localhost', :vhost => 'euston-daemons-test', :user => 'euston-daemons-test-user', :pass => 'password' }
|
|
30
|
+
|
|
31
|
+
mongo_connection = Mongo::Connection.from_uri 'mongodb://0.0.0.0:27017/', :safe => true, :fsync => true, :journal => true
|
|
32
|
+
event_store_database = Mongo::DB.new 'euston-daemons-test-event-store', mongo_connection
|
|
33
|
+
read_model_database = Mongo::DB.new 'euston-daemons-test-read-model', mongo_connection
|
|
34
|
+
|
|
35
|
+
RSpec.configure do |config|
|
|
36
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
|
37
|
+
|
|
38
|
+
config.before(:each) do
|
|
39
|
+
@event_store_database = event_store_database
|
|
40
|
+
@read_model_database = read_model_database
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
config.before(:each, :euston_event_store) do
|
|
44
|
+
mongo_config = Euston::EventStore::Persistence::Mongodb::Config.instance
|
|
45
|
+
mongo_config.database = event_store_database.name
|
|
46
|
+
|
|
47
|
+
@persistence_factory = Euston::EventStore::Persistence::Mongodb::MongoPersistenceFactory.build
|
|
48
|
+
@persistence_factory.init
|
|
49
|
+
|
|
50
|
+
@event_store = Euston::EventStore::OptimisticEventStore.new @persistence_factory
|
|
51
|
+
Euston::Repository.event_store = @event_store
|
|
52
|
+
|
|
53
|
+
def publish_command command
|
|
54
|
+
hash = command.to_hash
|
|
55
|
+
command = { :headers => Euston::CommandHeaders.from_hash(hash[:headers]), :body => hash[:body] }
|
|
56
|
+
Euston::CommandBus.publish command[:headers], command[:body]
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
config.before(:each, :purge_event_store) do
|
|
61
|
+
purge_database event_store_database
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
config.before(:each, :purge_mongo) do
|
|
65
|
+
purge_database event_store_database
|
|
66
|
+
purge_database read_model_database
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
config.before(:each, :purge_rabbitmq) do
|
|
70
|
+
initialize_rabbitmq amqp_config
|
|
71
|
+
initialize_amqp amqp_config
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
config.before(:each, :purge_read_model) do
|
|
75
|
+
purge_database read_model_database
|
|
76
|
+
end
|
|
77
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
class Cranky::Factory
|
|
2
|
+
def create_counter_command
|
|
3
|
+
hash = define :class => Hash,
|
|
4
|
+
:id => Uuid.generate
|
|
5
|
+
|
|
6
|
+
Euston::Daemons::SampleModel::CreateCounter.new hash
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def increment_counter_command
|
|
10
|
+
hash = define :class => Hash,
|
|
11
|
+
:counter_id => Uuid.generate,
|
|
12
|
+
:amount => 1 + rand(9)
|
|
13
|
+
|
|
14
|
+
Euston::Daemons::SampleModel::IncrementCounter.new hash
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
class Cranky::Factory
|
|
2
|
+
def event_message
|
|
3
|
+
headers = { :id => Euston.uuid.generate,
|
|
4
|
+
:type => Faker::Lorem.words(2).join('_'),
|
|
5
|
+
:version => 1,
|
|
6
|
+
:timestamp => Time.now.to_f }
|
|
7
|
+
|
|
8
|
+
body = { :number => rand(9) + 1 }
|
|
9
|
+
|
|
10
|
+
Euston::EventStore::EventMessage.new 'headers' => headers, 'body' => body
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
def initialize_amqp config
|
|
2
|
+
AMQP.settings.merge! config
|
|
3
|
+
@channel = AMQP::Channel.new
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
def initialize_rabbitmq config
|
|
7
|
+
@rabbitmqadmin = RabbitMqAdminCli.new
|
|
8
|
+
@rabbitmqadmin.initialize_vhost config[:vhost]
|
|
9
|
+
@rabbitmqadmin.initialize_user config[:vhost], config[:user], config[:pass]
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def purge_database database
|
|
13
|
+
database.collections.each { |collection| collection.remove unless collection.name.downcase =~ /^system/ }
|
|
14
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
module Euston
|
|
2
|
+
module Daemons
|
|
3
|
+
module SampleModel
|
|
4
|
+
class CreateCounter < Euston::Command
|
|
5
|
+
validates :id, :presence => true
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
class IncrementCounter < Euston::Command
|
|
9
|
+
validates :counter_id, :presence => true
|
|
10
|
+
validates :amount, :presence => true
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
module Euston
|
|
2
|
+
module Daemons
|
|
3
|
+
module SampleModel
|
|
4
|
+
class Counter
|
|
5
|
+
include Euston::AggregateRoot
|
|
6
|
+
|
|
7
|
+
created_by :create_counter do |command|
|
|
8
|
+
apply_event :counter_created, 1, command
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
consumes :increment_counter, :id => :counter_id do |command|
|
|
12
|
+
apply_event :counter_incremented, 1, :count => @count + command.amount
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
applies :counter_created do |event|
|
|
16
|
+
@count = 0
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
applies :counter_incremented do |event|
|
|
20
|
+
@count = event.count
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
load_snapshot 1 do |snapshot|
|
|
24
|
+
@count = snapshot[:count]
|
|
25
|
+
@snapshot_loaded = snapshot
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
take_snapshot 1 do
|
|
29
|
+
{ :count => @count }
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
attr_reader :count, :snapshot_loaded
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
module Euston
|
|
2
|
+
module Daemons
|
|
3
|
+
module SampleModel
|
|
4
|
+
class Counter2
|
|
5
|
+
include Euston::AggregateRoot
|
|
6
|
+
|
|
7
|
+
created_by :create_counter do |command|
|
|
8
|
+
apply_event :counter_created, 1, command
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
consumes :increment_counter, :id => :counter_id do |command|
|
|
12
|
+
apply_event :counter_incremented, 1, :count => @count + command.amount
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
subscribes :external_thing_happened do |headers, event|
|
|
16
|
+
apply_event :noted_that_external_thing_happened, 1
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
applies :counter_created do |event|
|
|
20
|
+
@count = 0
|
|
21
|
+
@external_thing_happened = false
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
applies :counter_incremented do |event|
|
|
25
|
+
@count = event.count
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
applies :noted_that_external_thing_happened do |event|
|
|
29
|
+
@external_thing_happened = true
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
load_snapshot 1 do |snapshot|
|
|
33
|
+
@count = snapshot[:count]
|
|
34
|
+
@external_thing_happened = snapshot[:heard_about_external_thing]
|
|
35
|
+
@snapshot_loaded = snapshot
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
take_snapshot 1 do
|
|
39
|
+
{ :count => @count, :heard_about_external_thing => @external_thing_happened }
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
attr_reader :count, :snapshot_loaded
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|