replay 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +7 -0
  2. data/.rvmrc +1 -1
  3. data/Gemfile +7 -3
  4. data/Guardfile +10 -0
  5. data/LICENSE +21 -0
  6. data/README.md +153 -0
  7. data/Rakefile +15 -0
  8. data/lib/replay.rb +39 -10
  9. data/lib/replay/backends.rb +50 -0
  10. data/lib/replay/event_declarations.rb +36 -0
  11. data/lib/replay/event_decorator.rb +13 -0
  12. data/lib/replay/events.rb +24 -0
  13. data/lib/replay/inflector.rb +55 -0
  14. data/lib/replay/observer.rb +18 -0
  15. data/lib/replay/publisher.rb +72 -0
  16. data/lib/replay/repository.rb +61 -0
  17. data/lib/replay/repository/configuration.rb +30 -0
  18. data/lib/replay/repository/identity_map.rb +25 -0
  19. data/lib/replay/router.rb +5 -0
  20. data/lib/replay/router/default_router.rb +21 -0
  21. data/lib/replay/rspec.rb +50 -0
  22. data/lib/replay/subscription_manager.rb +28 -0
  23. data/lib/replay/test.rb +64 -0
  24. data/lib/replay/test/test_event_stream.rb +19 -0
  25. data/lib/replay/version.rb +1 -1
  26. data/proofs/all.rb +7 -0
  27. data/proofs/proofs_init.rb +10 -0
  28. data/proofs/replay/inflector_proof.rb +32 -0
  29. data/proofs/replay/publisher_proof.rb +170 -0
  30. data/proofs/replay/repository_configuration_proof.rb +67 -0
  31. data/proofs/replay/repository_proof.rb +46 -0
  32. data/proofs/replay/subscriber_manager_proof.rb +39 -0
  33. data/proofs/replay/test_proof.rb +28 -0
  34. data/replay.gemspec +5 -4
  35. data/test/replay/observer_spec.rb +37 -0
  36. data/test/replay/router/default_router_spec.rb +43 -0
  37. data/test/test_helper.rb +10 -0
  38. metadata +65 -48
  39. data/README +0 -27
  40. data/lib/replay/active_record_event_store.rb +0 -32
  41. data/lib/replay/domain.rb +0 -33
  42. data/lib/replay/event.rb +0 -27
  43. data/lib/replay/event_store.rb +0 -55
  44. data/lib/replay/projector.rb +0 -19
  45. data/lib/replay/test_storage.rb +0 -8
  46. data/lib/replay/unknown_event_error.rb +0 -2
  47. data/test/spec_helper.rb +0 -6
  48. data/test/test_events.sqlite3 +0 -0
  49. data/test/unit/active_record_event_store_spec.rb +0 -24
  50. data/test/unit/domain_spec.rb +0 -53
  51. data/test/unit/event_spec.rb +0 -13
  52. data/test/unit/event_store_spec.rb +0 -28
  53. data/test/unit/projector_spec.rb +0 -19
