onstomp 1.0.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. data/.gitignore +4 -0
  2. data/.yardopts +2 -1
  3. data/Rakefile +147 -0
  4. data/extra_doc/API.md +491 -0
  5. data/extra_doc/API.md.erb +33 -0
  6. data/extra_doc/DeveloperNarrative.md +123 -0
  7. data/extra_doc/UserNarrative.md +511 -0
  8. data/lib/onstomp.rb +5 -5
  9. data/lib/onstomp/client.rb +6 -1
  10. data/lib/onstomp/components/frame.rb +6 -6
  11. data/lib/onstomp/components/frame_headers.rb +18 -18
  12. data/lib/onstomp/components/scopes/transaction_scope.rb +11 -11
  13. data/lib/onstomp/components/subscription.rb +2 -2
  14. data/lib/onstomp/components/threaded_processor.rb +1 -1
  15. data/lib/onstomp/components/uri.rb +1 -1
  16. data/lib/onstomp/connections/base.rb +5 -5
  17. data/lib/onstomp/connections/heartbeating.rb +2 -2
  18. data/lib/onstomp/connections/serializers/stomp_1.rb +6 -6
  19. data/lib/onstomp/connections/serializers/stomp_1_1.rb +2 -2
  20. data/lib/onstomp/connections/stomp_1_0.rb +1 -1
  21. data/lib/onstomp/connections/stomp_1_1.rb +1 -1
  22. data/lib/onstomp/failover.rb +4 -0
  23. data/lib/onstomp/failover/buffers.rb +1 -0
  24. data/lib/onstomp/failover/buffers/receipts.rb +101 -0
  25. data/lib/onstomp/failover/buffers/written.rb +2 -2
  26. data/lib/onstomp/failover/client.rb +15 -12
  27. data/lib/onstomp/failover/failover_configurable.rb +3 -3
  28. data/lib/onstomp/failover/pools/base.rb +1 -1
  29. data/lib/onstomp/failover/uri.rb +41 -16
  30. data/lib/onstomp/interfaces/client_configurable.rb +1 -1
  31. data/lib/onstomp/interfaces/client_events.rb +30 -11
  32. data/lib/onstomp/interfaces/connection_events.rb +5 -1
  33. data/lib/onstomp/interfaces/event_manager.rb +2 -2
  34. data/lib/onstomp/interfaces/frame_methods.rb +169 -8
  35. data/lib/onstomp/interfaces/uri_configurable.rb +3 -3
  36. data/lib/onstomp/open-uri/client_extensions.rb +4 -4
  37. data/lib/onstomp/version.rb +2 -2
  38. data/onstomp.gemspec +0 -1
  39. data/spec/onstomp/components/threaded_processor_spec.rb +21 -0
  40. data/spec/onstomp/connections/base_spec.rb +15 -0
  41. data/spec/onstomp/failover/buffers/receipts_spec.rb +189 -0
  42. data/spec/onstomp/failover/buffers/written_spec.rb +167 -1
  43. data/spec/onstomp/failover/client_spec.rb +70 -1
  44. data/spec/onstomp/failover/failover_events_spec.rb +1 -2
  45. data/spec/onstomp/failover/uri_spec.rb +37 -4
  46. data/spec/onstomp/full_stacks/failover_spec.rb +76 -25
  47. data/spec/onstomp/full_stacks/onstomp_spec.rb +52 -8
  48. data/spec/onstomp/full_stacks/onstomp_ssh_spec.rb +83 -0
  49. data/spec/onstomp/full_stacks/test_broker.rb +45 -29
  50. metadata +11 -15
  51. data/DeveloperNarrative.md +0 -15
  52. data/UserNarrative.md +0 -8
@@ -66,6 +66,27 @@ module OnStomp::Components
66
66
  end
67
67
  end
68
68
 
