stomper 1.0.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|