stomp 1.1.4 → 1.1.5

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,345 @@
1
+ require 'spec_helper'
2
+
3
+ describe Stomp::Connection do
4
+
5
+ before(:each) do
6
+ @parameters = {
7
+ :hosts => [
8
+ {:login => "login1", :passcode => "passcode1", :host => "localhost", :port => 61616, :ssl => false},
9
+ {:login => "login2", :passcode => "passcode2", :host => "remotehost", :port => 61617, :ssl => false}
10
+ ],
11
+ :initial_reconnect_delay => 0.01,
12
+ :max_reconnect_delay => 30.0,
13
+ :use_exponential_back_off => true,
14
+ :back_off_multiplier => 2,
15
+ :max_reconnect_attempts => 0,
16
+ :randomize => false,
17
+ :backup => false,
18
+ :timeout => -1,
19
+ :connect_headers => {}
20
+ }
21
+
22
+ #POG:
23
+ class Stomp::Connection
24
+ def _receive( s )
25
+ end
26
+ end
27
+
28
+ # clone() does a shallow copy, we want a deep one so we can garantee the hosts order
29
+ normal_parameters = Marshal::load(Marshal::dump(@parameters))
30
+
31
+ @tcp_socket = mock(:tcp_socket, :close => nil, :puts => nil, :write => nil)
32
+ TCPSocket.stub!(:open).and_return @tcp_socket
33
+ @connection = Stomp::Connection.new(normal_parameters)
34
+ end
35
+
36
+ describe "(created using a hash)" do
37
+ it "should uncamelize and symbolize the main hash keys" do
38
+ used_hash = {
39
+ "hosts" => [
40
+ {:login => "login2", :passcode => "passcode2", :host => "remotehost", :port => 61617, :ssl => false},
41
+ {:login => "login1", :passcode => "passcode1", :host => "localhost", :port => 61616, :ssl => false}
42
+ ],
43
+ "initialReconnectDelay" => 0.01,
44
+ "maxReconnectDelay" => 30.0,
45
+ "useExponentialBackOff" => true,
46
+ "backOffMultiplier" => 2,
47
+ "maxReconnectAttempts" => 0,
48
+ "randomize" => false,
49
+ "backup" => false,
50
+ "timeout" => -1
51
+ }
52
+
53
+ @connection = Stomp::Connection.new(used_hash)
54
+ @connection.instance_variable_get(:@parameters).should == @parameters
55
+ end
56
+
57
+ it "should be reliable" do
58
+ @connection.instance_variable_get(:@reliable).should be_true
59
+ end
60
+ it "should start with first host in array" do
61
+ @connection.instance_variable_get(:@host).should == "localhost"
62
+ end
63
+
64
+ it "should change host to next one with randomize false" do
65
+ @connection.change_host
66
+ @connection.instance_variable_get(:@host).should == "remotehost"
67
+ end
68
+
69
+ it "should use default port (61613) if none is given" do
70
+ hash = {:hosts => [{:login => "login2", :passcode => "passcode2", :host => "remotehost", :ssl => false}]}
71
+ @connection = Stomp::Connection.new hash
72
+ @connection.instance_variable_get(:@port).should == 61613
73
+ end
74
+
75
+ context "when dealing with content-length header" do
76
+ it "should not suppress it when receiving :suppress_content_length => false" do
77
+ @tcp_socket.should_receive(:puts).with("content-length:7")
78
+ @connection.publish "/queue", "message", :suppress_content_length => false
79
+ end
80
+
81
+ it "should not suppress it when :suppress_content_length is nil" do
82
+ @tcp_socket.should_receive(:puts).with("content-length:7")
83
+ @connection.publish "/queue", "message"
84
+ end
85
+
86
+ it "should suppress it when receiving :suppress_content_length => true" do
87
+ @tcp_socket.should_not_receive(:puts).with("content-length:7")
88
+ @connection.publish "/queue", "message", :suppress_content_length => true
89
+ end
90
+ end
91
+
92
+ describe "when unacknowledging a message" do
93
+
94
+ before :each do
95
+ @message = Stomp::Message.new(nil)
96
+ @message.body = "message body"
97
+ @message.headers = {"destination" => "/queue/original", "message-id" => "ID"}
98
+
99
+ @transaction_id = "transaction-#{@message.headers["message-id"]}-0"
100
+
101
+ @retry_headers = {
102
+ :destination => @message.headers["destination"],
103
+ :transaction => @transaction_id,
104
+ :retry_count => 1
105
+ }
106
+ end
107
+
108
+ it "should use a transaction" do
109
+ @connection.should_receive(:begin).with(@transaction_id).ordered
110
+ @connection.should_receive(:commit).with(@transaction_id).ordered
111
+ @connection.unreceive @message
112
+ end
113
+
114
+ it "should acknowledge the original message if ack mode is client" do
115
+ @connection.should_receive(:ack).with(@message.headers["message-id"], :transaction => @transaction_id)
116
+ @connection.subscribe(@message.headers["destination"], :ack => "client")
117
+ @connection.unreceive @message
118
+ end
119
+
120
+ it "should acknowledge the original message if forced" do
121
+ @connection.subscribe(@message.headers["destination"])
122
+ @connection.should_receive(:ack)
123
+ @connection.unreceive(@message, :force_client_ack => true)
124
+ end
125
+
126
+ it "should not acknowledge the original message if ack mode is not client or it did not subscribe to the queue" do
127
+ @connection.subscribe(@message.headers["destination"], :ack => "client")
128
+ @connection.should_receive(:ack)
129
+ @connection.unreceive @message
130
+
131
+ # At this time the message headers are symbolized
132
+ @connection.unsubscribe(@message.headers[:destination])
133
+ @connection.should_not_receive(:ack)
134
+ @connection.unreceive @message
135
+ @connection.subscribe(@message.headers[:destination], :ack => "individual")
136
+ @connection.unreceive @message
137
+ end
138
+
139
+ it "should send the message back to the queue it came" do
140
+ @connection.subscribe(@message.headers["destination"], :ack => "client")
141
+ @connection.should_receive(:publish).with(@message.headers["destination"], @message.body, @retry_headers)
142
+ @connection.unreceive @message
143
+ end
144
+
145
+ it "should increment the retry_count header" do
146
+ @message.headers["retry_count"] = 4
147
+ @connection.unreceive @message
148
+ @message.headers[:retry_count].should == 5
149
+ end
150
+
151
+ it "should not send the message to the dead letter queue as persistent if redeliveries equal max redeliveries" do
152
+ max_redeliveries = 5
153
+ dead_letter_queue = "/queue/Dead"
154
+
155
+ @message.headers["retry_count"] = max_redeliveries
156
+ transaction_id = "transaction-#{@message.headers["message-id"]}-#{@message.headers["retry_count"]}"
157
+ @retry_headers = @retry_headers.merge :transaction => transaction_id, :retry_count => @message.headers["retry_count"] + 1
158
+ @connection.should_receive(:publish).with(@message.headers["destination"], @message.body, @retry_headers)
159
+ @connection.unreceive @message, :dead_letter_queue => dead_letter_queue, :max_redeliveries => max_redeliveries
160
+ end
161
+
162
+ it "should send the message to the dead letter queue as persistent if max redeliveries have been reached" do
163
+ max_redeliveries = 5
164
+ dead_letter_queue = "/queue/Dead"
165
+
166
+ @message.headers["retry_count"] = max_redeliveries + 1
167
+ transaction_id = "transaction-#{@message.headers["message-id"]}-#{@message.headers["retry_count"]}"
168
+ @retry_headers = @retry_headers.merge :persistent => true, :transaction => transaction_id, :retry_count => @message.headers["retry_count"] + 1, :original_destination=> @message.headers["destination"]
169
+ @connection.should_receive(:publish).with(dead_letter_queue, @message.body, @retry_headers)
170
+ @connection.unreceive @message, :dead_letter_queue => dead_letter_queue, :max_redeliveries => max_redeliveries
171
+ end
172
+
173
+ it "should rollback the transaction and raise the exception if happened during transaction" do
174
+ @connection.should_receive(:publish).and_raise "Error"
175
+ @connection.should_receive(:abort).with(@transaction_id)
176
+ lambda {@connection.unreceive @message}.should raise_error("Error")
177
+ end
178
+
179
+ end
180
+
181
+ describe "when using ssl" do
182
+
183
+ # Mocking ruby's openssl extension, so we can test without requiring openssl
184
+ module ::OpenSSL
185
+ module SSL
186
+ VERIFY_NONE = 0
187
+
188
+ class SSLSocket
189
+ end
190
+
191
+ class SSLContext
192
+ attr_accessor :verify_mode
193
+ end
194
+ end
195
+ end
196
+
197
+ before(:each) do
198
+ ssl_parameters = {:hosts => [{:login => "login2", :passcode => "passcode2", :host => "remotehost", :ssl => true}]}
199
+ @ssl_socket = mock(:ssl_socket, :puts => nil, :write => nil)
200
+
201
+ TCPSocket.should_receive(:open).and_return @tcp_socket
202
+ OpenSSL::SSL::SSLSocket.should_receive(:new).and_return(@ssl_socket)
203
+ @ssl_socket.should_receive(:connect)
204
+
205
+ @connection = Stomp::Connection.new ssl_parameters
206
+ end
207
+
208
+ it "should use ssl socket if ssl use is enabled" do
209
+ @connection.instance_variable_get(:@socket).should == @ssl_socket
210
+ end
211
+
212
+ it "should use default port for ssl (61612) if none is given" do
213
+ @connection.instance_variable_get(:@port).should == 61612
214
+ end
215
+
216
+ end
217
+
218
+ describe "when called to increase reconnect delay" do
219
+ it "should exponentialy increase when use_exponential_back_off is true" do
220
+ @connection.increase_reconnect_delay.should == 0.02
221
+ @connection.increase_reconnect_delay.should == 0.04
222
+ @connection.increase_reconnect_delay.should == 0.08
223
+ end
224
+ it "should not increase when use_exponential_back_off is false" do
225
+ @parameters[:use_exponential_back_off] = false
226
+ @connection = Stomp::Connection.new(@parameters)
227
+ @connection.increase_reconnect_delay.should == 0.01
228
+ @connection.increase_reconnect_delay.should == 0.01
229
+ end
230
+ it "should not increase when max_reconnect_delay is reached" do
231
+ @parameters[:initial_reconnect_delay] = 8.0
232
+ @connection = Stomp::Connection.new(@parameters)
233
+ @connection.increase_reconnect_delay.should == 16.0
234
+ @connection.increase_reconnect_delay.should == 30.0
235
+ end
236
+
237
+ it "should change to next host on socket error" do
238
+ @connection.instance_variable_set(:@failure, "some exception")
239
+ #retries the same host
240
+ TCPSocket.should_receive(:open).and_raise "exception"
241
+ #tries the new host
242
+ TCPSocket.should_receive(:open).and_return @tcp_socket
243
+
244
+ @connection.socket
245
+ @connection.instance_variable_get(:@host).should == "remotehost"
246
+ end
247
+
248
+ it "should use default options if those where not given" do
249
+ expected_hash = {
250
+ :hosts => [
251
+ {:login => "login2", :passcode => "passcode2", :host => "remotehost", :port => 61617, :ssl => false},
252
+ # Once connected the host is sent to the end of array
253
+ {:login => "login1", :passcode => "passcode1", :host => "localhost", :port => 61616, :ssl => false}
254
+ ],
255
+ :initial_reconnect_delay => 0.01,
256
+ :max_reconnect_delay => 30.0,
257
+ :use_exponential_back_off => true,
258
+ :back_off_multiplier => 2,
259
+ :max_reconnect_attempts => 0,
260
+ :randomize => false,
261
+ :backup => false,
262
+ :timeout => -1,
263
+ :connect_headers => {}
264
+ }
265
+
266
+ used_hash = {
267
+ :hosts => [
268
+ {:login => "login1", :passcode => "passcode1", :host => "localhost", :port => 61616, :ssl => false},
269
+ {:login => "login2", :passcode => "passcode2", :host => "remotehost", :port => 61617, :ssl => false}
270
+ ]
271
+ }
272
+
273
+ @connection = Stomp::Connection.new(used_hash)
274
+ @connection.instance_variable_get(:@parameters).should == expected_hash
275
+ end
276
+
277
+ it "should use the given options instead of default ones" do
278
+ used_hash = {
279
+ :hosts => [
280
+ {:login => "login2", :passcode => "passcode2", :host => "remotehost", :port => 61617, :ssl => false},
281
+ {:login => "login1", :passcode => "passcode1", :host => "localhost", :port => 61616, :ssl => false}
282
+ ],
283
+ :initial_reconnect_delay => 5.0,
284
+ :max_reconnect_delay => 100.0,
285
+ :use_exponential_back_off => false,
286
+ :back_off_multiplier => 3,
287
+ :max_reconnect_attempts => 10,
288
+ :randomize => true,
289
+ :backup => false,
290
+ :timeout => -1,
291
+ :connect_headers => {:lerolero => "ronaldo"},
292
+ :dead_letter_queue => "queue/Error",
293
+ :max_redeliveries => 10
294
+ }
295
+
296
+ @connection = Stomp::Connection.new(used_hash)
297
+ received_hash = @connection.instance_variable_get(:@parameters)
298
+
299
+ #Using randomize we can't assure the hosts order
300
+ received_hash.delete(:hosts)
301
+ used_hash.delete(:hosts)
302
+
303
+ received_hash.should == used_hash
304
+ end
305
+
306
+ end
307
+
308
+ end
309
+
310
+ describe "when closing a socket" do
311
+ it "should close the tcp connection" do
312
+ @tcp_socket.should_receive(:close)
313
+ @connection.obj_send(:close_socket).should be_true
314
+ end
315
+ it "should ignore exceptions" do
316
+ @tcp_socket.should_receive(:close).and_raise "exception"
317
+ @connection.obj_send(:close_socket).should be_true
318
+ end
319
+ end
320
+
321
+ describe "when checking if max reconnect attempts have been reached" do
322
+ it "should return false if not using failover" do
323
+ host = @parameters[:hosts][0]
324
+ @connection = Stomp::Connection.new(host[:login], host[:passcode], host[:host], host[:port], reliable = true, 5, connect_headers = {})
325
+ @connection.instance_variable_set(:@connection_attempts, 10000)
326
+ @connection.max_reconnect_attempts?.should be_false
327
+ end
328
+ it "should return false if max_reconnect_attempts = 0" do
329
+ @connection.instance_variable_set(:@connection_attempts, 10000)
330
+ @connection.max_reconnect_attempts?.should be_false
331
+ end
332
+ it "should return true if connection attempts > max_reconnect_attempts" do
333
+ limit = 10000
334
+ @parameters[:max_reconnect_attempts] = limit
335
+ @connection = Stomp::Connection.new(@parameters)
336
+
337
+ @connection.instance_variable_set(:@connection_attempts, limit)
338
+ @connection.max_reconnect_attempts?.should be_false
339
+
340
+ @connection.instance_variable_set(:@connection_attempts, limit+1)
341
+ @connection.max_reconnect_attempts?.should be_true
342
+ end
343
+ end
344
+ end
345
+
@@ -0,0 +1,56 @@
1
+ require 'spec_helper'
2
+
3
+ describe Stomp::Message do
4
+
5
+ context 'when initializing a new message' do
6
+
7
+ context 'with invalid parameters' do
8
+ it 'should return an empty message when receiving an empty string or nil parameter' do
9
+ message = Stomp::Message.new('')
10
+ message.should be_empty
11
+ end
12
+
13
+ it 'should raise Stomp::Error::InvalidFormat when receiving a invalid formated message' do
14
+ lambda{ Stomp::Message.new('any invalid format') }.should raise_error(Stomp::Error::InvalidFormat)
15
+ end
16
+ end
17
+
18
+ context 'with valid parameters' do
19
+ subject do
20
+ @message = ["CONNECTED\n", "session:host_address\n", "\n", "body value\n", "\000\n"]
21
+ Stomp::Message.new(@message.join)
22
+ end
23
+
24
+ it 'should parse the headers' do
25
+ subject.headers.should == {'session' => 'host_address'}
26
+ end
27
+
28
+ it 'should parse the body' do
29
+ subject.body.should == @message[3]
30
+ end
31
+
32
+ it 'should parse the command' do
33
+ subject.command.should == @message[0].chomp
34
+ end
35
+ end
36
+
37
+ context 'with multiple line ends on the body' do
38
+ subject do
39
+ @message = ["CONNECTED\n", "session:host_address\n", "\n", "body\n\n value\n\n\n", "\000\n"]
40
+ Stomp::Message.new(@message.join)
41
+ end
42
+
43
+ it 'should parse the headers' do
44
+ subject.headers.should == {'session' => 'host_address'}
45
+ end
46
+
47
+ it 'should parse the body' do
48
+ subject.body.should == @message[3]
49
+ end
50
+
51
+ it 'should parse the command' do
52
+ subject.command.should == @message[0].chomp
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,14 @@
1
+ begin
2
+ require 'spec'
3
+ rescue LoadError
4
+ require 'rubygems'
5
+ #gem 'rspec'
6
+ require 'spec'
7
+ end
8
+
9
+ dir = File.dirname(__FILE__)
10
+ lib_path = File.expand_path("#{dir}/../lib")
11
+ $LOAD_PATH.unshift lib_path unless $LOAD_PATH.include?(lib_path)
12
+
13
+ require 'stomp'
14
+
data/stomp.gemspec ADDED
@@ -0,0 +1,78 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{stomp}
8
+ s.version = "1.1.5"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Brian McCallister", "Marius Mathiesen", "Thiago Morello"]
12
+ s.date = %q{2010-03-17}
13
+ s.description = %q{Ruby client for the Stomp messaging protocol}
14
+ s.email = ["brianm@apache.org", "marius@stones.com", "morellon@gmail.com"]
15
+ s.executables = ["catstomp", "stompcat"]
16
+ s.extra_rdoc_files = [
17
+ "LICENSE",
18
+ "README.rdoc"
19
+ ]
20
+ s.files = [
21
+ ".gitignore",
22
+ "CHANGELOG.rdoc",
23
+ "LICENSE",
24
+ "README.rdoc",
25
+ "Rakefile",
26
+ "bin/catstomp",
27
+ "bin/stompcat",
28
+ "examples/consumer.rb",
29
+ "examples/publisher.rb",
30
+ "lib/stomp.rb",
31
+ "lib/stomp/client.rb",
32
+ "lib/stomp/connection.rb",
33
+ "lib/stomp/errors.rb",
34
+ "lib/stomp/ext/hash.rb",
35
+ "lib/stomp/message.rb",
36
+ "lib/stomp/version.rb",
37
+ "spec/client_shared_examples.rb",
38
+ "spec/client_spec.rb",
39
+ "spec/connection_spec.rb",
40
+ "spec/message_spec.rb",
41
+ "spec/spec_helper.rb",
42
+ "stomp.gemspec",
43
+ "test/test_client.rb",
44
+ "test/test_connection.rb",
45
+ "test/test_helper.rb"
46
+ ]
47
+ s.homepage = %q{http://stomp.codehaus.org/}
48
+ s.rdoc_options = ["--charset=UTF-8"]
49
+ s.require_paths = ["lib"]
50
+ s.rubygems_version = %q{1.3.5}
51
+ s.summary = %q{Ruby client for the Stomp messaging protocol}
52
+ s.test_files = [
53
+ "spec/client_shared_examples.rb",
54
+ "spec/client_spec.rb",
55
+ "spec/connection_spec.rb",
56
+ "spec/message_spec.rb",
57
+ "spec/spec_helper.rb",
58
+ "test/test_client.rb",
59
+ "test/test_connection.rb",
60
+ "test/test_helper.rb",
61
+ "examples/consumer.rb",
62
+ "examples/publisher.rb"
63
+ ]
64
+
65
+ if s.respond_to? :specification_version then
66
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
67
+ s.specification_version = 3
68
+
69
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
70
+ s.add_development_dependency(%q<rspec>, [">= 0"])
71
+ else
72
+ s.add_dependency(%q<rspec>, [">= 0"])
73
+ end
74
+ else
75
+ s.add_dependency(%q<rspec>, [">= 0"])
76
+ end
77
+ end
78
+