amq-client 1.0.0.pre2 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +8 -5
- data/.travis.yml +4 -1
- data/amq-client.gemspec +1 -1
- data/bin/ci/before_build.sh +13 -11
- data/lib/amq/client/async/adapter.rb +31 -8
- data/lib/amq/client/async/adapters/coolio.rb +4 -0
- data/lib/amq/client/async/adapters/event_machine.rb +9 -8
- data/lib/amq/client/async/auth_mechanism_adapter.rb +69 -0
- data/lib/amq/client/async/auth_mechanism_adapter/external.rb +27 -0
- data/lib/amq/client/async/auth_mechanism_adapter/plain.rb +24 -0
- data/lib/amq/client/async/channel.rb +6 -5
- data/lib/amq/client/async/extensions/rabbitmq/cancel.rb +7 -7
- data/lib/amq/client/extensions/rabbitmq/cancel.rb +2 -2
- data/lib/amq/client/settings.rb +5 -4
- data/lib/amq/client/version.rb +1 -1
- data/spec/integration/coolio/basic_return_spec.rb +4 -4
- data/spec/integration/coolio/exchange_declare_spec.rb +0 -1
- data/spec/integration/eventmachine/basic_publish_with_framing_spec.rb +4 -2
- data/spec/integration/eventmachine/basic_return_spec.rb +3 -3
- data/spec/integration/eventmachine/concurrent_basic_publish_spec.rb +2 -2
- data/spec/integration/eventmachine/connection_start_spec.rb +63 -0
- data/spec/integration/eventmachine/consumer_cancellation_notification_spec.rb +76 -0
- data/spec/integration/eventmachine/exchange_declare_spec.rb +0 -1
- metadata +63 -74
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/amq-client.gemspec
CHANGED
data/bin/ci/before_build.sh
CHANGED
@@ -1,24 +1,26 @@
|
|
1
1
|
#!/bin/sh
|
2
2
|
|
3
|
+
${RABBITMQCTL:="sudo rabbitmqctl"}
|
4
|
+
|
3
5
|
# guest:guest has full access to /
|
4
6
|
|
5
|
-
|
6
|
-
|
7
|
-
|
7
|
+
$RABBITMQCTL add_vhost /
|
8
|
+
$RABBITMQCTL add_user guest guest
|
9
|
+
$RABBITMQCTL set_permissions -p / guest ".*" ".*" ".*"
|
8
10
|
|
9
11
|
|
10
12
|
# guest:guest has full access to amq_client_testbed
|
11
13
|
# amq_client_gem:amq_client_gem has full access to /amq_client_testbed
|
12
14
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
15
|
+
$RABBITMQCTL delete_vhost "amq_client_testbed"
|
16
|
+
$RABBITMQCTL add_vhost "amq_client_testbed"
|
17
|
+
$RABBITMQCTL delete_user amq_client_gem
|
18
|
+
$RABBITMQCTL add_user amq_client_gem amq_client_gem_password
|
19
|
+
$RABBITMQCTL set_permissions -p amq_client_testbed guest ".*" ".*" ".*"
|
20
|
+
$RABBITMQCTL set_permissions -p amq_client_testbed amq_client_gem ".*" ".*" ".*"
|
19
21
|
|
20
22
|
|
21
23
|
# amqp_gem_reader:reader_password has read access to amq_client_testbed
|
22
24
|
|
23
|
-
|
24
|
-
|
25
|
+
$RABBITMQCTL add_user amq_client_gem_reader reader_password
|
26
|
+
$RABBITMQCTL set_permissions -p amq_client_testbed amq_client_gem_reader "^---$" "^---$" ".*"
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require "amq/client/logging"
|
4
4
|
require "amq/client/settings"
|
5
|
+
require "amq/client/async/auth_mechanism_adapter"
|
5
6
|
require "amq/client/async/entity"
|
6
7
|
require "amq/client/async/channel"
|
7
8
|
|
@@ -274,13 +275,13 @@ module AMQ
|
|
274
275
|
# @return [Fixnum] Heartbeat interval this client uses, in seconds.
|
275
276
|
# @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.4.2.6)
|
276
277
|
def heartbeat_interval
|
277
|
-
@
|
278
|
+
@heartbeat_interval
|
278
279
|
end # heartbeat_interval
|
279
280
|
|
280
281
|
# Returns true if heartbeats are enabled (heartbeat interval is greater than 0)
|
281
282
|
# @return [Boolean]
|
282
283
|
def heartbeats_enabled?
|
283
|
-
|
284
|
+
@heartbeat_interval && (@heartbeat_interval > 0)
|
284
285
|
end
|
285
286
|
|
286
287
|
|
@@ -368,6 +369,8 @@ module AMQ
|
|
368
369
|
# @private
|
369
370
|
# @api plugin
|
370
371
|
def handle_connection_interruption
|
372
|
+
self.cancel_heartbeat_sender
|
373
|
+
|
371
374
|
@channels.each { |n, c| c.handle_connection_interruption }
|
372
375
|
self.exec_callback_yielding_self(:after_connection_interruption)
|
373
376
|
end # handle_connection_interruption
|
@@ -509,9 +512,17 @@ module AMQ
|
|
509
512
|
# @api plugin
|
510
513
|
# @see http://tools.ietf.org/rfc/rfc2595.txt RFC 2595
|
511
514
|
def encode_credentials(username, password)
|
512
|
-
|
515
|
+
auth_mechanism_adapter.encode_credentials(username, password)
|
513
516
|
end # encode_credentials(username, password)
|
514
517
|
|
518
|
+
# Retrieves an AuthMechanismAdapter that will encode credentials for
|
519
|
+
# this Adapter.
|
520
|
+
#
|
521
|
+
# @api plugin
|
522
|
+
def auth_mechanism_adapter
|
523
|
+
@auth_mechanism_adapter ||= AuthMechanismAdapter.for_adapter(self)
|
524
|
+
end
|
525
|
+
|
515
526
|
|
516
527
|
# Processes a single frame.
|
517
528
|
#
|
@@ -600,7 +611,7 @@ module AMQ
|
|
600
611
|
# @status undefined. So lets do this. MK.
|
601
612
|
opening!
|
602
613
|
|
603
|
-
self.send_frame(Protocol::Connection::StartOk.encode(@client_properties,
|
614
|
+
self.send_frame(Protocol::Connection::StartOk.encode(@client_properties, mechanism, self.encode_credentials(username, password), @locale))
|
604
615
|
end
|
605
616
|
|
606
617
|
|
@@ -608,12 +619,16 @@ module AMQ
|
|
608
619
|
#
|
609
620
|
# @api plugin
|
610
621
|
# @see http://bit.ly/amqp091reference AMQP 0.9.1 protocol reference (Section 1.4.2.6)
|
611
|
-
def handle_tune(
|
612
|
-
@channel_max =
|
613
|
-
@frame_max =
|
614
|
-
|
622
|
+
def handle_tune(connection_tune)
|
623
|
+
@channel_max = connection_tune.channel_max.freeze
|
624
|
+
@frame_max = connection_tune.frame_max.freeze
|
625
|
+
|
626
|
+
client_heartbeat = @settings[:heartbeat] || @settings[:heartbeat_interval] || 0
|
627
|
+
|
628
|
+
@heartbeat_interval = negotiate_heartbeat_value(client_heartbeat, connection_tune.heartbeat)
|
615
629
|
|
616
630
|
self.send_frame(Protocol::Connection::TuneOk.encode(@channel_max, [settings[:frame_max], @frame_max].min, @heartbeat_interval))
|
631
|
+
self.initialize_heartbeat_sender if heartbeats_enabled?
|
617
632
|
end # handle_tune(method)
|
618
633
|
|
619
634
|
|
@@ -652,6 +667,14 @@ module AMQ
|
|
652
667
|
|
653
668
|
protected
|
654
669
|
|
670
|
+
def negotiate_heartbeat_value(client_value, server_value)
|
671
|
+
if client_value == 0 || server_value == 0
|
672
|
+
[client_value, server_value].max
|
673
|
+
else
|
674
|
+
[client_value, server_value].min
|
675
|
+
end
|
676
|
+
end
|
677
|
+
|
655
678
|
# Returns next frame from buffer whenever possible
|
656
679
|
#
|
657
680
|
# @api private
|
@@ -31,10 +31,10 @@ module AMQ
|
|
31
31
|
# @option settings [String] :vhost ("/") Virtual host to use.
|
32
32
|
# @option settings [String] :user ("guest") Username to use for authentication.
|
33
33
|
# @option settings [String] :pass ("guest") Password to use for authentication.
|
34
|
+
# @option settings [String] :auth_mechanism ("PLAIN") SASL authentication mechanism to use.
|
34
35
|
# @option settings [String] :ssl (false) Should be use TLS (SSL) for connection?
|
35
36
|
# @option settings [String] :timeout (nil) Connection timeout.
|
36
|
-
# @option settings [
|
37
|
-
# @option settings [String] :broker (nil) Broker name (use if you intend to use broker-specific features).
|
37
|
+
# @option settings [Fixnum] :heartbeat (0) Connection heartbeat, in seconds.
|
38
38
|
# @option settings [Fixnum] :frame_max (131072) Maximum frame size to use. If broker cannot support frames this large, broker's maximum value will be used instead.
|
39
39
|
#
|
40
40
|
# @param [Hash] settings
|
@@ -164,7 +164,7 @@ module AMQ
|
|
164
164
|
raise self.class.authentication_failure_exception_class.new(settings)
|
165
165
|
}
|
166
166
|
|
167
|
-
@mechanism = "PLAIN"
|
167
|
+
@mechanism = @settings.fetch(:auth_mechanism, "PLAIN")
|
168
168
|
@locale = @settings.fetch(:locale, "en_GB")
|
169
169
|
@client_properties = Settings.client_properties.merge(@settings.fetch(:client_properties, Hash.new))
|
170
170
|
|
@@ -172,8 +172,6 @@ module AMQ
|
|
172
172
|
|
173
173
|
self.reset
|
174
174
|
self.set_pending_connect_timeout((@settings[:timeout] || 3).to_f) unless defined?(JRUBY_VERSION)
|
175
|
-
|
176
|
-
self.initialize_heartbeat_sender if self.heartbeats_enabled?
|
177
175
|
end # initialize(*args)
|
178
176
|
|
179
177
|
|
@@ -267,8 +265,6 @@ module AMQ
|
|
267
265
|
@handling_skipped_hearbeats = false
|
268
266
|
@last_server_heartbeat = Time.now
|
269
267
|
|
270
|
-
self.initialize_heartbeat_sender if self.heartbeat_interval > 0
|
271
|
-
|
272
268
|
self.handshake
|
273
269
|
end
|
274
270
|
|
@@ -356,7 +352,7 @@ module AMQ
|
|
356
352
|
def handle_skipped_hearbeats
|
357
353
|
if !@handling_skipped_hearbeats && @tcp_connection_established && !@intentionally_closing_connection
|
358
354
|
@handling_skipped_hearbeats = true
|
359
|
-
|
355
|
+
self.cancel_heartbeat_sender
|
360
356
|
|
361
357
|
self.run_skipped_heartbeats_callbacks
|
362
358
|
end
|
@@ -368,6 +364,11 @@ module AMQ
|
|
368
364
|
@heartbeats_timer = EventMachine::PeriodicTimer.new(self.heartbeat_interval, &method(:send_heartbeat))
|
369
365
|
end
|
370
366
|
|
367
|
+
# @private
|
368
|
+
def cancel_heartbeat_sender
|
369
|
+
@heartbeats_timer.cancel if @heartbeats_timer
|
370
|
+
end
|
371
|
+
|
371
372
|
|
372
373
|
|
373
374
|
self.handle(Protocol::Connection::Start) do |connection, frame|
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module AMQ::Client::Async
|
4
|
+
# Provides a flexible method for encoding AMQP credentials. PLAIN and
|
5
|
+
# EXTERNAL are provided by this gem. In order to implement a new
|
6
|
+
# authentication mechanism, create a subclass like so:
|
7
|
+
#
|
8
|
+
# class MyAuthMechanism < AMQ::Client::Async::AuthMechanismAdapter
|
9
|
+
# auth_mechanism "X-MYAUTH"
|
10
|
+
#
|
11
|
+
# def encode_credentials(username, password)
|
12
|
+
# # ...
|
13
|
+
# end
|
14
|
+
# end
|
15
|
+
class AuthMechanismAdapter
|
16
|
+
|
17
|
+
# Find and instantiate an AuthMechanismAdapter.
|
18
|
+
#
|
19
|
+
# @param [Adapter] adapter The Adapter for which to encode credentials.
|
20
|
+
# @return [AuthMechanismAdapter] An AuthMechanismAdapter that can encode
|
21
|
+
# credentials for the Adapter.
|
22
|
+
# @raise [NotImplementedError] The Adapter's mechanism does not
|
23
|
+
# correspond to any known AuthMechanismAdapter.
|
24
|
+
def self.for_adapter(adapter)
|
25
|
+
registry[adapter.mechanism].new adapter
|
26
|
+
end
|
27
|
+
|
28
|
+
protected
|
29
|
+
|
30
|
+
# Used by subclasses to declare the mechanisms that an
|
31
|
+
# AuthMechanismAdapter understands.
|
32
|
+
#
|
33
|
+
# @param [Array<String>] mechanisms One or more mechanisms that can be
|
34
|
+
# handled by the subclass.
|
35
|
+
def self.auth_mechanism(*mechanisms)
|
36
|
+
mechanisms.each {|mechanism| registry[mechanism] = self}
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
# Accesses the registry of AuthMechanismAdapter subclasses. Keys in
|
42
|
+
# this hash are the names of the authentication mechanisms; values are
|
43
|
+
# the classes that handle them. Referencing an unknown mechanism from
|
44
|
+
# this Hash will raise NotImplementedError.
|
45
|
+
def self.registry
|
46
|
+
@@registry ||= Hash.new {raise NotImplementedError}
|
47
|
+
end
|
48
|
+
|
49
|
+
public
|
50
|
+
|
51
|
+
# The Adapter that this AuthMechanismAdapter operates on behalf of.
|
52
|
+
attr_reader :adapter
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
# Create a new AuthMechanismAdapter. Users of this class should instead
|
57
|
+
# retrieve an instance through for_adapter.
|
58
|
+
def initialize(adapter)
|
59
|
+
@adapter = adapter
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# pre-require builtin auth mechanisms
|
65
|
+
Dir[File.join(File.dirname(__FILE__),
|
66
|
+
File.basename(__FILE__, '.rb'),
|
67
|
+
'*')].each do |f|
|
68
|
+
require f
|
69
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module AMQ::Client::Async
|
4
|
+
|
5
|
+
# Manages the encoding of credentials for the EXTERNAL authentication
|
6
|
+
# mechanism.
|
7
|
+
class AuthMechanismAdapter::External < AuthMechanismAdapter
|
8
|
+
|
9
|
+
auth_mechanism "EXTERNAL"
|
10
|
+
|
11
|
+
# Encodes a username and password for the EXTERNAL mechanism. Since
|
12
|
+
# authentication is handled by an encapsulating protocol like SSL or
|
13
|
+
# UNIX domain sockets, EXTERNAL doesn't pass along any username or
|
14
|
+
# password information at all and this method always returns the
|
15
|
+
# empty string.
|
16
|
+
#
|
17
|
+
# @param [String] username The username to encode. This parameter is
|
18
|
+
# ignored.
|
19
|
+
# @param [String] password The password to encode. This parameter is
|
20
|
+
# ignored.
|
21
|
+
# @return [String] The username and password, encoded for the
|
22
|
+
# EXTERNAL mechanism. This is always the empty string.
|
23
|
+
def encode_credentials(username, password)
|
24
|
+
""
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module AMQ::Client::Async
|
4
|
+
|
5
|
+
# Manages the encoding of credentials for the PLAIN authentication
|
6
|
+
# mechanism.
|
7
|
+
class AuthMechanismAdapter::Plain < AuthMechanismAdapter
|
8
|
+
|
9
|
+
auth_mechanism "PLAIN"
|
10
|
+
|
11
|
+
# Encodes credentials for the given username and password. This
|
12
|
+
# involves sending the password across the wire in plaintext, so
|
13
|
+
# PLAIN authentication should only be used over a secure transport
|
14
|
+
# layer.
|
15
|
+
#
|
16
|
+
# @param [String] username The username to encode.
|
17
|
+
# @param [String] password The password to encode.
|
18
|
+
# @return [String] The username and password, encoded for the PLAIN
|
19
|
+
# mechanism.
|
20
|
+
def encode_credentials(username, password)
|
21
|
+
"\0#{username}\0#{password}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -133,7 +133,7 @@ module AMQ
|
|
133
133
|
# Acknowledge one or all messages on the channel.
|
134
134
|
#
|
135
135
|
# @api public
|
136
|
-
# @see
|
136
|
+
# @see files.travis-ci.org/docs/amqp/0.9.1/AMQP091Reference.pdf AMQP 0.9.1 protocol reference (Section 1.8.3.13.)
|
137
137
|
def acknowledge(delivery_tag, multiple = false)
|
138
138
|
@connection.send_frame(Protocol::Basic::Ack.encode(self.id, delivery_tag, multiple))
|
139
139
|
|
@@ -143,7 +143,7 @@ module AMQ
|
|
143
143
|
# Reject a message with given delivery tag.
|
144
144
|
#
|
145
145
|
# @api public
|
146
|
-
# @see
|
146
|
+
# @see files.travis-ci.org/docs/amqp/0.9.1/AMQP091Reference.pdf AMQP 0.9.1 protocol reference (Section 1.8.3.14.)
|
147
147
|
def reject(delivery_tag, requeue = true)
|
148
148
|
@connection.send_frame(Protocol::Basic::Reject.encode(self.id, delivery_tag, requeue))
|
149
149
|
|
@@ -156,7 +156,7 @@ module AMQ
|
|
156
156
|
# @return [Channel] self
|
157
157
|
#
|
158
158
|
# @note RabbitMQ as of 2.3.1 does not support basic.recover with requeue = false.
|
159
|
-
# @see
|
159
|
+
# @see files.travis-ci.org/docs/amqp/0.9.1/AMQP091Reference.pdf AMQP 0.9.1 protocol reference (Section 1.8.3.16.)
|
160
160
|
# @api public
|
161
161
|
def recover(requeue = true, &block)
|
162
162
|
@connection.send_frame(Protocol::Basic::Recover.encode(@id, requeue))
|
@@ -181,7 +181,7 @@ module AMQ
|
|
181
181
|
|
182
182
|
self.redefine_callback :qos, &block
|
183
183
|
self
|
184
|
-
end # qos
|
184
|
+
end # qos
|
185
185
|
|
186
186
|
# Asks the peer to pause or restart the flow of content data sent to a consumer.
|
187
187
|
# This is a simple flowcontrol mechanism that a peer can use to avoid overflowing its
|
@@ -191,7 +191,7 @@ module AMQ
|
|
191
191
|
#
|
192
192
|
# @param [Boolean] active Desired flow state.
|
193
193
|
#
|
194
|
-
# @see
|
194
|
+
# @see files.travis-ci.org/docs/amqp/0.9.1/AMQP091Reference.pdf AMQP 0.9.1 protocol reference (Section 1.5.2.3.)
|
195
195
|
# @api public
|
196
196
|
def flow(active = false, &block)
|
197
197
|
@connection.send_frame(Protocol::Channel::Flow.encode(@id, active))
|
@@ -413,6 +413,7 @@ module AMQ
|
|
413
413
|
def handle_close(channel_close)
|
414
414
|
self.status = :closed
|
415
415
|
self.connection.clear_frames_on(self.id)
|
416
|
+
|
416
417
|
self.exec_callback_yielding_self(:error, channel_close)
|
417
418
|
|
418
419
|
self.handle_connection_interruption(channel_close)
|
@@ -10,17 +10,17 @@ module AMQ
|
|
10
10
|
module RabbitMQ
|
11
11
|
module Basic
|
12
12
|
module ConsumerMixin
|
13
|
-
|
13
|
+
|
14
14
|
def on_cancel(&block)
|
15
15
|
self.append_callback(:scancel, &block)
|
16
16
|
|
17
17
|
self
|
18
18
|
end # on_cancel(&block)
|
19
|
-
|
19
|
+
|
20
20
|
def handle_cancel(basic_cancel)
|
21
21
|
self.exec_callback(:scancel, basic_cancel)
|
22
22
|
end # handle_cancel(basic_cancel)
|
23
|
-
|
23
|
+
|
24
24
|
def self.included receiver
|
25
25
|
receiver.handle(Protocol::Basic::Cancel) do |connection, method_frame|
|
26
26
|
channel = connection.channels[method_frame.channel]
|
@@ -31,17 +31,17 @@ module AMQ
|
|
31
31
|
consumer.handle_cancel(basic_cancel) if consumer
|
32
32
|
end
|
33
33
|
end
|
34
|
-
|
34
|
+
|
35
35
|
end # ConsumerMixin
|
36
|
-
|
36
|
+
|
37
37
|
module QueueMixin
|
38
|
-
|
38
|
+
|
39
39
|
# @api public
|
40
40
|
def on_cancel(&block)
|
41
41
|
@default_consumer.on_cancel(&block)
|
42
42
|
end # on_cancel(&block)
|
43
43
|
end
|
44
|
-
|
44
|
+
|
45
45
|
end # Basic
|
46
46
|
end # RabbitMQ
|
47
47
|
end # Extensions
|
@@ -2,13 +2,13 @@
|
|
2
2
|
|
3
3
|
require "amq/client/async/extensions/rabbitmq/cancel"
|
4
4
|
|
5
|
-
# Basic.
|
5
|
+
# Basic.Cancel
|
6
6
|
module AMQ
|
7
7
|
module Client
|
8
8
|
# backwards compatibility
|
9
9
|
# @private
|
10
10
|
Extensions = Async::Extensions unless defined?(Extensions)
|
11
|
-
|
11
|
+
|
12
12
|
module Settings
|
13
13
|
CLIENT_PROPERTIES[:capabilities] ||= {}
|
14
14
|
CLIENT_PROPERTIES[:capabilities][:consumer_cancel_notify] = true
|
data/lib/amq/client/settings.rb
CHANGED
@@ -23,9 +23,10 @@ module AMQ
|
|
23
23
|
:port => AMQ::Protocol::DEFAULT_PORT,
|
24
24
|
|
25
25
|
# login
|
26
|
-
:user
|
27
|
-
:pass
|
28
|
-
:
|
26
|
+
:user => "guest",
|
27
|
+
:pass => "guest",
|
28
|
+
:auth_mechanism => "PLAIN",
|
29
|
+
:vhost => "/",
|
29
30
|
|
30
31
|
# connection timeout
|
31
32
|
:timeout => nil,
|
@@ -51,7 +52,7 @@ module AMQ
|
|
51
52
|
:information => "http://github.com/ruby-amqp/amq-client",
|
52
53
|
:version => AMQ::Client::VERSION
|
53
54
|
}
|
54
|
-
|
55
|
+
|
55
56
|
def self.client_properties
|
56
57
|
@client_properties ||= CLIENT_PROPERTIES
|
57
58
|
end
|
data/lib/amq/client/version.rb
CHANGED
@@ -15,7 +15,7 @@ describe "AMQ::Client::CoolioClient", "Basic.Return", :nojruby => true do
|
|
15
15
|
coolio_amqp_connect do |client|
|
16
16
|
channel = AMQ::Client::Channel.new(client, 1)
|
17
17
|
channel.open do
|
18
|
-
queue = AMQ::Client::Queue.new(client, channel).declare(false, false, false,
|
18
|
+
queue = AMQ::Client::Queue.new(client, channel).declare(false, false, false, false)
|
19
19
|
|
20
20
|
# need to delete the queue manually because we don't start consumption,
|
21
21
|
# hence, no auto-delete
|
@@ -26,14 +26,14 @@ describe "AMQ::Client::CoolioClient", "Basic.Return", :nojruby => true do
|
|
26
26
|
end
|
27
27
|
|
28
28
|
messages.each do |message|
|
29
|
-
exchange.publish(message, AMQ::Protocol::EMPTY_STRING, {},
|
29
|
+
exchange.publish(message, AMQ::Protocol::EMPTY_STRING, {}, true, false)
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
33
|
done(0.6) { @returned_messages.size == messages.size }
|
34
34
|
end
|
35
35
|
|
36
|
-
@returned_messages.should == ["
|
36
|
+
@returned_messages.should == ["NO_ROUTE"] * messages.size
|
37
37
|
end
|
38
38
|
end
|
39
|
-
end
|
39
|
+
end
|
@@ -10,7 +10,7 @@ describe AMQ::Client::EventMachineClient, "Basic.Publish" do
|
|
10
10
|
default_timeout 21.0
|
11
11
|
|
12
12
|
context "when message size exceeds negotiated frame size" do
|
13
|
-
let(:message) { "z" * 1024 * 1024 *
|
13
|
+
let(:message) { "z" * 1024 * 1024 * 2 }
|
14
14
|
|
15
15
|
it "correctly frames things" do
|
16
16
|
@received_messages = []
|
@@ -41,11 +41,13 @@ describe AMQ::Client::EventMachineClient, "Basic.Publish" do
|
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
|
-
|
44
|
+
delayed(15.0) {
|
45
45
|
# we don't care about the exact number, just the fact that there are
|
46
46
|
# no UNEXPECTED_FRAME connection-level exceptions. MK.
|
47
47
|
@received_messages.size.should > 10
|
48
48
|
@received_messages.all? {|m| m == message}.should be_true
|
49
|
+
|
50
|
+
done
|
49
51
|
}
|
50
52
|
end
|
51
53
|
end # em_amqp_connect
|
@@ -25,7 +25,7 @@ describe AMQ::Client::EventMachineClient, "Basic.Return" do
|
|
25
25
|
end
|
26
26
|
|
27
27
|
messages.each do |message|
|
28
|
-
exchange.publish(message, AMQ::Protocol::EMPTY_STRING, {},
|
28
|
+
exchange.publish(message, AMQ::Protocol::EMPTY_STRING, {}, true, false)
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
@@ -34,7 +34,7 @@ describe AMQ::Client::EventMachineClient, "Basic.Return" do
|
|
34
34
|
}
|
35
35
|
end
|
36
36
|
|
37
|
-
@returned_messages.should == ["
|
37
|
+
@returned_messages.should == ["NO_ROUTE"] * messages.size
|
38
38
|
end
|
39
39
|
end
|
40
|
-
end
|
40
|
+
end
|
@@ -57,7 +57,7 @@ if mri?
|
|
57
57
|
30.times do
|
58
58
|
Thread.new do
|
59
59
|
messages.each do |message|
|
60
|
-
exchange.publish(message, queue.name, {}, false,
|
60
|
+
exchange.publish(message, queue.name, {}, false, false)
|
61
61
|
end
|
62
62
|
end
|
63
63
|
end
|
@@ -76,4 +76,4 @@ if mri?
|
|
76
76
|
end # it
|
77
77
|
end # context
|
78
78
|
end # describe
|
79
|
-
end
|
79
|
+
end
|
@@ -10,6 +10,69 @@ describe AMQ::Client::EventMachineClient, "Connection.Start" do
|
|
10
10
|
include EventedSpec::SpecHelper
|
11
11
|
default_timeout 0.5
|
12
12
|
|
13
|
+
it "uses PLAIN authentication by default" do
|
14
|
+
em do
|
15
|
+
AMQ::Client::EventMachineClient.new(0).mechanism.should eq "PLAIN"
|
16
|
+
done
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
it "uses PLAIN authentication when explicitly set" do
|
21
|
+
em do
|
22
|
+
AMQ::Client::EventMachineClient.new(0, :auth_mechanism => "PLAIN").mechanism.should eq "PLAIN"
|
23
|
+
done
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
it "properly encodes username and password for PLAIN authentication" do
|
28
|
+
em do
|
29
|
+
client = AMQ::Client::EventMachineClient.new 0, :auth_mechanism => "PLAIN"
|
30
|
+
client.encode_credentials("user", "pass").should eq "\0user\0pass"
|
31
|
+
done
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
it "uses EXTERNAL authentication when explicitly set" do
|
36
|
+
em do
|
37
|
+
AMQ::Client::EventMachineClient.new(0, :auth_mechanism => "EXTERNAL").mechanism.should eq "EXTERNAL"
|
38
|
+
done
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
it "skips encoding username and password for EXTERNAL authentication" do
|
43
|
+
em do
|
44
|
+
client = AMQ::Client::EventMachineClient.new 0, :auth_mechanism => "EXTERNAL"
|
45
|
+
client.encode_credentials("user", "pass").should eq ""
|
46
|
+
done
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
it "allows user-defined authentication mechanisms" do
|
51
|
+
Class.new AMQ::Client::Async::AuthMechanismAdapter do
|
52
|
+
auth_mechanism "FOO"
|
53
|
+
|
54
|
+
def encode_credentials(username, password)
|
55
|
+
"foo"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
em do
|
60
|
+
client = AMQ::Client::EventMachineClient.new 0, :auth_mechanism => "FOO"
|
61
|
+
client.encode_credentials("user", "pass").should eq "foo"
|
62
|
+
done
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
it "fails for unimplemented authentication mechanisms" do
|
67
|
+
em do
|
68
|
+
client = AMQ::Client::EventMachineClient.new 0, :auth_mechanism => "BAR"
|
69
|
+
expect do
|
70
|
+
client.encode_credentials("user", "pass")
|
71
|
+
end.to raise_error(NotImplementedError)
|
72
|
+
done
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
13
76
|
context "with valid credentials" do
|
14
77
|
it "should trigger the callback" do
|
15
78
|
em do
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'integration/eventmachine/spec_helper'
|
5
|
+
|
6
|
+
require "amq/client/extensions/rabbitmq"
|
7
|
+
|
8
|
+
describe AMQ::Client::EventMachineClient, "basic.cancel notification" do
|
9
|
+
include EventedSpec::SpecHelper
|
10
|
+
default_timeout 4
|
11
|
+
|
12
|
+
let(:messages) { (0..99).map {|i| "Message #{i}" } }
|
13
|
+
|
14
|
+
it "works for default consumer" do
|
15
|
+
@received_basic_cancel_ok = false
|
16
|
+
em_amqp_connect do |client|
|
17
|
+
channel = AMQ::Client::Channel.new(client, 1)
|
18
|
+
channel.open do
|
19
|
+
queue = AMQ::Client::Queue.new(client, channel).declare(false, false, false, true)
|
20
|
+
queue.bind("amq.fanout")
|
21
|
+
exchange = AMQ::Client::Exchange.new(client, channel, "amq.fanout", :fanout)
|
22
|
+
|
23
|
+
queue.consume(true) do |amq_method|
|
24
|
+
messages.each do |message|
|
25
|
+
exchange.publish(message)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
queue.default_consumer.on_cancel do |basic_cancel|
|
30
|
+
@received_basic_cancel_ok = true
|
31
|
+
end
|
32
|
+
|
33
|
+
delayed(1.0) { queue.delete }
|
34
|
+
|
35
|
+
done(2.5) {
|
36
|
+
@received_basic_cancel_ok.should be_true
|
37
|
+
}
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end # it
|
41
|
+
|
42
|
+
it "works for other consumers" do
|
43
|
+
@cancellation_notifications = []
|
44
|
+
|
45
|
+
em_amqp_connect do |client|
|
46
|
+
channel = AMQ::Client::Channel.new(client, 1)
|
47
|
+
channel.open do
|
48
|
+
queue = AMQ::Client::Queue.new(client, channel).declare(false, false, false, true)
|
49
|
+
queue.bind("amq.fanout")
|
50
|
+
exchange = AMQ::Client::Exchange.new(client, channel, "amq.fanout", :fanout)
|
51
|
+
|
52
|
+
consumer1 = AMQ::Client::Async::Consumer.new(channel, queue, "#{queue.name}-consumer-#{Time.now}-#{rand}")
|
53
|
+
consumer2 = AMQ::Client::Async::Consumer.new(channel, queue, "#{queue.name}-consumer-#{Time.now}-#{rand}")
|
54
|
+
consumer1.consume do |_|
|
55
|
+
messages.each do |message|
|
56
|
+
exchange.publish(message)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
consumer2.consume
|
60
|
+
|
61
|
+
consumer1.on_cancel do |basic_cancel|
|
62
|
+
@cancellation_notifications << 1
|
63
|
+
end
|
64
|
+
consumer2.on_cancel do |basic_cancel|
|
65
|
+
@cancellation_notifications << 2
|
66
|
+
end
|
67
|
+
|
68
|
+
delayed(1.0) { queue.delete }
|
69
|
+
|
70
|
+
done(2.5) {
|
71
|
+
@cancellation_notifications.sort.should == [1, 2]
|
72
|
+
}
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end # it
|
76
|
+
end # describe AMQ::Client::EventMachineClient, "Basic.Consume"
|
metadata
CHANGED
@@ -1,73 +1,68 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: amq-client
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
prerelease:
|
6
|
-
segments:
|
7
|
-
- 1
|
8
|
-
- 0
|
9
|
-
- 0
|
10
|
-
- pre
|
11
|
-
- 2
|
12
|
-
version: 1.0.0.pre2
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
prerelease:
|
13
6
|
platform: ruby
|
14
|
-
authors:
|
7
|
+
authors:
|
15
8
|
- Jakub Stastny
|
16
9
|
- Michael S. Klishin
|
17
10
|
- Theo Hultberg
|
18
11
|
- Mark Abramov
|
19
|
-
autorequire:
|
12
|
+
autorequire:
|
20
13
|
bindir: bin
|
21
14
|
cert_chain: []
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
- !ruby/object:Gem::Dependency
|
15
|
+
date: 2013-03-23 00:00:00.000000000 Z
|
16
|
+
dependencies:
|
17
|
+
- !ruby/object:Gem::Dependency
|
26
18
|
name: eventmachine
|
27
|
-
|
28
|
-
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: !binary |-
|
24
|
+
MA==
|
29
25
|
none: false
|
30
|
-
|
26
|
+
requirement: !ruby/object:Gem::Requirement
|
27
|
+
requirements:
|
31
28
|
- - ">="
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: !binary |-
|
31
|
+
MA==
|
32
|
+
none: false
|
33
|
+
prerelease: false
|
37
34
|
type: :runtime
|
38
|
-
|
39
|
-
- !ruby/object:Gem::Dependency
|
35
|
+
- !ruby/object:Gem::Dependency
|
40
36
|
name: amq-protocol
|
41
|
-
|
42
|
-
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: 1.2.0
|
43
42
|
none: false
|
44
|
-
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
45
|
- - ">="
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
- 9
|
51
|
-
- 4
|
52
|
-
version: 0.9.4
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 1.2.0
|
48
|
+
none: false
|
49
|
+
prerelease: false
|
53
50
|
type: :runtime
|
54
|
-
version_requirements: *id002
|
55
51
|
description: amq-client is a fully-featured, low-level AMQP 0.9.1 client with pluggable networking I/O adapters (EventMachine, cool.io, Eventpanda and so on) and supposed to back more opinionated AMQP clients (such as amqp gem) or be used directly in cases when access to more advanced AMQP 0.9.1 features is more important that convenient APIs
|
56
|
-
email:
|
57
|
-
-
|
52
|
+
email:
|
53
|
+
- !binary |-
|
54
|
+
c3Rhc3RueUAxMDFpZGVhcy5jeg==
|
58
55
|
- michael@novemberain.com
|
59
56
|
executables: []
|
60
|
-
|
61
57
|
extensions: []
|
62
|
-
|
63
|
-
extra_rdoc_files:
|
58
|
+
extra_rdoc_files:
|
64
59
|
- README.textile
|
65
|
-
files:
|
66
|
-
- .gitignore
|
67
|
-
- .gitmodules
|
68
|
-
- .rspec
|
69
|
-
- .travis.yml
|
70
|
-
- .yardopts
|
60
|
+
files:
|
61
|
+
- ".gitignore"
|
62
|
+
- ".gitmodules"
|
63
|
+
- ".rspec"
|
64
|
+
- ".travis.yml"
|
65
|
+
- ".yardopts"
|
71
66
|
- Gemfile
|
72
67
|
- LICENSE
|
73
68
|
- README.textile
|
@@ -153,6 +148,9 @@ files:
|
|
153
148
|
- lib/amq/client/async/adapters/coolio.rb
|
154
149
|
- lib/amq/client/async/adapters/event_machine.rb
|
155
150
|
- lib/amq/client/async/adapters/eventmachine.rb
|
151
|
+
- lib/amq/client/async/auth_mechanism_adapter.rb
|
152
|
+
- lib/amq/client/async/auth_mechanism_adapter/external.rb
|
153
|
+
- lib/amq/client/async/auth_mechanism_adapter/plain.rb
|
156
154
|
- lib/amq/client/async/callbacks.rb
|
157
155
|
- lib/amq/client/async/channel.rb
|
158
156
|
- lib/amq/client/async/consumer.rb
|
@@ -210,6 +208,7 @@ files:
|
|
210
208
|
- spec/integration/eventmachine/concurrent_basic_publish_spec.rb
|
211
209
|
- spec/integration/eventmachine/connection_close_spec.rb
|
212
210
|
- spec/integration/eventmachine/connection_start_spec.rb
|
211
|
+
- spec/integration/eventmachine/consumer_cancellation_notification_spec.rb
|
213
212
|
- spec/integration/eventmachine/exchange_declare_spec.rb
|
214
213
|
- spec/integration/eventmachine/queue_declare_spec.rb
|
215
214
|
- spec/integration/eventmachine/regressions/amqp_gem_issue66_spec.rb
|
@@ -227,39 +226,29 @@ files:
|
|
227
226
|
- tasks.rb
|
228
227
|
homepage: http://github.com/ruby-amqp/amq-client
|
229
228
|
licenses: []
|
230
|
-
|
231
|
-
post_install_message:
|
229
|
+
post_install_message:
|
232
230
|
rdoc_options: []
|
233
|
-
|
234
|
-
require_paths:
|
231
|
+
require_paths:
|
235
232
|
- lib
|
236
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
233
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
234
|
+
requirements:
|
235
|
+
- - ">="
|
236
|
+
- !ruby/object:Gem::Version
|
237
|
+
version: !binary |-
|
238
|
+
MA==
|
237
239
|
none: false
|
238
|
-
|
240
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
241
|
+
requirements:
|
239
242
|
- - ">="
|
240
|
-
- !ruby/object:Gem::Version
|
241
|
-
|
242
|
-
|
243
|
-
- 0
|
244
|
-
version: "0"
|
245
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
243
|
+
- !ruby/object:Gem::Version
|
244
|
+
version: !binary |-
|
245
|
+
MA==
|
246
246
|
none: false
|
247
|
-
requirements:
|
248
|
-
- - ">"
|
249
|
-
- !ruby/object:Gem::Version
|
250
|
-
hash: 25
|
251
|
-
segments:
|
252
|
-
- 1
|
253
|
-
- 3
|
254
|
-
- 1
|
255
|
-
version: 1.3.1
|
256
247
|
requirements: []
|
257
|
-
|
258
248
|
rubyforge_project: amq-client
|
259
249
|
rubygems_version: 1.8.24
|
260
|
-
signing_key:
|
250
|
+
signing_key:
|
261
251
|
specification_version: 3
|
262
252
|
summary: amq-client is a fully-featured, low-level AMQP 0.9.1 client
|
263
253
|
test_files: []
|
264
|
-
|
265
|
-
has_rdoc:
|
254
|
+
has_rdoc:
|