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.
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