amqp-spec 0.2.7 → 0.3.0

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/HISTORY CHANGED
@@ -10,10 +10,6 @@
10
10
 
11
11
  * Minimal functionality implemented
12
12
 
13
- == 0.0.3 / 2010-10-13
14
-
15
- * Bunch of non-working specs added
16
-
17
13
  == 0.0.4 / 2010-10-14
18
14
 
19
15
  * Problems with default_options resolved
@@ -30,22 +26,10 @@
30
26
 
31
27
  * Make sure Thread.current[:mq] state is cleaned after each example
32
28
 
33
- == 0.1.4 / 2010-10-15
34
-
35
- * Problematic tests all fixed
36
-
37
29
  == 0.1.7 / 2010-10-15
38
30
 
39
31
  * em interface improved for timeout arg
40
32
 
41
- == 0.1.8 / 2010-10-15
42
-
43
- * Add AMQP as a dependency
44
-
45
- == 0.1.9 / 2010-10-15
46
-
47
- * SpecHelper class methods refactored
48
-
49
33
  == 0.1.11 / 2010-10-18
50
34
 
51
35
  * Optional delay added to done
@@ -54,30 +38,22 @@
54
38
 
55
39
  * Rspec 2 support added
56
40
 
57
- == 0.2.1 / 2010-10-28
58
-
59
- * RSpec2-specific examples added
60
-
61
41
  == 0.2.2 / 2010-10-31
62
42
 
63
43
  * Metadata in Rspec 1
64
44
 
65
- == 0.2.3 / 2010-10-31
66
-
67
- * Documentation cleaned up
68
-
69
- == 0.2.4 / 2010-11-01
45
+ == 0.2.7 / 2010-11-04
70
46
 
71
- * Release
47
+ * Make AMQP.cleanup_state more thorough
72
48
 
73
- == 0.2.5 / 2010-11-04
49
+ == 0.2.8 / 2010-11-15
74
50
 
75
- * Minor Gemfile update
51
+ * syncronize method added for wrapping async calls
76
52
 
77
- == 0.2.6 / 2010-11-04
53
+ == 0.2.9 / 2010-11-16
78
54
 
79
- * Fixed subtly failing specs
55
+ * Fallback to a separate default timeout
80
56
 
81
- == 0.2.7 / 2010-11-04
57
+ == 0.3.0 / 2010-11-16
82
58
 
83
- * Make AMQP.cleanup_state more thorough
59
+ * Hooks em_before/em_after implemented
data/README.rdoc CHANGED
@@ -8,52 +8,56 @@ Simple API for writing asynchronous EventMachine/AMQP specs. Supports RSpec and
8
8
 
9
9
  == Description
10
10
 