69
+ describe ".prepare_to_close" do
70
+ it "should do nothing special if it is not running" do
71
+ processor.stub(:running? => false)
72
+ processor.prepare_to_close
73
+ end
74
+ it "should stop its worker thread, flush the connection's buffer then restart the thread" do
75
+ # ugg....
76
+ def processor.stopped?
77
+ @run_thread.stop?
78
+ end
79
+ client.stub(:connected? => true)
80
+ processor.start
81
+ connection.should_receive(:flush_write_buffer).and_return do
82
+ processor.stopped?.should be_true
83
+ nil
84
+ end
85
+ processor.prepare_to_close
86
+ processor.stopped?.should be_false
87
+ end
88
+ end
89
+
69
90
  describe ".join" do
70
91
  it "should block the current thread until connection is no longer alive" do
71
92
  joined_properly = false
@@ -94,6 +94,21 @@ module OnStomp::Connections
94
94
  end
95
95
  end
96
96
 
97
+ describe ".flush_write_buffer" do
98
+ it "should run until the buffer is empty" do
99
+ connection.stub(:connected? => true)
100
+ IO.stub(:select => true)
101
+ connection.push_write_buffer 'FRAME_SERIALIZED', frame
102
+ connection.push_write_buffer 'FRAME_SERIALIZED', frame
103
+ connection.push_write_buffer 'FRAME_SERIALIZED', frame
104
+ io.should_receive(:write_nonblock).exactly(6).times.and_return do |d|
105
+ 8
106
+ end
107
+ connection.flush_write_buffer
108
+ connection.shift_write_buffer.should be_nil
109
+ end
110
+ end
111
+
97
112
  describe ".io_process_write" do
98
113
  it "should not write if the buffer is empty" do
99
114
  io.should_not_receive :write_nonblock
