carrot 0.8.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.markdown CHANGED
@@ -2,11 +2,11 @@
2
2
 
3
3
  A synchronous amqp client. Based on Aman's amqp client:
4
4
 
5
- [http://github.com/tmm1/amqp/tree/master] (http://github.com/tmm1/amqp/tree/master)
5
+ [http://github.com/tmm1/amqp/tree/master](http://github.com/tmm1/amqp/tree/master)
6
6
 
7
7
  ## Motivation
8
8
 
9
- This client does not use eventmachine so no background thread necessary. As a result, it is much easier to use from script/console and Passenger. It also solves the problem of buffering messages and ack responses. For more details see [this thread] (http://groups.google.com/group/ruby-amqp/browse_thread/thread/fdae324a0ebb1961/fa185fdce1841b68).
9
+ This client does not use eventmachine so no background thread necessary. As a result, it is much easier to use from script/console and Passenger. It also solves the problem of buffering messages and ack responses. For more details see [this thread](http://groups.google.com/group/ruby-amqp/browse_thread/thread/fdae324a0ebb1961/fa185fdce1841b68).
10
10
 
11
11
  There is currently no way to prevent buffering using eventmachine. Support for prefetch is still unreliable.
12
12
 
data/Rakefile CHANGED
@@ -1,7 +1,6 @@
1
1
  require 'rake'
2
2
  require 'rake/testtask'
3
3
  require 'rake/rdoctask'
4
- require 'rcov/rcovtask'
5
4
 
6
5
  begin
7
6
  require 'jeweler'
@@ -12,7 +11,6 @@ begin
12
11
  s.description = "A synchronous version of the ruby amqp client"
13
12
  s.summary = "A synchronous version of the ruby amqp client"
14
13
  s.authors = ["Amos Elliston"]
15
- s.add_development_dependency "rcov"
16
14
  s.add_development_dependency "mocha"
17
15
  end
18
16
  Jeweler::GemcutterTasks.new
@@ -34,10 +32,4 @@ Rake::RDocTask.new do |rdoc|
34
32
  rdoc.rdoc_files.include('lib/**/*.rb')
35
33
  end
36
34
 
37
- Rcov::RcovTask.new do |t|
38
- t.libs << ['lib', 'test']
39
- t.test_files = FileList['test/**/*_test.rb']
40
- t.verbose = true
41
- end
42
-
43
35
  task :default => :test
data/VERSION.yml CHANGED
@@ -1,5 +1,5 @@
1
- ---
2
- :major: 0
3
- :minor: 8
4
- :build:
5
- :patch: 1
1
+ ---
2
+ :major: 1
3
+ :minor: 0
4
+ :patch: 0
5
+ :build: !!null
data/carrot.gemspec CHANGED
@@ -1,68 +1,62 @@
1
1
  # Generated by jeweler
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{carrot}
8
- s.version = "0.8.1"
8
+ s.version = "1.0.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Amos Elliston"]
12
- s.date = %q{2010-11-01}
12
+ s.date = %q{2011-08-03}
13
13
  s.description = %q{A synchronous version of the ruby amqp client}
14
14
  s.email = %q{amos@geni.com}
15
15
  s.extra_rdoc_files = [
16
16
  "LICENSE",
17
- "README.markdown"
17
+ "README.markdown"
18
18
  ]
19
19
  s.files = [
20
- ".gitignore",
21
- "LICENSE",
22
- "README.markdown",
23
- "Rakefile",
24
- "VERSION.yml",
25
- "carrot.gemspec",
26
- "lib/amqp/buffer.rb",
27
- "lib/amqp/exchange.rb",
28
- "lib/amqp/frame.rb",
29
- "lib/amqp/header.rb",
30
- "lib/amqp/protocol.rb",
31
- "lib/amqp/queue.rb",
32
- "lib/amqp/server.rb",
33
- "lib/amqp/spec.rb",
34
- "lib/carrot.rb",
35
- "lib/examples/simple_pop.rb",
36
- "protocol/amqp-0.8.json",
37
- "protocol/amqp-0.8.xml",
38
- "protocol/codegen.rb",
39
- "protocol/doc.txt",
40
- "test/carrot_test.rb",
41
- "test/test_helper.rb"
20
+ "LICENSE",
21
+ "README.markdown",
22
+ "Rakefile",
23
+ "VERSION.yml",
24
+ "carrot.gemspec",
25
+ "lib/carrot.rb",
26
+ "lib/carrot/amqp/buffer.rb",
27
+ "lib/carrot/amqp/exchange.rb",
28
+ "lib/carrot/amqp/frame.rb",
29
+ "lib/carrot/amqp/header.rb",
30
+ "lib/carrot/amqp/protocol.rb",
31
+ "lib/carrot/amqp/queue.rb",
32
+ "lib/carrot/amqp/server.rb",
33
+ "lib/carrot/amqp/spec.rb",
34
+ "lib/examples/simple_pop.rb",
35
+ "protocol/amqp-0.8.json",
36
+ "protocol/amqp-0.8.xml",
37
+ "protocol/codegen.rb",
38
+ "protocol/doc.txt",
39
+ "test/buffer_test.rb",
40
+ "test/carrot_test.rb",
41
+ "test/frame_test.rb",
42
+ "test/protocol_test.rb",
43
+ "test/test_helper.rb"
42
44
  ]
43
45
  s.homepage = %q{http://github.com/famoseagle/carrot}
44
- s.rdoc_options = ["--charset=UTF-8"]
45
46
  s.require_paths = ["lib"]
46
47
  s.rubygems_version = %q{1.3.7}
47
48
  s.summary = %q{A synchronous version of the ruby amqp client}
48
- s.test_files = [
49
- "test/carrot_test.rb",
50
- "test/test_helper.rb"
51
- ]
52
49
 
53
50
  if s.respond_to? :specification_version then
54
51
  current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
55
52
  s.specification_version = 3
56
53
 
57
54
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
58
- s.add_development_dependency(%q<rcov>, [">= 0"])
59
55
  s.add_development_dependency(%q<mocha>, [">= 0"])
60
56
  else
61
- s.add_dependency(%q<rcov>, [">= 0"])
62
57
  s.add_dependency(%q<mocha>, [">= 0"])
63
58
  end
64
59
  else
65
- s.add_dependency(%q<rcov>, [">= 0"])
66
60
  s.add_dependency(%q<mocha>, [">= 0"])
67
61
  end
68
62
  end
data/lib/carrot.rb CHANGED
@@ -8,14 +8,14 @@ class Carrot
8
8
  end
9
9
 
10
10
  $:.unshift File.expand_path(File.dirname(File.expand_path(__FILE__)))
11
- require 'amqp/spec'
12
- require 'amqp/buffer'
13
- require 'amqp/exchange'
14
- require 'amqp/frame'
15
- require 'amqp/header'
16
- require 'amqp/queue'
17
- require 'amqp/server'
18
- require 'amqp/protocol'
11
+ require 'carrot/amqp/spec'
12
+ require 'carrot/amqp/buffer'
13
+ require 'carrot/amqp/exchange'
14
+ require 'carrot/amqp/frame'
15
+ require 'carrot/amqp/header'
16
+ require 'carrot/amqp/queue'
17
+ require 'carrot/amqp/server'
18
+ require 'carrot/amqp/protocol'
19
19
 
20
20
  class Carrot
21
21
  @logging = false
@@ -274,128 +274,3 @@ module Carrot::AMQP
274
274
  end
275
275
  end
276
276
  end
277
-
278
- if $0 =~ /bacon/ or $0 == __FILE__
279
- require 'bacon'
280
- include AMQP
281
-
282
- describe Buffer do
283
- before do
284
- @buf = Buffer.new
285
- end
286
-
287
- should 'have contents' do
288
- @buf.contents.should == ''
289
- end
290
-
291
- should 'initialize with data' do
292
- @buf = Buffer.new('abc')
293
- @buf.contents.should == 'abc'
294
- end
295
-
296
- should 'append raw data' do
297
- @buf << 'abc'
298
- @buf << 'def'
299
- @buf.contents.should == 'abcdef'
300
- end
301
-
302
- should 'append other buffers' do
303
- @buf << Buffer.new('abc')
304
- @buf.data.should == 'abc'
305
- end
306
-
307
- should 'have a position' do
308
- @buf.pos.should == 0
309
- end
310
-
311
- should 'have a length' do
312
- @buf.length.should == 0
313
- @buf << 'abc'
314
- @buf.length.should == 3
315
- end
316
-
317
- should 'know the end' do
318
- @buf.empty?.should == true
319
- end
320
-
321
- should 'read and write data' do
322
- @buf._write('abc')
323
- @buf.rewind
324
- @buf._read(2).should == 'ab'
325
- @buf._read(1).should == 'c'
326
- end
327
-
328
- should 'raise on overflow' do
329
- lambda{ @buf._read(1) }.should.raise Buffer::Overflow
330
- end
331
-
332
- should 'raise on invalid types' do
333
- lambda{ @buf.read(:junk) }.should.raise Buffer::InvalidType
334
- lambda{ @buf.write(:junk, 1) }.should.raise Buffer::InvalidType
335
- end
336
-
337
- { :octet => 0b10101010,
338
- :short => 100,
339
- :long => 100_000_000,
340
- :longlong => 666_555_444_333_222_111,
341
- :shortstr => 'hello',
342
- :longstr => 'bye'*500,
343
- :timestamp => time = Time.at(Time.now.to_i),
344
- :table => { :this => 'is', :a => 'hash', :with => {:nested => 123, :and => time, :also => 123.456} },
345
- :bit => true
346
- }.each do |type, value|
347
-
348
- should "read and write a #{type}" do
349
- @buf.write(type, value)
350
- @buf.rewind
351
- @buf.read(type).should == value
352
- @buf.should.be.empty
353
- end
354
-
355
- end
356
-
357
- should 'read and write multiple bits' do
358
- bits = [true, false, false, true, true, false, false, true, true, false]
359
- @buf.write(:bit, bits)
360
- @buf.write(:octet, 100)
361
-
362
- @buf.rewind
363
-
364
- bits.map do
365
- @buf.read(:bit)
366
- end.should == bits
367
- @buf.read(:octet).should == 100
368
- end
369
-
370
- should 'read and write properties' do
371
- properties = ([
372
- [:octet, 1],
373
- [:shortstr, 'abc'],
374
- [:bit, true],
375
- [:bit, false],
376
- [:shortstr, nil],
377
- [:timestamp, nil],
378
- [:table, { :a => 'hash' }],
379
- ]*5).sort_by{rand}
380
-
381
- @buf.write(:properties, properties)
382
- @buf.rewind
383
- @buf.read(:properties, *properties.map{|type,_| type }).should == properties.map{|_,value| value }
384
- @buf.should.be.empty
385
- end
386
-
387
- should 'do transactional reads with #extract' do
388
- @buf.write :octet, 8
389
- orig = @buf.to_s
390
-
391
- @buf.rewind
392
- @buf.extract do |b|
393
- b.read :octet
394
- b.read :short
395
- end
396
-
397
- @buf.pos.should == 0
398
- @buf.data.should == orig
399
- end
400
- end
401
- end
File without changes
@@ -0,0 +1,62 @@
1
+ module Carrot::AMQP
2
+ class Frame #:nodoc: all
3
+ def initialize payload = nil, channel = 0
4
+ @channel, @payload = channel, payload
5
+ end
6
+ attr_accessor :channel, :payload
7
+
8
+ def id
9
+ self.class::ID
10
+ end
11
+
12
+ def to_binary
13
+ buf = Buffer.new
14
+ buf.write :octet, id
15
+ buf.write :short, channel
16
+ buf.write :longstr, payload
17
+ buf.write :octet, FOOTER
18
+ buf.rewind
19
+ buf
20
+ end
21
+
22
+ def to_s
23
+ to_binary.to_s
24
+ end
25
+
26
+ def == frame
27
+ [ :id, :channel, :payload ].inject(true) do |eql, field|
28
+ eql and __send__(field) == frame.__send__(field)
29
+ end
30
+ end
31
+
32
+ class Invalid < StandardError; end
33
+
34
+ class Method
35
+ def initialize payload = nil, channel = 0
36
+ super
37
+ unless @payload.is_a? Protocol::Class::Method or @payload.nil?
38
+ @payload = Protocol.parse(@payload)
39
+ end
40
+ end
41
+ end
42
+
43
+ class Header
44
+ def initialize payload = nil, channel = 0
45
+ super
46
+ unless @payload.is_a? Protocol::Header or @payload.nil?
47
+ @payload = Protocol::Header.new(@payload)
48
+ end
49
+ end
50
+ end
51
+
52
+ class Body; end
53
+
54
+ def self.parse(buf)
55
+ buf = Buffer.new(buf) unless buf.is_a? Buffer
56
+ buf.extract do
57
+ id, channel, payload, footer = buf.read(:octet, :short, :longstr, :octet)
58
+ Frame.types[id].new(payload, channel) if footer == FOOTER
59
+ end
60
+ end
61
+ end
62
+ end
File without changes
@@ -156,54 +156,3 @@ module Carrot::AMQP
156
156
  #:stopdoc:
157
157
  end
158
158
  end
159
-
160
- if $0 =~ /bacon/ or $0 == __FILE__
161
- require 'bacon'
162
- include AMQP
163
-
164
- describe Protocol do
165
- should 'instantiate methods with arguments' do
166
- meth = Protocol::Connection::StartOk.new nil, 'PLAIN', nil, 'en_US'
167
- meth.locale.should == 'en_US'
168
- end
169
-
170
- should 'instantiate methods with named parameters' do
171
- meth = Protocol::Connection::StartOk.new :locale => 'en_US',
172
- :mechanism => 'PLAIN'
173
- meth.locale.should == 'en_US'
174
- end
175
-
176
- should 'convert methods to binary' do
177
- meth = Protocol::Connection::Secure.new :challenge => 'secret'
178
- meth.to_binary.should.be.kind_of? Buffer
179
-
180
- meth.to_s.should == [ 10, 20, 6, 'secret' ].pack('nnNa*')
181
- end
182
-
183
- should 'convert binary to method' do
184
- orig = Protocol::Connection::Secure.new :challenge => 'secret'
185
- copy = Protocol.parse orig.to_binary
186
- orig.should == copy
187
- end
188
-
189
- should 'convert headers to binary' do
190
- head = Protocol::Header.new Protocol::Basic,
191
- size = 5,
192
- weight = 0,
193
- :content_type => 'text/json',
194
- :delivery_mode => 1,
195
- :priority => 1
196
- head.to_s.should == [ 60, weight, 0, size, 0b1001_1000_0000_0000, 9, 'text/json', 1, 1 ].pack('nnNNnCa*CC')
197
- end
198
-
199
- should 'convert binary to header' do
200
- orig = Protocol::Header.new Protocol::Basic,
201
- size = 5,
202
- weight = 0,
203
- :content_type => 'text/json',
204
- :delivery_mode => 1,
205
- :priority => 1
206
- Protocol::Header.new(orig.to_binary).should == orig
207
- end
208
- end
209
- end
@@ -1,14 +1,16 @@
1
1
  module Carrot::AMQP
2
2
  class Queue
3
3
  attr_reader :name, :carrot
4
- attr_accessor :delivery_tag
4
+ attr_accessor :delivery_tag, :opts
5
5
 
6
6
  def initialize(carrot, name, opts = {})
7
7
  @opts = opts
8
8
  @name = name
9
9
  @carrot = carrot
10
+
11
+ @opts[:queue] = name
10
12
  server.send_frame(
11
- Protocol::Queue::Declare.new({ :queue => name, :nowait => true }.merge(opts))
13
+ Protocol::Queue::Declare.new(@opts.merge(:nowait => true))
12
14
  )
13
15
  end
14
16
 
@@ -50,9 +52,9 @@ module Carrot::AMQP
50
52
  status.last
51
53
  end
52
54
 
53
- def status(opts = {}, &blk)
55
+ def status
54
56
  server.send_frame(
55
- Protocol::Queue::Declare.new({ :queue => name, :passive => true }.merge(opts))
57
+ Protocol::Queue::Declare.new(opts)
56
58
  )
57
59
  method = server.next_method
58
60
  return [nil, nil] if method.kind_of?(Protocol::Connection::Close)
@@ -2,6 +2,12 @@ require 'socket'
2
2
  require 'thread'
3
3
  require 'timeout'
4
4
 
5
+ begin
6
+ require 'openssl'
7
+ rescue LoadError
8
+ warn "Unable to load SSL extension - you will be unable to make ssl connections."
9
+ end
10
+
5
11
  module Carrot::AMQP
6
12
  class Server
7
13
  CONNECT_TIMEOUT = 1.0
@@ -23,6 +29,9 @@ module Carrot::AMQP
23
29
  @insist = opts[:insist]
24
30
  @status = 'NOT CONNECTED'
25
31
 
32
+ @use_ssl = !!opts[:ssl]
33
+ @ssl_verify = opts[:ssl_verify] || OpenSSL::SSL::VERIFY_PEER
34
+
26
35
  @multithread = opts[:multithread]
27
36
  start_session
28
37
  end
@@ -93,6 +102,23 @@ module Carrot::AMQP
93
102
  end
94
103
  end
95
104
 
105
+ def start_ssl
106
+ unless defined?(OpenSSL)
107
+ raise "SSL Extension not installed"
108
+ end
109
+
110
+ ctx = OpenSSL::SSL::SSLContext.new
111
+ ctx.verify_mode = @ssl_verify
112
+
113
+ @socket = OpenSSL::SSL::SSLSocket.new(@socket, ctx)
114
+ @socket.sync_close = true
115
+ @socket.connect
116
+
117
+ if ctx.verify_mode != OpenSSL::SSL::VERIFY_NONE
118
+ @socket.post_connection_check(@host)
119
+ end
120
+ end
121
+
96
122
  def socket
97
123
  return @socket if @socket and not @socket.closed?
98
124
 
@@ -106,6 +132,9 @@ module Carrot::AMQP
106
132
  if Socket.constants.include? 'TCP_NODELAY'
107
133
  @socket.setsockopt Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1
108
134
  end
135
+
136
+ start_ssl if @use_ssl
137
+
109
138
  @status = 'CONNECTED'
110
139
  rescue SocketError, SystemCallError, IOError, Timeout::Error => e
111
140
  msg = e.message << " - #{@host}:#{@port}"
File without changes
@@ -0,0 +1,122 @@
1
+ require 'test_helper'
2
+ require 'carrot/amqp/buffer'
3
+
4
+ module Carrot::AMQP
5
+ context 'Buffer' do
6
+ setup do
7
+ @buf = Buffer.new
8
+ end
9
+
10
+ test 'have contents' do
11
+ assert_equal '', @buf.contents
12
+ end
13
+
14
+ test 'initialize with data' do
15
+ @buf = Buffer.new('abc')
16
+ assert_equal 'abc', @buf.contents
17
+ end
18
+
19
+ test 'append raw data' do
20
+ @buf << 'abc'
21
+ @buf << 'def'
22
+ assert_equal 'abcdef', @buf.contents
23
+ end
24
+
25
+ test 'append other buffers' do
26
+ @buf << Buffer.new('abc')
27
+ assert_equal 'abc', @buf.contents
28
+ end
29
+
30
+ test 'have a position' do
31
+ assert_equal 0, @buf.pos
32
+ end
33
+
34
+ test 'have a length' do
35
+ assert_equal 0, @buf.length
36
+ @buf << 'abc'
37
+ assert_equal 3, @buf.length
38
+ end
39
+
40
+ test 'know the end' do
41
+ assert_equal true, @buf.empty?
42
+ end
43
+
44
+ test 'read and write data' do
45
+ @buf._write('abc')
46
+ @buf.rewind
47
+ assert_equal 'ab', @buf._read(2)
48
+ assert_equal 'c', @buf._read(1)
49
+ end
50
+
51
+ test 'raise on overflow' do
52
+ assert_raise(Buffer::Overflow) { @buf._read(1) }
53
+ end
54
+
55
+ test 'raise on invalid types' do
56
+ assert_raise(Buffer::InvalidType) { @buf.read(:junk) }
57
+ assert_raise(Buffer::InvalidType) { @buf.write(:junk, 1) }
58
+ end
59
+
60
+ { :octet => 0b10101010,
61
+ :short => 100,
62
+ :long => 100_000_000,
63
+ :longlong => 666_555_444_333_222_111,
64
+ :shortstr => 'hello',
65
+ :longstr => 'bye'*500,
66
+ :timestamp => time = Time.at(Time.now.to_i),
67
+ :table => { :this => 'is', :a => 'hash', :with => {:nested => 123, :and => time, :also => 123.456} },
68
+ :bit => true
69
+ }.each do |type, value|
70
+
71
+ test "read and write a #{type}" do
72
+ @buf.write(type, value)
73
+ @buf.rewind
74
+ assert_equal value, @buf.read(type)
75
+ assert_equal true, @buf.empty?
76
+ end
77
+
78
+ end
79
+
80
+ test 'read and write multiple bits' do
81
+ bits = [true, false, false, true, true, false, false, true, true, false]
82
+ @buf.write(:bit, bits)
83
+ @buf.write(:octet, 100)
84
+
85
+ @buf.rewind
86
+
87
+ assert_equal bits, bits.collect{ @buf.read(:bit) }
88
+ assert_equal 100, @buf.read(:octet)
89
+ end
90
+
91
+ test 'read and write properties' do
92
+ properties = ([
93
+ [:octet, 1],
94
+ [:shortstr, 'abc'],
95
+ [:bit, true],
96
+ [:bit, false],
97
+ [:shortstr, nil],
98
+ [:timestamp, nil],
99
+ [:table, { :a => 'hash' }],
100
+ ]*5).sort_by{rand}
101
+
102
+ @buf.write(:properties, properties)
103
+ @buf.rewind
104
+ assert_equal properties.map{|_,value| value }, @buf.read(:properties, *properties.map{|type,_| type })
105
+ assert_equal true, @buf.empty?
106
+ end
107
+
108
+ test 'do transactional reads with #extract' do
109
+ @buf.write :octet, 8
110
+ orig = @buf.to_s
111
+
112
+ @buf.rewind
113
+ @buf.extract do |b|
114
+ b.read :octet
115
+ b.read :short
116
+ end
117
+
118
+ assert_equal 0, @buf.pos
119
+ assert_equal orig, @buf.data
120
+ end
121
+ end
122
+ end
data/test/carrot_test.rb CHANGED
@@ -1,25 +1,23 @@
1
1
  require 'test_helper'
2
2
 
3
- class CarrotTest < Test::Unit::TestCase
3
+ context 'test queue' do
4
4
  TEST_QUEUE = '_carrot_test'
5
-
6
- test "simple server connection" do
7
- c = Carrot.new
5
+ setup do
6
+ @carrot = Carrot.new
7
+ @q = @carrot.queue(TEST_QUEUE)
8
+ @q.purge
8
9
  end
9
10
 
10
11
  test "large messages" do
11
12
  msg = 'a' * 1024 * 1024
12
- q = Carrot.queue(TEST_QUEUE)
13
- q.publish(msg)
14
- assert_equal msg, q.pop
13
+ @q.publish(msg)
14
+ assert_equal msg, @q.pop
15
15
  end
16
16
 
17
17
  test "reset" do
18
- c = Carrot.new
19
- q = c.queue(TEST_QUEUE)
20
- count = q.message_count
21
- q.publish('test')
22
- c.reset
23
- assert_equal count + 1, q.message_count
18
+ count = @q.message_count
19
+ @q.publish('test')
20
+ @carrot.reset
21
+ assert_equal count + 1, @q.message_count
24
22
  end
25
23
  end
@@ -0,0 +1,56 @@
1
+ require 'test_helper'
2
+
3
+ module Carrot::AMQP
4
+ context 'Frame' do
5
+ test 'handle basic frame types' do
6
+ assert_equal 1, Frame::Method.new.id
7
+ assert_equal 2, Frame::Header.new.id
8
+ assert_equal 3, Frame::Body.new.id
9
+ end
10
+
11
+ test 'convert method frames to binary' do
12
+ meth = Protocol::Connection::Secure.new :challenge => 'secret'
13
+
14
+ frame = Frame::Method.new(meth)
15
+ assert frame.to_binary.kind_of?(Buffer)
16
+ assert_equal [ 1, 0, meth.to_s.length, meth.to_s, 206 ].pack('CnNa*C'), frame.to_s
17
+ end
18
+
19
+ test 'convert binary to method frames' do
20
+ orig = Frame::Method.new Protocol::Connection::Secure.new(:challenge => 'secret')
21
+
22
+ copy = Frame.parse(orig.to_binary)
23
+ assert_equal orig, copy
24
+ end
25
+
26
+ test 'ignore partial frames until ready' do
27
+ frame = Frame::Method.new Protocol::Connection::Secure.new(:challenge => 'secret')
28
+ data = frame.to_s
29
+
30
+ buf = Buffer.new
31
+ assert_equal nil, Frame.parse(buf)
32
+
33
+ buf << data[0..5]
34
+ assert_equal nil, Frame.parse(buf)
35
+
36
+ buf << data[6..-1]
37
+ assert_equal frame, Frame.parse(buf)
38
+
39
+ assert_equal nil, Frame.parse(buf)
40
+ end
41
+
42
+ test 'convert header frames to binary' do
43
+ head = Protocol::Header.new(Protocol::Basic, :priority => 1)
44
+
45
+ frame = Frame::Header.new(head)
46
+ assert_equal [ 2, 0, head.to_s.length, head.to_s, 206 ].pack('CnNa*C'), frame.to_s
47
+ end
48
+
49
+ test 'convert binary to header frame' do
50
+ orig = Frame::Header.new Protocol::Header.new(Protocol::Basic, :priority => 1)
51
+
52
+ copy = Frame.parse(orig.to_binary)
53
+ assert_equal orig, copy
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,52 @@
1
+ require 'test_helper'
2
+
3
+ module Carrot::AMQP
4
+ context 'Protocol' do
5
+ test 'instantiate methods with arguments' do
6
+ meth = Protocol::Connection::StartOk.new(nil, 'PLAIN', nil, 'en_US')
7
+ assert_equal 'en_US', meth.locale
8
+ end
9
+
10
+ test 'instantiate methods with named parameters' do
11
+ meth = Protocol::Connection::StartOk.new(:locale => 'en_US', :mechanism => 'PLAIN')
12
+ assert_equal 'en_US', meth.locale
13
+ end
14
+
15
+ test 'convert methods to binary' do
16
+ meth = Protocol::Connection::Secure.new(:challenge => 'secret')
17
+ assert meth.to_binary.kind_of?(Buffer)
18
+
19
+ assert_equal [ 10, 20, 6, 'secret' ].pack('nnNa*'), meth.to_s
20
+ end
21
+
22
+ test 'convert binary to method' do
23
+ orig = Protocol::Connection::Secure.new(:challenge => 'secret')
24
+ copy = Protocol.parse orig.to_binary
25
+ assert_equal copy, orig
26
+ end
27
+
28
+ test 'convert headers to binary' do
29
+ head = Protocol::Header.new(
30
+ Protocol::Basic,
31
+ size = 5,
32
+ weight = 0,
33
+ :content_type => 'text/json',
34
+ :delivery_mode => 1,
35
+ :priority => 1
36
+ )
37
+ assert_equal [ 60, weight, 0, size, 0b1001_1000_0000_0000, 9, 'text/json', 1, 1 ].pack('nnNNnCa*CC'), head.to_s
38
+ end
39
+
40
+ test 'convert binary to header' do
41
+ orig = Protocol::Header.new(
42
+ Protocol::Basic,
43
+ size = 5,
44
+ weight = 0,
45
+ :content_type => 'text/json',
46
+ :delivery_mode => 1,
47
+ :priority => 1
48
+ )
49
+ assert_equal orig, Protocol::Header.new(orig.to_binary)
50
+ end
51
+ end
52
+ end
data/test/test_helper.rb CHANGED
@@ -1,18 +1,27 @@
1
- require 'rubygems'
1
+ dir = File.dirname(File.expand_path(__FILE__))
2
+ $LOAD_PATH.unshift dir + '/../lib'
3
+ require 'carrot'
2
4
  require 'test/unit'
3
- #require 'shoulda'
4
- require 'mocha'
5
- require File.dirname(__FILE__) + '/../lib/carrot'
6
-
7
- class << Test::Unit::TestCase
8
- def test(name, &block)
9
- test_name = "test_#{name.gsub(/[\s\W]/,'_')}"
10
- raise ArgumentError, "#{test_name} is already defined" if self.instance_methods.include? test_name
11
- define_method test_name, &block
12
- end
5
+ require 'rubygems'
6
+ require 'pp'
13
7
 
14
- def xtest(name, &block)
15
- # no-op, an empty test method is defined to prevent "no tests in testcase" errors when all tests are disabled
16
- define_method(:test_disabled) { assert true }
8
+ ##
9
+ # test/spec/mini 3
10
+ # http://gist.github.com/25455
11
+ # chris@ozmm.org
12
+ # file:lib/test/spec/mini.rb
13
+ #
14
+ def context(*args, &block)
15
+ return super unless (name = args.first) && block
16
+ require 'test/unit'
17
+ klass = Class.new(defined?(ActiveSupport::TestCase) ? ActiveSupport::TestCase : Test::Unit::TestCase) do
18
+ def self.test(name, &block)
19
+ define_method("test_#{name.gsub(/\W/,'_')}", &block) if block
20
+ end
21
+ def self.xtest(*args) end
22
+ def self.setup(&block) define_method(:setup, &block) end
23
+ def self.teardown(&block) define_method(:teardown, &block) end
17
24
  end
25
+ (class << klass; self end).send(:define_method, :name) { name.gsub(/\W/,'_') }
26
+ klass.class_eval &block
18
27
  end
metadata CHANGED
@@ -1,117 +1,93 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: carrot
3
- version: !ruby/object:Gem::Version
4
- hash: 61
5
- prerelease: false
6
- segments:
7
- - 0
8
- - 8
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ segments:
9
6
  - 1
10
- version: 0.8.1
7
+ - 0
8
+ - 0
9
+ prerelease: false
11
10
  platform: ruby
12
- authors:
11
+ authors:
13
12
  - Amos Elliston
14
- autorequire:
13
+ autorequire: !!null
15
14
  bindir: bin
16
15
  cert_chain: []
17
-
18
- date: 2010-11-01 00:00:00 -07:00
19
- default_executable:
20
- dependencies:
21
- - !ruby/object:Gem::Dependency
22
- name: rcov
23
- prerelease: false
24
- requirement: &id001 !ruby/object:Gem::Requirement
25
- none: false
26
- requirements:
27
- - - ">="
28
- - !ruby/object:Gem::Version
29
- hash: 3
30
- segments:
31
- - 0
32
- version: "0"
33
- type: :development
34
- version_requirements: *id001
35
- - !ruby/object:Gem::Dependency
16
+ date: 2011-08-03 00:00:00.000000000 -07:00
17
+ default_executable: !!null
18
+ dependencies:
19
+ - !ruby/object:Gem::Dependency
36
20
  name: mocha
37
- prerelease: false
38
- requirement: &id002 !ruby/object:Gem::Requirement
21
+ requirement: &2152420380 !ruby/object:Gem::Requirement
39
22
  none: false
40
- requirements:
41
- - - ">="
42
- - !ruby/object:Gem::Version
43
- hash: 3
44
- segments:
23
+ requirements:
24
+ - - ! '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ segments:
45
28
  - 0
46
- version: "0"
47
29
  type: :development
48
- version_requirements: *id002
30
+ prerelease: false
31
+ version_requirements: *2152420380
49
32
  description: A synchronous version of the ruby amqp client
50
33
  email: amos@geni.com
51
34
  executables: []
52
-
53
35
  extensions: []
54
-
55
- extra_rdoc_files:
36
+ extra_rdoc_files:
56
37
  - LICENSE
57
38
  - README.markdown
58
- files:
59
- - .gitignore
39
+ files:
60
40
  - LICENSE
61
41
  - README.markdown
62
42
  - Rakefile
63
43
  - VERSION.yml
64
44
  - carrot.gemspec
65
- - lib/amqp/buffer.rb
66
- - lib/amqp/exchange.rb
67
- - lib/amqp/frame.rb
68
- - lib/amqp/header.rb
69
- - lib/amqp/protocol.rb
70
- - lib/amqp/queue.rb
71
- - lib/amqp/server.rb
72
- - lib/amqp/spec.rb
73
45
  - lib/carrot.rb
46
+ - lib/carrot/amqp/buffer.rb
47
+ - lib/carrot/amqp/exchange.rb
48
+ - lib/carrot/amqp/frame.rb
49
+ - lib/carrot/amqp/header.rb
50
+ - lib/carrot/amqp/protocol.rb
51
+ - lib/carrot/amqp/queue.rb
52
+ - lib/carrot/amqp/server.rb
53
+ - lib/carrot/amqp/spec.rb
74
54
  - lib/examples/simple_pop.rb
75
55
  - protocol/amqp-0.8.json
76
56
  - protocol/amqp-0.8.xml
77
57
  - protocol/codegen.rb
78
58
  - protocol/doc.txt
59
+ - test/buffer_test.rb
79
60
  - test/carrot_test.rb
61
+ - test/frame_test.rb
62
+ - test/protocol_test.rb
80
63
  - test/test_helper.rb
81
64
  has_rdoc: true
82
65
  homepage: http://github.com/famoseagle/carrot
83
66
  licenses: []
84
-
85
- post_install_message:
86
- rdoc_options:
87
- - --charset=UTF-8
88
- require_paths:
67
+ post_install_message: !!null
68
+ rdoc_options: []
69
+ require_paths:
89
70
  - lib
90
- required_ruby_version: !ruby/object:Gem::Requirement
71
+ required_ruby_version: !ruby/object:Gem::Requirement
91
72
  none: false
92
- requirements:
93
- - - ">="
94
- - !ruby/object:Gem::Version
95
- hash: 3
96
- segments:
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ segments:
97
78
  - 0
98
- version: "0"
99
- required_rubygems_version: !ruby/object:Gem::Requirement
79
+ required_rubygems_version: !ruby/object:Gem::Requirement
100
80
  none: false
101
- requirements:
102
- - - ">="
103
- - !ruby/object:Gem::Version
104
- hash: 3
105
- segments:
81
+ requirements:
82
+ - - ! '>='
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
85
+ segments:
106
86
  - 0
107
- version: "0"
108
87
  requirements: []
109
-
110
- rubyforge_project:
88
+ rubyforge_project: !!null
111
89
  rubygems_version: 1.3.7
112
- signing_key:
90
+ signing_key: !!null
113
91
  specification_version: 3
114
92
  summary: A synchronous version of the ruby amqp client
115
- test_files:
116
- - test/carrot_test.rb
117
- - test/test_helper.rb
93
+ test_files: []
data/.gitignore DELETED
@@ -1,3 +0,0 @@
1
- *.sw?
2
- .DS_Store
3
- coverage
data/lib/amqp/frame.rb DELETED
@@ -1,121 +0,0 @@
1
- module Carrot::AMQP
2
- class Frame #:nodoc: all
3
- def initialize payload = nil, channel = 0
4
- @channel, @payload = channel, payload
5
- end
6
- attr_accessor :channel, :payload
7
-
8
- def id
9
- self.class::ID
10
- end
11
-
12
- def to_binary
13
- buf = Buffer.new
14
- buf.write :octet, id
15
- buf.write :short, channel
16
- buf.write :longstr, payload
17
- buf.write :octet, FOOTER
18
- buf.rewind
19
- buf
20
- end
21
-
22
- def to_s
23
- to_binary.to_s
24
- end
25
-
26
- def == frame
27
- [ :id, :channel, :payload ].inject(true) do |eql, field|
28
- eql and __send__(field) == frame.__send__(field)
29
- end
30
- end
31
-
32
- class Invalid < StandardError; end
33
-
34
- class Method
35
- def initialize payload = nil, channel = 0
36
- super
37
- unless @payload.is_a? Protocol::Class::Method or @payload.nil?
38
- @payload = Protocol.parse(@payload)
39
- end
40
- end
41
- end
42
-
43
- class Header
44
- def initialize payload = nil, channel = 0
45
- super
46
- unless @payload.is_a? Protocol::Header or @payload.nil?
47
- @payload = Protocol::Header.new(@payload)
48
- end
49
- end
50
- end
51
-
52
- class Body; end
53
-
54
- def self.parse(buf)
55
- buf = Buffer.new(buf) unless buf.is_a? Buffer
56
- buf.extract do
57
- id, channel, payload, footer = buf.read(:octet, :short, :longstr, :octet)
58
- Frame.types[id].new(payload, channel) if footer == FOOTER
59
- end
60
- end
61
- end
62
- end
63
-
64
- if $0 =~ /bacon/ or $0 == __FILE__
65
- require 'rubygems'
66
- require 'bacon'
67
- include AMQP
68
-
69
- describe Frame do
70
- should 'handle basic frame types' do
71
- Frame::Method.new.id.should == 1
72
- Frame::Header.new.id.should == 2
73
- Frame::Body.new.id.should == 3
74
- end
75
-
76
- should 'convert method frames to binary' do
77
- meth = Protocol::Connection::Secure.new :challenge => 'secret'
78
-
79
- frame = Frame::Method.new(meth)
80
- frame.to_binary.should.be.kind_of? Buffer
81
- frame.to_s.should == [ 1, 0, meth.to_s.length, meth.to_s, 206 ].pack('CnNa*C')
82
- end
83
-
84
- should 'convert binary to method frames' do
85
- orig = Frame::Method.new Protocol::Connection::Secure.new(:challenge => 'secret')
86
-
87
- copy = Frame.parse(orig.to_binary)
88
- copy.should == orig
89
- end
90
-
91
- should 'ignore partial frames until ready' do
92
- frame = Frame::Method.new Protocol::Connection::Secure.new(:challenge => 'secret')
93
- data = frame.to_s
94
-
95
- buf = Buffer.new
96
- Frame.parse(buf).should == nil
97
-
98
- buf << data[0..5]
99
- Frame.parse(buf).should == nil
100
-
101
- buf << data[6..-1]
102
- Frame.parse(buf).should == frame
103
-
104
- Frame.parse(buf).should == nil
105
- end
106
-
107
- should 'convert header frames to binary' do
108
- head = Protocol::Header.new(Protocol::Basic, :priority => 1)
109
-
110
- frame = Frame::Header.new(head)
111
- frame.to_s.should == [ 2, 0, head.to_s.length, head.to_s, 206 ].pack('CnNa*C')
112
- end
113
-
114
- should 'convert binary to header frame' do
115
- orig = Frame::Header.new Protocol::Header.new(Protocol::Basic, :priority => 1)
116
-
117
- copy = Frame.parse(orig.to_binary)
118
- copy.should == orig
119
- end
120
- end
121
- end