onstomp 1.0.0 → 1.0.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.
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')