@@ -0,0 +1,189 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require 'spec_helper'
3
+
4
+ module OnStomp::Failover::Buffers
5
+ describe Receipts, :failover => true do
6
+ let(:clients) {
7
+ ['client 1', 'client 2', 'client 3'].map do |c|
8
+ mock(c).tap do |m|
9
+ m.extend OnStomp::Interfaces::ClientEvents
10
+ end
11
+ end
12
+ }
13
+ let(:active_client) { clients.first }
14
+ let(:failover) {
15
+ mock('failover client', :client_pool => clients,
16
+ :active_client => active_client).tap do |m|
17
+ m.extend OnStomp::Failover::FailoverEvents
18
+ end
19
+ }
20
+ let(:buffer) {
21
+ Receipts.new failover
22
+ }
23
+ let(:partial_transaction) {
24
+ [
25
+ OnStomp::Components::Frame.new('BEGIN', :transaction => 't-1234'),
26
+ OnStomp::Components::Frame.new('SEND', {:transaction => 't-1234'}, 'message 1'),
27
+ OnStomp::Components::Frame.new('SEND', {:transaction => 't-1234'}, 'message 2'),
28
+ OnStomp::Components::Frame.new('ACK', {:transaction => 't-1234',
29
+ :'message-id' => 'm-99991'}),
30
+ OnStomp::Components::Frame.new('SEND', {:transaction => 't-1234'}, 'message 3'),
31
+ ]
32
+ }
33
+
34
+ def receipt_for frame
35
+ raise "frame does not have a receipt header" unless frame.header?(:receipt)
36
+ OnStomp::Components::Frame.new 'RECEIPT', :'receipt-id' => frame[:receipt]
37
+ end
38
+
39
+ describe "basic replaying" do
40
+ before(:each) do
41
+ buffer
42
+ end
43
+ ['ACK', 'NACK'].each do |command|
44
+ it "should not replay #{command} frames" do
45
+ frame = OnStomp::Components::Frame.new command
46
+ active_client.trigger_before_transmitting frame
47
+ active_client.should_not_receive(:transmit)
48
+ failover.trigger_failover_event :connected, clients.first
49
+ end
50
+ end
51
+ it "should attach a receipt header to frames lacking one" do
52
+ frame = OnStomp::Components::Frame.new 'SEND',
53
+ { :destination => '/queue/test' }, 'body of message'
54
+ active_client.trigger_before_transmitting frame
55
+ frame.header?(:receipt).should be_true
56
+ end
57
+ it "should not molest existing receipt headeres" do
58
+ frame = OnStomp::Components::Frame.new 'SUBSCRIBE',
59
+ { :destination => '/queue/test', :receipt => 'r-1234' }
60
+ active_client.trigger_before_transmitting frame
61
+ frame[:receipt].should == 'r-1234'
62
+ end
63
+ it "should replay SEND frames" do
64
+ frame = OnStomp::Components::Frame.new 'SEND',
65
+ { :destination => '/queue/test' }, 'body of message'
66
+ active_client.trigger_before_transmitting frame
67
+ active_client.should_receive(:transmit).with(an_onstomp_frame(
68
+ 'SEND', {:destination => '/queue/test'}, 'body of message'))
69
+ failover.trigger_failover_event :connected, :on, clients.first
70
+ end
71
+ it "should debuffer non-transactional SEND frames" do
72
+ frame = OnStomp::Components::Frame.new 'SEND',
73
+ { :destination => '/queue/test' }, 'body of message'
74
+ active_client.trigger_before_transmitting frame
75
+ active_client.trigger_after_receiving receipt_for(frame)
76
+ active_client.should_not_receive(:transmit)
77
+ failover.trigger_failover_event :connected, :on, clients.first
78
+ end
79
+ it "should replay SUBSCRIBE frames, even receipted ones" do
80
+ frame = OnStomp::Components::Frame.new 'SUBSCRIBE',
81
+ { :destination => '/queue/test', :id => 's-1234' }
82
+ active_client.trigger_before_transmitting frame
83
+ active_client.trigger_after_receiving receipt_for(frame)
84
+ active_client.should_receive(:transmit).with(an_onstomp_frame(
85
+ 'SUBSCRIBE', {:destination => '/queue/test', :id => 's-1234'}))
86
+ failover.trigger_failover_event :connected, :on, clients.first
87
+ end
88
+ it "should debuffer SUBSCRIBE frames as soon as UNSUBSCRIBE is in the write buffer (does not need to be receipted)" do
89
+ frame = OnStomp::Components::Frame.new 'SUBSCRIBE',
90
+ { :destination => '/queue/test', :id => 's-1234' }
91
+ active_client.trigger_before_transmitting frame
92
+ active_client.trigger_after_transmitting frame
93
+ frame = OnStomp::Components::Frame.new 'UNSUBSCRIBE', :id => 's-1234'
94
+ active_client.trigger_before_transmitting frame
95
+ active_client.should_not_receive :transmit
96
+ failover.trigger_failover_event :connected, :on, clients.first
97
+ end
98
+ it "should not debuffer incomplete transactions" do
99
+ replayed = []
100
+ partial_transaction.each do |f|
101
+ active_client.trigger_before_transmitting f
102
+ active_client.trigger_after_transmitting f
103
+ end
104
+ active_client.stub(:transmit).and_return { |f| replayed << f; f }
105
+ failover.trigger_failover_event :connected, :on, clients.first
106
+ replayed.should == partial_transaction.reject { |f| ['ACK', 'NACK'].include? f.command }
107
+ end
108
+ ['ABORT', 'COMMIT'].each do |trans_fin|
109
+ it "should not debuffer transactions when #{trans_fin} is only buffered" do
110
+ fin_frame = OnStomp::Components::Frame.new trans_fin, {:transaction => 't-1234'}
111
+ replayed = []
112
+ partial_transaction.each do |f|
113
+ active_client.trigger_before_transmitting f
114
+ active_client.trigger_after_transmitting f
115
+ end
116
+ active_client.trigger_before_transmitting fin_frame
117
+ active_client.stub(:transmit).and_return { |f| replayed << f; f }
118
+ failover.trigger_failover_event :connected, :on, clients.first
119
+ replayed.should ==
120
+ (partial_transaction.reject { |f| ['ACK', 'NACK'].include? f.command } +
121
+ [fin_frame])
122
+ end
123
+ it "should debuffer a transaction when #{trans_fin} has been written" do
124
+ fin_frame = OnStomp::Components::Frame.new trans_fin, {:transaction => 't-1234'}
125
+ replayed = []
126
+ partial_transaction.each do |f|
127
+ active_client.trigger_before_transmitting f
128
+ active_client.trigger_after_transmitting f
129
+ end
130
+ active_client.trigger_before_transmitting fin_frame
131
+ active_client.trigger_after_receiving receipt_for(fin_frame)
132
+ active_client.stub(:transmit).and_return { |f| replayed << f; f }
133
+ failover.trigger_failover_event :connected, :on, clients.first
134
+ replayed.should be_empty
135
+ end
136
+ end
137
+ end
138
+
139
+ describe "replaying while you replay (Xzibit Approved)" do
140
+ let(:frame_list) {
141
+ [
142
+ OnStomp::Components::Frame.new('SEND', {:destination => '/queue/test'}, 'message 1'),
143
+ OnStomp::Components::Frame.new('SUBSCRIBE', :id => 's-1234', :destination => '/queue/test'),
144
+ OnStomp::Components::Frame.new('BEGIN', :transaction => 't-1234'),
145
+ OnStomp::Components::Frame.new('NACK', :'message-id' => 'm-99992'),
146
+ OnStomp::Components::Frame.new('SEND', {:transaction => 't-1234'}, 'message 2'),
147
+ OnStomp::Components::Frame.new('ACK', :'message-id' => 'm-99993'),
148
+ OnStomp::Components::Frame.new('SEND', {:transaction => 't-1234'}, 'message 3'),
149
+ OnStomp::Components::Frame.new('UNSUBSCRIBE', :id => 's-1234'),
150
+ OnStomp::Components::Frame.new('SUBSCRIBE', :id => 's-5678', :destination => '/queue/test'),
151
+ OnStomp::Components::Frame.new('ACK', {:transaction => 't-1234',
152
+ :'message-id' => 'm-99991'}),
153
+ OnStomp::Components::Frame.new('SEND', {:transaction => 't-1234'}, 'message 4'),
154
+ ]
155
+ }
156
+ let(:expected_replay) {
157
+ frame_list.reject do |f|
158
+ ['ACK', 'NACK'].include?(f.command) || f[:id] == 's-1234'
159
+ end
160
+ }
161
+ let(:client1_frames) { [] }
162
+ let(:client3_frames) { [] }
163
+ before(:each) do
164
+ buffer
165
+ frame_list.each do |f|
166
+ active_client.trigger_before_transmitting f
167
+ end
168
+ end
169
+ it "should replay properly if failover reconnects while replaying" do
170
+ extra_frame = OnStomp::Components::Frame.new 'SEND',
171
+ {:destination => '/queue/test'}, 'yet another freaking message'
172
+ clients.last.stub(:transmit).and_return { |f| client3_frames << f; f }
173
+ active_client.stub(:transmit).and_return do |f|
174
+ client1_frames << f
175
+ if f.command == 'BEGIN'
176
+ # Add a fresh frame to the buffer
177
+ active_client.trigger_before_transmitting extra_frame
178
+ # Signal the a reconnect in the midst of replaying.
179
+ failover.trigger_failover_event :connected, :on, clients.last
180
+ end
181
+ f
182
+ end
183
+ failover.trigger_failover_event :connected, :on, active_client
184
+ client1_frames.should == expected_replay
185
+ client3_frames.should == expected_replay + [extra_frame]
186
+ end
187
+ end
188
+ end
189
+ end
@@ -3,6 +3,172 @@ require 'spec_helper'
3
3
 
