amqp 0.7.0 → 0.7.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|