evented-spec 0.4.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/.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
|