4
4
  module OnStomp::Failover::Buffers
5
5
  describe Written, :failover => true do
6
-
6
+ let(:clients) {
7
+ ['client 1', 'client 2', 'client 3'].map do |c|
8
+ mock(c).tap do |m|
9
+ m.extend OnStomp::Interfaces::ClientEvents
10
+ end
11
+ end
12
+ }
13
+ let(:active_client) { clients.first }
14
+ let(:failover) {
15
+ mock('failover client', :client_pool => clients,
16
+ :active_client => active_client).tap do |m|
17
+ m.extend OnStomp::Failover::FailoverEvents
18
+ end
19
+ }
20
+ let(:buffer) {
21
+ Written.new failover
22
+ }
23
+ let(:partial_transaction) {
24
+ [
25
+ OnStomp::Components::Frame.new('BEGIN', :transaction => 't-1234'),
26
+ OnStomp::Components::Frame.new('SEND', {:transaction => 't-1234'}, 'message 1'),
27
+ OnStomp::Components::Frame.new('SEND', {:transaction => 't-1234'}, 'message 2'),
28
+ OnStomp::Components::Frame.new('ACK', {:transaction => 't-1234',
29
+ :'message-id' => 'm-99991'}),
30
+ OnStomp::Components::Frame.new('SEND', {:transaction => 't-1234'}, 'message 3'),
31
+ ]
32
+ }
33
+
34
+ describe "basic replaying" do
35
+ before(:each) do
36
+ buffer
37
+ end
38
+ ['ACK', 'NACK'].each do |command|
39
+ it "should not replay #{command} frames" do
40
+ frame = OnStomp::Components::Frame.new command
41
+ active_client.trigger_before_transmitting frame
42
+ active_client.should_not_receive(:transmit)
43
+ failover.trigger_failover_event :connected, clients.first
44
+ end
45
+ end
46
+ it "should replay SEND frames" do
47
+ frame = OnStomp::Components::Frame.new 'SEND',
48
+ { :destination => '/queue/test' }, 'body of message'
49
+ active_client.trigger_before_transmitting frame
50
+ active_client.should_receive(:transmit).with(an_onstomp_frame(
51
+ 'SEND', {:destination => '/queue/test'}, 'body of message'))
52
+ failover.trigger_failover_event :connected, :on, clients.first
53
+ end
54
+ it "should debuffer non-transactional SEND frames" do
55
+ frame = OnStomp::Components::Frame.new 'SEND',
56
+ { :destination => '/queue/test' }, 'body of message'
57
+ active_client.trigger_before_transmitting frame
58
+ active_client.trigger_after_transmitting frame
59
+ active_client.should_not_receive(:transmit)
60
+ failover.trigger_failover_event :connected, :on, clients.first
61
+ end
62
+ it "should replay SUBSCRIBE frames, even fully written ones" do
63
+ frame = OnStomp::Components::Frame.new 'SUBSCRIBE',
64
+ { :destination => '/queue/test', :id => 's-1234' }
65
+ active_client.trigger_before_transmitting frame
66
+ active_client.trigger_after_transmitting frame
67
+ active_client.should_receive(:transmit).with(an_onstomp_frame(
68
+ 'SUBSCRIBE', {:destination => '/queue/test', :id => 's-1234'}))
69
+ failover.trigger_failover_event :connected, :on, clients.first
70
+ end
71
+ it "should debuffer SUBSCRIBE frames as soon as UNSUBSCRIBE is in the write buffer (does not need to be fully written)" do
72
+ frame = OnStomp::Components::Frame.new 'SUBSCRIBE',
73
+ { :destination => '/queue/test', :id => 's-1234' }
74
+ active_client.trigger_before_transmitting frame
75
+ active_client.trigger_after_transmitting frame
76
+
77
+ frame = OnStomp::Components::Frame.new 'UNSUBSCRIBE', :id => 's-1234'
78
+
79
+ active_client.trigger_before_transmitting frame
80
+ active_client.should_not_receive :transmit
81
+ failover.trigger_failover_event :connected, :on, clients.first
82
+ end
83
+ it "should not debuffer incomplete transactions" do
84
+ replayed = []
85
+ partial_transaction.each do |f|
86
+ active_client.trigger_before_transmitting f
87
+ active_client.trigger_after_transmitting f
88
+ end
89
+ active_client.stub(:transmit).and_return { |f| replayed << f; f }
90
+ failover.trigger_failover_event :connected, :on, clients.first
91
+ replayed.should == partial_transaction.reject { |f| ['ACK', 'NACK'].include? f.command }
92
+ end
93
+ ['ABORT', 'COMMIT'].each do |trans_fin|
94
+ it "should not debuffer transactions when #{trans_fin} is only buffered" do
95
+ fin_frame = OnStomp::Components::Frame.new trans_fin, {:transaction => 't-1234'}
96
+ replayed = []
97
+ partial_transaction.each do |f|
98
+ active_client.trigger_before_transmitting f
99
+ active_client.trigger_after_transmitting f
100
+ end
101
+ active_client.trigger_before_transmitting fin_frame
102
+ active_client.stub(:transmit).and_return { |f| replayed << f; f }
103
+ failover.trigger_failover_event :connected, :on, clients.first
104
+ replayed.should ==
105
+ (partial_transaction.reject { |f| ['ACK', 'NACK'].include? f.command } +
106
+ [fin_frame])
107
+ end
108
+ it "should debuffer a transaction when #{trans_fin} has been written" do
109
+ fin_frame = OnStomp::Components::Frame.new trans_fin, {:transaction => 't-1234'}
110
+ replayed = []
111
+ partial_transaction.each do |f|
112
+ active_client.trigger_before_transmitting f
113
+ active_client.trigger_after_transmitting f
114
+ end
115
+ active_client.trigger_before_transmitting fin_frame
116
+ active_client.trigger_after_transmitting fin_frame
117
+ active_client.stub(:transmit).and_return { |f| replayed << f; f }
118
+ failover.trigger_failover_event :connected, :on, clients.first
119
+ replayed.should be_empty
120
+ end
121
+ end
122
+ end
123
+
124
+ describe "replaying while you replay (Xzibit Approved)" do
125
+ let(:frame_list) {
126
+ [
127
+ OnStomp::Components::Frame.new('SEND', {:destination => '/queue/test'}, 'message 1'),
128
+ OnStomp::Components::Frame.new('SUBSCRIBE', :id => 's-1234', :destination => '/queue/test'),
129
+ OnStomp::Components::Frame.new('BEGIN', :transaction => 't-1234'),
130
+ OnStomp::Components::Frame.new('NACK', :'message-id' => 'm-99992'),
131
+ OnStomp::Components::Frame.new('SEND', {:transaction => 't-1234'}, 'message 2'),
132
+ OnStomp::Components::Frame.new('ACK', :'message-id' => 'm-99993'),
133
+ OnStomp::Components::Frame.new('SEND', {:transaction => 't-1234'}, 'message 3'),
134
+ OnStomp::Components::Frame.new('UNSUBSCRIBE', :id => 's-1234'),
135
+ OnStomp::Components::Frame.new('SUBSCRIBE', :id => 's-5678', :destination => '/queue/test'),
136
+ OnStomp::Components::Frame.new('ACK', {:transaction => 't-1234',
137
+ :'message-id' => 'm-99991'}),
138
+ OnStomp::Components::Frame.new('SEND', {:transaction => 't-1234'}, 'message 4'),
139
+ ]
140
+ }
141
+ let(:expected_replay) {
142
+ frame_list.reject do |f|
143
+ ['ACK', 'NACK'].include?(f.command) || f[:id] == 's-1234'
144
+ end
145
+ }
146
+ let(:client1_frames) { [] }
147
+ let(:client3_frames) { [] }
148
+ before(:each) do
149
+ buffer
150
+ frame_list.each do |f|
151
+ active_client.trigger_before_transmitting f
152
+ end
153
+ end
154
+ it "should replay properly if failover reconnects while replaying" do
155
+ extra_frame = OnStomp::Components::Frame.new 'SEND',
156
+ {:destination => '/queue/test'}, 'yet another freaking message'
157
+ clients.last.stub(:transmit).and_return { |f| client3_frames << f; f }
158
+ active_client.stub(:transmit).and_return do |f|
159
+ client1_frames << f
160
+ if f.command == 'BEGIN'
161
+ # Add a fresh frame to the buffer
162
+ active_client.trigger_before_transmitting extra_frame
163
+ # Signal the a reconnect in the midst of replaying.
164
+ failover.trigger_failover_event :connected, :on, clients.last
165
+ end
166
+ f
167
+ end
168
+ failover.trigger_failover_event :connected, :on, active_client
169
+ client1_frames.should == expected_replay
170
+ client3_frames.should == expected_replay + [extra_frame]
171
+ end
172
+ end
7
173
  end
