amqp 0.7.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +3 -2
- data/CHANGELOG +25 -0
- data/Gemfile +4 -2
- data/README.md +2 -0
- data/{amqp.todo → TODO} +1 -3
- data/amqp.gemspec +3 -3
- data/bin/irb +2 -2
- data/bin/jenkins.sh +25 -0
- data/bin/set_test_suite_realms_up.sh +21 -0
- data/doc/EXAMPLE_01_PINGPONG +1 -1
- data/doc/EXAMPLE_02_CLOCK +1 -1
- data/doc/EXAMPLE_03_STOCKS +1 -1
- data/doc/EXAMPLE_04_MULTICLOCK +1 -1
- data/doc/EXAMPLE_05_ACK +1 -1
- data/doc/EXAMPLE_05_POP +1 -1
- data/doc/EXAMPLE_06_HASHTABLE +1 -1
- data/examples/{mq/ack.rb → ack.rb} +6 -6
- data/examples/{mq/automatic_binding_for_default_direct_exchange.rb → automatic_binding_for_default_direct_exchange.rb} +4 -4
- data/examples/{mq/callbacks.rb → callbacks.rb} +2 -2
- data/examples/{mq/clock.rb → clock.rb} +5 -5
- data/examples/{mq/hashtable.rb → hashtable.rb} +4 -4
- data/examples/{mq/internal.rb → internal.rb} +5 -5
- data/examples/{mq/logger.rb → logger.rb} +5 -5
- data/examples/{mq/multiclock.rb → multiclock.rb} +4 -4
- data/examples/{mq/pingpong.rb → pingpong.rb} +5 -5
- data/examples/{mq/pop.rb → pop.rb} +3 -3
- data/examples/{mq/primes-simple.rb → primes-simple.rb} +0 -0
- data/examples/{mq/primes.rb → primes.rb} +6 -6
- data/examples/{amqp/simple.rb → simple.rb} +1 -1
- data/examples/{mq/stocks.rb → stocks.rb} +5 -5
- data/lib/amqp.rb +8 -112
- data/lib/amqp/basic_client.rb +58 -0
- data/lib/amqp/channel.rb +937 -0
- data/lib/amqp/client.rb +72 -79
- data/lib/{mq → amqp}/collection.rb +12 -2
- data/lib/amqp/connection.rb +115 -0
- data/lib/amqp/exceptions.rb +18 -0
- data/lib/{mq → amqp}/exchange.rb +32 -34
- data/lib/{ext → amqp/ext}/em.rb +1 -1
- data/lib/{ext → amqp/ext}/emfork.rb +0 -0
- data/lib/amqp/frame.rb +3 -3
- data/lib/{mq → amqp}/header.rb +5 -11
- data/lib/{mq → amqp}/logger.rb +2 -2
- data/lib/amqp/protocol.rb +2 -2
- data/lib/{mq → amqp}/queue.rb +20 -17
- data/lib/{mq → amqp}/rpc.rb +20 -8
- data/lib/amqp/server.rb +1 -1
- data/lib/amqp/version.rb +1 -1
- data/lib/mq.rb +20 -964
- data/protocol/codegen.rb +1 -1
- data/research/api.rb +3 -3
- data/research/primes-forked.rb +5 -5
- data/research/primes-processes.rb +5 -5
- data/research/primes-threaded.rb +5 -5
- data/spec/integration/authentication_spec.rb +114 -0
- data/spec/integration/automatic_binding_for_default_direct_exchange_spec.rb +13 -12
- data/spec/{unit/mq → integration}/channel_close_spec.rb +2 -2
- data/spec/{unit/mq → integration}/exchange_declaration_spec.rb +26 -14
- data/spec/{unit/mq → integration}/queue_declaration_spec.rb +4 -4
- data/spec/integration/queue_exclusivity_spec.rb +95 -0
- data/spec/integration/reply_queue_communication_spec.rb +63 -0
- data/spec/integration/store_and_forward_spec.rb +121 -0
- data/spec/integration/topic_subscription_spec.rb +193 -0
- data/spec/integration/workload_distribution_spec.rb +245 -0
- data/spec/spec_helper.rb +16 -32
- data/spec/unit/{mq/mq_basic_spec.rb → amqp/basic_spec.rb} +4 -4
- data/spec/unit/{mq → amqp}/collection_spec.rb +22 -7
- data/spec/unit/amqp/connection_spec.rb +116 -0
- data/spec/unit/amqp/frame_spec.rb +18 -18
- data/spec/unit/amqp/protocol_spec.rb +9 -11
- metadata +54 -49
- data/lib/ext/blankslate.rb +0 -9
- data/spec/mq_helper.rb +0 -70
- data/spec/unit/amqp/client_spec.rb +0 -472
- data/spec/unit/amqp/misc_spec.rb +0 -123
- data/spec/unit/mq/misc_spec.rb +0 -228
- data/spec/unit/mq/queue_spec.rb +0 -71
@@ -0,0 +1,95 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe "Non-exclusive queue" do
|
6
|
+
|
7
|
+
#
|
8
|
+
# Environment
|
9
|
+
#
|
10
|
+
|
11
|
+
include AMQP::Spec
|
12
|
+
|
13
|
+
default_timeout 5
|
14
|
+
|
15
|
+
amqp_before do
|
16
|
+
@connection1 = AMQP.connect
|
17
|
+
@connection2 = AMQP.connect
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
|
22
|
+
#
|
23
|
+
# Examples
|
24
|
+
#
|
25
|
+
|
26
|
+
it "can be used across multiple connections" do
|
27
|
+
@connection1.should_not == @connection2
|
28
|
+
|
29
|
+
channel1 = AMQP::Channel.new(@connection1)
|
30
|
+
channel2 = AMQP::Channel.new(@connection2)
|
31
|
+
|
32
|
+
instance1 = AMQP::Queue.new(channel1, "amqpgem.integration.queues.non-exclusive", :exclusive => false, :auto_delete => true)
|
33
|
+
instance2 = AMQP::Queue.new(channel2, "amqpgem.integration.queues.non-exclusive", :exclusive => false, :auto_delete => true)
|
34
|
+
|
35
|
+
exchange1 = channel1.fanout("amqpgem.integration.exchanges.fanout1", :auto_delete => true)
|
36
|
+
exchange2 = channel2.fanout("amqpgem.integration.exchanges.fanout2", :auto_delete => true)
|
37
|
+
|
38
|
+
|
39
|
+
instance1.bind(exchange1).subscribe do |payload|
|
40
|
+
end
|
41
|
+
|
42
|
+
instance2.bind(exchange2).subscribe do |payload|
|
43
|
+
end
|
44
|
+
|
45
|
+
done(0.2) {
|
46
|
+
channel1.should be_open
|
47
|
+
channel1.close
|
48
|
+
|
49
|
+
channel2.should be_open
|
50
|
+
channel2.close
|
51
|
+
}
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
|
57
|
+
describe "Exclusive queue" do
|
58
|
+
|
59
|
+
#
|
60
|
+
# Environment
|
61
|
+
#
|
62
|
+
|
63
|
+
include AMQP::Spec
|
64
|
+
|
65
|
+
default_timeout 1
|
66
|
+
|
67
|
+
amqp_before do
|
68
|
+
@connection1 = AMQP.connect
|
69
|
+
@connection2 = AMQP.connect
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
#
|
74
|
+
# Examples
|
75
|
+
#
|
76
|
+
|
77
|
+
it "can ONLY be used by ONE connection" do
|
78
|
+
@connection1.should_not == @connection2
|
79
|
+
|
80
|
+
channel1 = AMQP::Channel.new(@connection1)
|
81
|
+
channel2 = AMQP::Channel.new(@connection2)
|
82
|
+
|
83
|
+
AMQP::Queue.new(channel1, "amqpgem.integration.queues.exclusive", :exclusive => true)
|
84
|
+
sleep 0.1
|
85
|
+
|
86
|
+
AMQP::Queue.new(channel2, "amqpgem.integration.queues.exclusive", :exclusive => true)
|
87
|
+
|
88
|
+
|
89
|
+
done(0.2) {
|
90
|
+
channel1.should_not be_closed
|
91
|
+
# because it is a channel-level exception
|
92
|
+
channel2.should be_closed
|
93
|
+
}
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require "spec_helper"
|
3
|
+
|
4
|
+
describe "Exclusive server-named queue" do
|
5
|
+
|
6
|
+
#
|
7
|
+
# Environment
|
8
|
+
#
|
9
|
+
|
10
|
+
include AMQP::Spec
|
11
|
+
|
12
|
+
default_timeout 1
|
13
|
+
|
14
|
+
amqp_before do
|
15
|
+
@channel = AMQP::Channel.new
|
16
|
+
@channel.should be_open
|
17
|
+
|
18
|
+
@exchange = AMQP::Exchange.default(@channel)
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
|
23
|
+
it "can be used for temporary point-to-point communication" do
|
24
|
+
@exchange.channel.should == @channel
|
25
|
+
|
26
|
+
@channel.queue("", :exclusive => true) do |queue1|
|
27
|
+
@channel.queue("", :exclusive => true) do |queue2|
|
28
|
+
request_timestamp = Time.now
|
29
|
+
reply_timestamp = nil
|
30
|
+
|
31
|
+
queue1.subscribe do |header, body|
|
32
|
+
header.timestamp.to_i.should == request_timestamp.to_i
|
33
|
+
header.app_id.should == "Client"
|
34
|
+
header.reply_to.should == queue2.name
|
35
|
+
|
36
|
+
reply_timestamp = Time.now
|
37
|
+
@exchange.publish(rand(1000), :routing_key => header.reply_to, :reply_to => queue1.name, :app_id => "Server", :timestamp => reply_timestamp)
|
38
|
+
end
|
39
|
+
|
40
|
+
queue2.subscribe do |header, body|
|
41
|
+
header.timestamp.to_i.should == reply_timestamp.to_i
|
42
|
+
header.app_id.should == "Server"
|
43
|
+
header.reply_to.should == queue1.name
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
# publish the request
|
48
|
+
@exchange.publish(rand(1000),
|
49
|
+
:routing_key => queue1.name,
|
50
|
+
:reply_to => queue2.name,
|
51
|
+
:app_id => "Client",
|
52
|
+
:timestamp => request_timestamp,
|
53
|
+
:mandatory => true,
|
54
|
+
:immediate => true)
|
55
|
+
|
56
|
+
done(0.1) {
|
57
|
+
queue1.unsubscribe
|
58
|
+
queue2.unsubscribe
|
59
|
+
}
|
60
|
+
end # do
|
61
|
+
end # do
|
62
|
+
end # it
|
63
|
+
end # describe
|
@@ -0,0 +1,121 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require "spec_helper"
|
3
|
+
|
4
|
+
describe "Store-and-forward routing" do
|
5
|
+
|
6
|
+
#
|
7
|
+
# Environment
|
8
|
+
#
|
9
|
+
|
10
|
+
include AMQP::Spec
|
11
|
+
include AMQP::SpecHelper
|
12
|
+
|
13
|
+
em_before { AMQP.cleanup_state }
|
14
|
+
em_after { AMQP.cleanup_state }
|
15
|
+
|
16
|
+
default_options AMQP_OPTS
|
17
|
+
default_timeout 10
|
18
|
+
|
19
|
+
amqp_before do
|
20
|
+
@channel = AMQP::Channel.new
|
21
|
+
@channel.should be_open
|
22
|
+
end
|
23
|
+
|
24
|
+
after(:all) do
|
25
|
+
AMQP.cleanup_state
|
26
|
+
done
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
#
|
31
|
+
# Examples
|
32
|
+
#
|
33
|
+
|
34
|
+
context "that uses fanout exchange" do
|
35
|
+
context "with a single bound queue" do
|
36
|
+
amqp_before do
|
37
|
+
@exchange = @channel.fanout("amqpgem.integration.snf.fanout", :auto_delete => true)
|
38
|
+
@queue = @channel.queue("amqpgem.integration.snf.queue1", :auto_delete => true)
|
39
|
+
|
40
|
+
@queue.bind(@exchange)
|
41
|
+
end
|
42
|
+
|
43
|
+
it "allows asynchronous subscription to messages WITHOUT acknowledgements" do
|
44
|
+
number_of_received_messages = 0
|
45
|
+
# put a little pressure
|
46
|
+
expected_number_of_messages = 300
|
47
|
+
# It is always a good idea to use non-ASCII charachters in
|
48
|
+
# various test suites. MK.
|
49
|
+
dispatched_data = "libertà è participazione (inviato a #{Time.now.to_i})"
|
50
|
+
|
51
|
+
@queue.subscribe(:ack => false) do |payload|
|
52
|
+
number_of_received_messages += 1
|
53
|
+
if RUBY_VERSION =~ /^1.9/
|
54
|
+
payload.force_encoding("UTF-8").should == dispatched_data
|
55
|
+
else
|
56
|
+
payload.should == dispatched_data
|
57
|
+
end
|
58
|
+
end # subscribe
|
59
|
+
|
60
|
+
expected_number_of_messages.times do
|
61
|
+
@exchange.publish(dispatched_data)
|
62
|
+
end
|
63
|
+
|
64
|
+
# 6 seconds are for Rubinius, it is surprisingly slow on this workload
|
65
|
+
done(4.0) {
|
66
|
+
number_of_received_messages.should == expected_number_of_messages
|
67
|
+
@queue.unsubscribe
|
68
|
+
}
|
69
|
+
end # it
|
70
|
+
|
71
|
+
|
72
|
+
it "allows asynchronous subscription to messages WITH acknowledgements" do
|
73
|
+
number_of_received_messages = 0
|
74
|
+
expected_number_of_messages = 500
|
75
|
+
|
76
|
+
@queue.subscribe(:ack => true) do |payload|
|
77
|
+
number_of_received_messages += 1
|
78
|
+
end # subscribe
|
79
|
+
|
80
|
+
expected_number_of_messages.times do
|
81
|
+
@exchange.publish(rand)
|
82
|
+
end
|
83
|
+
|
84
|
+
# 6 seconds are for Rubinius, it is surprisingly slow on this workload
|
85
|
+
done(3.0) {
|
86
|
+
number_of_received_messages.should == expected_number_of_messages
|
87
|
+
@queue.unsubscribe
|
88
|
+
}
|
89
|
+
end # it
|
90
|
+
|
91
|
+
|
92
|
+
|
93
|
+
it "allows synchronous fetching of messages" do
|
94
|
+
number_of_received_messages = 0
|
95
|
+
expected_number_of_messages = 300
|
96
|
+
|
97
|
+
dispatched_data = "fetch me synchronously"
|
98
|
+
|
99
|
+
expected_number_of_messages.times do
|
100
|
+
@exchange.publish(dispatched_data)
|
101
|
+
end
|
102
|
+
|
103
|
+
expected_number_of_messages.times do
|
104
|
+
@queue.pop do |payload|
|
105
|
+
number_of_received_messages += 1
|
106
|
+
|
107
|
+
if RUBY_VERSION =~ /^1.9/
|
108
|
+
payload.force_encoding("UTF-8").should == dispatched_data
|
109
|
+
else
|
110
|
+
payload.should == dispatched_data
|
111
|
+
end
|
112
|
+
end # pop
|
113
|
+
end # do
|
114
|
+
|
115
|
+
done(0.5) {
|
116
|
+
number_of_received_messages.should == expected_number_of_messages
|
117
|
+
}
|
118
|
+
end # it
|
119
|
+
end # context
|
120
|
+
end # context
|
121
|
+
end # describe
|
@@ -0,0 +1,193 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require "spec_helper"
|
3
|
+
|
4
|
+
describe "Topic-based subscription" do
|
5
|
+
|
6
|
+
#
|
7
|
+
# Environment
|
8
|
+
#
|
9
|
+
|
10
|
+
include AMQP::Spec
|
11
|
+
include AMQP::SpecHelper
|
12
|
+
|
13
|
+
em_before { AMQP.cleanup_state }
|
14
|
+
em_after { AMQP.cleanup_state }
|
15
|
+
|
16
|
+
default_options AMQP_OPTS
|
17
|
+
default_timeout 10
|
18
|
+
|
19
|
+
amqp_before do
|
20
|
+
@channel = AMQP::Channel.new
|
21
|
+
@channel.should be_open
|
22
|
+
|
23
|
+
@exchange = @channel.topic
|
24
|
+
end
|
25
|
+
|
26
|
+
after(:all) do
|
27
|
+
AMQP.cleanup_state
|
28
|
+
done
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
#
|
33
|
+
# Examples
|
34
|
+
#
|
35
|
+
|
36
|
+
context "when keys match exactly" do
|
37
|
+
it "routes messages to bound queues" do
|
38
|
+
@aapl_queue = @channel.queue("AAPL queue", :auto_delete => true)
|
39
|
+
@amzn_queue = @channel.queue("AMZN queue", :auto_delete => true)
|
40
|
+
|
41
|
+
received_messages = {
|
42
|
+
@aapl_queue.name => 0,
|
43
|
+
@amzn_queue.name => 0
|
44
|
+
}
|
45
|
+
|
46
|
+
expected_messages = {
|
47
|
+
@aapl_queue.name => 4,
|
48
|
+
@amzn_queue.name => 2
|
49
|
+
}
|
50
|
+
|
51
|
+
@aapl_queue.bind(@exchange, :key => "nasdaq.aapl").subscribe do |payload|
|
52
|
+
received_messages[@aapl_queue.name] += 1
|
53
|
+
end
|
54
|
+
@amzn_queue.bind(@exchange, :key => "nasdaq.amzn").subscribe do |payload|
|
55
|
+
received_messages[@amzn_queue.name] += 1
|
56
|
+
end
|
57
|
+
|
58
|
+
4.times do
|
59
|
+
@exchange.publish(332 + rand(1000)/400.0, :key => "nasdaq.aapl")
|
60
|
+
end
|
61
|
+
|
62
|
+
2.times do
|
63
|
+
@exchange.publish(181 + rand(1000)/400.0, :key => "nasdaq.amzn")
|
64
|
+
end
|
65
|
+
|
66
|
+
# publish some messages none of our queues should be receiving
|
67
|
+
3.times do
|
68
|
+
@exchange.publish(626 + rand(1000)/400.0, :key => "nasdaq.goog")
|
69
|
+
end # do
|
70
|
+
|
71
|
+
done(0.2) {
|
72
|
+
received_messages.should == expected_messages
|
73
|
+
@aapl_queue.unsubscribe
|
74
|
+
@amzn_queue.unsubscribe
|
75
|
+
}
|
76
|
+
end # it
|
77
|
+
end # context
|
78
|
+
|
79
|
+
|
80
|
+
context "when key matches on * (single word globbing)" do
|
81
|
+
it "routes messages to bound queues" do
|
82
|
+
@nba_queue = @channel.queue("NBA queue", :auto_delete => true)
|
83
|
+
@knicks_queue = @channel.queue("New York Knicks queue", :auto_delete => true)
|
84
|
+
@celtics_queue = @channel.queue("Boston Celtics queue", :auto_delete => true)
|
85
|
+
|
86
|
+
received_messages = {
|
87
|
+
@nba_queue.name => 0,
|
88
|
+
@knicks_queue.name => 0,
|
89
|
+
@celtics_queue.name => 0
|
90
|
+
}
|
91
|
+
|
92
|
+
expected_messages = {
|
93
|
+
@nba_queue.name => 7,
|
94
|
+
@knicks_queue.name => 2,
|
95
|
+
@celtics_queue.name => 3
|
96
|
+
}
|
97
|
+
|
98
|
+
@nba_queue.bind(@exchange, :key => "sports.nba.*").subscribe do |payload|
|
99
|
+
received_messages[@nba_queue.name] += 1
|
100
|
+
end
|
101
|
+
|
102
|
+
@knicks_queue.bind(@exchange, :key => "sports.nba.knicks").subscribe do |payload|
|
103
|
+
received_messages[@knicks_queue.name] += 1
|
104
|
+
end
|
105
|
+
|
106
|
+
@celtics_queue.bind(@exchange, :key => "sports.nba.celtics").subscribe do |payload|
|
107
|
+
received_messages[@celtics_queue.name] += 1
|
108
|
+
end
|
109
|
+
|
110
|
+
@exchange.publish("Houston Rockets 104 : New York Knicks 89", :key => "sports.nba.knicks")
|
111
|
+
@exchange.publish("Phoenix Suns 129 : New York Knicks 121", :key => "sports.nba.knicks")
|
112
|
+
|
113
|
+
@exchange.publish("Ray Allen hit a 21-foot jumper with 24.5 seconds remaining on the clock to give Boston a win over Detroit last night in the TD Garden", :key => "sports.nba.celtics")
|
114
|
+
@exchange.publish("Garnett's Return Sparks Celtics Over Magic at Garden", :key => "sports.nba.celtics")
|
115
|
+
@exchange.publish("Tricks of the Trade: Allen Reveals Magic of Big Shots", :key => "sports.nba.celtics")
|
116
|
+
|
117
|
+
@exchange.publish("Blatche, Wall lead Wizards over Jazz 108-101", :key => "sports.nba.jazz")
|
118
|
+
@exchange.publish("Deron Williams Receives NBA Cares Community Assist Award", :key => "sports.nba.jazz")
|
119
|
+
|
120
|
+
done(0.2) {
|
121
|
+
received_messages.should == expected_messages
|
122
|
+
|
123
|
+
@nba_queue.unsubscribe
|
124
|
+
@knicks_queue.unsubscribe
|
125
|
+
@celtics_queue.unsubscribe
|
126
|
+
}
|
127
|
+
end # it
|
128
|
+
end # context
|
129
|
+
|
130
|
+
|
131
|
+
|
132
|
+
|
133
|
+
context "when key matches on # (multiple words globbing)" do
|
134
|
+
it "routes messages to bound queues" do
|
135
|
+
@sports_queue = @channel.queue("Sports queue", :auto_delete => true)
|
136
|
+
@nba_queue = @channel.queue("NBA queue", :auto_delete => true)
|
137
|
+
@knicks_queue = @channel.queue("New York Knicks queue", :auto_delete => true)
|
138
|
+
@celtics_queue = @channel.queue("Boston Celtics queue", :auto_delete => true)
|
139
|
+
|
140
|
+
received_messages = {
|
141
|
+
@sports_queue.name => 0,
|
142
|
+
@nba_queue.name => 0,
|
143
|
+
@knicks_queue.name => 0,
|
144
|
+
@celtics_queue.name => 0
|
145
|
+
}
|
146
|
+
|
147
|
+
expected_messages = {
|
148
|
+
@sports_queue.name => 9,
|
149
|
+
@nba_queue.name => 7,
|
150
|
+
@knicks_queue.name => 2,
|
151
|
+
@celtics_queue.name => 3
|
152
|
+
}
|
153
|
+
|
154
|
+
@sports_queue.bind(@exchange, :key => "sports.#").subscribe do |payload|
|
155
|
+
received_messages[@sports_queue.name] += 1
|
156
|
+
end
|
157
|
+
|
158
|
+
@nba_queue.bind(@exchange, :key => "*.nba.*").subscribe do |payload|
|
159
|
+
received_messages[@nba_queue.name] += 1
|
160
|
+
end
|
161
|
+
|
162
|
+
@knicks_queue.bind(@exchange, :key => "sports.nba.knicks").subscribe do |payload|
|
163
|
+
received_messages[@knicks_queue.name] += 1
|
164
|
+
end
|
165
|
+
|
166
|
+
@celtics_queue.bind(@exchange, :key => "#.celtics").subscribe do |payload|
|
167
|
+
received_messages[@celtics_queue.name] += 1
|
168
|
+
end
|
169
|
+
|
170
|
+
@exchange.publish("Houston Rockets 104 : New York Knicks 89", :key => "sports.nba.knicks")
|
171
|
+
@exchange.publish("Phoenix Suns 129 : New York Knicks 121", :key => "sports.nba.knicks")
|
172
|
+
|
173
|
+
@exchange.publish("Ray Allen hit a 21-foot jumper with 24.5 seconds remaining on the clock to give Boston a win over Detroit last night in the TD Garden", :key => "sports.nba.celtics")
|
174
|
+
@exchange.publish("Garnett's Return Sparks Celtics Over Magic at Garden", :key => "sports.nba.celtics")
|
175
|
+
@exchange.publish("Tricks of the Trade: Allen Reveals Magic of Big Shots", :key => "sports.nba.celtics")
|
176
|
+
|
177
|
+
@exchange.publish("Blatche, Wall lead Wizards over Jazz 108-101", :key => "sports.nba.jazz")
|
178
|
+
@exchange.publish("Deron Williams Receives NBA Cares Community Assist Award", :key => "sports.nba.jazz")
|
179
|
+
|
180
|
+
@exchange.publish("Philadelphia's Daniel Briere has been named as an All-Star replacement for Jarome Iginla.", :key => "sports.nhl.allstargame")
|
181
|
+
@exchange.publish("Devils blank Sid- and Malkin-less Penguins 2-0", :key => "sports.nhl.penguins")
|
182
|
+
|
183
|
+
done(0.2) {
|
184
|
+
received_messages.should == expected_messages
|
185
|
+
|
186
|
+
@sports_queue.unsubscribe
|
187
|
+
@nba_queue.unsubscribe
|
188
|
+
@knicks_queue.unsubscribe
|
189
|
+
@celtics_queue.unsubscribe
|
190
|
+
}
|
191
|
+
end # it
|
192
|
+
end # context
|
193
|
+
end # describe
|