amqp 0.7.0 → 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. data/.gitignore +3 -2
  2. data/CHANGELOG +25 -0
  3. data/Gemfile +4 -2
  4. data/README.md +2 -0
  5. data/{amqp.todo → TODO} +1 -3
  6. data/amqp.gemspec +3 -3
  7. data/bin/irb +2 -2
  8. data/bin/jenkins.sh +25 -0
  9. data/bin/set_test_suite_realms_up.sh +21 -0
  10. data/doc/EXAMPLE_01_PINGPONG +1 -1
  11. data/doc/EXAMPLE_02_CLOCK +1 -1
  12. data/doc/EXAMPLE_03_STOCKS +1 -1
  13. data/doc/EXAMPLE_04_MULTICLOCK +1 -1
  14. data/doc/EXAMPLE_05_ACK +1 -1
  15. data/doc/EXAMPLE_05_POP +1 -1
  16. data/doc/EXAMPLE_06_HASHTABLE +1 -1
  17. data/examples/{mq/ack.rb → ack.rb} +6 -6
  18. data/examples/{mq/automatic_binding_for_default_direct_exchange.rb → automatic_binding_for_default_direct_exchange.rb} +4 -4
  19. data/examples/{mq/callbacks.rb → callbacks.rb} +2 -2
  20. data/examples/{mq/clock.rb → clock.rb} +5 -5
  21. data/examples/{mq/hashtable.rb → hashtable.rb} +4 -4
  22. data/examples/{mq/internal.rb → internal.rb} +5 -5
  23. data/examples/{mq/logger.rb → logger.rb} +5 -5
  24. data/examples/{mq/multiclock.rb → multiclock.rb} +4 -4
  25. data/examples/{mq/pingpong.rb → pingpong.rb} +5 -5
  26. data/examples/{mq/pop.rb → pop.rb} +3 -3
  27. data/examples/{mq/primes-simple.rb → primes-simple.rb} +0 -0
  28. data/examples/{mq/primes.rb → primes.rb} +6 -6
  29. data/examples/{amqp/simple.rb → simple.rb} +1 -1
  30. data/examples/{mq/stocks.rb → stocks.rb} +5 -5
  31. data/lib/amqp.rb +8 -112
  32. data/lib/amqp/basic_client.rb +58 -0
  33. data/lib/amqp/channel.rb +937 -0
  34. data/lib/amqp/client.rb +72 -79
  35. data/lib/{mq → amqp}/collection.rb +12 -2
  36. data/lib/amqp/connection.rb +115 -0
  37. data/lib/amqp/exceptions.rb +18 -0
  38. data/lib/{mq → amqp}/exchange.rb +32 -34
  39. data/lib/{ext → amqp/ext}/em.rb +1 -1
  40. data/lib/{ext → amqp/ext}/emfork.rb +0 -0
  41. data/lib/amqp/frame.rb +3 -3
  42. data/lib/{mq → amqp}/header.rb +5 -11
  43. data/lib/{mq → amqp}/logger.rb +2 -2
  44. data/lib/amqp/protocol.rb +2 -2
  45. data/lib/{mq → amqp}/queue.rb +20 -17
  46. data/lib/{mq → amqp}/rpc.rb +20 -8
  47. data/lib/amqp/server.rb +1 -1
  48. data/lib/amqp/version.rb +1 -1
  49. data/lib/mq.rb +20 -964
  50. data/protocol/codegen.rb +1 -1
  51. data/research/api.rb +3 -3
  52. data/research/primes-forked.rb +5 -5
  53. data/research/primes-processes.rb +5 -5
  54. data/research/primes-threaded.rb +5 -5
  55. data/spec/integration/authentication_spec.rb +114 -0
  56. data/spec/integration/automatic_binding_for_default_direct_exchange_spec.rb +13 -12
  57. data/spec/{unit/mq → integration}/channel_close_spec.rb +2 -2
  58. data/spec/{unit/mq → integration}/exchange_declaration_spec.rb +26 -14
  59. data/spec/{unit/mq → integration}/queue_declaration_spec.rb +4 -4
  60. data/spec/integration/queue_exclusivity_spec.rb +95 -0
  61. data/spec/integration/reply_queue_communication_spec.rb +63 -0
  62. data/spec/integration/store_and_forward_spec.rb +121 -0
  63. data/spec/integration/topic_subscription_spec.rb +193 -0
  64. data/spec/integration/workload_distribution_spec.rb +245 -0
  65. data/spec/spec_helper.rb +16 -32
  66. data/spec/unit/{mq/mq_basic_spec.rb → amqp/basic_spec.rb} +4 -4
  67. data/spec/unit/{mq → amqp}/collection_spec.rb +22 -7
  68. data/spec/unit/amqp/connection_spec.rb +116 -0
  69. data/spec/unit/amqp/frame_spec.rb +18 -18
  70. data/spec/unit/amqp/protocol_spec.rb +9 -11
  71. metadata +54 -49
  72. data/lib/ext/blankslate.rb +0 -9
  73. data/spec/mq_helper.rb +0 -70
  74. data/spec/unit/amqp/client_spec.rb +0 -472
  75. data/spec/unit/amqp/misc_spec.rb +0 -123
  76. data/spec/unit/mq/misc_spec.rb +0 -228
  77. 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 Buffer
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 Protocol::Connection::Secure.new(:challenge => 'secret')
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 Protocol::Connection::Secure.new(:challenge => 'secret')
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 Protocol::Header.new(Protocol::Basic, :priority => 1)
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
- - 0
9
- version: 0.7.0
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-01-18 00:00:00 +00:00
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: stastny@101ideas.cz
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/amqp/simple.rb
71
- - examples/mq/ack.rb
72
- - examples/mq/automatic_binding_for_default_direct_exchange.rb
73
- - examples/mq/callbacks.rb
74
- - examples/mq/clock.rb
75
- - examples/mq/hashtable.rb
76
- - examples/mq/internal.rb
77
- - examples/mq/logger.rb
78
- - examples/mq/multiclock.rb
79
- - examples/mq/pingpong.rb
80
- - examples/mq/pop.rb
81
- - examples/mq/primes-simple.rb
82
- - examples/mq/primes.rb
83
- - examples/mq/stocks.rb
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/mq_helper.rb
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/client_spec.rb
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: "[\e[32mVersion 0.7\e[0m] [BUG] Sync API for queues and exchanges, support for server-generated queues & exchange names (via semi-lazy collection).\n\
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"
@@ -1,9 +0,0 @@
1
- # encoding: utf-8
2
-
3
- unless defined?(BlankSlate)
4
- class BlankSlate < BasicObject; end if defined?(BasicObject)
5
-
6
- class BlankSlate #:nodoc:
7
- instance_methods.each { |m| undef_method m unless m =~ /^__/ }
8
- end
9
- end
@@ -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