11
- EventMachine-based code, including synchronous {AMQP library}[http://github.com/tmm1/amqp] is
12
- notoriously difficult to test. To the point that many people recommend using either
13
- Mocks[http://github.com/danielsdeleo/moqueue] or {synchronous libraries}[http://github.com/celldee/bunny]
14
- instead of EM-based libraries in unit tests. This is not always an option, however - sometimes your code
15
- is supposed to run inside event loop, and you want to test a real thing, not mocks.
16
-
17
- EM-Spec[http://github.com/tmm1/em-spec] gem made it easier to write evented specs, but it has several drawbacks.
18
- First, it is not easy to manage both EM.run and AMQP.start loops at the same time. Second, AMQP is not
19
- properly stopped and deactivated upon exceptions and timeouts, resulting in AMQP library state leak
20
- between examples and multiple mystereous failures.
21
-
22
- AMQP-Spec is built upon EM-Spec code but makes it easier to test AMQP event loops specifically. API is
23
- very similar to EM-Spec, only a bit extended. The final goal is to make writing AMQP specs reasonably
24
- pleasant experience and dispel the notion that evented AMQP-based libs are impossible to unit-test.
25
-
26
- Mind you, you still have to properly manage your AMQP broker in order to prevent broker state from leaking
27
- between examples. You can try to combine AMQP-Spec and Moqueue[http://github.com/danielsdeleo/moqueue]
28
- if you want to abstract away actual broker interactions, but still specify some event-based expectations.
11
+ EventMachine-based code, including synchronous {AMQP library}[http://github.com/tmm1/amqp]
12
+ is notoriously difficult to test. To the point that many people recommend using either
13
+ Mocks[http://github.com/danielsdeleo/moqueue] or {synchronous}[http://github.com/celldee/bunny]
14
+ libraries instead of EM-based libraries in unit tests. This is not always an option, however -
15
+ sometimes your code just has to run inside the event loop, and you want to test a real thing,
16
+ not mocks.
17
+
18
+ EM-Spec[http://github.com/tmm1/em-spec] gem made it easier to write evented specs, but it
19
+ has several drawbacks. First, it is not easy to manage both EM.run and AMQP.start loops
20
+ at the same time. Second, AMQP is not properly stopped and deactivated upon exceptions and
21
+ timeouts, resulting in state leak between examples and multiple mystereous failures.
22
+
23
+ AMQP-Spec is based on EM-Spec code but makes it easier to test AMQP event loops specifically.
24
+ API is very similar to EM-Spec's, only a bit extended. The final goal is to make writing AMQP
25
+ specs reasonably pleasant experience and dispel the notion that evented AMQP-based libs are
26
+ impossible to unit-test.
27
+
28
+ Mind you, you still have to properly manage your AMQP broker in order to prevent broker
29
+ state from leaking between examples. You can try to combine AMQP-Spec and
30
+ Moqueue[http://github.com/danielsdeleo/moqueue] if you want to abstract away actual broker
31
+ interactions, but still specify some event-based expectations.
29
32
 
30
33
  ==Rspec
31
34
 
32
- There are several ways to use amqp-spec. To use it as a helper, include AMQP::SpecHelper in your describe block.
33
- You then use either 'amqp' or 'em' methods to wrap your evented test code. Inside the amqp/em block, you must call
34
- #done after your expectations. Everything works normally otherwise. You can use default_timeout and default_options
35
- macros to avoid manually setting AMQP options in each example. However, if you DO manually set options inside
36
- the example, they override the defaults.
35
+ There are several ways to use amqp-spec. To use it as a helper, include AMQP::SpecHelper
36
+ in your describe block. You then use either 'amqp' or 'em' methods to wrap your evented
37
+ test code. Inside the amqp/em block, you must call #done after your expectations. Everything
38
+ works normally otherwise. You can set default_timeout and default_options to avoid manually
39
+ setting AMQP options for each example. However, if you DO supply options to #amqp method
40
+ inside the example, they override the defaults.
37
41
 
38
- Default options and default timeout are local for each example group and inherited by its nested groups,
39
- different example groups can have separate defaults. Please note that this is different from em-spec where
40
- default_timeout is effectively a global setting.
42
+ Default options and default timeout are local for each example group and inherited by
43
+ its nested groups, unconnected example groups DO NOT share defaults. Please note that
44
+ this is different from EM-Spec where default_timeout is effectively a global setting.
45
+
46
+ In order to setup/teardown EM state before/after your examples, you'll need to use
47
+ *em_before{}* and *em_after{}* hooks. These hooks are similar to standard RSpec's
48
+ *before/after* hooks but run inside the EM event loop before/after your example block.
41
49
 
42
50
  require "amqp-spec/rspec"
43
51
 
44
52
  describe AMQP do
45
53
  include AMQP::SpecHelper
46
54
 
47
- default_options :host => 'my.amqp.broker.org', :port => '21118'
55
+ default_options = {:host => 'my.amqp.broker.org', :port => '21118'}
48
56
  # Can be used to set default options for your amqp{} event loops
49
57
 
50
- default_timeout 1
58
+ default_timeout = 1
51
59
  # Can be used to set default :spec_timeout for your evented specs
52
60
 
53
- before(:each) do
54
- puts EM.reactor_running?
55
- end
56
-
57
61
  it "works normally when not using #amqp or #em" do
58
62
  1.should == 1
59
63
  end
@@ -78,25 +82,31 @@ default_timeout is effectively a global setting.
78
82
 
79
83
  it "optionally raises timeout exception if your loop hangs for some reason" do
80
84
  proc {
81
- amqp(:spec_timeout => 3){}
85
+ amqp(:spec_timeout => 0.5){}
82
86
  }.should raise_error SpecTimeoutExceededError
83
87
  end
84
88
 
85
89
  end
86
90
 
87
- Another option is to include AMQP::Spec in your describe block. This will patch Rspec so that all of your
88
- examples run inside an amqp block automatically. A word of caution about before{} and after{} hooks in your example
89
- groups including AMQP::Spec. Each of these hooks will run in its separate EM loop that you'll need to shut down
90
- either manually (done) or via default_timeout. Essentially, this means that any EM-related state that you'd like
91
- to setup/teardown using these hooks will be lost as each example will run in a separate EM loop. In order to
92
- run setup/teardown hooks inside the EM loop, you'll need to use before_amqp{} and after_amqp{} hooks that run
93
- inside the EM loop but before/after AMQP loop (these hooks are currently not implemented)
91
+ Another option is to include AMQP::Spec in your describe block. This will patch Rspec so
92
+ that all of your examples run inside an amqp block automatically. A word of caution about
93
+ *before{}*/*after{}* hooks in your example groups including AMQP::Spec. Each of these hooks
94
+ will run in its separate EM loop that you'll need to shut down either manually (done) or
95
+ via timeout. Essentially, this means that any EM-related state that you'd like to set up or
96
+ tear down using these hooks will be lost as example itself will run in a different EM loop.
97
+
98
+ In short, you should avoid using *before/after* if you include AMQP::Spec - instead, use
99
+ *em_before/em_after* hooks that run inside the EM event loop. One more note: you don't need
100
+ to call 'done' inside *em_before/em_after*, otherwise it'll shut down the reactor.
101
+
94
102
 
95
103
  describe AMQP do
96
104
  include AMQP::Spec
97
105
 
98
- default_options :host => 'my.amqp.broker.org', :port => '21118'
99
- default_timeout 1
106
+ default_options = {:host => 'my.amqp.broker.org', :port => '21118'}
107
+ default_timeout = 1
108
+
109
+ em_before { @start = Time.now }
100
110
 
101
111
  it "requires a call to #done in every example" do
102
112
  1.should == 1
@@ -104,10 +114,9 @@ inside the EM loop but before/after AMQP loop (these hooks are currently not imp
104
114
  end
105
115
 
106
116
  it "runs test code in an amqp block automatically" do
107
- start = Time.now
108
117
 
109
118
  EM.add_timer(0.5){
110
- (Time.now-start).should be_close( 0.5, 0.1 )
119
+ (Time.now-@start).should be_close( 0.5, 0.1 )
111
120
  done
112
121
  }
113
122
  end
@@ -122,9 +131,9 @@ inside the EM loop but before/after AMQP loop (these hooks are currently not imp
122
131
  end
123
132
  end
124
133
 
125
- Finally, you can include AMQP::EMSpec in your describe block. This will run all the group examples
126
- inside em block instead of amqp. before{} and after{} hooks should be finished with 'done', same as
127
- when including AMQP::Spec, and same caution about using them applies.
134
+ Finally, you can include AMQP::EMSpec in your describe block. This will run all the group
135
+ examples inside em block instead of amqp. *before/after* hooks should be finished
136
+ with #done, same as when including AMQP::Spec, and same caution about using them applies.
128
137
 
129
138
  describe AMQP do
130
139
  include AMQP::EMSpec
@@ -157,9 +166,11 @@ when including AMQP::Spec, and same caution about using them applies.
157
166
 
158
167
  ==General notes
159
168
 
160
- For a developer new to evented specs, it is not easy to internalize that the blocks given to asynchronous
161
- methods are turned into real callbacks, intended to fire some time later. It is not easy to keep track of
162
- the actual execution path of your code, when your blocks are supposed to fire and in what sequence.
169
+ For a developer new to evented specs, it is not easy to internalize that the blocks given
170
+ to asynchronous methods are turned into real callbacks, intended to fire some time later.
171
+ It is not easy to keep track of the actual execution path of your code, when your blocks
172
+ are supposed to fire and in what sequence.
173
+
163
174
  Take the following spec as an example:
164
175
 
165
176
  it 'receives published message' do
@@ -174,22 +185,24 @@ Take the following spec as an example:
174
185
  end
175
186
  end
176
187
 
177
- Seems like a straightforward spec: you subscribe to a message queue, you set expectations inside
178
- your subscribe block, then you publish into this queue, then you call done. What may be wrong with it?
179
- Well, if you happen to use this spec against live AMQP broker, everything may be wrong.
180
- First, communication delays. There is no guarantee that by the time you publish your message, the queue
181
- have been either created or subscribed to. There is also no guarantee that your subscriber received
182
- the message by the time you are unsubscribing and deleting your queue.
183
- Second, sequence of your blocks. Remember, they are delayed callbacks! Don't just assume your previous
184
- block is already executed when you start your new asynchronous action. In this spec, when done is called,
185
- it stops everything before your subscribe callback even has a chance to fire. As a result, you'll get a
186
- PASSING spec even though your expectation was never executed!
187
-
188
- How to improve this spec? Allow some time for async actions to finish: either use EM timers or pass
189
- :nowait=>false to your asynch calls to force them into synchronicity. Keep in mind the sequence in which
190
- your callbacks are expected to fire - so place your done call at the end of subscribe block in this
191
- example. If you want to be paranoid, you can set flags inside your callbacks and then check that they
192
- actually fired at all AFTER your amqp/em block. Something like this will do the trick:
188
+ Seems like a straightforward spec: you subscribe to a message queue, you set expectations
189
+ inside your subscribe block, then you publish into this queue, then you call done. What may
190
+ be wrong with it? Well, if you happen to use this spec against live AMQP broker, everything
191
+ may be wrong. First, communication delays. There is no guarantee that by the time you publish
192
+ your message, the queue have been either created or subscribed to. There is also no guarantee
193
+ that your subscriber received the message by the time you are unsubscribing and deleting your
194
+ queue. Second, sequence of your blocks. Remember, they are delayed callbacks! Don't just
195
+ assume your previous block is already executed when you start your new asynchronous action.
196
+ In this spec, when done is called, it stops everything before your subscribe callback even
197
+ has a chance to fire. As a result, you'll get a PASSING spec even though your expectation
198
+ was never executed!
199
+
200
+ How to improve this spec? Allow some time for async actions to finish: either use EM timers
201
+ or pass :nowait=>false to your asynch calls to force them into synchronicity. Keep in mind
202
+ the sequence in which your callbacks are expected to fire - so place your done call at the
203
+ end of subscribe block in this example. If you want to be paranoid, you can set flags inside
204
+ your callbacks and then check that they actually fired at all AFTER your amqp/em block.
205
+ Something like this will do the trick:
193
206
 
194
207
  it 'receives published message' do
195
208
  amqp do
@@ -208,10 +221,11 @@ actually fired at all AFTER your amqp/em block. Something like this will do the
208
221
 
209
222
  ==Limitations
210
223
 
211
- AMQP-Spec can be currently used with Rspec only. I suppose, there is nothing special in extending EM-Spec's
212
- test unit and bacon support, I just do not have experience dealing with these platforms. Another limitation,
213
- it uses native Fibers and therefore not compatible with Ruby 1.8. Again, it seems possible to rewrite it in
214
- 1.8-compatible style, with string evals and Fiber backport, but I'd rather leave this work to someone else.
224
+ AMQP-Spec can be currently used with Rspec only. I suppose, there is nothing special in
225
+ extending EM-Spec's test unit and bacon support, I just do not have experience dealing with
226
+ these platforms. Another limitation, it uses native Fibers and therefore not compatible with
227
+ Ruby 1.8. Again, it seems possible to rewrite it in 1.8-compatible style, with string evals
228
+ and Fiber backport, but I'd rather leave this work to someone else.
215
229
 
216
230
  Any help improving this library is greatly appreciated...
217
231
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.7
1
+ 0.3.0
data/lib/amqp-spec.rb CHANGED
@@ -20,5 +20,5 @@ end
20
20
 
21
21
  # Require all ruby source files located under directory lib/amqp-spec
22
22
  # If you need files in specific order, you should specify it here before the glob
23
- AMQP::Spec.require_libs %W[**/*]
23
+ AMQP::Spec.require_libs %W[rspec]
24
24
 
@@ -1,5 +1,6 @@
1
1
  require 'mq'
2
2
 
3
+ # Monkey patching some methods into AMQP to make it more testable
3
4
  module AMQP
4
5
 
5
6
  # Initializes new AMQP client/connection without starting another EM loop
@@ -24,9 +25,9 @@ module AMQP
24
25
  # Cleans up AMQP state after AMQP connection closes
25
26
  def self.cleanup_state
26
27
  # MQ.reset ?
27
- Thread.list.each {|thread| thread[:mq] = nil }
28
- Thread.list.each {|thread| thread[:mq_id] = nil }
29
- @conn = nil
30
- @closing = false
28
+ Thread.list.each { |thread| thread[:mq] = nil }
29
+ Thread.list.each { |thread| thread[:mq_id] = nil }
30
+ @conn = nil
31
+ @closing = false
31
32
  end
32
33
  end
@@ -0,0 +1,160 @@
1
+ require 'fiber' unless Fiber.respond_to?(:current)
2
+
3
+ module AMQP
4
+
5
+ module SpecHelper
6
+
7
+ # Represents example running inside some type of event loop
8
+ class EventedExample
9
+
10
+ # Create new evented example
11
+ def initialize opts = {}, example_group_instance, &block
12
+ @opts, @example_group_instance, @block = opts, example_group_instance, block
13
+ end
14
+
15
+ # Sets timeout for currently running example
16
+ #
17
+ def timeout(spec_timeout)
18
+ EM.cancel_timer(@spec_timer) if @spec_timer
19
+ @spec_timer = EM.add_timer(spec_timeout) do
20
+ @spec_exception = SpecTimeoutExceededError.new "Example timed out"
21
+ done
22
+ end
23
+ end
24
+
25
+ # Breaks the event loop and finishes the spec.
26
+ #
27
+ # This is under-implemented (generic) method that only implements optional delay.
28
+ # It should be given a block that does actual work of finishing up the event loop
29
+ # and cleaning any remaining artifacts.
30
+ #
31
+ # Please redefine it inside descendant class and call super.
32
+ #
33
+ def done delay=nil, &block
34
+ if delay
35
+ EM.add_timer delay, &block
36
+ else
37
+ block.call
38
+ end
39
+ end
40
+
41
+ # Retrieves metadata passed in from enclosing example groups
42
+ #
43
+ def metadata
44
+ @metadata ||= @example_group_instance.metadata.dup rescue {}
45
+ end
46
+
47
+ # Runs hooks of specified type (hopefully, inside the event loop)
48
+ #
49
+ def run_hooks type
50
+ hooks = @example_group_instance.class.em_hooks[type]
51
+ (:before == type ? hooks : hooks.reverse).each do |hook|
52
+ if @example_group_instance.respond_to? :instance_eval_without_event_loop
53
+ @example_group_instance.instance_eval_without_event_loop(&hook)
54
+ else
55
+ @example_group_instance.instance_eval(&hook) #_with_rescue(&hook)
56
+ end
57
+ end
58
+ end
59
+
60
+ # Runs given block inside EM event loop.
61
+ # Double-round exception handler needed because some of the exceptions bubble
62
+ # outside of event loop due to asynchronous nature of evented examples
63
+ #
64
+ def run_em_loop
65
+ begin
66
+ EM.run do
67
+ run_hooks :before
68
+
69
+ @spec_exception = nil
70
+ timeout(@opts[:spec_timeout]) if @opts[:spec_timeout]
71
+ begin
72
+ yield
73
+ rescue Exception => @spec_exception
74
+ # p "Inside loop, caught #{@spec_exception}"
75
+ done # We need to properly terminate the event loop
76
+ end
77
+ end
78
+ rescue Exception => @spec_exception
79
+ # p "Outside loop, caught #{@spec_exception}"
80
+ run_hooks :after # Event loop was broken, but we still need to run em_after hooks
81
+ ensure
82
+ finish_example
83
+ end
84
+ end
85
+
86
+ # Stops EM event loop. It is called from #done
87
+ #
88
+ def finish_em_loop
89
+ run_hooks :after
90
+ EM.stop_event_loop if EM.reactor_running?
91
+ end
92
+
93
+ # Called from #run_event_loop when event loop is stopped, but before example returns.
94
+ # Descendant classes may redefine to clean up type-specific state.
95
+ #
96
+ def finish_example
97
+ raise @spec_exception if @spec_exception
98
+ end
99
+
100
+ end # class EventedExample
101
+
102
+ # Represents spec running inside AMQP.run loop
103
+ class EMExample < EventedExample
104
+
105
+ # Run @block inside the EM.run event loop
106
+ def run
107
+ run_em_loop &@block
108
+ end
109
+
110
+ # Breaks the EM event loop and finishes the spec.
111
+ # Done yields to any given block first, then stops EM event loop.
112
+ #
113
+ def done(delay=nil)
114
+ super(delay) do
115
+ yield if block_given?
116
+ EM.next_tick do
117
+ finish_em_loop
118
+ end
119
+ end
120
+ end # done
121
+ end # class EMExample < EventedExample
122
+
123
+ # Represents spec running inside AMQP.run loop
124
+ class AMQPExample < EventedExample
125
+
126
+ # Run @block inside the AMQP.start loop
127
+ def run
128
+ run_em_loop do
129
+ AMQP.start_connection @opts, &@block
130
+ end
131
+ end
132
+
133
+ # Breaks the event loop and finishes the spec. It yields to any given block first,
134
+ # then stops AMQP, EM event loop and cleans up AMQP state.
135
+ #
136
+ def done(delay=nil)
137
+ super(delay) do
138
+ yield if block_given?
139
+ EM.next_tick do
140
+ if AMQP.conn and not AMQP.closing
141
+ AMQP.stop_connection do
142
+ finish_em_loop
143
+ end
144
+ else
145
+ finish_em_loop
146
+ end
147
+ end
148
+ end
149
+ end
150
+
151
+ # Called from run_event_loop when event loop is finished, before any exceptions
152
+ # is raised or example returns. We ensure AMQP state cleanup here
153
+ def finish_example
154
+ AMQP.cleanup_state
155
+ super
156
+ end
157
+
158
+ end # class AMQPExample < EventedExample
159
+ end # module SpecHelper
160
+ end # module AMQP
@@ -1,51 +1,49 @@
1
- require 'fiber' unless Fiber.respond_to?(:current)
2
1
  require 'amqp-spec/amqp'
2
+ require 'amqp-spec/evented_example'
3
3
 
4
4
  # You can include one of the following modules into your example groups:
5
5
  # AMQP::SpecHelper,
6
6
  # AMQP::Spec,
7
7
  # AMQP::EMSpec.
8
8
  #
9
- # AMQP::SpecHelper module defines #ampq method that can be safely used inside your specs(examples)
10
- # to test expectations inside running AMQP.start loop. Each loop is running in a separate Fiber,
11
- # and you can control for timeouts using either :spec_timeout option given to #amqp method,
12
- # or setting default timeout with class method default_timeout(timeout). In addition to #amqp
13
- # method, you can use #em method - it creates plain EM.run loop without starting AMQP.
9
+ # AMQP::SpecHelper module defines #ampq and #em methods that can be safely used inside
10
+ # your specs (examples) to test code running inside AMQP.start or EM.run loop
11
+ # respectively. Each example is running in a separate event loop,you can control
12
+ # for timeouts either with :spec_timeout option given to #amqp/#em method or setting
13
+ # a default timeout using default_timeout(timeout) macro inside describe/context block.
14
14
  #
15
- # If you include AMQP::Spec module into your example group, each example of this group will run
16
- # inside AMQP.start loop without the need to explicitly call 'amqp'. In order to provide options
17
- # to AMQP loop, default_options class method is defined. Remember, when using AMQP::Specs, you
18
- # will have a single set of AMQP.start options for all your examples.
15
+ # If you include AMQP::Spec module into your example group, each example of this group
16
+ # will run inside AMQP.start loop without the need to explicitly call 'amqp'. In order to
17
+ # provide options to AMQP loop, default_options({opts}) macro is defined.
19
18
  #
20
19
  # Including AMQP::EMSpec module into your example group, each example of this group will run
21
20
  # inside EM.run loop without the need to explicitly call 'em'.
22
21
  #
23
- # In order to stop AMQP/EM loop, you should call 'done' AFTER you are sure that your example is finished.
24
- # For example, if you are using subscribe block that tests expectations on messages, 'done' should be
25
- # probably called at the end of this block.
22
+ # In order to stop AMQP/EM loop, you should call 'done' AFTER you are sure that your
23
+ # example is finished and your expectations executed. For example if you are using
24
+ # subscribe block that tests expectations on messages, 'done' should be probably called
25
+ # at the end of this block.
26
26
  #
27
27
  module AMQP
28
- # AMQP::SpecHelper module defines #ampq method that can be safely used inside your specs(examples)
29
- # to test expectations inside running AMQP.start loop. Each loop is running in a separate Fiber,
30
- # and you can control for timeouts using either :spec_timeout option given to #amqp method,
31
- # or setting default timeout with class method default_timeout(timeout). In addition to #amqp
32
- # method, you can use #em method - it creates plain EM.run loop without starting AMQP.
33
- #
34
- # TODO: Define 'async' method wrapping async requests and returning results... 'async_loop' too for subscribe block?
35
- # TODO: 'evented_before', 'evented_after' that will be run inside EM before the example
28
+
29
+ # AMQP::SpecHelper module defines #ampq and #em methods that can be safely used inside
30
+ # your specs (examples) to test code running inside AMQP.start or EM.run loop
31
+ # respectively. Each example is running in a separate event loop,you can control
32
+ # for timeouts either with :spec_timeout option given to #amqp/#em method or setting
33
+ # a default timeout using default_timeout(timeout) macro inside describe/context block.
36
34
  #
37
35
  # noinspection RubyArgCount
38
36
  module SpecHelper
39
37
 
40
38
  SpecTimeoutExceededError = Class.new(RuntimeError)
41
39
 
42
- # Class methods (macros) for example group that includes SpecHelper
40
+ # Class methods (macros) for any example groups that includes SpecHelper.
41
+ # You can use these methods as macros inside describe/context block.
43
42
  #
44
43
  module GroupMethods
45
- unless respond_to?(:metadata)
46
- # Hacking in metadata into RSpec1 to imitate Rspec2's metadata.
47
- # You can add to metadata Hash to pass options into examples and
48
- # nested groups.
44
+ unless respond_to? :metadata
45
+ # Hacking in metadata into RSpec1 to imitate Rspec2's metadata. Now you can add
46
+ # anything to metadata Hash to pass options into examples and nested groups.
49
47
  #
50
48
  def metadata
51
49
  @metadata ||= superclass.metadata.dup rescue {}
@@ -55,96 +53,76 @@ module AMQP
55
53
  # Sets/retrieves default timeout for running evented specs for this
56
54
  # example group and its nested groups.
57
55
  #
58
- def default_timeout(spec_timeout=nil)
59
- metadata[:em_default_timeout] = spec_timeout if spec_timeout
60
- metadata[:em_default_timeout]
56
+ def default_timeout spec_timeout=nil
57
+ metadata[:em_timeout] = spec_timeout if spec_timeout
58
+ metadata[:em_timeout]
61
59
  end
62
60
 
63
61
  # Sets/retrieves default AMQP.start options for this example group
64
62
  # and its nested groups.
65
63
  #
66
- def default_options(opts=nil)
67
- metadata[:em_default_options] = opts if opts
68
- metadata[:em_default_options]
64
+ def default_options opts=nil
65
+ metadata[:em_defaults] = opts if opts
66
+ metadata[:em_defaults]
67
+ end
68
+
69
+ # Add before hook that will run inside EM event loop
70
+ def em_before scope = :each, &block
71
+ raise ArgumentError, "em_before only supports :each scope" unless :each == scope
72
+ em_hooks[:before] << block
73
+ end
74
+
75
+ # Add after hook that will run inside EM event loop
76
+ def em_after scope = :each, &block
77
+ raise ArgumentError, "em_after only supports :each scope" unless :each == scope
78
+ em_hooks[:after] << block
79
+ end
80
+
81
+ # Collection of evented hooks
82
+ def em_hooks
83
+ metadata[:em_hooks] ||= {:before => [], :after => []}
69
84
  end
70
85
  end
71
86
 
72
- def self.included(example_group)
87
+ def self.included example_group
73
88
  unless example_group.respond_to? :default_timeout
74
- example_group.extend(GroupMethods)
75
- example_group.metadata[:em_default_options] = {}
76
- example_group.metadata[:em_default_timeout] = nil
89
+ example_group.extend GroupMethods
90
+ example_group.metadata[:em_defaults] = {}
91
+ example_group.metadata[:em_timeout] = nil
77
92
  end
78
93
  end
79
94
 
80
-
81
- # Yields to given block inside EM.run and AMQP.start loops. This method takes any option that is
82
- # also accepted by EventMachine::connect. Also, options for AMQP.start include:
83
- # * :user => String (default ‘guest’) - The username as defined by the AMQP server.
84
- # * :pass => String (default ‘guest’) - The password for the associated :user as defined by the AMQP server.
85
- # * :vhost => String (default ’/’) - The virtual host as defined by the AMQP server.
95
+ # Yields to a given block inside EM.run and AMQP.start loops. This method takes
96
+ # any option that is accepted by EventMachine::connect. Options for AMQP.start include:
97
+ # * :user => String (default ‘guest’) - Username as defined by the AMQP server.
98
+ # * :pass => String (default ‘guest’) - Password as defined by the AMQP server.
99
+ # * :vhost => String (default ’/’) - Virtual host as defined by the AMQP server.
86
100
  # * :timeout => Numeric (default nil) - *Connection* timeout, measured in seconds.
87
- # * :logging => true | false (default false) - Toggle the extremely verbose AMQP logging.
101
+ # * :logging => Bool (default false) - Toggle the extremely verbose AMQP logging.
88
102
  #
89
- # In addition to EM and AMQP options, :spec_timeout option (in seconds) is used to force spec to timeout
90
- # if something goes wrong and EM/AMQP loop hangs for some reason. SpecTimeoutExceededError is raised.
103
+ # In addition to EM and AMQP options, :spec_timeout option (in seconds) is used
104
+ # to force spec to timeout if something goes wrong and EM/AMQP loop hangs for some
105
+ # reason. SpecTimeoutExceededError is raised if it happens.
91
106
  #
92
107
  def amqp opts={}, &block
93
108
  opts = self.class.default_options.merge opts
94
- begin
95
- EM.run do
96
- @_em_spec_with_amqp = true
97
- @_em_spec_exception = nil
98
- spec_timeout = opts.delete(:spec_timeout) || self.class.default_timeout
99
- timeout(spec_timeout) if spec_timeout
100
- @_em_spec_fiber = Fiber.new do
101
- begin
102
- AMQP.start_connection opts, &block
103
- rescue Exception => @_em_spec_exception
104
- done
105
- end
106
- Fiber.yield
107
- end
108
-
109
- @_em_spec_fiber.resume
110
- end
111
- rescue Exception => outer_spec_exception
112
- # Make sure AMQP state is cleaned even after Rspec failures
113
- AMQP.cleanup_state
114
- raise outer_spec_exception
115
- end
109
+ opts[:spec_timeout] ||= self.class.default_timeout
110
+ @evented_example = AMQPExample.new(opts, self, &block)
111
+ @evented_example.run
116
112
  end
117
113
 
118
- # Yields to block inside EM loop, :spec_timeout option (in seconds) is used to force spec to timeout
119
- # if something goes wrong and EM/AMQP loop hangs for some reason. SpecTimeoutExceededError is raised.
114
+ # Yields to block inside EM loop, :spec_timeout option (in seconds) is used to
115
+ # force spec to timeout if something goes wrong and EM/AMQP loop hangs for some
116
+ # reason. SpecTimeoutExceededError is raised if it happens.
120
117
  #
121
- def em(spec_timeout = self.class.default_timeout, &block)
122
- spec_timeout = spec_timeout[:spec_timeout] || self.class.default_timeout if spec_timeout.is_a?(Hash)
123
- EM.run do
124
- @_em_spec_with_amqp = false
125
- @_em_spec_exception = nil
126
- timeout(spec_timeout) if spec_timeout
127
- @_em_spec_fiber = Fiber.new do
128
- begin
129
- block.call
130
- rescue Exception => @_em_spec_exception
131
- done
132
- end
133
- Fiber.yield
134
- end
135
-
136
- @_em_spec_fiber.resume
137
- end
138
- end
139
-
140
- # Sets timeout for current running example
141
- #
142
- def timeout(spec_timeout)
143
- EM.cancel_timer(@_em_timer) if @_em_timer
144
- @_em_timer = EM.add_timer(spec_timeout) do
145
- @_em_spec_exception = SpecTimeoutExceededError.new
146
- done
118
+ def em opts = {}, &block
119
+ if opts.is_a? Hash
120
+ opts[:spec_timeout] ||= self.class.default_timeout
121
+ else
122
+ opts = {spec_timeout: opts}
147
123
  end
124
+ @evented_example = EMExample.new(opts, self, &block)
125
+ @evented_example.run
148
126
  end
149
127
 
150
128
  # Breaks the event loop and finishes the spec. This should be called after
@@ -156,58 +134,31 @@ module AMQP
156
134
  # that your (default or explicit) spec timeout may fire before your delayed done
157
135
  # callback is due, leading to SpecTimeoutExceededError
158
136
  #
159
- def done(delay=nil)
160
- done_proc = proc do
161
- yield if block_given?
162
- EM.next_tick do
163
- if @_em_spec_with_amqp
164
- if AMQP.conn and not AMQP.closing
165
- AMQP.stop_connection do
166
- finish_em_spec_fiber { AMQP.cleanup_state }
167
- end
168
- else
169
- finish_em_spec_fiber { AMQP.cleanup_state }
170
- end
171
- else
172
- finish_em_spec_fiber
173
- end
174
- end
175
- end
176
- if delay
177
- EM.add_timer delay, &done_proc
178
- else
179
- done_proc.call
180
- end
137
+ def done *args, &block
138
+ @evented_example.done *args, &block
181
139
  end
182
140
 
183
- # Retrieves metadata passed in from enclosing example groups
141
+ # Manually sets timeout for currently running example
184
142
  #
185
- def metadata
186
- @metadata ||= self.class.metadata.dup rescue {}
143
+ def timeout *args
144
+ @evented_example.timeout *args
187
145
  end
188
146
 
189
- private
147
+ end # module SpecHelper
190
148
 
191
- # Stops EM loop, executes optional block, finishes off fiber and raises exception if any
192
- #
193
- def finish_em_spec_fiber
194
- EM.stop_event_loop if EM.reactor_running?
195
- yield if block_given?
196
- @_em_spec_fiber.resume if @_em_spec_fiber.alive?
197
- raise @_em_spec_exception if @_em_spec_exception
198
- end
199
- end
200
-
201
- # If you include AMQP::Spec module into your example group, each example of this group will run
202
- # inside AMQP.start loop without the need to explicitly call 'amqp'. In order to provide options
203
- # to AMQP loop, default_options class method is defined. Remember, when using AMQP::Specs, you
204
- # will have a single set of AMQP.start options for all your examples.
149
+ # If you include AMQP::Spec module into your example group, each example of this group
150
+ # will run inside AMQP.start loop without the need to explicitly call 'amqp'. In order
151
+ # to provide options to AMQP loop, default_options class method is defined. Remember,
152
+ # when using AMQP::Specs, you'll have a single set of AMQP.start options for all your
153
+ # examples.
205
154
  #
206
155
  module Spec
207
156
  def self.included(example_group)
208
157
  example_group.send(:include, SpecHelper)
209
158
  end
210
159
 
160
+ alias instance_eval_without_event_loop instance_eval
161
+
211
162
  def instance_eval(&block)
212
163
  amqp do
213
164
  super(&block)
@@ -215,18 +166,20 @@ module AMQP
215
166
  end
216
167
  end
217
168
 
218
- # Including AMQP::EMSpec module into your example group, each example of this group will run
219
- # inside EM.run loop without the need to explicitly call 'em'.
169
+ # Including AMQP::EMSpec module into your example group, each example of this group
170
+ # will run inside EM.run loop without the need to explicitly call 'em'.
220
171
  #
221
172
  module EMSpec
222
173
  def self.included(example_group)
223
174
  example_group.send(:include, SpecHelper)
224
175
  end
225
176
 
177
+ alias instance_eval_without_event_loop instance_eval
178
+
226
179
  def instance_eval(&block)
227
180
  em do
228
181
  super(&block)
229
182
  end
230
183
  end
231
184
  end
232
- end
185
+ end
@@ -0,0 +1,156 @@
1
+ require 'spec_helper'
2
+
3
+ shared_examples_for 'hooked em specs' do
4
+ it 'should execute em_before' do
5
+ em do
6
+ @hooks_called.should include :em_before
7
+ @hooks_called.should_not include :em_after
8
+ done
9
+ end
10
+ end
11
+
12
+ it 'should execute em_after if business exception is raised' do
13
+ em do
14
+ expect {
15
+ raise StandardError
16
+ }.to raise_error
17
+ done
18
+ end
19
+ end
20
+
21
+ it 'should execute em_after if RSpec expectation fails' do
22
+ em do
23
+ expect { :this.should == :fail
24
+ }.to raise_error RSPEC::Expectations::ExpectationNotMetError
25
+ done
26
+ end
27
+ end
28
+ end
29
+
30
+ shared_examples_for 'hooked amqp specs' do
31
+ it 'should execute em_before' do
32
+ amqp do
33
+ @hooks_called.should include :em_before
34
+ @hooks_called.should_not include :em_after
35
+ done
36
+ end
37
+ end
38
+
39
+ it 'should execute em_after if business exception is raised' do
40
+ amqp do
41
+ expect {
42
+ raise StandardError
43
+ }.to raise_error
44
+ done
45
+ end
46
+ end
47
+
48
+ it 'should execute em_after if RSpec expectation fails' do
49
+ amqp do
50
+ expect { :this.should == :fail
51
+ }.to raise_error RSPEC::Expectations::ExpectationNotMetError
52
+ done
53
+ end
54
+ end
55
+ end
56
+
57
+ describe AMQP, " with em_before/em_after" do
58
+ before { @hooks_called = [] } #; puts "In before: #{self}"} #
59
+
60
+ describe AMQP, " tested with AMQP::SpecHelper" do
61
+ include AMQP::SpecHelper
62
+ default_options AMQP_OPTS if defined? AMQP_OPTS
63
+
64
+ before { @hooks_called << :before } #; puts "In before 2: #{self}" }
65
+
66
+ em_before { @hooks_called << :em_before } # puts "In em_before: #{self}";
67
+ em_after { @hooks_called << :em_after } # puts "In em_after: #{self}";
68
+
69
+ context 'for non-evented specs' do
70
+ after { @hooks_called.should == [:before] }
71
+
72
+ it 'should NOT execute em_before or em_after' do
73
+ @hooks_called.should_not include :em_before
74
+ @hooks_called.should_not include :em_after
75
+ end
76
+
77
+ it 'should NOT execute em_after if business exception is raised' do
78
+ expect { raise StandardError
79
+ }.to raise_error
80
+ end
81
+
82
+ it 'should execute em_after if RSpec expectation fails' do
83
+ expect { :this.should == :fail
84
+ }.to raise_error RSPEC::Expectations::ExpectationNotMetError
85
+ end
86
+ end # context 'for non-evented specs'
87
+
88
+ context 'for evented specs' do #, pending: true do
89
+ after { @hooks_called.should include :before, :em_before, :em_after }
90
+
91
+ context 'with em block' do
92
+
93
+ it_should_behave_like 'hooked em specs'
94
+
95
+ context 'inside nested example group' do
96
+ before { @hooks_called << :context_before }
97
+ em_before { @hooks_called << :context_em_before }
98
+ em_after { @hooks_called << :context_em_after }
99
+
100
+ after { @hooks_called.should include :before,
101
+ :context_before,
102
+ :em_before,
103
+ :context_em_before,
104
+ :context_em_after,
105
+ :em_after }
106
+
107
+ it 'should fire both nested :before hooks' do
108
+ em do
109
+ @hooks_called.should include :before,
110
+ :context_before,
111
+ :em_before,
112
+ :context_em_before
113
+ @hooks_called.should_not include :em_after, :context_em_after
114
+ done
115
+ end
116
+ end
117
+
118
+ it_should_behave_like 'hooked em specs'
119
+
120
+ end # context 'inside nested example group'
121
+ end # context 'with em block'
122
+
123
+ context 'with amqp block' do
124
+
125
+ it_should_behave_like 'hooked amqp specs'
126
+
127
+ context 'inside nested example group' do
128
+ before { @hooks_called << :context_before }
129
+ em_before { @hooks_called << :context_em_before }
130
+ em_after { @hooks_called << :context_em_after }
131
+
132
+ after { @hooks_called.should include :before,
133
+ :context_before,
134
+ :em_before,
135
+ :context_em_before,
136
+ :context_em_after,
137
+ :em_after }
138
+
139
+ it 'should fire both nested :before hooks' do
140
+ amqp do
141
+ @hooks_called.should include :before,
142
+ :context_before,
143
+ :em_before,
144
+ :context_em_before
145
+ @hooks_called.should_not include :em_after, :context_em_after
146
+ done
147
+ end
148
+ end
149
+
150
+ it_should_behave_like 'hooked amqp specs'
151
+
152
+ end # context 'inside nested example group'
153
+ end # context 'with amqp block'
154
+ end # context 'for evented specs'
155
+ end # describe AMQP, " tested with AMQP::SpecHelper"
156
+ end # describe AMQP, " with em_before/em_after"
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe 'Following examples should all be failing:' do
3
+ describe 'Following 8 examples should all be failing:' do
4
4
  describe EventMachine, " when running failing examples" do
5
5
  include AMQP::EMSpec
6
6
 
@@ -19,8 +19,6 @@ describe 'Following examples should all be failing:' do
19
19
  describe EventMachine, " when testing with AMQP::EMSpec with a maximum execution time per test" do
20
20
  include AMQP::EMSpec
21
21
 
22
- # For RSpec 1, default_timeout and default_options are global
23
- # For RSpec 2, default_timeout and default_options are example-group local, inheritable by nested groups
24
22
  default_timeout 1
25
23
 
26
24
  it 'should timeout before reaching done' do
@@ -37,8 +35,6 @@ describe 'Following examples should all be failing:' do
37
35
 
38
36
  include AMQP::Spec
39
37
 
40
- # For RSpec 1, default_timeout and default_options are global
41
- # For RSpec 2, default_timeout and default_options are example-group local, inheritable by nested groups
42
38
  default_timeout 1
43
39
 
44
40
  it 'should timeout before reaching done' do
@@ -1,5 +1,4 @@
1
- require_relative 'spec_helper.rb'
1
+ require 'spec_helper'
2
2
 
3
3
  describe '!!!!!!!!! LEAKING OR PROBLEMATIC EXAMPLES !!!!!!!!!' do
4
- end
5
-
4
+ end
@@ -1,4 +1,4 @@
1
- require_relative 'spec_helper.rb'
1
+ require 'spec_helper'
2
2
 
3
3
  def publish_and_consume_once(queue_name="test_sink", data="data")
4
4
  amqp do
@@ -27,8 +27,8 @@ describe 'Evented AMQP specs' do
27
27
  default_options AMQP_OPTS if defined? AMQP_OPTS
28
28
  default_timeout 1
29
29
 
30
- puts "Default timeout: #{default_timeout}, Default options:"
31
- p default_options
30
+ puts "Default timeout: #{default_timeout}"
31
+ puts "Default options :#{default_options}"
32
32
 
33
33
  it_should_behave_like 'SpecHelper examples'
34
34
 
@@ -1,4 +1,4 @@
1
- require_relative 'spec_helper.rb'
1
+ require 'spec_helper'
2
2
 
3
3
  describe 'Plain EM, no AMQP' do
4
4
  describe EventMachine, " when testing with AMQP::SpecHelper" do
@@ -47,6 +47,7 @@ shared_examples_for 'SpecHelper examples' do
47
47
  AMQP.conn.should be_nil
48
48
  end
49
49
 
50
+ # TODO: remove dependency on (possibly long) DNS lookup
50
51
  it "should gracefully exit if no AMQP connection was made" do
51
52
  expect {
52
53
  amqp(:host => 'Impossible') do
@@ -58,6 +59,7 @@ shared_examples_for 'SpecHelper examples' do
58
59
  end
59
60
 
60
61
  it_should_behave_like 'done examples'
62
+
61
63
  it_should_behave_like 'timeout examples'
62
64
  end
63
65
 
@@ -101,7 +103,7 @@ shared_examples_for 'timeout examples' do
101
103
 
102
104
  it 'should timeout before reaching done because of default spec timeout' do
103
105
  expect { amqp { EM.add_timer(2) { done } } }.
104
- to raise_error SpecTimeoutExceededError
106
+ to raise_error SpecTimeoutExceededError
105
107
  (Time.now-@start).should be_close(1.0, 0.1)
106
108
  end
107
109
 
@@ -117,13 +119,13 @@ shared_examples_for 'timeout examples' do
117
119
 
118
120
  specify "spec timeout given in amqp options has higher priority than default" do
119
121
  expect { amqp(:spec_timeout => 0.2) {} }.
120
- to raise_error SpecTimeoutExceededError
122
+ to raise_error SpecTimeoutExceededError
121
123
  (Time.now-@start).should be_close(0.2, 0.1)
122
124
  end
123
125
 
124
126
  specify "but timeout call inside amqp loop has even higher priority" do
125
127
  expect { amqp(:spec_timeout => 0.5) { timeout(0.2) } }.
126
- to raise_error SpecTimeoutExceededError
128
+ to raise_error SpecTimeoutExceededError
127
129
  (Time.now-@start).should be_close(0.2, 0.1)
128
130
  end
129
131
 
@@ -131,25 +133,22 @@ shared_examples_for 'timeout examples' do
131
133
  AMQP.conn.should be_nil
132
134
  end
133
135
 
134
- if rspec2?
135
- context 'embedded context can set up separate defaults' do
136
- default_timeout 0.2 # Can be used to set default :spec_timeout for all your amqp-based specs
136
+ context 'embedded context can set up separate defaults' do
137
+ default_timeout 0.2 # Can be used to set default :spec_timeout for all evented specs
137
138
 
138
- specify 'default timeout should be 0.2' do
139
- expect { amqp { EM.add_timer(2) { done } } }.to raise_error SpecTimeoutExceededError
140
- (Time.now-@start).should be_close(0.2, 0.1)
141
- end
139
+ specify 'default timeout should be 0.2' do
140
+ expect { em { EM.add_timer(2) { done } } }.to raise_error SpecTimeoutExceededError
141
+ (Time.now-@start).should be_close(0.2, 0.1)
142
+ end
142
143
 
143
- context 'deeply embedded context can set up separate defaults' do
144
- default_timeout 0.5 # Can be used to set default :spec_timeout for all your amqp-based specs
144
+ context 'deeply embedded context can set up separate defaults' do
145
+ default_timeout 0.5
145
146
 
146
- specify 'default timeout should be 0.5' do
147
- expect { amqp { EM.add_timer(2) { done } } }.to raise_error SpecTimeoutExceededError
148
- (Time.now-@start).should be_close(0.5, 0.1)
149
- end
147
+ specify 'default timeout should be 0.5' do
148
+ expect { amqp { EM.add_timer(2) { done } } }.to raise_error SpecTimeoutExceededError
149
+ (Time.now-@start).should be_close(0.5, 0.1)
150
150
  end
151
151
  end
152
-
153
152
  end
154
153
  end
155
154
 
data/spec/spec_helper.rb CHANGED
@@ -12,6 +12,10 @@ def rspec2?
12
12
  defined?(RSpec)
13
13
  end
14
14
 
15
+ # Done is defined as noop to help share examples between evented and non-evented specs
16
+ def done
17
+ end
18
+
15
19
  RSPEC = rspec2? ? RSpec : Spec
16
20
 
17
21
  amqp_config = File.dirname(__FILE__) + '/amqp.yml'
metadata CHANGED
@@ -1,13 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: amqp-spec
3
3
  version: !ruby/object:Gem::Version
4
- hash: 25
5
4
  prerelease: false
6
5
  segments:
7
6
  - 0
8
- - 2
9
- - 7
10
- version: 0.2.7
7
+ - 3
8
+ - 0
9
+ version: 0.3.0
11
10
  platform: ruby
12
11
  authors:
13
12
  - Arvicco
@@ -15,7 +14,7 @@ autorequire:
15
14
  bindir: bin
16
15
  cert_chain: []
17
16
 
18
- date: 2010-11-04 00:00:00 +03:00
17
+ date: 2010-11-16 00:00:00 +03:00
19
18
  default_executable:
20
19
  dependencies:
21
20
  - !ruby/object:Gem::Dependency
@@ -26,7 +25,6 @@ dependencies:
26
25
  requirements:
27
26
  - - ">="
28
27
  - !ruby/object:Gem::Version
29
- hash: 13
30
28
  segments:
31
29
  - 1
32
30
  - 2
@@ -42,7 +40,6 @@ dependencies:
42
40
  requirements:
43
41
  - - ~>
44
42
  - !ruby/object:Gem::Version
45
- hash: 9
46
43
  segments:
47
44
  - 0
48
45
  - 6
@@ -62,10 +59,12 @@ extra_rdoc_files:
62
59
  - README.rdoc
63
60
  files:
64
61
  - lib/amqp-spec/amqp.rb
62
+ - lib/amqp-spec/evented_example.rb
65
63
  - lib/amqp-spec/rspec.rb
66
64
  - lib/amqp-spec.rb
67
65
  - lib/version.rb
68
66
  - spec/amqp.yml
67
+ - spec/em_hooks_spec.rb
69
68
  - spec/failing_rspec_spec.rb
70
69
  - spec/problematic_rspec_spec.rb
71
70
  - spec/rspec_amqp_spec.rb
@@ -104,7 +103,6 @@ required_ruby_version: !ruby/object:Gem::Requirement
104
103
  requirements:
105
104
  - - ">="
106
105
  - !ruby/object:Gem::Version
107
- hash: 3
108
106
  segments:
109
107
  - 0
110
108
  version: "0"
@@ -113,7 +111,6 @@ required_rubygems_version: !ruby/object:Gem::Requirement
113
111
  requirements:
114
112
  - - ">="
115
113
  - !ruby/object:Gem::Version
116
- hash: 3
117
114
  segments:
118
115
  - 0
119
116
  version: "0"
@@ -126,6 +123,7 @@ specification_version: 3
126
123
  summary: Simple API for writing asynchronous EventMachine/AMQP specs. Supports RSpec and RSpec2.
127
124
  test_files:
128
125
  - spec/amqp.yml
126
+ - spec/em_hooks_spec.rb
129
127
  - spec/failing_rspec_spec.rb
130
128
  - spec/problematic_rspec_spec.rb
131
129
  - spec/rspec_amqp_spec.rb