8
174
  end
@@ -4,7 +4,9 @@ require 'spec_helper'
4
4
  module OnStomp::Failover
5
5
  describe Client, :failover => true do
6
6
  let(:active_client) {
7
- mock('active client')
7
+ mock('active client').tap do |m|
8
+ m.extend OnStomp::Interfaces::ClientEvents
9
+ end
8
10
  }
9
11
  let(:client) {
10
12
  Client.new('failover:(stomp:///,stomp+ssl:///)').tap do |c|
@@ -26,6 +28,73 @@ module OnStomp::Failover
26
28
  end
27
29
  end
28
30
 
31
+ describe ".connect" do
32
+ it "should call reconnect" do
33
+ client.should_receive(:reconnect).and_return(true)
34
+ client.connect.should == client
35
+ end
36
+ it "should raise an maximum retries error if reconnect is false" do
37
+ client.stub(:reconnect => false)
38
+ lambda {
39
+ client.connect
40
+ }.should raise_error(OnStomp::Failover::MaximumRetriesExceededError)
41
+ end
42
+ it "should trigger :on_failover_connect_failure if connecting raises an exception" do
43
+ triggered = false
44
+ client.on_failover_connect_failure { |*_| triggered = true }
45
+ active_client.stub(:connected? => false)
46
+ active_client.should_receive(:connect).and_return do
47
+ active_client.stub(:connected? => true)
48
+ raise "find yourself a big lady"
49
+ end
50
+ client.connect
51
+ triggered.should be_true
52
+ end
53
+ end
54
+
55
+ describe ".disconnect" do
56
+ let(:connection) {
57
+ mock('connection').tap do |m|
58
+ m.extend OnStomp::Interfaces::ConnectionEvents
59
+ end
60
+ }
61
+ let(:client_pool) {
62
+ [active_client].tap do |m|
63
+ m.stub(:next_client => active_client)
64
+ end
65
+ }
66
+ before(:each) do
67
+ # Get the hooks installed on our mocks
68
+ active_client.stub(:connection => connection)
69
+ client.stub(:client_pool => client_pool)
70
+ client.__send__ :create_client_pool
71
+ end
72
+ it "should do nothing special if there is no active client" do
73
+ client.stub(:active_client => nil)
74
+ client.disconnect
75
+ end
76
+ it "should wait until the active client is ready, then call its disconnect method" do
77
+ active_client.stub(:connected? => false)
78
+ active_client.stub(:connect).and_return do
79
+ active_client.stub(:connected? => true)
80
+ end
81
+ client.connect
82
+ actual_disconnect = client.method(:disconnect)
83
+ client.stub(:disconnect).and_return do |*args|
84
+ active_client.stub(:connected? => false)
85
+ # Fire this off in a separate thread, as would be the real case
86
+ t = Thread.new do
87
+ connection.trigger_event :on_closed, active_client, connection
88
+ end
89
+ Thread.pass while t.alive?
90
+ actual_disconnect.call *args
91
+ end
92
+
93
+ active_client.should_receive(:disconnect).with(:header1 => 'value 1')
94
+ client.disconnect :header1 => 'value 1'
95
+ end
96
+ end
97
+
29
98
  describe ".transmit" do
30
99
  it "should transmit on the active client if there is one" do
31
100
  active_client.should_receive(:transmit).with('test', :coming => 'home')