evented-spec 0.4.0 → 0.4.1
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 +8 -1
- data/README.textile +51 -9
- data/Rakefile +3 -4
- data/VERSION +1 -1
- data/lib/evented-spec.rb +22 -1
- data/lib/evented-spec/amqp_spec.rb +27 -0
- data/lib/evented-spec/coolio_spec.rb +26 -0
- data/lib/evented-spec/em_spec.rb +26 -0
- data/lib/evented-spec/evented_example.rb +13 -5
- data/lib/evented-spec/evented_example/amqp_example.rb +8 -7
- data/lib/evented-spec/evented_example/coolio_example.rb +4 -18
- data/lib/evented-spec/evented_example/em_example.rb +6 -12
- data/lib/evented-spec/{amqp.rb → ext/amqp.rb} +31 -2
- data/lib/evented-spec/ext/coolio.rb +14 -0
- data/lib/evented-spec/spec_helper.rb +141 -0
- data/lib/evented-spec/spec_helper/amqp_helpers.rb +55 -0
- data/lib/evented-spec/spec_helper/coolio_helpers.rb +49 -0
- data/lib/evented-spec/spec_helper/event_machine_helpers.rb +52 -0
- data/spec/em_hooks_spec.rb +3 -3
- data/spec/evented-spec/adapters/adapter_seg.rb +156 -0
- data/spec/evented-spec/adapters/amqp_spec.rb +58 -0
- data/spec/evented-spec/adapters/cool_io_spec.rb +30 -0
- data/spec/evented-spec/adapters/em_spec.rb +29 -0
- data/spec/{em_defaults_spec.rb → evented-spec/defaults_options_spec.rb} +0 -0
- data/spec/{em_metadata_spec.rb → evented-spec/evented_spec_metadata_spec.rb} +0 -0
- data/spec/{util_spec.rb → evented-spec/util_spec.rb} +0 -0
- data/spec/{failing_rspec_spec.rb → integration/failing_rspec_spec.rb} +1 -1
- data/spec/spec_helper.rb +18 -9
- data/tasks/spec.rake +7 -2
- metadata +44 -24
- data/lib/evented-spec/rspec.rb +0 -267
- data/spec/cool_io_spec.rb +0 -72
- data/spec/rspec_amqp_spec.rb +0 -116
- data/spec/rspec_em_spec.rb +0 -53
- data/spec/shared_examples.rb +0 -194
@@ -0,0 +1,14 @@
|
|
1
|
+
# Monkey patching some methods into Cool.io to make it more testable
|
2
|
+
module Coolio
|
3
|
+
class Loop
|
4
|
+
# Cool.io provides no means to change the default loop which makes sense in
|
5
|
+
# most situations, but not ours.
|
6
|
+
def self.default_loop=(event_loop)
|
7
|
+
if RUBY_VERSION >= "1.9.0"
|
8
|
+
Thread.current.instance_variable_set :@_coolio_loop, event_loop
|
9
|
+
else
|
10
|
+
@@_coolio_loop = event_loop
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
# You can include one of the following modules into your example groups:
|
2
|
+
# EventedSpec::SpecHelper,
|
3
|
+
# EventedSpec::AMQPSpec,
|
4
|
+
# EventedSpec::EMSpec.
|
5
|
+
#
|
6
|
+
# EventedSpec::SpecHelper module defines #ampq and #em methods that can be safely used inside
|
7
|
+
# your specs (examples) to test code running inside AMQP.start or EM.run loop
|
8
|
+
# respectively. Each example is running in a separate event loop,you can control
|
9
|
+
# for timeouts either with :spec_timeout option given to #amqp/#em method or setting
|
10
|
+
# a default timeout using default_timeout(timeout) macro inside describe/context block.
|
11
|
+
#
|
12
|
+
# If you include EventedSpec::Spec module into your example group, each example of this group
|
13
|
+
# will run inside AMQP.start loop without the need to explicitly call 'amqp'. In order to
|
14
|
+
# provide options to AMQP loop, default_options({opts}) macro is defined.
|
15
|
+
#
|
16
|
+
# Including EventedSpec::EMSpec module into your example group, each example of this group will
|
17
|
+
# run inside EM.run loop without the need to explicitly call 'em'.
|
18
|
+
#
|
19
|
+
# In order to stop AMQP/EM loop, you should call 'done' AFTER you are sure that your
|
20
|
+
# example is finished and your expectations executed. For example if you are using
|
21
|
+
# subscribe block that tests expectations on messages, 'done' should be probably called
|
22
|
+
# at the end of this block.
|
23
|
+
#
|
24
|
+
module EventedSpec
|
25
|
+
|
26
|
+
# EventedSpec::SpecHelper module defines #ampq and #em methods that can be safely used inside
|
27
|
+
# your specs (examples) to test code running inside AMQP.start or EM.run loop
|
28
|
+
# respectively. Each example is running in a separate event loop, you can control
|
29
|
+
# for timeouts either with :spec_timeout option given to #amqp/#em/#coolio method or setting
|
30
|
+
# a default timeout using default_timeout(timeout) macro inside describe/context block.
|
31
|
+
module SpecHelper
|
32
|
+
# Error which shows in RSpec log when example does not call #done inside
|
33
|
+
# of event loop.
|
34
|
+
SpecTimeoutExceededError = Class.new(RuntimeError)
|
35
|
+
|
36
|
+
# Class methods (macros) for any example groups that includes SpecHelper.
|
37
|
+
# You can use these methods as macros inside describe/context block.
|
38
|
+
module GroupMethods
|
39
|
+
# Returns evented-spec related metadata for particular example group.
|
40
|
+
# Metadata is cloned from parent to children, so that children inherit
|
41
|
+
# all the options and hooks set in parent example groups
|
42
|
+
#
|
43
|
+
# @return [Hash] hash with example group metadata
|
44
|
+
def evented_spec_metadata
|
45
|
+
if @evented_spec_metadata
|
46
|
+
@evented_spec_metadata
|
47
|
+
else
|
48
|
+
@evented_spec_metadata = superclass.evented_spec_metadata rescue {}
|
49
|
+
@evented_spec_metadata = EventedSpec::Util.deep_clone(@evented_spec_metadata)
|
50
|
+
end
|
51
|
+
end # evented_spec_metadata
|
52
|
+
|
53
|
+
# Sets/retrieves default timeout for running evented specs for this
|
54
|
+
# example group and its nested groups.
|
55
|
+
#
|
56
|
+
# @param [Float] desired timeout for the example group
|
57
|
+
# @return [Float]
|
58
|
+
def default_timeout(spec_timeout = nil)
|
59
|
+
if spec_timeout
|
60
|
+
default_options[:spec_timeout] = spec_timeout
|
61
|
+
else
|
62
|
+
default_options[:spec_timeout] || self.superclass.default_timeout
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Sets/retrieves default AMQP.start options for this example group
|
67
|
+
# and its nested groups.
|
68
|
+
#
|
69
|
+
# @param [Hash] context-specific options for helper methods like #amqp, #em, #coolio
|
70
|
+
# @return [Hash]
|
71
|
+
def default_options(opts = nil)
|
72
|
+
evented_spec_metadata[:default_options] ||= {}
|
73
|
+
if opts
|
74
|
+
evented_spec_metadata[:default_options].merge!(opts)
|
75
|
+
else
|
76
|
+
evented_spec_metadata[:default_options]
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# Collection of evented hooks for current example group
|
81
|
+
#
|
82
|
+
# @return [Hash] hash with hooks
|
83
|
+
def evented_spec_hooks
|
84
|
+
evented_spec_metadata[:es_hooks] ||= Hash.new
|
85
|
+
end
|
86
|
+
|
87
|
+
# Collection of evented hooks of predefined type for current example group
|
88
|
+
#
|
89
|
+
# @param [Symbol] hook type
|
90
|
+
# @return [Array] hooks
|
91
|
+
def evented_spec_hooks_for(type)
|
92
|
+
evented_spec_hooks[type] ||= []
|
93
|
+
end # evented_spec_hooks_for
|
94
|
+
end
|
95
|
+
|
96
|
+
def self.included(example_group)
|
97
|
+
unless example_group.respond_to? :default_timeout
|
98
|
+
example_group.extend GroupMethods
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# Retrieves default options passed in from enclosing example groups
|
103
|
+
#
|
104
|
+
# @return [Hash] default option for currently running example
|
105
|
+
def default_options
|
106
|
+
@default_options ||= self.class.default_options.dup rescue {}
|
107
|
+
end
|
108
|
+
|
109
|
+
# Executes an operation after certain delay
|
110
|
+
#
|
111
|
+
# @param [Float] time to wait before operation
|
112
|
+
def delayed(time, &block)
|
113
|
+
@evented_example.delayed(time) do
|
114
|
+
@example_group_instance.instance_eval(&block)
|
115
|
+
end
|
116
|
+
end # delayed
|
117
|
+
|
118
|
+
# Breaks the event loop and finishes the spec. This should be called after
|
119
|
+
# you are reasonably sure that your expectations succeeded.
|
120
|
+
# Done yields to any given block first, then stops EM event loop.
|
121
|
+
# For amqp specs, stops AMQP and cleans up AMQP state.
|
122
|
+
#
|
123
|
+
# You may pass delay (in seconds) to done. If you do so, please keep in mind
|
124
|
+
# that your (default or explicit) spec timeout may fire before your delayed done
|
125
|
+
# callback is due, leading to SpecTimeoutExceededError
|
126
|
+
#
|
127
|
+
# @param [Float] Delay before event loop is stopped
|
128
|
+
def done(*args, &block)
|
129
|
+
@evented_example.done *args, &block if @evented_example
|
130
|
+
end
|
131
|
+
|
132
|
+
# Manually sets timeout for currently running example. If spec doesn't call
|
133
|
+
# #done before timeout, it is marked as failed on timeout.
|
134
|
+
#
|
135
|
+
# @param [Float] Delay before event loop is stopped with error
|
136
|
+
def timeout(*args)
|
137
|
+
@evented_example.timeout *args if @evented_example
|
138
|
+
end
|
139
|
+
|
140
|
+
end # module SpecHelper
|
141
|
+
end # EventedSpec
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module EventedSpec
|
2
|
+
module SpecHelper
|
3
|
+
module AMQPHelpers # naming is v
|
4
|
+
module GroupMethods
|
5
|
+
# Adds before hook that will run inside AMQP connection (AMQP.start loop)
|
6
|
+
# before example starts
|
7
|
+
#
|
8
|
+
# @param [Symbol] scope for hook (only :each is supported currently)
|
9
|
+
# @yield hook block
|
10
|
+
def amqp_before(scope = :each, &block)
|
11
|
+
raise ArgumentError, "amqp_before only supports :each scope" unless :each == scope
|
12
|
+
evented_spec_hooks_for(:amqp_before) << block
|
13
|
+
end
|
14
|
+
|
15
|
+
# Adds after hook that will run inside AMQP connection (AMQP.start loop)
|
16
|
+
# after example finishes
|
17
|
+
#
|
18
|
+
# @param [Symbol] scope for hook (only :each is supported currently)
|
19
|
+
# @yield hook block
|
20
|
+
def amqp_after(scope = :each, &block)
|
21
|
+
raise ArgumentError, "amqp_after only supports :each scope" unless :each == scope
|
22
|
+
evented_spec_hooks_for(:amqp_after).unshift block
|
23
|
+
end
|
24
|
+
end # module GroupMethods
|
25
|
+
|
26
|
+
module ExampleMethods
|
27
|
+
# Yields to a given block inside EM.run and AMQP.start loops.
|
28
|
+
#
|
29
|
+
# @param [Hash] options for amqp connection initialization
|
30
|
+
# @option opts [String] :user ('guest') Username as defined by the AMQP server.
|
31
|
+
# @option opts [String] :pass ('guest') Password as defined by the AMQP server.
|
32
|
+
# @option opts [String] :vhost ('/') Virtual host as defined by the AMQP server.
|
33
|
+
# @option opts [Numeric] :timeout (nil) *Connection* timeout, measured in seconds.
|
34
|
+
# @option opts [Boolean] :logging (false) Toggle the extremely verbose AMQP logging.
|
35
|
+
# @option opts [Numeric] :spec_timeout (nil) Amount of time before spec is stopped by timeout
|
36
|
+
# @yield block to execute after amqp connects
|
37
|
+
def amqp(opts = {}, &block)
|
38
|
+
opts = default_options.merge opts
|
39
|
+
@evented_example = AMQPExample.new(opts, self, &block)
|
40
|
+
@evented_example.run
|
41
|
+
end
|
42
|
+
end # module ExampleMethods
|
43
|
+
end # module AMQP
|
44
|
+
end # module SpecHelper
|
45
|
+
end # module EventedSpec
|
46
|
+
|
47
|
+
module EventedSpec
|
48
|
+
module SpecHelper
|
49
|
+
module GroupMethods
|
50
|
+
include EventedSpec::SpecHelper::AMQPHelpers::GroupMethods
|
51
|
+
end # module GroupMethods
|
52
|
+
|
53
|
+
include EventedSpec::SpecHelper::AMQPHelpers::ExampleMethods
|
54
|
+
end # module SpecHelper
|
55
|
+
end # module EventedSpec
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module EventedSpec
|
2
|
+
module SpecHelper
|
3
|
+
module CoolioHelpers
|
4
|
+
module GroupHelpers
|
5
|
+
# Adds before hook that will run inside coolio event loop before example starts.
|
6
|
+
#
|
7
|
+
# @param [Symbol] scope for hook (only :each is supported currently)
|
8
|
+
# @yield hook block
|
9
|
+
def coolio_before(scope = :each, &block)
|
10
|
+
raise ArgumentError, "coolio_before only supports :each scope" unless :each == scope
|
11
|
+
evented_spec_hooks_for(:coolio_before) << block
|
12
|
+
end
|
13
|
+
|
14
|
+
# Adds after hook that will run inside coolio event loop after example finishes.
|
15
|
+
#
|
16
|
+
# @param [Symbol] scope for hook (only :each is supported currently)
|
17
|
+
# @yield hook block
|
18
|
+
def coolio_after(scope = :each, &block)
|
19
|
+
raise ArgumentError, "coolio_after only supports :each scope" unless :each == scope
|
20
|
+
evented_spec_hooks_for(:coolio_after).unshift block
|
21
|
+
end
|
22
|
+
end # module GroupHelpers
|
23
|
+
|
24
|
+
module ExampleHelpers
|
25
|
+
# Yields to block inside cool.io loop, :spec_timeout option (in seconds) is used to
|
26
|
+
# force spec to timeout if something goes wrong and EM/AMQP loop hangs for some
|
27
|
+
# reason.
|
28
|
+
#
|
29
|
+
# @param [Hash] options for cool.io
|
30
|
+
# @param opts [Numeric] :spec_timeout (nil) Amount of time before spec is stopped by timeout
|
31
|
+
# @yield block to execute after cool.io loop starts
|
32
|
+
def coolio(opts = {}, &block)
|
33
|
+
opts = default_options.merge opts
|
34
|
+
@evented_example = CoolioExample.new(opts, self, &block)
|
35
|
+
@evented_example.run
|
36
|
+
end
|
37
|
+
end # module ExampleHelpers
|
38
|
+
end # module CoolioHelpers
|
39
|
+
end # module SpecHelper
|
40
|
+
end # module EventedSpec
|
41
|
+
|
42
|
+
module EventedSpec
|
43
|
+
module SpecHelper
|
44
|
+
module GroupMethods
|
45
|
+
include EventedSpec::SpecHelper::CoolioHelpers::GroupHelpers
|
46
|
+
end # module GroupHelpers
|
47
|
+
include EventedSpec::SpecHelper::CoolioHelpers::ExampleHelpers
|
48
|
+
end # module SpecHelper
|
49
|
+
end # module EventedSpec
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module EventedSpec
|
2
|
+
module SpecHelper
|
3
|
+
module EventMachineHelpers
|
4
|
+
module GroupMethods
|
5
|
+
# Adds before hook that will run inside EM event loop before example starts.
|
6
|
+
#
|
7
|
+
# @param [Symbol] scope for hook (only :each is supported currently)
|
8
|
+
# @yield hook block
|
9
|
+
def em_before(scope = :each, &block)
|
10
|
+
raise ArgumentError, "em_before only supports :each scope" unless :each == scope
|
11
|
+
evented_spec_hooks_for(:em_before) << block
|
12
|
+
end
|
13
|
+
|
14
|
+
# Adds after hook that will run inside EM event loop after example finishes.
|
15
|
+
#
|
16
|
+
# @param [Symbol] scope for hook (only :each is supported currently)
|
17
|
+
# @yield hook block
|
18
|
+
def em_after(scope = :each, &block)
|
19
|
+
raise ArgumentError, "em_after only supports :each scope" unless :each == scope
|
20
|
+
evented_spec_hooks_for(:em_after).unshift block
|
21
|
+
end
|
22
|
+
end # module GroupMethods
|
23
|
+
|
24
|
+
module ExampleMethods
|
25
|
+
# Yields to block inside EM loop, :spec_timeout option (in seconds) is used to
|
26
|
+
# force spec to timeout if something goes wrong and EM/AMQP loop hangs for some
|
27
|
+
# reason.
|
28
|
+
#
|
29
|
+
# For compatibility with EM-Spec API, em method accepts either options Hash
|
30
|
+
# or numeric timeout in seconds.
|
31
|
+
#
|
32
|
+
# @param [Hash] options for eventmachine
|
33
|
+
# @param opts [Numeric] :spec_timeout (nil) Amount of time before spec is stopped by timeout
|
34
|
+
# @yield block to execute after eventmachine loop starts
|
35
|
+
def em(opts = {}, &block)
|
36
|
+
opts = default_options.merge(opts.is_a?(Hash) ? opts : { :spec_timeout => opts })
|
37
|
+
@evented_example = EMExample.new(opts, self, &block)
|
38
|
+
@evented_example.run
|
39
|
+
end
|
40
|
+
end # module ExampleMethods
|
41
|
+
end # module EventMachine
|
42
|
+
end # module SpecHelper
|
43
|
+
end # module EventedSpec
|
44
|
+
|
45
|
+
module EventedSpec
|
46
|
+
module SpecHelper
|
47
|
+
module GroupMethods
|
48
|
+
include EventedSpec::SpecHelper::EventMachineHelpers::GroupMethods
|
49
|
+
end # module GroupMethods
|
50
|
+
include EventedSpec::SpecHelper::EventMachineHelpers::ExampleMethods
|
51
|
+
end # module SpecHelper
|
52
|
+
end # module EventedSpec
|
data/spec/em_hooks_spec.rb
CHANGED
@@ -43,7 +43,7 @@ shared_examples_for 'hooked em specs' do
|
|
43
43
|
# Expectation is set in after{} hook
|
44
44
|
em do
|
45
45
|
expect { :this.should == :fail
|
46
|
-
}.to raise_error
|
46
|
+
}.to raise_error RSpec::Expectations::ExpectationNotMetError
|
47
47
|
done
|
48
48
|
end
|
49
49
|
end
|
@@ -74,7 +74,7 @@ shared_examples_for 'hooked amqp specs' do
|
|
74
74
|
# Expectation is set in after{} hook
|
75
75
|
amqp do
|
76
76
|
expect { :this.should == :fail
|
77
|
-
}.to raise_error
|
77
|
+
}.to raise_error RSpec::Expectations::ExpectationNotMetError
|
78
78
|
done
|
79
79
|
end
|
80
80
|
end
|
@@ -108,7 +108,7 @@ describe EventedSpec::SpecHelper, ".em_before/.em_after" do
|
|
108
108
|
|
109
109
|
it 'should execute em_after if RSpec expectation fails' do
|
110
110
|
expect { :this.should == :fail
|
111
|
-
}.to raise_error
|
111
|
+
}.to raise_error RSpec::Expectations::ExpectationNotMetError
|
112
112
|
end
|
113
113
|
end # context 'for non-evented specs'
|
114
114
|
|
@@ -0,0 +1,156 @@
|
|
1
|
+
# Our assumptions with this seg:
|
2
|
+
# - let(:prefix) is defined (e.g. 'coolio_')
|
3
|
+
# - let(:method_name) is defined (e.g. 'coolio')
|
4
|
+
# - #{prefix}running? method is defined in example group, it is true inside
|
5
|
+
# #{method_name} call block, and false outside of it
|
6
|
+
#
|
7
|
+
shared_examples_for "EventedSpec adapter" do
|
8
|
+
# Unfortunately, I know no other way to extract variables from let(...)
|
9
|
+
prefix = self.new.prefix
|
10
|
+
method_name = self.new.method_name
|
11
|
+
|
12
|
+
def loop_running?
|
13
|
+
send("#{prefix}running?")
|
14
|
+
end
|
15
|
+
|
16
|
+
def loop(*args)
|
17
|
+
send(method_name, *args) do
|
18
|
+
yield
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
before(:each) { loop_running?.should be_false }
|
23
|
+
after(:each) { loop_running?.should be_false }
|
24
|
+
|
25
|
+
describe "sanity check:" do
|
26
|
+
it "we should not be in #{method_name} loop unless explicitly asked" do
|
27
|
+
loop_running?.should be_false
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "#{method_name}" do
|
32
|
+
it "should execute given block in the right scope" do
|
33
|
+
@variable = 1
|
34
|
+
loop do
|
35
|
+
@variable.should == 1
|
36
|
+
@variable = true
|
37
|
+
done
|
38
|
+
end
|
39
|
+
@variable.should == true
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should start default event loop and give control" do
|
43
|
+
loop do
|
44
|
+
loop_running?.should be_true
|
45
|
+
done
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should stop the event loop afterwards" do
|
50
|
+
loop do
|
51
|
+
done
|
52
|
+
end
|
53
|
+
loop_running?.should be_false
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should raise SpecTimeoutExceededError when #done is not issued" do
|
57
|
+
expect {
|
58
|
+
loop do
|
59
|
+
end
|
60
|
+
}.to raise_error(EventedSpec::SpecHelper::SpecTimeoutExceededError)
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should propagate mismatched rspec expectations" do
|
64
|
+
expect {
|
65
|
+
loop do
|
66
|
+
:fail.should == :win
|
67
|
+
end
|
68
|
+
}.to raise_error(RSpec::Expectations::ExpectationNotMetError)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
describe "#done" do
|
74
|
+
it "should execute given block" do
|
75
|
+
loop do
|
76
|
+
done(0.05) do
|
77
|
+
@variable = true
|
78
|
+
end
|
79
|
+
end
|
80
|
+
@variable.should be_true
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should cancel timeout" do
|
84
|
+
expect {
|
85
|
+
loop do
|
86
|
+
done(0.2)
|
87
|
+
end
|
88
|
+
}.to_not raise_error
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe "hooks" do
|
93
|
+
context "before" do
|
94
|
+
send("#{prefix}before") do
|
95
|
+
@called_back = true
|
96
|
+
loop_running?.should be_true
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should run before example starts" do
|
100
|
+
loop do
|
101
|
+
@called_back.should be_true
|
102
|
+
done
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
context "after" do
|
108
|
+
send("#{prefix}after") do
|
109
|
+
@called_back = true
|
110
|
+
loop_running?.should be_true
|
111
|
+
end
|
112
|
+
|
113
|
+
it "should run after example finishes" do
|
114
|
+
loop do
|
115
|
+
@called_back.should be_false
|
116
|
+
done
|
117
|
+
end
|
118
|
+
@called_back.should be_true
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
describe "#delayed" do
|
124
|
+
it "should run an operation after certain amount of time" do
|
125
|
+
loop(:spec_timeout => 3) do
|
126
|
+
time = Time.now
|
127
|
+
delayed(0.5) do
|
128
|
+
(Time.now - time).should be_within(0.3).of(0.5)
|
129
|
+
done
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
it "should preserve context" do
|
135
|
+
loop(:spec_timeout => 3) do
|
136
|
+
@instance_var = true
|
137
|
+
delayed(0.1) do
|
138
|
+
@instance_var.should be_true
|
139
|
+
done
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
|
146
|
+
describe "error handling" do
|
147
|
+
it "bubbles failing expectations up to Rspec" do
|
148
|
+
expect {
|
149
|
+
loop do
|
150
|
+
:this.should == :fail
|
151
|
+
end
|
152
|
+
}.to raise_error(RSpec::Expectations::ExpectationNotMetError)
|
153
|
+
loop_running?.should be_false
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|