stomper 1.0.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +5 -0
- data/{spec/spec.opts → .rspec} +0 -2
- data/Gemfile +4 -0
- data/LICENSE +201 -201
- data/README.md +130 -0
- data/Rakefile +5 -0
- data/examples/basic.rb +38 -0
- data/examples/events.rb +54 -0
- data/features/acking_messages.feature +147 -0
- data/features/disconnecting.feature +12 -0
- data/features/establish_connection.feature +44 -0
- data/features/protocol_version_negotiation.feature +61 -0
- data/features/receipts.feature +72 -0
- data/features/scopes.feature +32 -0
- data/features/secure_connections.feature +38 -0
- data/features/send_and_message.feature +28 -0
- data/features/steps/acking_messages_steps.rb +39 -0
- data/features/steps/disconnecting_steps.rb +8 -0
- data/features/steps/establish_connection_steps.rb +74 -0
- data/features/steps/frame_transmission_steps.rb +35 -0
- data/features/steps/protocol_version_negotiation_steps.rb +15 -0
- data/features/steps/receipts_steps.rb +79 -0
- data/features/steps/scopes_steps.rb +52 -0
- data/features/steps/secure_connections_steps.rb +41 -0
- data/features/steps/send_and_message_steps.rb +35 -0
- data/features/steps/subscribing_steps.rb +36 -0
- data/features/steps/threaded_receiver_steps.rb +8 -0
- data/features/steps/transactions_steps.rb +0 -0
- data/features/subscribing.feature +151 -0
- data/features/support/env.rb +11 -0
- data/features/support/header_helpers.rb +12 -0
- data/features/support/ssl/README +6 -0
- data/features/support/ssl/broker_cert.csr +17 -0
- data/features/support/ssl/broker_cert.pem +72 -0
- data/features/support/ssl/broker_key.pem +27 -0
- data/features/support/ssl/client_cert.csr +17 -0
- data/features/support/ssl/client_cert.pem +72 -0
- data/features/support/ssl/client_key.pem +27 -0
- data/features/support/ssl/demoCA/cacert.pem +17 -0
- data/features/support/ssl/demoCA/index.txt +2 -0
- data/features/support/ssl/demoCA/index.txt.attr +1 -0
- data/features/support/ssl/demoCA/index.txt.attr.old +1 -0
- data/features/support/ssl/demoCA/index.txt.old +1 -0
- data/features/support/ssl/demoCA/newcerts/01.pem +72 -0
- data/features/support/ssl/demoCA/newcerts/02.pem +72 -0
- data/features/support/ssl/demoCA/private/cakey.pem +17 -0
- data/features/support/ssl/demoCA/serial +1 -0
- data/features/support/ssl/demoCA/serial.old +1 -0
- data/features/support/test_stomp_server.rb +150 -0
- data/features/threaded_receiver.feature +11 -0
- data/features/transactions.feature +66 -0
- data/lib/stomper.rb +30 -20
- data/lib/stomper/connection.rb +442 -102
- data/lib/stomper/errors.rb +59 -0
- data/lib/stomper/extensions.rb +10 -0
- data/lib/stomper/extensions/common.rb +258 -0
- data/lib/stomper/extensions/events.rb +213 -0
- data/lib/stomper/extensions/heartbeat.rb +101 -0
- data/lib/stomper/extensions/scoping.rb +56 -0
- data/lib/stomper/frame.rb +54 -0
- data/lib/stomper/frame_serializer.rb +217 -0
- data/lib/stomper/headers.rb +15 -0
- data/lib/stomper/receipt_manager.rb +36 -0
- data/lib/stomper/receivers.rb +7 -0
- data/lib/stomper/receivers/threaded.rb +71 -0
- data/lib/stomper/scopes.rb +9 -0
- data/lib/stomper/scopes/header_scope.rb +49 -0
- data/lib/stomper/scopes/receipt_scope.rb +44 -0
- data/lib/stomper/scopes/transaction_scope.rb +109 -0
- data/lib/stomper/sockets.rb +66 -28
- data/lib/stomper/subscription_manager.rb +79 -0
- data/lib/stomper/support.rb +68 -0
- data/lib/stomper/support/1.8/frame_serializer.rb +53 -0
- data/lib/stomper/support/1.8/headers.rb +183 -0
- data/lib/stomper/support/1.9/frame_serializer.rb +64 -0
- data/lib/stomper/support/1.9/headers.rb +172 -0
- data/lib/stomper/support/ruby.rb +13 -0
- data/lib/stomper/uris.rb +49 -0
- data/lib/stomper/version.rb +7 -0
- data/spec/spec_helper.rb +13 -9
- data/spec/stomper/connection_spec.rb +712 -0
- data/spec/stomper/extensions/common_spec.rb +187 -0
- data/spec/stomper/extensions/events_spec.rb +78 -0
- data/spec/stomper/extensions/heartbeat_spec.rb +103 -0
- data/spec/stomper/extensions/scoping_spec.rb +21 -0
- data/spec/stomper/frame_serializer_1.8_spec.rb +318 -0
- data/spec/stomper/frame_serializer_spec.rb +316 -0
- data/spec/stomper/frame_spec.rb +36 -0
- data/spec/stomper/headers_spec.rb +224 -0
- data/spec/stomper/receipt_manager_spec.rb +91 -0
- data/spec/stomper/receivers/threaded_spec.rb +116 -0
- data/spec/stomper/scopes/header_scope_spec.rb +42 -0
- data/spec/stomper/scopes/receipt_scope_spec.rb +51 -0
- data/spec/stomper/scopes/transaction_scope_spec.rb +183 -0
- data/spec/stomper/sockets_spec.rb +113 -0
- data/spec/stomper/subscription_manager_spec.rb +107 -0
- data/spec/stomper/support_spec.rb +69 -0
- data/spec/stomper/uris_spec.rb +54 -0
- data/spec/stomper_spec.rb +9 -0
- data/spec/support/custom_argument_matchers.rb +57 -0
- data/spec/support/existential_frame_matchers.rb +19 -0
- data/spec/support/frame_header_matchers.rb +10 -0
- data/stomper.gemspec +30 -0
- metadata +272 -97
- data/AUTHORS +0 -21
- data/CHANGELOG +0 -20
- data/README.rdoc +0 -120
- data/lib/stomper/client.rb +0 -34
- data/lib/stomper/frame_reader.rb +0 -73
- data/lib/stomper/frame_writer.rb +0 -21
- data/lib/stomper/frames.rb +0 -39
- data/lib/stomper/frames/abort.rb +0 -10
- data/lib/stomper/frames/ack.rb +0 -25
- data/lib/stomper/frames/begin.rb +0 -11
- data/lib/stomper/frames/client_frame.rb +0 -89
- data/lib/stomper/frames/commit.rb +0 -10
- data/lib/stomper/frames/connect.rb +0 -10
- data/lib/stomper/frames/connected.rb +0 -30
- data/lib/stomper/frames/disconnect.rb +0 -10
- data/lib/stomper/frames/error.rb +0 -21
- data/lib/stomper/frames/message.rb +0 -48
- data/lib/stomper/frames/receipt.rb +0 -19
- data/lib/stomper/frames/send.rb +0 -10
- data/lib/stomper/frames/server_frame.rb +0 -38
- data/lib/stomper/frames/subscribe.rb +0 -42
- data/lib/stomper/frames/unsubscribe.rb +0 -19
- data/lib/stomper/open_uri_interface.rb +0 -41
- data/lib/stomper/receipt_handlers.rb +0 -23
- data/lib/stomper/receiptor.rb +0 -38
- data/lib/stomper/subscriber.rb +0 -76
- data/lib/stomper/subscription.rb +0 -128
- data/lib/stomper/subscriptions.rb +0 -95
- data/lib/stomper/threaded_receiver.rb +0 -59
- data/lib/stomper/transaction.rb +0 -185
- data/lib/stomper/transactor.rb +0 -50
- data/lib/stomper/uri.rb +0 -55
- data/spec/client_spec.rb +0 -29
- data/spec/connection_spec.rb +0 -22
- data/spec/frame_reader_spec.rb +0 -37
- data/spec/frame_writer_spec.rb +0 -27
- data/spec/frames/client_frame_spec.rb +0 -66
- data/spec/frames/indirect_frame_spec.rb +0 -45
- data/spec/frames/server_frame_spec.rb +0 -85
- data/spec/open_uri_interface_spec.rb +0 -132
- data/spec/receiptor_spec.rb +0 -35
- data/spec/shared_connection_examples.rb +0 -79
- data/spec/subscriber_spec.rb +0 -77
- data/spec/subscription_spec.rb +0 -157
- data/spec/subscriptions_spec.rb +0 -145
- data/spec/threaded_receiver_spec.rb +0 -33
- data/spec/transaction_spec.rb +0 -139
- data/spec/transactor_spec.rb +0 -46
@@ -0,0 +1,13 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
::Stomper::Support::RUBY_SUPPORT = RUBY_VERSION >= '1.9' ? '1.9' : '1.8'
|
3
|
+
|
4
|
+
# Module for supporting Ruby 1.8.7
|
5
|
+
module Stomper::Support::Ruby1_8
|
6
|
+
end
|
7
|
+
|
8
|
+
# Module for supporting Ruby 1.9
|
9
|
+
module Stomper::Support::Ruby1_9
|
10
|
+
end
|
11
|
+
|
12
|
+
require "stomper/support/#{::Stomper::Support::RUBY_SUPPORT}/frame_serializer"
|
13
|
+
require "stomper/support/#{::Stomper::Support::RUBY_SUPPORT}/headers"
|
data/lib/stomper/uris.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
# Subclasses of URI::Generic to ease working with Stomp URIs.
|
4
|
+
module URI
|
5
|
+
# This class encapsulates a URI with a schema of "stomp". For example,
|
6
|
+
# "stomp://host.domain.tld"
|
7
|
+
class STOMP < ::URI::Generic
|
8
|
+
# Specifies the default port of a standard Stomp connection. Any URI
|
9
|
+
# without explicit port specified will use this value instead.
|
10
|
+
#
|
11
|
+
# @note The Stomp specification does not define any default ports, this port
|
12
|
+
# has been chosen because it is fairly common amongst brokers that
|
13
|
+
# provide a Stomp interface, such as Apache's ActiveMQ.
|
14
|
+
DEFAULT_PORT = 61613
|
15
|
+
|
16
|
+
# Creates a TCP socket connection to the host and port specified by
|
17
|
+
# this URI.
|
18
|
+
# @return Stomper::Sockets::TCP
|
19
|
+
def create_socket(*args)
|
20
|
+
::Stomper::Sockets::TCP.new(self.host||'localhost', self.port)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# This class encapsulates a URI with a schema of "stomp+ssl". For example,
|
25
|
+
# "stomp+ssl://host.domain.tld"
|
26
|
+
class STOMP_SSL < ::URI::STOMP
|
27
|
+
# Specifies the default port of a standard Stomp connection. Any URI
|
28
|
+
# without explicit port specified will use this value instead.
|
29
|
+
#
|
30
|
+
# @note The Stomp specification does not define any default ports, this port
|
31
|
+
# has been chosen because it is fairly common amongst brokers that
|
32
|
+
# provide a Secure Stomp interface, such as Apache's ActiveMQ.
|
33
|
+
DEFAULT_PORT = 61612
|
34
|
+
|
35
|
+
# Creates a SSL socket connection to the host and port specified by
|
36
|
+
# this URI. If a hash is included as the last argument to the call,
|
37
|
+
# it will be passed along as SSL options to {Stomper::Sockets::SSL#initialize}
|
38
|
+
# @return Stomper::Sockets::SSL
|
39
|
+
def create_socket(*args)
|
40
|
+
::Stomper::Sockets::SSL.new(self.host||'localhost', self.port,
|
41
|
+
(args.last.is_a?(Hash) ? args.pop : {}))
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Add these classes to the URI @@schemas hash, thus making URI aware
|
46
|
+
# of these two handlers.
|
47
|
+
@@schemes['STOMP'] = STOMP
|
48
|
+
@@schemes['STOMP+SSL'] = STOMP_SSL
|
49
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,16 +1,20 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
Dir[File.expand_path('support', File.dirname(__FILE__)) + "/**/*.rb"].each { |f| require f }
|
3
|
+
|
4
|
+
if RUBY_VERSION < '1.9'
|
5
|
+
class Symbol
|
6
|
+
def <=>(other)
|
7
|
+
self.to_s <=> other.to_s
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
begin
|
9
13
|
require 'simplecov'
|
10
14
|
SimpleCov.start do
|
11
15
|
add_filter "/spec/"
|
12
16
|
end
|
17
|
+
rescue LoadError
|
13
18
|
end
|
14
19
|
|
15
20
|
require 'stomper'
|
16
|
-
|
@@ -0,0 +1,712 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
module Stomper
|
5
|
+
describe Connection do
|
6
|
+
before(:each) do
|
7
|
+
@uri = mock("uri", :path => '',
|
8
|
+
:query => '',
|
9
|
+
:is_a? => true,
|
10
|
+
:host => nil,
|
11
|
+
:user => nil,
|
12
|
+
:password => nil)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should alias Stomper::Client to Stomper::Connection" do
|
16
|
+
::Stomper::Client.should == ::Stomper::Connection
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "default configuration" do
|
20
|
+
before(:each) do
|
21
|
+
@uri.stub!(:host => 'uri.host.name')
|
22
|
+
@connection = Connection.new(@uri)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should default to all supported protocol versions" do
|
26
|
+
@connection.versions.should == Stomper::Connection::PROTOCOL_VERSIONS
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should default to no heartbeating" do
|
30
|
+
@connection.heartbeats.should == [ 0, 0 ]
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should default the virtual host to the URI's host" do
|
34
|
+
@connection.host.should == 'uri.host.name'
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should have an empty login and passcode" do
|
38
|
+
@connection.login.should == ''
|
39
|
+
@connection.passcode.should == ''
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should default to a threaded receiver" do
|
43
|
+
@connection.receiver_class.should == ::Stomper::Receivers::Threaded
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should include Extensions::Common" do
|
47
|
+
@connection.should be_a_kind_of(::Stomper::Extensions::Common)
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should include Extensions::Events" do
|
51
|
+
@connection.should be_a_kind_of(::Stomper::Extensions::Events)
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should include Extensions::Heartbeat" do
|
55
|
+
@connection.should be_a_kind_of(::Stomper::Extensions::Heartbeat)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe "configuration through uri" do
|
60
|
+
before(:each) do
|
61
|
+
@uri.stub!(:path => '/path/dest',
|
62
|
+
:query => 'versions=1.1&versions=1.0')
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should use the version query parameter" do
|
66
|
+
connection = Connection.new(@uri)
|
67
|
+
connection.versions.should == ['1.0', '1.1']
|
68
|
+
|
69
|
+
@uri.stub!(:query => 'versions=1.1&versions=1.1')
|
70
|
+
connection = Connection.new(@uri)
|
71
|
+
connection.versions.should == ['1.1']
|
72
|
+
|
73
|
+
@uri.stub!(:query => 'versions=1.0')
|
74
|
+
connection = Connection.new(@uri)
|
75
|
+
connection.versions.should == ['1.0']
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should use the user and password of the URI" do
|
79
|
+
@uri.stub!(:user => 'some guy')
|
80
|
+
@uri.stub!(:password => 's3cr3tk3yz')
|
81
|
+
connection = Connection.new(@uri)
|
82
|
+
connection.login.should == 'some guy'
|
83
|
+
connection.passcode.should == 's3cr3tk3yz'
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should use the login and passcode query parameters" do
|
87
|
+
@uri.stub!(:query => 'login=other%20dude&passcode=yermom')
|
88
|
+
connection = Connection.new(@uri)
|
89
|
+
connection.login.should == 'other dude'
|
90
|
+
connection.passcode.should == 'yermom'
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should use the receiver_class query parameter" do
|
94
|
+
@uri.stub!(:query => 'receiver_class=Stomper::Scopes::HeaderScope')
|
95
|
+
connection = Connection.new(@uri)
|
96
|
+
connection.receiver_class.should == ::Stomper::Scopes::HeaderScope
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
describe "configuration through options" do
|
101
|
+
it "should use the version option" do
|
102
|
+
connection = Connection.new(@uri, { :versions => '1.0' })
|
103
|
+
connection.versions.should == [ '1.0' ]
|
104
|
+
|
105
|
+
connection = Connection.new(@uri, { 'versions' => ['1.1', '1.1'] })
|
106
|
+
connection.versions.should == ['1.1']
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should use the login and passcode options" do
|
110
|
+
connection = Connection.new(@uri, { :login => 'me also', 'passcode' => 'm3t00'})
|
111
|
+
connection.login.should == 'me also'
|
112
|
+
connection.passcode.should == 'm3t00'
|
113
|
+
end
|
114
|
+
|
115
|
+
it "should use the receiver_class option" do
|
116
|
+
connection = Connection.new(@uri, :receiver_class => ::Stomper::Scopes::HeaderScope)
|
117
|
+
connection.receiver_class.should == ::Stomper::Scopes::HeaderScope
|
118
|
+
connection = Connection.new(@uri, :receiver_class => 'Stomper::Scopes::ReceiptScope')
|
119
|
+
connection.receiver_class.should == ::Stomper::Scopes::ReceiptScope
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
describe "configuration collision" do
|
124
|
+
it "should favor the login/passcode option over the query over the user/password of the URI" do
|
125
|
+
@uri.stub!(:user => 'ian', :password => 's3cr3tz')
|
126
|
+
@uri.stub!(:query => 'login=not%20ian&passcode=my_super_secret_key')
|
127
|
+
connection = Connection.new(@uri)
|
128
|
+
connection.login.should == 'not ian'
|
129
|
+
connection.passcode.should == 'my_super_secret_key'
|
130
|
+
connection = Connection.new(@uri, { :login => '', :passcode => nil })
|
131
|
+
connection.login.should == ''
|
132
|
+
connection.passcode.should == ''
|
133
|
+
end
|
134
|
+
|
135
|
+
it "should favor the version option over the query parameter" do
|
136
|
+
@uri.stub!(:query => 'versions=1.1&versions=1.1')
|
137
|
+
connection = Connection.new(@uri, { :versions => '1.0' })
|
138
|
+
connection.versions.should == [ '1.0' ]
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
describe "version configuration" do
|
143
|
+
before(:each) do
|
144
|
+
@connection = Connection.new(@uri)
|
145
|
+
end
|
146
|
+
|
147
|
+
it "should only use versions numbers that are supported" do
|
148
|
+
@connection.versions = [ '1.1', '9.3', '1.0', '7.garbage' ]
|
149
|
+
@connection.versions.should == ['1.0', '1.1']
|
150
|
+
end
|
151
|
+
|
152
|
+
it "should raise an error when no supported versions have been specified" do
|
153
|
+
lambda { @connection.versions = [ '2.0', '3.8', '1.2' ] }.should raise_error(::Stomper::Errors::UnsupportedProtocolVersionError)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
describe "broker URI" do
|
158
|
+
it "should use the URI provided" do
|
159
|
+
uri = URI.parse('stomp:///')
|
160
|
+
connection = Connection.new(uri)
|
161
|
+
connection.uri.should == uri
|
162
|
+
end
|
163
|
+
|
164
|
+
it "should convert a string into a URI" do
|
165
|
+
connection = Connection.new('stomp:///')
|
166
|
+
connection.uri.should be_a_kind_of(::URI)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
describe "duration since transmitted and received" do
|
171
|
+
before(:each) do
|
172
|
+
@connection = Connection.new(@uri)
|
173
|
+
end
|
174
|
+
it "should return nil if no frames have been transmitted" do
|
175
|
+
@connection.duration_since_transmitted.should be_nil
|
176
|
+
end
|
177
|
+
|
178
|
+
it "should return nil if no frames have been received" do
|
179
|
+
@connection.duration_since_received.should be_nil
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
describe "Connection IO" do
|
184
|
+
before(:each) do
|
185
|
+
@socket = mock('socket', :closed? => false, :close => true, :shutdown => true)
|
186
|
+
@serializer = mock('serializer', :extend_for_protocol => true)
|
187
|
+
@connected_frame = mock('CONNECTED', :command => 'CONNECTED', :[] => '')
|
188
|
+
@connected_frame.stub!(:[]).with(:version).and_return('1.0')
|
189
|
+
@uri.should_receive(:create_socket).at_least(:once).and_return(@socket)
|
190
|
+
::Stomper::FrameSerializer.stub!(:new => @serializer)
|
191
|
+
@connection = Connection.new(@uri)
|
192
|
+
end
|
193
|
+
|
194
|
+
it "should create and connect a Connection through Connection.open/connect" do
|
195
|
+
@serializer.should_receive(:read_frame).at_least(:once).and_return(@connected_frame)
|
196
|
+
@serializer.should_receive(:write_frame).with(stomper_frame_with_headers({}, 'CONNECT')).at_least(:once).and_return { |f| f }
|
197
|
+
|
198
|
+
connection = @connection.class.open(@uri)
|
199
|
+
connection.connected?.should be_true
|
200
|
+
|
201
|
+
connection = @connection.class.connect(@uri)
|
202
|
+
connection.connected?.should be_true
|
203
|
+
end
|
204
|
+
|
205
|
+
it "should raise an error if the first frame received after CONNECT is sent is not CONNECTED" do
|
206
|
+
not_connected = mock('NOT CONNECTED', :command => 'NOT CONNECTED', :[] => '')
|
207
|
+
@serializer.should_receive(:write_frame).with(stomper_frame_with_headers({}, 'CONNECT')).once.and_return { |f| f }
|
208
|
+
@serializer.should_receive(:read_frame).at_least(:once).and_return(not_connected)
|
209
|
+
lambda { @connection.connect }.should raise_error(::Stomper::Errors::ConnectFailedError)
|
210
|
+
end
|
211
|
+
|
212
|
+
it "should send a DISCONNECT frame when disconnecting politely" do
|
213
|
+
@serializer.should_receive(:read_frame).at_least(:once).and_return(@connected_frame)
|
214
|
+
@serializer.should_receive(:write_frame).with(stomper_frame_with_headers({}, 'CONNECT')).once.and_return { |f| f }
|
215
|
+
@connection.connect
|
216
|
+
@serializer.should_receive(:write_frame).with(stomper_frame_with_headers({}, 'DISCONNECT')).once
|
217
|
+
@connection.disconnect
|
218
|
+
@connection.connected?.should be_false
|
219
|
+
end
|
220
|
+
|
221
|
+
describe "frame reading" do
|
222
|
+
before(:each) do
|
223
|
+
@serializer.should_receive(:read_frame).at_least(:once).and_return(@connected_frame)
|
224
|
+
@serializer.should_receive(:write_frame).with(stomper_frame_with_headers({}, 'CONNECT')).once.and_return { |f| f }
|
225
|
+
end
|
226
|
+
|
227
|
+
it "should have durations since received and transmitted" do
|
228
|
+
::Time.stub(:now => 1)
|
229
|
+
@connection.connect
|
230
|
+
::Time.stub(:now => 3)
|
231
|
+
@connection.duration_since_received.should == 2000
|
232
|
+
::Time.stub(:now => 2)
|
233
|
+
@connection.duration_since_transmitted.should == 1000
|
234
|
+
|
235
|
+
@serializer.stub(:write_frame => true)
|
236
|
+
@serializer.stub(:read_frame => mock('frame', :command => nil))
|
237
|
+
|
238
|
+
::Time.stub(:now => 2)
|
239
|
+
@connection.transmit ::Stomper::Frame.new('SEND', {}, 'test message')
|
240
|
+
::Time.stub(:now => 5)
|
241
|
+
@connection.duration_since_transmitted.should == 3000
|
242
|
+
|
243
|
+
::Time.stub(:now => 6)
|
244
|
+
@connection.receive
|
245
|
+
::Time.stub(:now => 8.5)
|
246
|
+
@connection.duration_since_received.should == 2500
|
247
|
+
end
|
248
|
+
|
249
|
+
it "should receive a frame" do
|
250
|
+
@connection.connect
|
251
|
+
frame = mock("frame", :command => 'MOCK')
|
252
|
+
@serializer.should_receive(:read_frame).and_return(frame)
|
253
|
+
@connection.receive.should == frame
|
254
|
+
end
|
255
|
+
|
256
|
+
it "should not receive_nonblock a frame if io is not ready" do
|
257
|
+
@connection.connect
|
258
|
+
@socket.should_receive(:ready?).and_return(false)
|
259
|
+
@serializer.should_not_receive(:read_frame)
|
260
|
+
@connection.receive_nonblock.should be_nil
|
261
|
+
end
|
262
|
+
|
263
|
+
it "should receive_nonblock a frame if io is ready" do
|
264
|
+
@connection.connect
|
265
|
+
frame = mock("frame", :command => 'MOCK')
|
266
|
+
@socket.should_receive(:ready?).and_return(true)
|
267
|
+
@serializer.should_receive(:read_frame).and_return(frame)
|
268
|
+
@connection.receive_nonblock.should == frame
|
269
|
+
end
|
270
|
+
|
271
|
+
it "should close the socket if reading a frame returns nil" do
|
272
|
+
@connection.connect
|
273
|
+
@serializer.should_receive(:read_frame).and_return(nil)
|
274
|
+
@connection.should_receive(:close).with(true)
|
275
|
+
@connection.receive.should be_nil
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
describe "connection state events" do
|
280
|
+
before(:each) do
|
281
|
+
@serializer.should_receive(:read_frame).at_least(:once).and_return(@connected_frame)
|
282
|
+
@serializer.should_receive(:write_frame).with(stomper_frame_with_headers({}, 'CONNECT')).once.and_return { |f| f }
|
283
|
+
end
|
284
|
+
|
285
|
+
it "should trigger on_connection_established after connecting" do
|
286
|
+
triggered = false
|
287
|
+
@connection.on_connection_established { triggered = true }
|
288
|
+
@connection.connect
|
289
|
+
triggered.should be_true
|
290
|
+
end
|
291
|
+
|
292
|
+
it "should trigger on_connection_closed & on_connection_disconnected after disconnecting" do
|
293
|
+
triggered = [false, false]
|
294
|
+
@connection.on_connection_closed { triggered[0] = true }
|
295
|
+
@connection.on_connection_disconnected { triggered[1] = true }
|
296
|
+
@connection.connect
|
297
|
+
@serializer.should_receive(:write_frame).with(stomper_frame_with_headers({}, 'DISCONNECT')).once
|
298
|
+
@connection.disconnect
|
299
|
+
triggered.should == [true, true]
|
300
|
+
end
|
301
|
+
|
302
|
+
it "should trigger on_connection_died before transmitting if the connection is dead" do
|
303
|
+
triggered = false
|
304
|
+
@connection.on_connection_died { triggered = true }
|
305
|
+
@connection.connect
|
306
|
+
@serializer.stub!(:write_frame).and_return { |f| f }
|
307
|
+
@connection.stub!(:alive?).and_return(false)
|
308
|
+
@connection.transmit(::Stomper::Frame.new('ACK'))
|
309
|
+
triggered.should be_true
|
310
|
+
end
|
311
|
+
|
312
|
+
it "should trigger on_connection_died before receiving if the connection is dead" do
|
313
|
+
triggered = false
|
314
|
+
@connection.on_connection_died { triggered = true }
|
315
|
+
@connection.connect
|
316
|
+
@connection.stub!(:alive?).and_return(false)
|
317
|
+
@serializer.stub!(:read_frame).and_return(::Stomper::Frame.new('MESSAGE'))
|
318
|
+
@connection.receive
|
319
|
+
triggered.should be_true
|
320
|
+
end
|
321
|
+
|
322
|
+
it "should trigger on_connection_died before receiving non-blocking (even if not ready) if the connection is dead" do
|
323
|
+
triggered = false
|
324
|
+
@connection.on_connection_died { triggered = true }
|
325
|
+
@connection.connect
|
326
|
+
@connection.stub!(:alive?).and_return(false)
|
327
|
+
@serializer.stub!(:read_frame).and_return(::Stomper::Frame.new('MESSAGE'))
|
328
|
+
@socket.stub!(:ready?).and_return(false)
|
329
|
+
@connection.receive_nonblock
|
330
|
+
triggered.should be_true
|
331
|
+
end
|
332
|
+
|
333
|
+
it "should trigger on_connection_terminated if the socket raises an IOError while transmitting" do
|
334
|
+
triggered = false
|
335
|
+
@connection.on_connection_terminated { triggered = true }
|
336
|
+
@connection.connect
|
337
|
+
@serializer.stub!(:write_frame).and_raise(IOError.new('io error'))
|
338
|
+
lambda { @connection.transmit(::Stomper::Frame.new('ACK')) }.should raise_error(IOError)
|
339
|
+
triggered.should be_true
|
340
|
+
end
|
341
|
+
|
342
|
+
it "should trigger on_connection_terminated if the socket raises a SystemCallError while transmitting" do
|
343
|
+
triggered = false
|
344
|
+
@connection.on_connection_terminated { triggered = true }
|
345
|
+
@connection.connect
|
346
|
+
@serializer.stub!(:write_frame).and_raise(SystemCallError.new('syscall error'))
|
347
|
+
lambda { @connection.transmit(::Stomper::Frame.new('ACK')) }.should raise_error(SystemCallError)
|
348
|
+
triggered.should be_true
|
349
|
+
end
|
350
|
+
|
351
|
+
it "should trigger on_connection_terminated if the socket raises an IOError while receiving" do
|
352
|
+
triggered = false
|
353
|
+
@connection.on_connection_terminated { triggered = true }
|
354
|
+
@connection.connect
|
355
|
+
@serializer.stub!(:read_frame).and_raise(IOError.new('io error'))
|
356
|
+
lambda { @connection.receive }.should raise_error(IOError)
|
357
|
+
triggered.should be_true
|
358
|
+
end
|
359
|
+
|
360
|
+
it "should trigger on_connection_terminated if the socket raises a SystemCallError while receiving" do
|
361
|
+
triggered = false
|
362
|
+
@connection.on_connection_terminated { triggered = true }
|
363
|
+
@connection.connect
|
364
|
+
@serializer.stub!(:read_frame).and_raise(SystemCallError.new('syscall error'))
|
365
|
+
lambda { @connection.receive }.should raise_error(SystemCallError)
|
366
|
+
triggered.should be_true
|
367
|
+
end
|
368
|
+
|
369
|
+
end
|
370
|
+
|
371
|
+
describe "frame events" do
|
372
|
+
before(:each) do
|
373
|
+
@serializer.should_receive(:read_frame).at_least(:once).and_return(@connected_frame)
|
374
|
+
@connected_frame.stub!(:[]).with(:version).and_return('1.1')
|
375
|
+
@serializer.should_receive(:write_frame).with(stomper_frame_with_headers({}, 'CONNECT')).once.and_return { |f| f }
|
376
|
+
@connection.connect
|
377
|
+
@serializer.stub!(:write_frame).and_return { |f| f }
|
378
|
+
end
|
379
|
+
|
380
|
+
it "should trigger all on_abort handlers when an ABORT frame is transmitted" do
|
381
|
+
triggered = [ false, false, false, false ]
|
382
|
+
@connection.on_abort { triggered[0] = true }
|
383
|
+
@connection.on_abort { triggered[1] = true }
|
384
|
+
@connection.before_transmitting { triggered[2] = true }
|
385
|
+
@connection.after_transmitting { triggered[3] = true }
|
386
|
+
@connection.transmit(::Stomper::Frame.new('ABORT'))
|
387
|
+
triggered.should == [true, true, true, true]
|
388
|
+
end
|
389
|
+
|
390
|
+
it "should trigger all on_ack handlers when an ACK frame is transmitted" do
|
391
|
+
triggered = [ false, false, false, false ]
|
392
|
+
@connection.on_ack { triggered[0] = true }
|
393
|
+
@connection.on_ack { triggered[1] = true }
|
394
|
+
@connection.before_transmitting { triggered[2] = true }
|
395
|
+
@connection.after_transmitting { triggered[3] = true }
|
396
|
+
@connection.transmit(::Stomper::Frame.new('ACK'))
|
397
|
+
triggered.should == [true, true, true, true]
|
398
|
+
end
|
399
|
+
|
400
|
+
it "should trigger all on_begin handlers when a BEGIN frame is transmitted" do
|
401
|
+
triggered = [ false, false, false, false ]
|
402
|
+
@connection.on_begin { triggered[0] = true }
|
403
|
+
@connection.on_begin { triggered[1] = true }
|
404
|
+
@connection.before_transmitting { triggered[2] = true }
|
405
|
+
@connection.after_transmitting { triggered[3] = true }
|
406
|
+
@connection.transmit(::Stomper::Frame.new('BEGIN'))
|
407
|
+
triggered.should == [true, true, true, true]
|
408
|
+
end
|
409
|
+
|
410
|
+
it "should trigger all on_commit handlers when a COMMIT frame is transmitted" do
|
411
|
+
triggered = [ false, false, false, false ]
|
412
|
+
@connection.on_commit { triggered[0] = true }
|
413
|
+
@connection.on_commit { triggered[1] = true }
|
414
|
+
@connection.before_transmitting { triggered[2] = true }
|
415
|
+
@connection.after_transmitting { triggered[3] = true }
|
416
|
+
@connection.transmit(::Stomper::Frame.new('COMMIT'))
|
417
|
+
triggered.should == [true, true, true, true]
|
418
|
+
end
|
419
|
+
|
420
|
+
it "should trigger all on_connect & on_stomp handlers when a CONNECT frame is transmitted" do
|
421
|
+
triggered = [ false, false, false, false, false ]
|
422
|
+
@connection.on_connect { triggered[0] = true }
|
423
|
+
@connection.on_stomp { triggered[1] = true }
|
424
|
+
@connection.on_connect { triggered[2] = true }
|
425
|
+
@connection.before_transmitting { triggered[3] = true }
|
426
|
+
@connection.after_transmitting { triggered[4] = true }
|
427
|
+
@connection.transmit(::Stomper::Frame.new('CONNECT'))
|
428
|
+
triggered.should == [true, true, true, true, true]
|
429
|
+
end
|
430
|
+
|
431
|
+
it "should trigger all on_disconnect handlers when a DISCONNECT frame is transmitted" do
|
432
|
+
triggered = [ false, false, false, false ]
|
433
|
+
@connection.on_disconnect { triggered[0] = true }
|
434
|
+
@connection.on_disconnect { triggered[1] = true }
|
435
|
+
@connection.before_transmitting { triggered[2] = true }
|
436
|
+
@connection.after_transmitting { triggered[3] = true }
|
437
|
+
@connection.transmit(::Stomper::Frame.new('DISCONNECT'))
|
438
|
+
triggered.should == [true, true, true, true]
|
439
|
+
end
|
440
|
+
|
441
|
+
it "should trigger all on_nack handlers when a NACK frame is transmitted" do
|
442
|
+
triggered = [ false, false, false, false ]
|
443
|
+
@connection.on_nack { triggered[0] = true }
|
444
|
+
@connection.on_nack { triggered[1] = true }
|
445
|
+
@connection.before_transmitting { triggered[2] = true }
|
446
|
+
@connection.after_transmitting { triggered[3] = true }
|
447
|
+
@connection.transmit(::Stomper::Frame.new('NACK'))
|
448
|
+
triggered.should == [true, true, true, true]
|
449
|
+
end
|
450
|
+
|
451
|
+
it "should trigger all on_send handlers when a SEND frame is transmitted" do
|
452
|
+
triggered = [ false, false, false, false ]
|
453
|
+
@connection.on_send { triggered[0] = true }
|
454
|
+
@connection.on_send { triggered[1] = true }
|
455
|
+
@connection.before_transmitting { triggered[2] = true }
|
456
|
+
@connection.after_transmitting { triggered[3] = true }
|
457
|
+
@connection.transmit(::Stomper::Frame.new('SEND'))
|
458
|
+
triggered.should == [true, true, true, true]
|
459
|
+
end
|
460
|
+
|
461
|
+
it "should trigger all on_subscribe handlers when a SUBSCRIBE frame is transmitted" do
|
462
|
+
triggered = [ false, false, false, false ]
|
463
|
+
@connection.on_subscribe { triggered[0] = true }
|
464
|
+
@connection.on_subscribe { triggered[1] = true }
|
465
|
+
@connection.before_transmitting { triggered[2] = true }
|
466
|
+
@connection.after_transmitting { triggered[3] = true }
|
467
|
+
@connection.transmit(::Stomper::Frame.new('SUBSCRIBE'))
|
468
|
+
triggered.should == [true, true, true, true]
|
469
|
+
end
|
470
|
+
|
471
|
+
it "should trigger all on_unsubscribe handlers when an UNSUBSCRIBE frame is transmitted" do
|
472
|
+
triggered = [ false, false, false, false ]
|
473
|
+
@connection.on_unsubscribe { triggered[0] = true }
|
474
|
+
@connection.on_unsubscribe { triggered[1] = true }
|
475
|
+
@connection.before_transmitting { triggered[2] = true }
|
476
|
+
@connection.after_transmitting { triggered[3] = true }
|
477
|
+
@connection.transmit(::Stomper::Frame.new('UNSUBSCRIBE'))
|
478
|
+
triggered.should == [true, true, true, true]
|
479
|
+
end
|
480
|
+
|
481
|
+
it "should trigger all on_client_beat handlers when a frame is transmitted without a command" do
|
482
|
+
triggered = [ false, false, false, false ]
|
483
|
+
@connection.on_client_beat { triggered[0] = true }
|
484
|
+
@connection.on_client_beat { triggered[1] = true }
|
485
|
+
@connection.before_transmitting { triggered[2] = true }
|
486
|
+
@connection.after_transmitting { triggered[3] = true }
|
487
|
+
@connection.transmit(::Stomper::Frame.new)
|
488
|
+
triggered.should == [true, true, true, true]
|
489
|
+
end
|
490
|
+
|
491
|
+
it "should trigger all on_connected handlers when a CONNECTED frame is received" do
|
492
|
+
triggered = [ false, false, false, false ]
|
493
|
+
@connection.on_connected { triggered[0] = true }
|
494
|
+
@connection.on_connected { triggered[1] = true }
|
495
|
+
@connection.before_receiving { triggered[2] = true }
|
496
|
+
@connection.after_receiving { triggered[3] = true }
|
497
|
+
@serializer.should_receive(:read_frame).and_return(::Stomper::Frame.new('CONNECTED'))
|
498
|
+
@connection.receive
|
499
|
+
triggered.should == [true, true, true, true]
|
500
|
+
end
|
501
|
+
|
502
|
+
it "should trigger all on_message handlers when a MESSAGE frame is received" do
|
503
|
+
triggered = [ false, false, false, false ]
|
504
|
+
@connection.on_message { triggered[0] = true }
|
505
|
+
@connection.on_message { triggered[1] = true }
|
506
|
+
@connection.before_receiving { triggered[2] = true }
|
507
|
+
@connection.after_receiving { triggered[3] = true }
|
508
|
+
@serializer.should_receive(:read_frame).and_return(::Stomper::Frame.new('MESSAGE'))
|
509
|
+
@connection.receive
|
510
|
+
triggered.should == [true, true, true, true]
|
511
|
+
end
|
512
|
+
|
513
|
+
it "should trigger all on_error handlers when an ERROR frame is received" do
|
514
|
+
triggered = [ false, false, false, false ]
|
515
|
+
@connection.on_error { triggered[0] = true }
|
516
|
+
@connection.on_error { triggered[1] = true }
|
517
|
+
@connection.before_receiving { triggered[2] = true }
|
518
|
+
@connection.after_receiving { triggered[3] = true }
|
519
|
+
@serializer.should_receive(:read_frame).and_return(::Stomper::Frame.new('ERROR'))
|
520
|
+
@connection.receive
|
521
|
+
triggered.should == [true, true, true, true]
|
522
|
+
end
|
523
|
+
|
524
|
+
it "should trigger all on_receipt handlers when a RECEIPT frame is received" do
|
525
|
+
triggered = [ false, false, false, false ]
|
526
|
+
@connection.on_receipt { triggered[0] = true }
|
527
|
+
@connection.on_receipt { triggered[1] = true }
|
528
|
+
@connection.before_receiving { triggered[2] = true }
|
529
|
+
@connection.after_receiving { triggered[3] = true }
|
530
|
+
@serializer.should_receive(:read_frame).and_return(::Stomper::Frame.new('RECEIPT'))
|
531
|
+
@connection.receive
|
532
|
+
triggered.should == [true, true, true, true]
|
533
|
+
end
|
534
|
+
|
535
|
+
it "should trigger all on_broker_beat handlers when a frame is received without a command" do
|
536
|
+
triggered = [ false, false, false, false ]
|
537
|
+
@connection.on_broker_beat { triggered[0] = true }
|
538
|
+
@connection.on_broker_beat { triggered[1] = true }
|
539
|
+
@connection.before_receiving { triggered[2] = true }
|
540
|
+
@connection.after_receiving { triggered[3] = true }
|
541
|
+
@serializer.should_receive(:read_frame).and_return(::Stomper::Frame.new)
|
542
|
+
@connection.receive
|
543
|
+
triggered.should == [true, true, true, true]
|
544
|
+
end
|
545
|
+
end
|
546
|
+
|
547
|
+
describe "receiver handling" do
|
548
|
+
before(:each) do
|
549
|
+
@receiver = mock('receiver')
|
550
|
+
@receiver_class = mock('receiver class', :new => @receiver)
|
551
|
+
@connection.stub!(:receiver_class).and_return(@receiver_class)
|
552
|
+
@serializer.should_receive(:read_frame).at_least(:once).and_return(@connected_frame)
|
553
|
+
@connected_frame.stub!(:[]).with(:version).and_return('1.0')
|
554
|
+
end
|
555
|
+
|
556
|
+
it "should connect and start a receiver if it is not connected" do
|
557
|
+
@serializer.should_receive(:write_frame).with(stomper_frame_with_headers({}, 'CONNECT')).once.and_return { |f| f }
|
558
|
+
@receiver.should_receive(:start)
|
559
|
+
@receiver.should_receive(:running?).and_return(true)
|
560
|
+
|
561
|
+
@connection.start
|
562
|
+
@connection.running?.should be_true
|
563
|
+
end
|
564
|
+
|
565
|
+
it "should stop a running receiver and disconnect if it is connected" do
|
566
|
+
@serializer.should_receive(:write_frame).with(stomper_frame_with_headers({}, 'CONNECT')).once.and_return { |f| f }
|
567
|
+
@serializer.should_receive(:write_frame).with(stomper_frame_with_headers({}, 'DISCONNECT')).once.and_return { |f| f }
|
568
|
+
@receiver.should_receive(:start)
|
569
|
+
@receiver.should_receive(:stop)
|
570
|
+
|
571
|
+
@connection.start
|
572
|
+
@connection.stop
|
573
|
+
end
|
574
|
+
|
575
|
+
it "should pass along headers to the connect frame when starting" do
|
576
|
+
@serializer.should_receive(:write_frame).with(stomper_frame_with_headers({:test => 'value', :other => 'val2'}, 'CONNECT')).once.and_return { |f| f }
|
577
|
+
@receiver.should_receive(:start)
|
578
|
+
|
579
|
+
@connection.start(:test => 'value', :other => 'val2')
|
580
|
+
end
|
581
|
+
|
582
|
+
it "should pass along headers to the disconnect frame when stopping" do
|
583
|
+
@serializer.should_receive(:write_frame).with(stomper_frame_with_headers({}, 'CONNECT')).once.and_return { |f| f }
|
584
|
+
@serializer.should_receive(:write_frame).with(stomper_frame_with_headers({:canon => 'crab', :violini => 'in unisono'}, 'DISCONNECT')).once.and_return { |f| f }
|
585
|
+
@receiver.should_receive(:start)
|
586
|
+
@receiver.should_receive(:stop)
|
587
|
+
|
588
|
+
@connection.start
|
589
|
+
@connection.stop(:canon => 'crab', :violini => 'in unisono')
|
590
|
+
end
|
591
|
+
|
592
|
+
it "should not attempt to stop a receiver that has not been started" do
|
593
|
+
@serializer.should_receive(:write_frame).with(stomper_frame_with_headers({}, 'CONNECT')).once.and_return { |f| f }
|
594
|
+
@serializer.should_receive(:write_frame).with(stomper_frame_with_headers({}, 'DISCONNECT')).once.and_return { |f| f }
|
595
|
+
@receiver.should_not_receive(:stop)
|
596
|
+
|
597
|
+
@connection.connect
|
598
|
+
@connection.stop
|
599
|
+
end
|
600
|
+
it "should not attempt to disconnect a receiver that is not connected" do
|
601
|
+
@serializer.should_receive(:write_frame).with(stomper_frame_with_headers({}, 'CONNECT')).once.and_return { |f| f }
|
602
|
+
@serializer.should_receive(:write_frame).with(stomper_frame_with_headers({}, 'DISCONNECT')).once.and_return { |f| f }
|
603
|
+
@receiver.should_receive(:start)
|
604
|
+
@receiver.should_receive(:stop)
|
605
|
+
|
606
|
+
@connection.start
|
607
|
+
@connection.disconnect
|
608
|
+
@connection.stop
|
609
|
+
end
|
610
|
+
|
611
|
+
it "should not attempt to connect a receiver that is already connected" do
|
612
|
+
@serializer.should_receive(:write_frame).with(stomper_frame_with_headers({}, 'CONNECT')).once.and_return { |f| f }
|
613
|
+
@receiver.should_receive(:start).once
|
614
|
+
|
615
|
+
@connection.connect
|
616
|
+
@connection.start
|
617
|
+
end
|
618
|
+
end
|
619
|
+
|
620
|
+
describe "heartbeat negotiation" do
|
621
|
+
before(:each) do
|
622
|
+
@serializer.should_receive(:read_frame).at_least(:once).and_return(@connected_frame)
|
623
|
+
@connected_frame.stub!(:[]).with(:version).and_return('1.1')
|
624
|
+
@serializer.stub!(:write_frame).and_return { |f| f }
|
625
|
+
end
|
626
|
+
it "should use 0 as a client parameter if either the client or server say so" do
|
627
|
+
@connected_frame.should_receive(:[]).with(:'heart-beat').and_return('1_000,0')
|
628
|
+
@connection.heartbeats = [0, 2_000]
|
629
|
+
@connection.connect
|
630
|
+
@connection.heartbeating.should == [0, 2_000]
|
631
|
+
@connection.disconnect
|
632
|
+
|
633
|
+
@connected_frame.should_receive(:[]).with(:'heart-beat').and_return('1_000,3_000')
|
634
|
+
@connection.heartbeats = [0, 2_000]
|
635
|
+
@connection.connect
|
636
|
+
@connection.heartbeating.should == [0, 2_000]
|
637
|
+
@connection.disconnect
|
638
|
+
|
639
|
+
@connected_frame.should_receive(:[]).with(:'heart-beat').and_return('1_000,0')
|
640
|
+
@connection.heartbeats = [3_000, 2_000]
|
641
|
+
@connection.connect
|
642
|
+
@connection.heartbeating.should == [0, 2_000]
|
643
|
+
@connection.disconnect
|
644
|
+
end
|
645
|
+
|
646
|
+
it "should use 0 as a broker parameter if either the client or broker say so" do
|
647
|
+
@connected_frame.should_receive(:[]).with(:'heart-beat').and_return('0,1_000')
|
648
|
+
@connection.heartbeats = [2_000, 0]
|
649
|
+
@connection.connect
|
650
|
+
@connection.heartbeating.should == [2_000, 0]
|
651
|
+
@connection.disconnect
|
652
|
+
|
653
|
+
@connected_frame.should_receive(:[]).with(:'heart-beat').and_return('3_000,1_000')
|
654
|
+
@connection.heartbeats = [2_000, 0]
|
655
|
+
@connection.connect
|
656
|
+
@connection.heartbeating.should == [2_000, 0]
|
657
|
+
@connection.disconnect
|
658
|
+
|
659
|
+
@connected_frame.should_receive(:[]).with(:'heart-beat').and_return('0,1_000')
|
660
|
+
@connection.heartbeats = [2_000, 3_000]
|
661
|
+
@connection.connect
|
662
|
+
@connection.heartbeating.should == [2_000, 0]
|
663
|
+
@connection.disconnect
|
664
|
+
end
|
665
|
+
|
666
|
+
it "should use the max of client/server beat durations if both are greater than zero" do
|
667
|
+
@connected_frame.should_receive(:[]).with(:'heart-beat').and_return('2_000,1_000')
|
668
|
+
@connection.heartbeats = [4_000, 1_000]
|
669
|
+
@connection.connect
|
670
|
+
@connection.heartbeating.should == [4_000, 2_000]
|
671
|
+
@connection.disconnect
|
672
|
+
|
673
|
+
@connected_frame.should_receive(:[]).with(:'heart-beat').and_return('3_000,2_000')
|
674
|
+
@connection.heartbeats = [1_000, 4_000]
|
675
|
+
@connection.connect
|
676
|
+
@connection.heartbeating.should == [2_000, 4_000]
|
677
|
+
@connection.disconnect
|
678
|
+
end
|
679
|
+
end
|
680
|
+
|
681
|
+
describe "version negotiation" do
|
682
|
+
before(:each) do
|
683
|
+
@serializer.should_receive(:read_frame).at_least(:once).and_return(@connected_frame)
|
684
|
+
end
|
685
|
+
it "should not include any 1.1 extensions if the negotiated protocol is 1.0" do
|
686
|
+
@serializer.should_receive(:write_frame).with(stomper_frame_with_headers({:'accept-version' => '1.0,1.1', :'heart-beat' => '0,0'}, 'CONNECT'))
|
687
|
+
@connected_frame.stub!(:[]).with(:version).and_return('1.0')
|
688
|
+
@connection.connect
|
689
|
+
@connection.version.should == '1.0'
|
690
|
+
@connection.should_not be_a_kind_of(::Stomper::Extensions::Common::V1_1)
|
691
|
+
@connection.should_not be_a_kind_of(::Stomper::Extensions::Heartbeat::V1_1)
|
692
|
+
end
|
693
|
+
|
694
|
+
it "should include Extensions::Protocols::V1_0 if the negotiated protocol is 1.1" do
|
695
|
+
@serializer.should_receive(:write_frame).with(stomper_frame_with_headers({:'accept-version' => '1.0,1.1', :'heart-beat' => '0,0'}, 'CONNECT'))
|
696
|
+
@connected_frame.stub!(:[]).with(:version).and_return('1.1')
|
697
|
+
@connection.connect
|
698
|
+
@connection.version.should == '1.1'
|
699
|
+
@connection.should be_a_kind_of(::Stomper::Extensions::Common::V1_1)
|
700
|
+
@connection.should be_a_kind_of(::Stomper::Extensions::Heartbeat::V1_1)
|
701
|
+
end
|
702
|
+
|
703
|
+
it "should raise an error if the version returned by the broker is not in the list of acceptable versions and close the connection" do
|
704
|
+
@serializer.should_receive(:write_frame).with(stomper_frame_with_headers({:'accept-version' => '1.0,1.1', :'heart-beat' => '0,0'}, 'CONNECT'))
|
705
|
+
@connected_frame.stub!(:[]).with(:version).and_return('2.0')
|
706
|
+
lambda { @connection.connect }.should raise_error(::Stomper::Errors::UnsupportedProtocolVersionError)
|
707
|
+
@connection.connected?.should be_false
|
708
|
+
end
|
709
|
+
end
|
710
|
+
end
|
711
|
+
end
|
712
|
+
end
|