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
@@ -8,53 +8,53 @@ describe AMQP::Frame do
|
|
8
8
|
include AMQP
|
9
9
|
|
10
10
|
it 'should handle basic frame types' do
|
11
|
-
Frame::Method.new.id.should == 1
|
12
|
-
Frame::Header.new.id.should == 2
|
13
|
-
Frame::Body.new.id.should == 3
|
11
|
+
AMQP::Frame::Method.new.id.should == 1
|
12
|
+
AMQP::Frame::Header.new.id.should == 2
|
13
|
+
AMQP::Frame::Body.new.id.should == 3
|
14
14
|
end
|
15
15
|
|
16
16
|
it 'should convert method frames to binary' do
|
17
|
-
meth = Protocol::Connection::Secure.new :challenge => 'secret'
|
17
|
+
meth = AMQP::Protocol::Connection::Secure.new :challenge => 'secret'
|
18
18
|
|
19
|
-
frame = Frame::Method.new(meth)
|
20
|
-
frame.to_binary.should be_kind_of
|
19
|
+
frame = AMQP::Frame::Method.new(meth)
|
20
|
+
frame.to_binary.should be_kind_of(AMQP::Buffer)
|
21
21
|
frame.to_s.should == [1, 0, meth.to_s.length, meth.to_s, 206].pack('CnNa*C')
|
22
22
|
end
|
23
23
|
|
24
24
|
it 'should convert binary to method frames' do
|
25
|
-
orig = Frame::Method.new
|
25
|
+
orig = AMQP::Frame::Method.new(AMQP::Protocol::Connection::Secure.new(:challenge => 'secret'))
|
26
26
|
|
27
|
-
copy = Frame.parse(orig.to_binary)
|
27
|
+
copy = AMQP::Frame.parse(orig.to_binary)
|
28
28
|
copy.should == orig
|
29
29
|
end
|
30
30
|
|
31
31
|
it 'should ignore partial frames until ready' do
|
32
|
-
frame = Frame::Method.new
|
32
|
+
frame = AMQP::Frame::Method.new(AMQP::Protocol::Connection::Secure.new(:challenge => 'secret'))
|
33
33
|
data = frame.to_s
|
34
34
|
|
35
|
-
buf = Buffer.new
|
36
|
-
Frame.parse(buf).should == nil
|
35
|
+
buf = AMQP::Buffer.new
|
36
|
+
AMQP::Frame.parse(buf).should == nil
|
37
37
|
|
38
38
|
buf << data[0..5]
|
39
|
-
Frame.parse(buf).should == nil
|
39
|
+
AMQP::Frame.parse(buf).should == nil
|
40
40
|
|
41
41
|
buf << data[6..-1]
|
42
|
-
Frame.parse(buf).should == frame
|
42
|
+
AMQP::Frame.parse(buf).should == frame
|
43
43
|
|
44
|
-
Frame.parse(buf).should == nil
|
44
|
+
AMQP::Frame.parse(buf).should == nil
|
45
45
|
end
|
46
46
|
|
47
47
|
it 'should convert header frames to binary' do
|
48
|
-
head = Protocol::Header.new(Protocol::Basic, :priority => 1)
|
48
|
+
head = AMQP::Protocol::Header.new(AMQP::Protocol::Basic, :priority => 1)
|
49
49
|
|
50
|
-
frame = Frame::Header.new(head)
|
50
|
+
frame = AMQP::Frame::Header.new(head)
|
51
51
|
frame.to_s.should == [2, 0, head.to_s.length, head.to_s, 206].pack('CnNa*C')
|
52
52
|
end
|
53
53
|
|
54
54
|
it 'should convert binary to header frame' do
|
55
|
-
orig = Frame::Header.new
|
55
|
+
orig = AMQP::Frame::Header.new(AMQP::Protocol::Header.new(AMQP::Protocol::Basic, :priority => 1))
|
56
56
|
|
57
|
-
copy = Frame.parse(orig.to_binary)
|
57
|
+
copy = AMQP::Frame.parse(orig.to_binary)
|
58
58
|
copy.should == orig
|
59
59
|
end
|
60
60
|
end
|
@@ -4,34 +4,32 @@ require "spec_helper"
|
|
4
4
|
require "amqp/protocol"
|
5
5
|
|
6
6
|
describe AMQP::Protocol do
|
7
|
-
include AMQP
|
8
|
-
|
9
7
|
it 'should instantiate methods with arguments' do
|
10
|
-
meth = Protocol::Connection::StartOk.new nil, 'PLAIN', nil, 'en_US'
|
8
|
+
meth = AMQP::Protocol::Connection::StartOk.new nil, 'PLAIN', nil, 'en_US'
|
11
9
|
meth.locale.should == 'en_US'
|
12
10
|
end
|
13
11
|
|
14
12
|
it 'should instantiate methods with named parameters' do
|
15
|
-
meth = Protocol::Connection::StartOk.new :locale => 'en_US',
|
13
|
+
meth = AMQP::Protocol::Connection::StartOk.new :locale => 'en_US',
|
16
14
|
:mechanism => 'PLAIN'
|
17
15
|
meth.locale.should == 'en_US'
|
18
16
|
end
|
19
17
|
|
20
18
|
it 'should convert methods to binary' do
|
21
|
-
meth = Protocol::Connection::Secure.new :challenge => 'secret'
|
22
|
-
meth.to_binary.should be_kind_of Buffer
|
19
|
+
meth = AMQP::Protocol::Connection::Secure.new :challenge => 'secret'
|
20
|
+
meth.to_binary.should be_kind_of AMQP::Buffer
|
23
21
|
|
24
22
|
meth.to_s.should == [10, 20, 6, 'secret'].pack('nnNa*')
|
25
23
|
end
|
26
24
|
|
27
25
|
it 'should convert binary to method' do
|
28
|
-
orig = Protocol::Connection::Secure.new :challenge => 'secret'
|
29
|
-
copy = Protocol.parse orig.to_binary
|
26
|
+
orig = AMQP::Protocol::Connection::Secure.new :challenge => 'secret'
|
27
|
+
copy = AMQP::Protocol.parse orig.to_binary
|
30
28
|
orig.should == copy
|
31
29
|
end
|
32
30
|
|
33
31
|
it 'should convert headers to binary' do
|
34
|
-
head = Protocol::Header.new Protocol::Basic,
|
32
|
+
head = AMQP::Protocol::Header.new AMQP::Protocol::Basic,
|
35
33
|
size = 5,
|
36
34
|
weight = 0,
|
37
35
|
:content_type => 'text/json',
|
@@ -42,12 +40,12 @@ describe AMQP::Protocol do
|
|
42
40
|
end
|
43
41
|
|
44
42
|
it 'should convert binary to header' do
|
45
|
-
orig = Protocol::Header.new Protocol::Basic,
|
43
|
+
orig = AMQP::Protocol::Header.new AMQP::Protocol::Basic,
|
46
44
|
size = 5,
|
47
45
|
weight = 0,
|
48
46
|
:content_type => 'text/json',
|
49
47
|
:delivery_mode => 1,
|
50
48
|
:priority => 1
|
51
|
-
Protocol::Header.new(orig.to_binary).should == orig
|
49
|
+
AMQP::Protocol::Header.new(orig.to_binary).should == orig
|
52
50
|
end
|
53
51
|
end
|
metadata
CHANGED
@@ -1,20 +1,22 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: amqp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
+
hash: 1
|
4
5
|
prerelease: false
|
5
6
|
segments:
|
6
7
|
- 0
|
7
8
|
- 7
|
8
|
-
-
|
9
|
-
version: 0.7.
|
9
|
+
- 1
|
10
|
+
version: 0.7.1
|
10
11
|
platform: ruby
|
11
12
|
authors:
|
12
13
|
- Aman Gupta
|
13
14
|
- Jakub Stastny aka botanicus
|
15
|
+
- Michael S. Klishin
|
14
16
|
autorequire:
|
15
17
|
bindir: bin
|
16
18
|
cert_chain:
|
17
|
-
date: 2011-
|
19
|
+
date: 2011-03-18 00:00:00 +03:00
|
18
20
|
default_executable:
|
19
21
|
dependencies:
|
20
22
|
- !ruby/object:Gem::Dependency
|
@@ -25,6 +27,7 @@ dependencies:
|
|
25
27
|
requirements:
|
26
28
|
- - ">="
|
27
29
|
- !ruby/object:Gem::Version
|
30
|
+
hash: 39
|
28
31
|
segments:
|
29
32
|
- 0
|
30
33
|
- 12
|
@@ -33,7 +36,9 @@ dependencies:
|
|
33
36
|
type: :runtime
|
34
37
|
version_requirements: *id001
|
35
38
|
description: An implementation of the AMQP protocol in Ruby/EventMachine for writing clients to the RabbitMQ message broker.
|
36
|
-
email:
|
39
|
+
email:
|
40
|
+
- michael@novemberain.com
|
41
|
+
- stastny@101ideas.cz
|
37
42
|
executables: []
|
38
43
|
|
39
44
|
extensions: []
|
@@ -55,11 +60,13 @@ files:
|
|
55
60
|
- Gemfile
|
56
61
|
- README.md
|
57
62
|
- Rakefile
|
63
|
+
- TODO
|
58
64
|
- amqp.gemspec
|
59
65
|
- amqp.pre.gemspec
|
60
|
-
- amqp.todo
|
61
66
|
- bin/cleanify.rb
|
62
67
|
- bin/irb
|
68
|
+
- bin/jenkins.sh
|
69
|
+
- bin/set_test_suite_realms_up.sh
|
63
70
|
- doc/EXAMPLE_01_PINGPONG
|
64
71
|
- doc/EXAMPLE_02_CLOCK
|
65
72
|
- doc/EXAMPLE_03_STOCKS
|
@@ -67,38 +74,41 @@ files:
|
|
67
74
|
- doc/EXAMPLE_05_ACK
|
68
75
|
- doc/EXAMPLE_05_POP
|
69
76
|
- doc/EXAMPLE_06_HASHTABLE
|
70
|
-
- examples/
|
71
|
-
- examples/
|
72
|
-
- examples/
|
73
|
-
- examples/
|
74
|
-
- examples/
|
75
|
-
- examples/
|
76
|
-
- examples/
|
77
|
-
- examples/
|
78
|
-
- examples/
|
79
|
-
- examples/
|
80
|
-
- examples/
|
81
|
-
- examples/
|
82
|
-
- examples/
|
83
|
-
- examples/
|
77
|
+
- examples/ack.rb
|
78
|
+
- examples/automatic_binding_for_default_direct_exchange.rb
|
79
|
+
- examples/callbacks.rb
|
80
|
+
- examples/clock.rb
|
81
|
+
- examples/hashtable.rb
|
82
|
+
- examples/internal.rb
|
83
|
+
- examples/logger.rb
|
84
|
+
- examples/multiclock.rb
|
85
|
+
- examples/pingpong.rb
|
86
|
+
- examples/pop.rb
|
87
|
+
- examples/primes-simple.rb
|
88
|
+
- examples/primes.rb
|
89
|
+
- examples/simple.rb
|
90
|
+
- examples/stocks.rb
|
84
91
|
- lib/amqp.rb
|
92
|
+
- lib/amqp/basic_client.rb
|
85
93
|
- lib/amqp/buffer.rb
|
94
|
+
- lib/amqp/channel.rb
|
86
95
|
- lib/amqp/client.rb
|
96
|
+
- lib/amqp/collection.rb
|
97
|
+
- lib/amqp/connection.rb
|
98
|
+
- lib/amqp/exceptions.rb
|
99
|
+
- lib/amqp/exchange.rb
|
100
|
+
- lib/amqp/ext/em.rb
|
101
|
+
- lib/amqp/ext/emfork.rb
|
87
102
|
- lib/amqp/frame.rb
|
103
|
+
- lib/amqp/header.rb
|
104
|
+
- lib/amqp/logger.rb
|
88
105
|
- lib/amqp/protocol.rb
|
106
|
+
- lib/amqp/queue.rb
|
107
|
+
- lib/amqp/rpc.rb
|
89
108
|
- lib/amqp/server.rb
|
90
109
|
- lib/amqp/spec.rb
|
91
110
|
- lib/amqp/version.rb
|
92
|
-
- lib/ext/blankslate.rb
|
93
|
-
- lib/ext/em.rb
|
94
|
-
- lib/ext/emfork.rb
|
95
111
|
- lib/mq.rb
|
96
|
-
- lib/mq/collection.rb
|
97
|
-
- lib/mq/exchange.rb
|
98
|
-
- lib/mq/header.rb
|
99
|
-
- lib/mq/logger.rb
|
100
|
-
- lib/mq/queue.rb
|
101
|
-
- lib/mq/rpc.rb
|
102
112
|
- protocol/amqp-0.8.json
|
103
113
|
- protocol/amqp-0.8.xml
|
104
114
|
- protocol/codegen.rb
|
@@ -107,37 +117,30 @@ files:
|
|
107
117
|
- research/primes-forked.rb
|
108
118
|
- research/primes-processes.rb
|
109
119
|
- research/primes-threaded.rb
|
120
|
+
- spec/integration/authentication_spec.rb
|
110
121
|
- spec/integration/automatic_binding_for_default_direct_exchange_spec.rb
|
111
|
-
- spec/
|
122
|
+
- spec/integration/channel_close_spec.rb
|
123
|
+
- spec/integration/exchange_declaration_spec.rb
|
124
|
+
- spec/integration/queue_declaration_spec.rb
|
125
|
+
- spec/integration/queue_exclusivity_spec.rb
|
126
|
+
- spec/integration/reply_queue_communication_spec.rb
|
127
|
+
- spec/integration/store_and_forward_spec.rb
|
128
|
+
- spec/integration/topic_subscription_spec.rb
|
129
|
+
- spec/integration/workload_distribution_spec.rb
|
112
130
|
- spec/spec_helper.rb
|
131
|
+
- spec/unit/amqp/basic_spec.rb
|
113
132
|
- spec/unit/amqp/buffer_spec.rb
|
114
|
-
- spec/unit/amqp/
|
133
|
+
- spec/unit/amqp/collection_spec.rb
|
134
|
+
- spec/unit/amqp/connection_spec.rb
|
115
135
|
- spec/unit/amqp/frame_spec.rb
|
116
|
-
- spec/unit/amqp/misc_spec.rb
|
117
136
|
- spec/unit/amqp/protocol_spec.rb
|
118
|
-
- spec/unit/mq/channel_close_spec.rb
|
119
|
-
- spec/unit/mq/collection_spec.rb
|
120
|
-
- spec/unit/mq/exchange_declaration_spec.rb
|
121
|
-
- spec/unit/mq/misc_spec.rb
|
122
|
-
- spec/unit/mq/mq_basic_spec.rb
|
123
|
-
- spec/unit/mq/queue_declaration_spec.rb
|
124
|
-
- spec/unit/mq/queue_spec.rb
|
125
137
|
has_rdoc: true
|
126
138
|
homepage: http://github.com/ruby-amqp/amqp
|
127
139
|
licenses: []
|
128
140
|
|
129
|
-
post_install_message:
|
130
|
-
[\e[32mVersion 0.7\e[0m] [BUG] Sync API for MQ#close (Channel.Close) [issue #34].\n\
|
131
|
-
[\e[32mVersion 0.7\e[0m] [FEATURE] AMQP URL from majek's fork, with some fixes. Example: AMQP.start(\"amqps://\")\n\
|
132
|
-
[\e[32mVersion 0.7\e[0m] [DEVELOP] Added some em-spec-based specs, bin/irb, Gemfile.\n\
|
133
|
-
[\e[32mVersion 0.7\e[0m] [FEATURE] Added MQ::Exchange.default for the default exchange.\n\
|
134
|
-
[\e[32mVersion 0.7\e[0m] [FEATURE] Raise an exception if we're trying to use Basic.Reject with RabbitMQ.\n\
|
135
|
-
[\e[32mVersion 0.7\e[0m] [FEATURE] Fail if an entity is re-declared with different options.\n\
|
136
|
-
[\e[32mVersion 0.7\e[0m] [BUG] Don't reconnect if the credentials are wrong.\n\
|
137
|
-
[\e[32mVersion 0.7\e[0m] [BUG] Fixed an exception which occurred when Queue#bind was called synchronously with a callback.\n\
|
138
|
-
[\e[32mVersion 0.7\e[0m] [DEVELOPMENT] Added a lot of specs (Bacon replaced by rSpec 2).\n"
|
141
|
+
post_install_message:
|
139
142
|
rdoc_options:
|
140
|
-
- --include=examples
|
143
|
+
- --include=examples --main README.md
|
141
144
|
require_paths:
|
142
145
|
- lib
|
143
146
|
required_ruby_version: !ruby/object:Gem::Requirement
|
@@ -145,6 +148,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
145
148
|
requirements:
|
146
149
|
- - ">="
|
147
150
|
- !ruby/object:Gem::Version
|
151
|
+
hash: 3
|
148
152
|
segments:
|
149
153
|
- 0
|
150
154
|
version: "0"
|
@@ -153,6 +157,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
153
157
|
requirements:
|
154
158
|
- - ">="
|
155
159
|
- !ruby/object:Gem::Version
|
160
|
+
hash: 3
|
156
161
|
segments:
|
157
162
|
- 0
|
158
163
|
version: "0"
|
data/lib/ext/blankslate.rb
DELETED
data/spec/mq_helper.rb
DELETED
@@ -1,70 +0,0 @@
|
|
1
|
-
# This helper supports writing specs for MQ (channel)
|
2
|
-
|
3
|
-
require 'mq'
|
4
|
-
|
5
|
-
# Mocking AMQP::Client::EM_CONNECTION_CLASS in order to
|
6
|
-
# specify MQ instance behavior without the need to start EM loop.
|
7
|
-
class MockConnection
|
8
|
-
|
9
|
-
def initialize
|
10
|
-
EM.stub(:reactor_running?).and_return(true)
|
11
|
-
end
|
12
|
-
|
13
|
-
def callback &block
|
14
|
-
callbacks << block
|
15
|
-
block.call(self) if block
|
16
|
-
end
|
17
|
-
|
18
|
-
def add_channel mq
|
19
|
-
channels[key = (channels.keys.max || 0) + 1] = mq
|
20
|
-
key
|
21
|
-
end
|
22
|
-
|
23
|
-
def send data, opts = {}
|
24
|
-
messages << {:data => data, :opts => opts}
|
25
|
-
end
|
26
|
-
|
27
|
-
def connected?
|
28
|
-
true
|
29
|
-
end
|
30
|
-
|
31
|
-
def channels
|
32
|
-
@channels||={}
|
33
|
-
end
|
34
|
-
|
35
|
-
def close
|
36
|
-
end
|
37
|
-
|
38
|
-
# Not part of AMQP::Client::EM_CONNECTION_CLASS interface, for mock introspection only
|
39
|
-
def callbacks
|
40
|
-
@callbacks||=[]
|
41
|
-
end
|
42
|
-
|
43
|
-
def messages
|
44
|
-
@messages||=[]
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
# Sets expectations about @header and @body passed to @consumer.
|
49
|
-
def should_pass_updated_header_and_data_to consumer, opts={}
|
50
|
-
# - Why update @header.properties if @header becomes nil anyways?'
|
51
|
-
# - Because @consumer receives @header and may inspect its properties
|
52
|
-
|
53
|
-
subject_mock(:@method).should_receive(:arguments).
|
54
|
-
with(no_args).and_return(:myprop => 'mine')
|
55
|
-
consumer.should_receive(:receive) do |header, body|
|
56
|
-
header.klass.should == (opts[:klass] || AMQP::Protocol::Test)
|
57
|
-
header.size.should == (opts[:size] || 4)
|
58
|
-
header.weight.should == (opts[:weight] || 2)
|
59
|
-
header.properties.should == (opts[:properties] ||
|
60
|
-
{:delivery_mode => 1, :myprop => 'mine'})
|
61
|
-
body.should == (opts[:body] || 'data')
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
# Sets expectations that all listed instance variables for subject are nil
|
66
|
-
def should_be_nil *ivars
|
67
|
-
ivars.each do |ivar|
|
68
|
-
subject.instance_variable_get(ivar).should be_nil
|
69
|
-
end
|
70
|
-
end
|
@@ -1,472 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
require "spec_helper"
|
4
|
-
require "amqp/client"
|
5
|
-
|
6
|
-
describe AMQP::Client do
|
7
|
-
include AMQP::SpecHelper
|
8
|
-
include AMQP
|
9
|
-
|
10
|
-
em_after { AMQP.cleanup_state }
|
11
|
-
|
12
|
-
context 'with AMQP.client set to BasicClient (default)' do
|
13
|
-
describe 'creating new connection to AMQP broker using .connect:', :broker => true do
|
14
|
-
it 'when .connect is called outside EM event loop, raises error' do
|
15
|
-
expect { Client.connect }.to raise_error /eventmachine not initialized/
|
16
|
-
end
|
17
|
-
|
18
|
-
context 'when .connect is called inside EM event loop:' do
|
19
|
-
include AMQP::SpecHelper
|
20
|
-
|
21
|
-
it 'calls EM.connect with AMQP::Client as a handler class and AMQP options, and' do
|
22
|
-
em do
|
23
|
-
opts = AMQP.settings.merge(AMQP_OPTS)
|
24
|
-
EM.should_receive(:connect).with(opts[:host], opts[:port], Client, opts)
|
25
|
-
Client.connect AMQP_OPTS
|
26
|
-
done
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
it 'either hits connection timeout (with :timeout option), or' do
|
31
|
-
expect { em do
|
32
|
-
Client.connect(:host => 'example.com', :timeout => 0.001)
|
33
|
-
done(2)
|
34
|
-
end
|
35
|
-
}.to raise_error AMQP::Error, /Could not connect to server example.com:5672/
|
36
|
-
end
|
37
|
-
|
38
|
-
it 'raises connection error (with unresolvable AMQP broker address), or' do
|
39
|
-
pending 'Need to rewrite to eliminate dependency on DNS loockup mechanism'
|
40
|
-
expect { em do
|
41
|
-
Client.connect(:host => 'impossible.')
|
42
|
-
done(2)
|
43
|
-
end
|
44
|
-
}.to raise_error EventMachine::ConnectionError, /unable to resolve server address/
|
45
|
-
end
|
46
|
-
|
47
|
-
it 'raises connection error (with wrong AMQP host), or' do
|
48
|
-
pending 'Need to rewrite to eliminate dependency on DNS loockup mechanism'
|
49
|
-
expect { em do
|
50
|
-
Client.connect(:host => 'example.com')
|
51
|
-
done(2)
|
52
|
-
end
|
53
|
-
}.to raise_error AMQP::Error, /Could not connect to server example.com:5672/
|
54
|
-
end
|
55
|
-
|
56
|
-
it 'raises connection error (with wrong AMQP port), or' do
|
57
|
-
expect { em do
|
58
|
-
Client.connect(:port => 131313)
|
59
|
-
done(2)
|
60
|
-
end
|
61
|
-
}.to raise_error AMQP::Error, /Could not connect to server 127.0.0.1:131313/
|
62
|
-
end
|
63
|
-
|
64
|
-
it 'returns client connecting to AMQP broker (with correct AMQP opts) - DELAY!' do
|
65
|
-
em do
|
66
|
-
client = Client.connect AMQP_OPTS
|
67
|
-
client.should_not be_connected
|
68
|
-
done(0.2) { client.should be_connected }
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
context 'when connection is attempted, initiated client:' do
|
73
|
-
include AMQP::EMSpec
|
74
|
-
em_before { @client = Client.connect AMQP_OPTS }
|
75
|
-
|
76
|
-
specify { @client.should_not be_connected; done }
|
77
|
-
|
78
|
-
context "after a delay, connection is established and the client:" do
|
79
|
-
it 'receives #connection_completed call from EM reactor' do
|
80
|
-
@client.should_receive(:connection_completed).with(no_args)
|
81
|
-
done(0.2)
|
82
|
-
end
|
83
|
-
|
84
|
-
it 'fires @connection_status block (if any) with :connected' do
|
85
|
-
# Set up status processing block first
|
86
|
-
@client.connection_status { |status| @status = status }
|
87
|
-
done(0.2) { @status.should == :connected }
|
88
|
-
end
|
89
|
-
|
90
|
-
it 'becomes connected' do
|
91
|
-
done(0.2) { @client.should be_connected }
|
92
|
-
end
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
end # context 'when .connect is called inside EM event loop:
|
97
|
-
end # creating new connection to AMQP broker using .connect
|
98
|
-
|
99
|
-
context 'given a client that is attempting to connect to AMQP broker using AMQP_OPTS' do
|
100
|
-
include AMQP::EMSpec
|
101
|
-
em_before { @client = Client.connect AMQP_OPTS }
|
102
|
-
subject { @client }
|
103
|
-
|
104
|
-
describe 'closing down' do
|
105
|
-
context 'calling #close' do
|
106
|
-
it 'just sets callback (to close connection) if @client is not yet connected' do
|
107
|
-
@client.should_not be_connected
|
108
|
-
@client.should_not_receive(:send)
|
109
|
-
@client.should_receive(:callback)
|
110
|
-
@client.close
|
111
|
-
done
|
112
|
-
end
|
113
|
-
|
114
|
-
context 'if @client is connected'
|
115
|
-
it 'closes all channels first if there are any' do
|
116
|
-
EM.add_timer(0.2) {
|
117
|
-
@client.should be_connected
|
118
|
-
channel1 = MQ.new(@client)
|
119
|
-
channel2 = MQ.new(@client)
|
120
|
-
channel1.should_receive(:close)
|
121
|
-
channel2.should_receive(:close)
|
122
|
-
@client.close
|
123
|
-
done }
|
124
|
-
end
|
125
|
-
|
126
|
-
it 'sends Protocol::Connection::Close method to broker' do
|
127
|
-
EM.add_timer(0.2) {
|
128
|
-
@client.should be_connected
|
129
|
-
@client.should_receive(:send) do |message|
|
130
|
-
message.should be_a Protocol::Connection::Close
|
131
|
-
end
|
132
|
-
@client.close
|
133
|
-
done }
|
134
|
-
end
|
135
|
-
end # 'calling #close'
|
136
|
-
|
137
|
-
context 'after broker responded to connection close request' do
|
138
|
-
it 'client receives Protocol::Connection::CloseOk method from broker' do
|
139
|
-
EM.add_timer(0.2) {
|
140
|
-
@client.should_receive(:process_frame) do |frame|
|
141
|
-
frame.payload.should be_a Protocol::Connection::CloseOk
|
142
|
-
end
|
143
|
-
@client.close
|
144
|
-
done(0.2) }
|
145
|
-
end
|
146
|
-
|
147
|
-
it 'calls block given to #close instead of pre-set callbacks' do
|
148
|
-
# stub it BEFORE #connection_completed fired!
|
149
|
-
@client.should_not_receive(:disconnected)
|
150
|
-
@client.should_not_receive(:reconnect)
|
151
|
-
EM.add_timer(0.2) {
|
152
|
-
@client.close { @on_disconnect_called = true }
|
153
|
-
done(0.2) { @on_disconnect_called.should be_true } }
|
154
|
-
end
|
155
|
-
|
156
|
-
context 'if no block was given to #close' do
|
157
|
-
|
158
|
-
it 'calls registered @on_disconnect hook' do
|
159
|
-
EM.add_timer(0.2) {
|
160
|
-
mock = mock('on_disconnect')
|
161
|
-
mock.should_receive(:call).with(no_args)
|
162
|
-
|
163
|
-
# subject_mock trips something and drops connection :(
|
164
|
-
@client.instance_exec { @on_disconnect = mock }
|
165
|
-
@client.close
|
166
|
-
done(0.2) }
|
167
|
-
end
|
168
|
-
|
169
|
-
it 'normally, @on_disconnect just calls private #disconnected method' do
|
170
|
-
# stub it BEFORE #connection_completed fired!
|
171
|
-
@client.should_receive(:disconnected)
|
172
|
-
EM.add_timer(0.2) { @client.close; done(0.2) }
|
173
|
-
end
|
174
|
-
|
175
|
-
it 'fires @connection_status block (if any) with :disconnected' do
|
176
|
-
EM.add_timer(0.2) {
|
177
|
-
# Set up status processing block first
|
178
|
-
@client.connection_status { |status| @status = status }
|
179
|
-
@client.close
|
180
|
-
done(0.2) { @status.should == :disconnected } }
|
181
|
-
end
|
182
|
-
|
183
|
-
it 'attempts to reconnect' do
|
184
|
-
@client.should_receive(:reconnect)
|
185
|
-
EM.add_timer(0.2) { @client.close; done(0.2) }
|
186
|
-
end
|
187
|
-
end # if no block was given to #close
|
188
|
-
end # after broker responded to connection close request
|
189
|
-
|
190
|
-
context '#unbind' do
|
191
|
-
it 'is a hook method called by EM when network connection is dropped' do
|
192
|
-
@client.should_receive(:unbind).with(no_args)
|
193
|
-
@client.close
|
194
|
-
done
|
195
|
-
end
|
196
|
-
|
197
|
-
it 'unsets @connected status' do
|
198
|
-
EM.add_timer(0.1) {
|
199
|
-
@client.should be_connected
|
200
|
-
@client.unbind
|
201
|
-
@client.should_not be_connected
|
202
|
-
done }
|
203
|
-
end
|
204
|
-
|
205
|
-
it 'seems that it implicitly calls #connection_completed' do
|
206
|
-
@client.should_receive(:connection_completed) do
|
207
|
-
@client.instance_exec do
|
208
|
-
# Avoid raising exception
|
209
|
-
@on_disconnect = method(:disconnected)
|
210
|
-
end
|
211
|
-
end
|
212
|
-
@client.unbind
|
213
|
-
done
|
214
|
-
end
|
215
|
-
|
216
|
-
it 'calls @on_disconnect hook' do
|
217
|
-
block_fired = false
|
218
|
-
EM.add_timer(0.1) {
|
219
|
-
@client.instance_exec do
|
220
|
-
@on_disconnect = proc { block_fired = true }
|
221
|
-
end
|
222
|
-
@client.unbind
|
223
|
-
done(0.1) { block_fired.should be_true } }
|
224
|
-
end
|
225
|
-
end
|
226
|
-
end # closing down
|
227
|
-
|
228
|
-
context 'reconnecting' do
|
229
|
-
include AMQP::EMSpec
|
230
|
-
|
231
|
-
it 're-initializes the client' do
|
232
|
-
@client.should_receive(:initialize)
|
233
|
-
@client.reconnect
|
234
|
-
done
|
235
|
-
end
|
236
|
-
|
237
|
-
it 'resets and clears existing channels, if any' do
|
238
|
-
channel1 = MQ.new(@client)
|
239
|
-
channel2 = MQ.new(@client)
|
240
|
-
EM.add_timer(0.2) {
|
241
|
-
channel1.should_receive(:reset)
|
242
|
-
channel2.should_receive(:reset)
|
243
|
-
@client.reconnect
|
244
|
-
@client.channels.should == {}
|
245
|
-
done
|
246
|
-
}
|
247
|
-
end
|
248
|
-
|
249
|
-
it 'reconnects to broker through EM.reconnect' do
|
250
|
-
EM.should_receive(:reconnect)
|
251
|
-
@client.reconnect
|
252
|
-
done
|
253
|
-
end
|
254
|
-
|
255
|
-
it 'delays reconnect attempt by 1 sec if reconnect is already in progress' do
|
256
|
-
EM.should_receive(:reconnect).exactly(1).times
|
257
|
-
EM.should_receive(:add_timer).with(1)
|
258
|
-
@client.reconnect
|
259
|
-
@client.reconnect
|
260
|
-
done
|
261
|
-
end
|
262
|
-
|
263
|
-
it 'attempts to automatically reconnect on #close' do
|
264
|
-
@client.should_receive(:reconnect)
|
265
|
-
EM.add_timer(0.2) { @client.close; done(0.2) }
|
266
|
-
end
|
267
|
-
end
|
268
|
-
|
269
|
-
context 'receiving data/processing frames' do
|
270
|
-
describe "#receive_data" do
|
271
|
-
it 'is a callback method that EM calls when it gets raw data from broker' do
|
272
|
-
@client.should_receive(:receive_data) do |data|
|
273
|
-
frame = Frame.parse(data)
|
274
|
-
frame.should be_an Frame::Method
|
275
|
-
frame.payload.should be_an Protocol::Connection::Start
|
276
|
-
done
|
277
|
-
end
|
278
|
-
end
|
279
|
-
|
280
|
-
it 'delegates actual frame processing to #process_frame' do
|
281
|
-
EM.add_timer(0.2) {
|
282
|
-
@client.should_receive(:process_frame).with(basic_header)
|
283
|
-
@client.receive_data(basic_header.to_s)
|
284
|
-
done }
|
285
|
-
end
|
286
|
-
|
287
|
-
it 'does not call #process_frame on incomplete frames' do
|
288
|
-
EM.add_timer(0.2) {
|
289
|
-
@client.should_not_receive(:process_frame)
|
290
|
-
@client.receive_data(basic_header.to_s[0..5])
|
291
|
-
done }
|
292
|
-
end
|
293
|
-
|
294
|
-
it 'calls #process_frame when frame is complete' do
|
295
|
-
EM.add_timer(0.2) {
|
296
|
-
@client.should_receive(:process_frame).with(basic_header)
|
297
|
-
@client.receive_data(basic_header.to_s[0..5])
|
298
|
-
@client.receive_data(basic_header.to_s[6..-1])
|
299
|
-
done }
|
300
|
-
end
|
301
|
-
end #receive_data
|
302
|
-
|
303
|
-
describe '#process_frame', '(client reaction to messages from broker)' do
|
304
|
-
|
305
|
-
it 'delegates frame processing to channel if the frame indicates channel' do
|
306
|
-
EM.add_timer(0.2) {
|
307
|
-
MQ.new(@client)
|
308
|
-
@client.channels[1].should_receive(:process_frame).
|
309
|
-
with(basic_header(:channel => 1))
|
310
|
-
@client.process_frame(basic_header(:channel => 1))
|
311
|
-
done }
|
312
|
-
end
|
313
|
-
|
314
|
-
describe ' Frame::Method', '(Method with args received)' do
|
315
|
-
describe 'Protocol::Connection::Start',
|
316
|
-
'(broker initiated start of AMQP connection)' do
|
317
|
-
let(:frame) { Frame::Method.new(Protocol::Connection::Start.new) }
|
318
|
-
|
319
|
-
it 'sends back to broker Protocol::Connection::StartOk with details' do
|
320
|
-
EM.add_timer(0.2) {
|
321
|
-
@client.should_receive(:send).
|
322
|
-
with(Protocol::Connection::StartOk.new(
|
323
|
-
{:platform => 'Ruby/EventMachine',
|
324
|
-
:product => 'AMQP',
|
325
|
-
:information => 'http://github.com/ruby-amqp/amqp',
|
326
|
-
:version => AMQP::VERSION}, 'AMQPLAIN',
|
327
|
-
{:LOGIN => AMQP.settings[:user],
|
328
|
-
:PASSWORD => AMQP.settings[:pass]}, 'en_US'))
|
329
|
-
@client.process_frame(frame)
|
330
|
-
done }
|
331
|
-
end
|
332
|
-
end # Protocol::Connection::Start
|
333
|
-
|
334
|
-
describe 'Protocol::Connection::Tune',
|
335
|
-
'(broker suggested connection parameters)' do
|
336
|
-
let(:frame) { Frame::Method.new(Protocol::Connection::Tune.new) }
|
337
|
-
|
338
|
-
it 'sends back to broker TuneOk with parameters and Open' do
|
339
|
-
EM.add_timer(0.2) {
|
340
|
-
@client.should_receive(:send) do |method|
|
341
|
-
if method.is_a? Protocol::Connection::TuneOk
|
342
|
-
method.should == Protocol::Connection::TuneOk.new(
|
343
|
-
:channel_max => 0,
|
344
|
-
:frame_max => 131072,
|
345
|
-
:heartbeat => 0)
|
346
|
-
else
|
347
|
-
method.should == Protocol::Connection::Open.new(
|
348
|
-
:virtual_host => AMQP.settings[:vhost],
|
349
|
-
:capabilities => '',
|
350
|
-
:insist => AMQP.settings[:insist])
|
351
|
-
end
|
352
|
-
end.exactly(2).times
|
353
|
-
@client.process_frame(frame)
|
354
|
-
done }
|
355
|
-
end
|
356
|
-
end # Protocol::Connection::Tune
|
357
|
-
|
358
|
-
describe 'Protocol::Connection::OpenOk',
|
359
|
-
'(broker confirmed connection opening)' do
|
360
|
-
let(:frame) { Frame::Method.new(AMQP::Protocol::Connection::OpenOk.new) }
|
361
|
-
|
362
|
-
it 'succeeds @client (as a deferrable)' do
|
363
|
-
@client.instance_variable_get(:@deferred_status).should == :unknown
|
364
|
-
@client.process_frame(frame)
|
365
|
-
done(0.1) {
|
366
|
-
@client.instance_variable_get(:@deferred_status).should == :succeeded }
|
367
|
-
end
|
368
|
-
end # Protocol::Connection::OpenOk
|
369
|
-
|
370
|
-
describe 'Protocol::Connection::Close',
|
371
|
-
'(unexpectedly received connection close from broker)' do
|
372
|
-
let(:frame) { Frame::Method.new(Protocol::Connection::Close.new(
|
373
|
-
:reply_code => 320,
|
374
|
-
:reply_text => "Nyanya",
|
375
|
-
:class_id => 10,
|
376
|
-
:method_id => 40)) }
|
377
|
-
|
378
|
-
it 'just prints debug info to STDERR' do
|
379
|
-
STDERR.should_receive(:puts).
|
380
|
-
with /Nyanya in AMQP::Protocol::Connection::Open/
|
381
|
-
@client.process_frame(frame)
|
382
|
-
done(0.1)
|
383
|
-
end
|
384
|
-
|
385
|
-
it 'should probably raise exception or something?'
|
386
|
-
end # Protocol::Connection::Close
|
387
|
-
|
388
|
-
describe 'Protocol::Connection::CloseOk',
|
389
|
-
'(broker confirmed our connection close request)' do
|
390
|
-
let(:frame) { Frame::Method.new(Protocol::Connection::CloseOk.new) }
|
391
|
-
|
392
|
-
it 'calls registered @on_disconnect hook' do
|
393
|
-
EM.add_timer(0.1) {
|
394
|
-
subject_mock(:@on_disconnect).should_receive(:call).with(no_args)
|
395
|
-
@client.process_frame(frame)
|
396
|
-
done }
|
397
|
-
end
|
398
|
-
|
399
|
-
end # Protocol::Connection::CloseOk
|
400
|
-
end # Frame::Method
|
401
|
-
end #process_frame
|
402
|
-
end # receiving data/processing frames
|
403
|
-
|
404
|
-
context 'channels' do
|
405
|
-
it 'starts with empty channels set' do
|
406
|
-
@client.channels.should be_empty
|
407
|
-
done
|
408
|
-
end
|
409
|
-
|
410
|
-
context '#add_channel' do
|
411
|
-
it 'adds given channel to channels set' do
|
412
|
-
mq = mock('mq')
|
413
|
-
@client.add_channel mq
|
414
|
-
@client.channels[1].should == mq
|
415
|
-
done
|
416
|
-
end
|
417
|
-
end
|
418
|
-
end
|
419
|
-
|
420
|
-
context '#send data' do
|
421
|
-
it 'formats data to be sent into Frame, setting channel to 0 by default' do
|
422
|
-
data = mock('data')
|
423
|
-
framed_data = mock('framed data')
|
424
|
-
data.should_receive(:to_frame).and_return(framed_data)
|
425
|
-
framed_data.should_receive(:channel=).with(0)
|
426
|
-
@client.send data
|
427
|
-
done
|
428
|
-
end
|
429
|
-
|
430
|
-
it 'sets channel number given in options' do
|
431
|
-
data = mock('data')
|
432
|
-
framed_data = mock('framed data')
|
433
|
-
data.should_receive(:to_frame).and_return(framed_data)
|
434
|
-
framed_data.should_receive(:channel=).with(1313)
|
435
|
-
@client.send data, :channel =>1313
|
436
|
-
done
|
437
|
-
end
|
438
|
-
|
439
|
-
it 'does not format data if it is already a Frame' do
|
440
|
-
data = basic_header
|
441
|
-
data.should_not_receive(:to_frame)
|
442
|
-
@client.send data
|
443
|
-
done
|
444
|
-
end
|
445
|
-
|
446
|
-
it 'then calls EM:Connection#send_data hook with framed data converted to String' do
|
447
|
-
EM.add_timer(0.1) {
|
448
|
-
data = basic_header
|
449
|
-
@client.should_receive(:send_data) do |data|
|
450
|
-
data.should be_a String
|
451
|
-
frame = Frame.parse(data)
|
452
|
-
frame.class.should == Frame::Header
|
453
|
-
frame.payload.class.should == Protocol::Header
|
454
|
-
frame.channel.should == 0
|
455
|
-
end
|
456
|
-
@client.send data
|
457
|
-
done }
|
458
|
-
end
|
459
|
-
end #send data
|
460
|
-
|
461
|
-
context '#connection_status' do
|
462
|
-
em_before { @called_with_statuses = [] }
|
463
|
-
it 'sets a block to be called on connection status changes' do
|
464
|
-
@client.connection_status { |status| @called_with_statuses << status }
|
465
|
-
@client.close
|
466
|
-
done(0.1) { @called_with_statuses.should == [:connected, :disconnected] }
|
467
|
-
end
|
468
|
-
|
469
|
-
end #connection_status
|
470
|
-
end #given a connected client
|
471
|
-
end # context with AMQP.client set to BasicClient (default)
|
472
|
-
end
|