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.
@@ -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