evented-spec 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +30 -0
- data/HISTORY +97 -0
- data/LICENSE +20 -0
- data/README.textile +162 -0
- data/Rakefile +24 -0
- data/VERSION +1 -0
- data/lib/amqp-spec.rb +5 -0
- data/lib/evented-spec.rb +2 -0
- data/lib/evented-spec/amqp.rb +27 -0
- data/lib/evented-spec/evented_example.rb +61 -0
- data/lib/evented-spec/evented_example/amqp_example.rb +52 -0
- data/lib/evented-spec/evented_example/coolio_example.rb +97 -0
- data/lib/evented-spec/evented_example/em_example.rb +87 -0
- data/lib/evented-spec/rspec.rb +267 -0
- data/lib/evented-spec/util.rb +32 -0
- data/lib/evented-spec/version.rb +8 -0
- data/spec/cool_io_spec.rb +72 -0
- data/spec/em_defaults_spec.rb +132 -0
- data/spec/em_hooks_spec.rb +231 -0
- data/spec/em_metadata_spec.rb +43 -0
- data/spec/failing_rspec_spec.rb +63 -0
- data/spec/rspec_amqp_spec.rb +116 -0
- data/spec/rspec_em_spec.rb +53 -0
- data/spec/shared_examples.rb +194 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +54 -0
- data/spec/util_spec.rb +51 -0
- data/tasks/common.rake +18 -0
- data/tasks/doc.rake +14 -0
- data/tasks/gem.rake +40 -0
- data/tasks/git.rake +34 -0
- data/tasks/spec.rake +15 -0
- data/tasks/version.rake +71 -0
- metadata +149 -0
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Example Groups", ".evented_spec_metadata" do
|
4
|
+
context "when EventedSpec::SpecHelper is included" do
|
5
|
+
include EventedSpec::SpecHelper
|
6
|
+
it "should assign some hash by default" do
|
7
|
+
self.class.evented_spec_metadata.should == {}
|
8
|
+
end
|
9
|
+
|
10
|
+
context "in nested group" do
|
11
|
+
evented_spec_metadata[:nested] = {}
|
12
|
+
evented_spec_metadata[:other] = :value
|
13
|
+
it "should merge metadata" do
|
14
|
+
self.class.evented_spec_metadata.should == {:nested => {}, :other => :value}
|
15
|
+
end
|
16
|
+
|
17
|
+
context "in deeply nested group" do
|
18
|
+
evented_spec_metadata[:nested][:deeply] = {}
|
19
|
+
evented_spec_metadata[:other] = "hello"
|
20
|
+
it "should merge metadata" do
|
21
|
+
self.class.evented_spec_metadata[:nested][:deeply].should == {}
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should allow to override merged metadata" do
|
25
|
+
self.class.evented_spec_metadata[:other].should == "hello"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context "in other deeply nested group" do
|
30
|
+
evented_spec_metadata[:nested][:other] = {}
|
31
|
+
it "should diverge without being tainted by neighbouring example groups" do
|
32
|
+
self.class.evented_spec_metadata.should == {:nested => {:other => {}}, :other => :value}
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context "when EventedSpec::SpecHelper is not included" do
|
39
|
+
it "should not be defined" do
|
40
|
+
self.class.should_not respond_to(:evented_spec_metadata)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Following 9 examples should all be failing:' do
|
4
|
+
describe EventMachine, " when running failing examples" do
|
5
|
+
include EventedSpec::EMSpec
|
6
|
+
|
7
|
+
it "should not bubble failures beyond rspec" do
|
8
|
+
EM.add_timer(0.1) do
|
9
|
+
:should_not_bubble.should == :failures
|
10
|
+
done
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should not block on failure" do
|
15
|
+
1.should == 2
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe EventMachine, " when testing with EventedSpec::EMSpec with a maximum execution time per test" do
|
20
|
+
include EventedSpec::EMSpec
|
21
|
+
|
22
|
+
default_timeout 1
|
23
|
+
|
24
|
+
it 'should timeout before reaching done' do
|
25
|
+
EM.add_timer(2) { done }
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should timeout before reaching done' do
|
29
|
+
timeout(0.3)
|
30
|
+
EM.add_timer(0.6) { done }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe AMQP, " when testing with EventedSpec::AMQPSpec with a maximum execution time per test" do
|
35
|
+
|
36
|
+
include EventedSpec::AMQPSpec
|
37
|
+
|
38
|
+
default_timeout 1
|
39
|
+
|
40
|
+
it 'should timeout before reaching done' do
|
41
|
+
EM.add_timer(2) { done }
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should timeout before reaching done' do
|
45
|
+
timeout(0.2)
|
46
|
+
EM.add_timer(0.5) { done }
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'should fail due to timeout, not hang up' do
|
50
|
+
timeout(0.2)
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'should fail due to default timeout, not hang up' do
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe AMQP, "when default timeout is not set" do
|
58
|
+
include EventedSpec::AMQPSpec
|
59
|
+
it "should fail by timeout anyway" do
|
60
|
+
1.should == 1
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
def publish_and_consume_once(queue_name="test_sink", data="data")
|
4
|
+
amqp(:spec_timeout => 0.5) do
|
5
|
+
AMQP::Channel.new do |channel, _|
|
6
|
+
exchange = channel.direct(queue_name)
|
7
|
+
queue = channel.queue(queue_name).bind(exchange)
|
8
|
+
queue.subscribe do |hdr, msg|
|
9
|
+
hdr.should be_an AMQP::Header
|
10
|
+
msg.should == data
|
11
|
+
done { queue.unsubscribe; queue.delete }
|
12
|
+
end
|
13
|
+
EM.add_timer(0.2) do
|
14
|
+
exchange.publish data
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe RSPEC do
|
21
|
+
it 'should work as normal without AMQP-Spec' do
|
22
|
+
1.should == 1
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe 'Evented AMQP specs' do
|
27
|
+
describe AMQP, " when testing with EventedSpec::SpecHelper" do
|
28
|
+
include EventedSpec::SpecHelper
|
29
|
+
|
30
|
+
default_options AMQP_OPTS if defined? AMQP_OPTS
|
31
|
+
default_timeout 1
|
32
|
+
|
33
|
+
puts "Default timeout: #{default_timeout}"
|
34
|
+
puts "Default options :#{default_options}"
|
35
|
+
|
36
|
+
it_should_behave_like 'SpecHelper examples'
|
37
|
+
|
38
|
+
context 'inside embedded context / example group' do
|
39
|
+
it_should_behave_like 'SpecHelper examples'
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe AMQP, " when testing with EventedSpec::AMQPSpec" do
|
44
|
+
include EventedSpec::AMQPSpec
|
45
|
+
|
46
|
+
default_options AMQP_OPTS if defined? AMQP_OPTS
|
47
|
+
default_timeout 1
|
48
|
+
|
49
|
+
it_should_behave_like 'Spec examples'
|
50
|
+
|
51
|
+
context 'inside embedded context / example group' do
|
52
|
+
it 'should inherit default_options/metadata from enclosing example group' do
|
53
|
+
# This is a guard against regression on dev box without notice
|
54
|
+
AMQP.connection.instance_variable_get(:@settings)[:host].should == AMQP_OPTS[:host]
|
55
|
+
self.class.default_options[:host].should == AMQP_OPTS[:host]
|
56
|
+
self.class.default_timeout.should == 1
|
57
|
+
done
|
58
|
+
end
|
59
|
+
|
60
|
+
it_should_behave_like 'Spec examples'
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe AMQP, " tested with EventedSpec::SpecHelper when Rspec failures occur" do
|
65
|
+
include EventedSpec::SpecHelper
|
66
|
+
|
67
|
+
default_options AMQP_OPTS if defined? AMQP_OPTS
|
68
|
+
|
69
|
+
it "bubbles failing expectations up to Rspec" do
|
70
|
+
expect {
|
71
|
+
amqp do
|
72
|
+
:this.should == :fail
|
73
|
+
end
|
74
|
+
}.to raise_error RSPEC::Expectations::ExpectationNotMetError
|
75
|
+
AMQP.connection.should == nil
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should NOT ignore failing expectations after 'done'" do
|
79
|
+
expect {
|
80
|
+
amqp do
|
81
|
+
done
|
82
|
+
:this.should == :fail
|
83
|
+
end
|
84
|
+
}.to raise_error RSPEC::Expectations::ExpectationNotMetError
|
85
|
+
AMQP.connection.should == nil
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should properly close AMQP connection after Rspec failures" do
|
89
|
+
AMQP.connection.should == nil
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe 'MQ', " when AMQP.queue/fanout/topic tries to access Thread.current[:mq] across examples" do
|
94
|
+
include EventedSpec::SpecHelper
|
95
|
+
|
96
|
+
default_options AMQP_OPTS if defined? AMQP_OPTS
|
97
|
+
|
98
|
+
it 'sends data to the queue' do
|
99
|
+
publish_and_consume_once
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'does not hang sending data to the same queue, again' do
|
103
|
+
publish_and_consume_once
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'cleans Thread.current[:mq] after pubsub examples' do
|
107
|
+
Thread.current[:mq].should be_nil
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
describe RSPEC, " when running an example group after another group that uses AMQP-Spec " do
|
113
|
+
it "should work normally" do
|
114
|
+
:does_not_hang.should_not be_false
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Plain EM, no AMQP' do
|
4
|
+
describe EventMachine, " when testing with EventedSpec::SpecHelper" do
|
5
|
+
include EventedSpec::SpecHelper
|
6
|
+
|
7
|
+
it "should not require a call to done when #em is not used" do
|
8
|
+
1.should == 1
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should have timers" do
|
12
|
+
start = Time.now
|
13
|
+
em do
|
14
|
+
EM.add_timer(0.5) {
|
15
|
+
(Time.now-start).should be_within(0.1).of(0.5)
|
16
|
+
done
|
17
|
+
}
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should be possible to set spec timeouts as a number of seconds" do
|
22
|
+
start = Time.now
|
23
|
+
expect {
|
24
|
+
em(0.5) do
|
25
|
+
EM.add_timer(1) { done }
|
26
|
+
end
|
27
|
+
}.to raise_error EventedSpec::SpecHelper::SpecTimeoutExceededError
|
28
|
+
(Time.now-start).should be_within(0.1).of(0.5)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should be possible to set spec timeout as an option (amqp interface compatibility)" do
|
32
|
+
start = Time.now
|
33
|
+
expect {
|
34
|
+
em(0.5) do
|
35
|
+
EM.add_timer(1) { done }
|
36
|
+
end
|
37
|
+
}.to raise_error EventedSpec::SpecHelper::SpecTimeoutExceededError
|
38
|
+
(Time.now-start).should be_within(0.1).of(0.5)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe EventMachine, " when testing with EventedSpec::EMSpec" do
|
43
|
+
include EventedSpec::EMSpec
|
44
|
+
|
45
|
+
it_should_behave_like 'Spec examples'
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe RSPEC, " when running an example group after groups that uses EM specs " do
|
50
|
+
it "should work normally" do
|
51
|
+
:does_not_hang.should_not be_false
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,194 @@
|
|
1
|
+
shared_examples_for 'SpecHelper examples' do
|
2
|
+
after do
|
3
|
+
EM.reactor_running?.should == false
|
4
|
+
AMQP.connection.should be_nil
|
5
|
+
end
|
6
|
+
|
7
|
+
it "should not require a call to done when #em/#amqp is not used" do
|
8
|
+
1.should == 1
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should properly work" do
|
12
|
+
amqp { done }
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should have timers" do
|
16
|
+
start = Time.now
|
17
|
+
amqp do
|
18
|
+
EM.add_timer(0.5) {
|
19
|
+
(Time.now-start).should be_within(0.1).of(0.5)
|
20
|
+
done
|
21
|
+
}
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should have deferrables' do
|
26
|
+
amqp do
|
27
|
+
defr = EM::DefaultDeferrable.new
|
28
|
+
defr.timeout(0.5)
|
29
|
+
defr.errback {
|
30
|
+
done
|
31
|
+
}
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should run AMQP.start loop with options given to #amqp" do
|
36
|
+
amqp(:vhost => '/', :user => 'guest') do
|
37
|
+
AMQP.connection.should be_connected
|
38
|
+
done
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should properly close AMQP connection if block completes normally" do
|
43
|
+
amqp do
|
44
|
+
AMQP.connection.should be_connected
|
45
|
+
done
|
46
|
+
end
|
47
|
+
AMQP.connection.should be_nil
|
48
|
+
end
|
49
|
+
|
50
|
+
# TODO: remove dependency on (possibly long) DNS lookup
|
51
|
+
it "should gracefully exit if no AMQP connection was made" do
|
52
|
+
expect {
|
53
|
+
amqp(:host => '192.168.0.256') do
|
54
|
+
AMQP.connection.should be_nil
|
55
|
+
done
|
56
|
+
end
|
57
|
+
}.to raise_error EventMachine::ConnectionError
|
58
|
+
AMQP.connection.should be_nil
|
59
|
+
end
|
60
|
+
|
61
|
+
it_should_behave_like 'done examples'
|
62
|
+
|
63
|
+
it_should_behave_like 'timeout examples'
|
64
|
+
end
|
65
|
+
|
66
|
+
shared_examples_for 'done examples' do
|
67
|
+
|
68
|
+
it 'should yield to block given to done (when amqp is used)' do
|
69
|
+
amqp do
|
70
|
+
done { @block_called = true; EM.reactor_running?.should == true }
|
71
|
+
end
|
72
|
+
@block_called.should == true
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'should yield to block given to done (when em is used)' do
|
76
|
+
em do
|
77
|
+
done { @block_called = true; EM.reactor_running?.should == true }
|
78
|
+
end
|
79
|
+
@block_called.should == true
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'should have delayed done (when amqp is used)' do
|
83
|
+
start = Time.now
|
84
|
+
amqp do
|
85
|
+
done(0.2) { @block_called = true; EM.reactor_running?.should == true }
|
86
|
+
end
|
87
|
+
@block_called.should == true
|
88
|
+
(Time.now-start).should be_within(0.1).of(0.2)
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'should have delayed done (when em is used)' do
|
92
|
+
start = Time.now
|
93
|
+
em do
|
94
|
+
done(0.2) { @block_called = true; EM.reactor_running?.should == true }
|
95
|
+
end
|
96
|
+
@block_called.should == true
|
97
|
+
(Time.now-start).should be_within(0.1).of(0.2)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
shared_examples_for 'timeout examples' do
|
102
|
+
before { @start = Time.now }
|
103
|
+
|
104
|
+
it 'should timeout before reaching done because of default spec timeout' do
|
105
|
+
expect { amqp { EM.add_timer(2) { done } } }.
|
106
|
+
to raise_error EventedSpec::SpecHelper::SpecTimeoutExceededError
|
107
|
+
(Time.now-@start).should be_within(0.1).of(1.0)
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'should timeout before reaching done because of explicit in-loop timeout' do
|
111
|
+
expect {
|
112
|
+
amqp do
|
113
|
+
timeout(0.2)
|
114
|
+
EM.add_timer(0.5) { done }
|
115
|
+
end
|
116
|
+
}.to raise_error EventedSpec::SpecHelper::SpecTimeoutExceededError
|
117
|
+
(Time.now-@start).should be_within(0.1).of(0.2)
|
118
|
+
end
|
119
|
+
|
120
|
+
specify "spec timeout given in amqp options has higher priority than default" do
|
121
|
+
expect { amqp(:spec_timeout => 0.2) {} }.
|
122
|
+
to raise_error EventedSpec::SpecHelper::SpecTimeoutExceededError
|
123
|
+
(Time.now-@start).should be_within(0.1).of(0.2)
|
124
|
+
end
|
125
|
+
|
126
|
+
specify "but timeout call inside amqp loop has even higher priority" do
|
127
|
+
expect { amqp(:spec_timeout => 0.5) { timeout(0.2) } }.
|
128
|
+
to raise_error EventedSpec::SpecHelper::SpecTimeoutExceededError
|
129
|
+
(Time.now-@start).should be_within(0.1).of(0.2)
|
130
|
+
end
|
131
|
+
|
132
|
+
specify "AMQP connection should not leak between examples" do
|
133
|
+
AMQP.connection.should be_nil
|
134
|
+
end
|
135
|
+
|
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
|
138
|
+
|
139
|
+
specify 'default timeout should be 0.2' do
|
140
|
+
expect { em { EM.add_timer(2) { done } } }.to raise_error EventedSpec::SpecHelper::SpecTimeoutExceededError
|
141
|
+
(Time.now-@start).should be_within(0.1).of(0.2)
|
142
|
+
end
|
143
|
+
|
144
|
+
context 'deeply embedded context can set up separate defaults' do
|
145
|
+
default_timeout 0.5
|
146
|
+
|
147
|
+
specify 'default timeout should be 0.5' do
|
148
|
+
expect { amqp { EM.add_timer(2) { done } } }.to raise_error EventedSpec::SpecHelper::SpecTimeoutExceededError
|
149
|
+
(Time.now-@start).should be_within(0.1).of(0.5)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
shared_examples_for 'Spec examples' do
|
156
|
+
after(:each) do
|
157
|
+
# By this time, EM loop is stopped, either by timeout, or by exception
|
158
|
+
EM.reactor_running?.should == false
|
159
|
+
end
|
160
|
+
|
161
|
+
it 'should work' do
|
162
|
+
done
|
163
|
+
end
|
164
|
+
|
165
|
+
it 'should have timers' do
|
166
|
+
start = Time.now
|
167
|
+
|
168
|
+
EM.add_timer(0.2) {
|
169
|
+
(Time.now-start).should be_within(0.1).of(0.2)
|
170
|
+
done
|
171
|
+
}
|
172
|
+
end
|
173
|
+
|
174
|
+
it 'should have periodic timers' do
|
175
|
+
num = 0
|
176
|
+
start = Time.now
|
177
|
+
|
178
|
+
timer = EM.add_periodic_timer(0.2) {
|
179
|
+
if (num += 1) == 2
|
180
|
+
(Time.now-start).should be_within(0.1).of(0.5)
|
181
|
+
EM.cancel_timer timer
|
182
|
+
done
|
183
|
+
end
|
184
|
+
}
|
185
|
+
end
|
186
|
+
|
187
|
+
it 'should have deferrables' do
|
188
|
+
defr = EM::DefaultDeferrable.new
|
189
|
+
defr.timeout(0.2)
|
190
|
+
defr.errback {
|
191
|
+
done
|
192
|
+
}
|
193
|
+
end
|
194
|
+
end
|