@@ -0,0 +1,170 @@
1
+ require_relative "../proofs_init.rb"
2
+ require 'replay/test'
3
+
4
+ class ReplayTest
5
+ include Replay::Publisher
6
+ include Replay::EventExaminer
7
+
8
+ key :pkey
9
+
10
+ def initialize(pkey = 1)
11
+ @pkey = pkey
12
+ end
13
+
14
+ events do
15
+ SomeEvent(pid: Integer)
16
+ UnhandledEvent(pid: Integer)
17
+ end
18
+
19
+ apply SomeEvent do |event|
20
+ @event_count ||= 0
21
+ @event_applied = event.pid
22
+ @event_count += 1
23
+ end
24
+
25
+ def pkey
26
+ @pkey
27
+ end
28
+ end
29
+
30
+ module ReplayTest::Proof
31
+ def sets_publish_time
32
+ publish SomeEvent(pid: 123)
33
+ events.last.published_at != nil && (Time.now - events.last.published_at) < 20
34
+ end
35
+
36
+ def published_at_not_considered_in_equality
37
+ event = SomeEvent(pid: 123)
38
+ event == event.with(:published_at => Time.now-100)
39
+ end
40
+
41
+ def defines_events?
42
+ self.class.const_defined?(:SomeEvent) && self.class.const_get(:SomeEvent).is_a?(Class)
43
+ end
44
+ def adds_convenience_method?
45
+ respond_to? :SomeEvent
46
+ end
47
+ def applies_event?(event)
48
+ apply(event)
49
+ @event_applied == event.pid
50
+ end
51
+
52
+ def applies_events?(events)
53
+ apply(events)
54
+ @event_count == events.count
55
+ end
56
+
57
+ def throws_unhandled_event?(raise_it = true)
58
+ begin
59
+ apply(UnhandledEvent(pid: 123), raise_it)
60
+ rescue Replay::UnhandledEventError => e
61
+ true && raise_it
62
+ rescue Exception
63
+ !raise_it || false
64
+ end
65
+ end
66
+
67
+ def can_publish_events?
68
+ event = SomeEvent(pid: 123)
69
+ publish(event)
70
+ events.detect{|e| e==event}
71
+ end
72
+
73
+ def subscribers_receive_events
74
+ sub = Class.new do
75
+ def published(stream, event)
76
+ @published = true
77
+ end
78
+ def published?; @published; end
79
+ end.new
80
+ add_subscriber(sub)
81
+ publish(ReplayTest::SomeEvent.new(pid: 123))
82
+ sub.published?
83
+ end
84
+ def subscribes()
85
+ sub = Class.new do
86
+ def published(stream, event)
87
+ @published = true
88
+ end
89
+ def published?; @published; end
90
+ end.new
91
+ add_subscriber(sub)
92
+ has_subscriber?(sub)
93
+ end
94
+ end
95
+
96
+ title "Publisher"
97
+
98
+ proof "Defines events given in the events block" do
99
+ r = ReplayTest.new
100
+ r.prove{ defines_events? }
101
+ end
102
+
103
+ proof "Adds a convenience method for an event constructor to the class" do
104
+ r = ReplayTest.new
105
+ r.prove{ adds_convenience_method? }
106
+ end
107
+
108
+ proof "Applies events singly" do
109
+ r = ReplayTest.new
110
+ r.prove{ applies_event? ReplayTest::SomeEvent.new(:pid => 123)}
111
+ end
112
+
113
+ proof "Applies events in ordered batches" do
114
+ r = ReplayTest.new
115
+ r.prove do applies_events?([
116
+ ReplayTest::SomeEvent.new(:pid => 123),
117
+ ReplayTest::SomeEvent.new(:pid => 234),
118
+ ReplayTest::SomeEvent.new(:pid => 456)
119
+ ])
120
+ end
121
+ end
122
+
123
+ proof "Throws an UnhandledEventError for unhandled events" do
124
+ r = ReplayTest.new
125
+ r.prove{ throws_unhandled_event? }
126
+ end
127
+
128
+ proof "Ignores unhandled events if requested" do
129
+ r = ReplayTest.new
130
+ r.prove{ throws_unhandled_event? false}
131
+ end
132
+
133
+ proof "Can publish events to the indicated stream" do
134
+ r = ReplayTest.new
135
+ r.prove { can_publish_events? }
136
+ end
137
+
138
+ proof "Subscriber can subscribe to events from publisher" do
139
+ r = ReplayTest.new
140
+ r.prove{ subscribes }
141
+ end
142
+
143
+ proof "Subscriber receives published events" do
144
+ r = ReplayTest.new
145
+ r.prove{ subscribers_receive_events }
146
+ end
147
+
148
+ proof "Returns self from apply" do
149
+ r = ReplayTest.new
150
+ r.prove{ apply([]) == self}
151
+ end
152
+ proof "Returns self from publish" do
153
+ r = ReplayTest.new
154
+ r.prove{ publish([]) == self}
155
+ end
156
+
157
+ proof "sets the publish time on events" do
158
+ r = ReplayTest.new
159
+ r.prove{ sets_publish_time }
160
+ end
161
+
162
+ proof "publish time is not part of equality" do
163
+ r = ReplayTest.new
164
+ r.prove{ published_at_not_considered_in_equality}
165
+ end
166
+
167
+ proof "Can implement initializer with arguments" do
168
+ r = ReplayTest.new(:foo)
169
+ r.prove { pkey == :foo }
170
+ end
@@ -0,0 +1,67 @@
1
+ require_relative "../proofs_init.rb"
2
+ require 'replay/test'
3
+
4
+ class Subscriber
5
+ def published(stream_id, event); end
6
+ end
7
+
8
+ module Replay::Repository::Configuration::Proof
9
+ def can_configure_store?
10
+ self.store = :memory
11
+ self.store == Replay::Backends::MemoryStore
12
+ end
13
+
14
+ def can_add_default_subscriber?
15
+ sub = Subscriber.new
16
+ self.add_default_subscriber sub
17
+ subscribers.include? sub
18
+ end
19
+
20
+ def subscribers_include_store
21
+ self.store = :memory
22
+ self.subscribers.include? Replay::Backends::MemoryStore
23
+ end
24
+
25
+ def requires_store_to_act_like_subscriber
26
+ begin
27
+ store = Class.new do
28
+ def self.event_stream(stream); end
29
+ end
30
+ self.store = store
31
+ rescue Replay::InvalidSubscriberError => e
32
+ return true
33
+ rescue Exception => e
34
+ end
35
+ false
36
+ end
37
+
38
+ def requires_store_to_load_events
39
+ begin
40
+ self.store = Subscriber.new
41
+ rescue Replay::InvalidStorageError
42
+ return true
43
+ rescue Exception => e
44
+ end
45
+ false
46
+ end
47
+ end
48
+
49
+ proof "can configure a store" do
50
+ Replay::Repository::Configuration.new.prove {can_configure_store?}
51
+ end
52
+
53
+ proof 'adding a store adds it as a subscriber' do
54
+ Replay::Repository::Configuration.new.prove { subscribers_include_store }
55
+ end
56
+
57
+ proof "can configure a default_subscriber" do
58
+ Replay::Repository::Configuration.new.prove {can_add_default_subscriber?}
59
+ end
60
+
61
+ proof "raises error if store won't load events" do
62
+ Replay::Repository::Configuration.new.prove {requires_store_to_load_events }
63
+ end
64
+
65
+ proof "raises error if store won't act like a subscriber" do
66
+ Replay::Repository::Configuration.new.prove {requires_store_to_act_like_subscriber }
67
+ end
@@ -0,0 +1,46 @@
1
+ require_relative "../proofs_init.rb"
2
+ require 'replay/test'
3
+
4
+ class Subscriber
5
+ def published(stream_id, event); end
6
+ end
7
+
8
+ class RepositoryTest
9
+ include Replay::Repository
10
+ include Singleton
11
+
12
+ class << self
13
+ attr_accessor :proven
14
+ end
15
+
16
+ def self.can_be_configured
17
+ self.configure do |config|
18
+ self.proven = true
19
+ end
20
+
21
+ self.proven
22
+ end
23
+ end
24
+
25
+ title "Repository interface"
26
+
27
+ proof "repository can be configured" do
28
+ RepositoryTest.prove {can_be_configured }
29
+ end
30
+
31
+ Proof::Output.class_exec do
32
+ writer :pending, :level => :info do |text|
33
+ prefix :pending, "PENDING: #{text}"
34
+ end
35
+ end
36
+
37
+ def pending(text = "pending test")
38
+ Proof::Output.pending "pending test"
39
+ end
40
+ proof "loads an instance of supplied class" do; pending; end
41
+ proof "load raises an error if event stream isn't found" do; pending; end
42
+ proof "load returns uncreated instance when :create is pending" do; false; end
43
+ proof "load returns a created instance when :create is true" do; pending; end
44
+
45
+ proof "reload returns the supplied instance in its current state" do; pending; end
46
+
@@ -0,0 +1,39 @@
1
+ require_relative "../proofs_init.rb"
2
+ require 'replay/test'
3
+
4
+ module Replay::SubscriptionManager::Proof
5
+ def only_adds_legit_subs
6
+ begin
7
+ add_subscriber(Object.new)
8
+ rescue Replay::InvalidSubscriberError => e
9
+ return true
10
+ end
11
+ false
12
+ end
13
+
14
+ def sub_gets_notified
15
+ sub = Class.new do
16
+ attr_accessor :stream, :event
17
+ def published(stream, event)
18
+ self.stream = stream
19
+ self.event = event
20
+ end
21
+ end.new
22
+ add_subscriber(sub)
23
+ notify_subscribers "123", "456"
24
+ sub.stream == '123' && sub.event == '456'
25
+ end
26
+ end
27
+
28
+ title "Subscription Manager"
29
+
30
+ proof "raises InvalidSubscriberError when subscriber fails to implement #published" do
31
+ sm = Replay::SubscriptionManager.new
32
+ sm.prove { only_adds_legit_subs }
33
+ end
34
+
35
+ proof "notifies proper subscriber when informed" do
36
+ sm = Replay::SubscriptionManager.new
37
+ sm.prove { sub_gets_notified }
38
+ end
39
+
@@ -0,0 +1,28 @@
1
+ require_relative "../proofs_init.rb"
2
+ require 'replay/test'
3
+
4
+ desc "proof for the test support provided by replay"
5
+
6
+ title "Test support"
7
+
8
+ proof "fuzzy matching of events" do
9
+ class TestEvent
10
+ include Replay::EventDecorator
11
+
12
+ values do
13
+ attribute :one, String
14
+ attribute :two, String
15
+ end
16
+
17
+ def matches_fuzzy(event)
18
+ self.kind_of_matches?(event)
19
+ end
20
+ end
21
+
22
+ e1 = TestEvent.new(one: '1')
23
+ e2 = TestEvent.new(one: '1', two: '2')
24
+
25
+ e1.prove{ matches_fuzzy(e2)}
26
+ e2.prove{ !matches_fuzzy(e1)}
27
+
28
+ end
data/replay.gemspec CHANGED
@@ -19,8 +19,9 @@ Gem::Specification.new do |s|
19
19
  s.require_paths = ["lib"]
20
20
 
21
21
  # specify any dependencies here; for example:
22
- s.add_development_dependency "activerecord"
23
- s.add_development_dependency "sqlite3-ruby"
24
- # s.add_runtime_dependency "rest-client"
25
- s.add_runtime_dependency "activesupport"
22
+ s.add_development_dependency "bundler", "~>1.3"
23
+ s.add_development_dependency "rake"
24
+ s.add_development_dependency "minitest"
25
+ #s.add_runtime_dependency "rest-client"
26
+ s.add_runtime_dependency "virtus", "~>1.0.0"
26
27
  end
@@ -0,0 +1,37 @@
1
+ require 'test_helper'
2
+
3
+ class ObservedEvent
4
+ end
5
+
6
+ class UnobservedEvent
7
+ end
8
+
9
+ class ObserverTest
10
+ include Replay::Observer
11
+ observe ObservedEvent do |stream, event|
12
+ @observed = true
13
+ end
14
+
15
+ def self.observed?
16
+ @observed
17
+ end
18
+
19
+ def self.reset
20
+ @observed=false
21
+ end
22
+ end
23
+
24
+ describe Replay::Observer do
25
+ before do
26
+ ObserverTest.reset
27
+ end
28
+ it "calls the observer block for observed events" do
29
+ ObserverTest.published('123', ObservedEvent.new)
30
+ ObserverTest.must_be :observed?
31
+ end
32
+
33
+ it "does not notify of unobserved events" do
34
+ ObserverTest.published('123', UnobservedEvent.new)
35
+ ObserverTest.wont_be :observed?
36
+ end
37
+ end
@@ -0,0 +1,43 @@
1
+ require 'test_helper'
2
+
3
+ module Router
4
+ module Test
5
+ def has_observer?(object)
6
+ @subscription_manager.has_subscriber?(object)
7
+ end
8
+ end
9
+ end
10
+ class TypedEvent
11
+
12
+ end
13
+ class Observer
14
+ def self.published(stream, event)
15
+ @typed=true
16
+ end
17
+
18
+ def self.typed_received?
19
+ @typed
20
+ end
21
+ end
22
+
23
+ Replay::Router::DefaultRouter.send(:include, Router::Test)
24
+
25
+ describe Replay::Router::DefaultRouter do
26
+ before do
27
+ @router = Replay::Router::DefaultRouter.instance
28
+ end
29
+ describe "adding observers" do
30
+ it "tracks the observing object" do
31
+ @router.add_observer(Observer)
32
+ assert(@router.has_observer?(Observer), "router does not track observer")
33
+ end
34
+ end
35
+ describe "event publishing" do
36
+ it "tells the observing object about events being published" do
37
+ @router.add_observer(Observer)
38
+ @router.published("123", TypedEvent.new)
39
+ assert Observer.typed_received?, "Did not receive notification of event"
40
+ end
41
+ end
42
+ end
43
+