amqp 0.7.0.pre → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +4 -0
 - data/.rspec +2 -0
 - data/CHANGELOG +8 -2
 - data/CONTRIBUTORS +22 -0
 - data/Gemfile +3 -3
 - data/README.md +20 -11
 - data/Rakefile +30 -6
 - data/amqp.gemspec +1 -1
 - data/bin/cleanify.rb +50 -0
 - data/examples/amqp/simple.rb +6 -4
 - data/examples/mq/ack.rb +8 -6
 - data/examples/mq/automatic_binding_for_default_direct_exchange.rb +65 -0
 - data/examples/mq/callbacks.rb +9 -1
 - data/examples/mq/clock.rb +17 -17
 - data/examples/mq/hashtable.rb +19 -10
 - data/examples/mq/internal.rb +13 -11
 - data/examples/mq/logger.rb +38 -36
 - data/examples/mq/multiclock.rb +16 -7
 - data/examples/mq/pingpong.rb +16 -7
 - data/examples/mq/pop.rb +8 -6
 - data/examples/mq/primes-simple.rb +2 -0
 - data/examples/mq/primes.rb +7 -5
 - data/examples/mq/stocks.rb +14 -5
 - data/lib/amqp.rb +12 -8
 - data/lib/amqp/buffer.rb +35 -158
 - data/lib/amqp/client.rb +34 -22
 - data/lib/amqp/frame.rb +8 -64
 - data/lib/amqp/protocol.rb +21 -70
 - data/lib/amqp/server.rb +11 -9
 - data/lib/amqp/spec.rb +8 -6
 - data/lib/amqp/version.rb +2 -0
 - data/lib/ext/blankslate.rb +3 -1
 - data/lib/ext/em.rb +2 -0
 - data/lib/ext/emfork.rb +13 -11
 - data/lib/mq.rb +253 -156
 - data/lib/mq/collection.rb +6 -88
 - data/lib/mq/exchange.rb +70 -13
 - data/lib/mq/header.rb +12 -6
 - data/lib/mq/logger.rb +9 -7
 - data/lib/mq/queue.rb +42 -30
 - data/lib/mq/rpc.rb +6 -4
 - data/protocol/codegen.rb +20 -18
 - data/research/api.rb +10 -46
 - data/research/primes-forked.rb +9 -7
 - data/research/primes-processes.rb +74 -72
 - data/research/primes-threaded.rb +9 -7
 - data/spec/integration/automatic_binding_for_default_direct_exchange_spec.rb +61 -0
 - data/spec/mq_helper.rb +70 -0
 - data/spec/spec_helper.rb +84 -29
 - data/spec/unit/amqp/buffer_spec.rb +178 -0
 - data/spec/unit/amqp/client_spec.rb +472 -0
 - data/spec/unit/amqp/frame_spec.rb +60 -0
 - data/spec/unit/amqp/misc_spec.rb +123 -0
 - data/spec/unit/amqp/protocol_spec.rb +53 -0
 - data/spec/unit/mq/channel_close_spec.rb +15 -0
 - data/spec/unit/mq/collection_spec.rb +129 -0
 - data/spec/unit/mq/exchange_declaration_spec.rb +524 -0
 - data/spec/unit/mq/misc_spec.rb +228 -0
 - data/spec/unit/mq/mq_basic_spec.rb +39 -0
 - data/spec/unit/mq/queue_declaration_spec.rb +97 -0
 - data/spec/unit/mq/queue_spec.rb +71 -0
 - metadata +33 -21
 - data/Gemfile.lock +0 -16
 - data/old/README +0 -30
 - data/old/Rakefile +0 -12
 - data/old/amqp-0.8.json +0 -606
 - data/old/amqp_spec.rb +0 -796
 - data/old/amqpc.rb +0 -695
 - data/old/codegen.rb +0 -148
 - data/spec/channel_close_spec.rb +0 -13
 - data/spec/sync_async_spec.rb +0 -52
 
    
        data/research/primes-threaded.rb
    CHANGED
    
    | 
         @@ -1,15 +1,17 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # encoding: utf-8
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
       1 
3 
     | 
    
         
             
            $:.unshift File.dirname(__FILE__) + '/../lib'
         
     | 
| 
       2 
4 
     | 
    
         
             
            require 'mq'
         
     | 
| 
       3 
5 
     | 
    
         | 
| 
       4 
6 
     | 
    
         
             
            MAX = 500
         
     | 
| 
       5 
7 
     | 
    
         | 
| 
       6 
     | 
    
         
            -
            def log 
     | 
| 
      
 8 
     | 
    
         
            +
            def log(*args)
         
     | 
| 
       7 
9 
     | 
    
         
             
              p args
         
     | 
| 
       8 
10 
     | 
    
         
             
            end
         
     | 
| 
       9 
11 
     | 
    
         | 
| 
       10 
12 
     | 
    
         
             
            # MQ.logging = true
         
     | 
| 
       11 
13 
     | 
    
         | 
| 
       12 
     | 
    
         
            -
            EM.run{
         
     | 
| 
      
 14 
     | 
    
         
            +
            EM.run {
         
     | 
| 
       13 
15 
     | 
    
         | 
| 
       14 
16 
     | 
    
         
             
              # worker
         
     | 
| 
       15 
17 
     | 
    
         | 
| 
         @@ -21,21 +23,21 @@ EM.run{ 
     | 
|
| 
       21 
23 
     | 
    
         
             
                end
         
     | 
| 
       22 
24 
     | 
    
         
             
              end
         
     | 
| 
       23 
25 
     | 
    
         | 
| 
       24 
     | 
    
         
            -
              MQ.queue('prime checker').subscribe{ |info, num|
         
     | 
| 
       25 
     | 
    
         
            -
                EM.defer(proc{
         
     | 
| 
      
 26 
     | 
    
         
            +
              MQ.queue('prime checker').subscribe { |info, num|
         
     | 
| 
      
 27 
     | 
    
         
            +
                EM.defer(proc {
         
     | 
| 
       26 
28 
     | 
    
         | 
| 
       27 
29 
     | 
    
         
             
                  log "prime checker #{Process.pid}-#{Thread.current.object_id}", :prime?, num
         
     | 
| 
       28 
30 
     | 
    
         
             
                  if Integer(num).prime?
         
     | 
| 
       29 
31 
     | 
    
         
             
                    MQ.queue(info.reply_to).publish(num, :reply_to => "#{Process.pid}-#{Thread.current.object_id}")
         
     | 
| 
       30 
32 
     | 
    
         
             
                    EM.stop_event_loop if num == '499'
         
     | 
| 
       31 
33 
     | 
    
         
             
                  end
         
     | 
| 
       32 
     | 
    
         
            -
             
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
       33 
35 
     | 
    
         
             
                })
         
     | 
| 
       34 
36 
     | 
    
         
             
              }
         
     | 
| 
       35 
37 
     | 
    
         | 
| 
       36 
38 
     | 
    
         
             
              # controller
         
     | 
| 
       37 
39 
     | 
    
         | 
| 
       38 
     | 
    
         
            -
              MQ.queue('prime collector').subscribe{ |info, prime|
         
     | 
| 
      
 40 
     | 
    
         
            +
              MQ.queue('prime collector').subscribe { |info, prime|
         
     | 
| 
       39 
41 
     | 
    
         
             
                log 'prime collector', :received, prime, :from, info.reply_to
         
     | 
| 
       40 
42 
     | 
    
         
             
                (@primes ||= []) << Integer(prime)
         
     | 
| 
       41 
43 
     | 
    
         
             
              }
         
     | 
| 
         @@ -46,4 +48,4 @@ EM.run{ 
     | 
|
| 
       46 
48 
     | 
    
         
             
                end
         
     | 
| 
       47 
49 
     | 
    
         
             
              end
         
     | 
| 
       48 
50 
     | 
    
         | 
| 
       49 
     | 
    
         
            -
            }
         
     | 
| 
      
 51 
     | 
    
         
            +
            }
         
     | 
| 
         @@ -0,0 +1,61 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # encoding: utf-8
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            describe "Queue that was bound to default direct exchange thanks to Automatic Mode (section 2.1.2.4 in AMQP 0.9.1 spec" do
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
              #
         
     | 
| 
      
 8 
     | 
    
         
            +
              # Environment
         
     | 
| 
      
 9 
     | 
    
         
            +
              #
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
              include AMQP::Spec
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
              default_timeout 10
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
              amqp_before do
         
     | 
| 
      
 16 
     | 
    
         
            +
                @channel   = MQ.new
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                @queue1    = @channel.queue("queue1")
         
     | 
| 
      
 19 
     | 
    
         
            +
                @queue2    = @channel.queue("queue2")
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                # Rely on default direct exchange binding, see section 2.1.2.4 Automatic Mode in AMQP 0.9.1 spec.
         
     | 
| 
      
 22 
     | 
    
         
            +
                @exchange = MQ::Exchange.default
         
     | 
| 
      
 23 
     | 
    
         
            +
              end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
              #
         
     | 
| 
      
 28 
     | 
    
         
            +
              # Examples
         
     | 
| 
      
 29 
     | 
    
         
            +
              #
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
              it "receives messages with routing key equals it's name" do
         
     | 
| 
      
 32 
     | 
    
         
            +
                number_of_received_messages = 0
         
     | 
| 
      
 33 
     | 
    
         
            +
                expected_number_of_messages = 3
         
     | 
| 
      
 34 
     | 
    
         
            +
                dispatched_data             = "to be received by queue1"
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                @queue1.subscribe do |payload|
         
     | 
| 
      
 37 
     | 
    
         
            +
                  number_of_received_messages += 1
         
     | 
| 
      
 38 
     | 
    
         
            +
                  payload.should == dispatched_data
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                  if number_of_received_messages == expected_number_of_messages
         
     | 
| 
      
 41 
     | 
    
         
            +
                    $stdout.puts "Got all the messages I expected, wrapping up..."
         
     | 
| 
      
 42 
     | 
    
         
            +
                    done
         
     | 
| 
      
 43 
     | 
    
         
            +
                  else
         
     | 
| 
      
 44 
     | 
    
         
            +
                    n = expected_number_of_messages - number_of_received_messages
         
     | 
| 
      
 45 
     | 
    
         
            +
                    $stdout.puts "Still waiting for #{n} more message(s)"
         
     | 
| 
      
 46 
     | 
    
         
            +
                  end
         
     | 
| 
      
 47 
     | 
    
         
            +
                end # subscribe
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                4.times do
         
     | 
| 
      
 50 
     | 
    
         
            +
                  @exchange.publish("some white noise", :routing_key => "killa key")
         
     | 
| 
      
 51 
     | 
    
         
            +
                end
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                expected_number_of_messages.times do
         
     | 
| 
      
 54 
     | 
    
         
            +
                  @exchange.publish(dispatched_data,    :routing_key => @queue1.name)    
         
     | 
| 
      
 55 
     | 
    
         
            +
                end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                4.times do
         
     | 
| 
      
 58 
     | 
    
         
            +
                  @exchange.publish("some white noise", :routing_key => "killa key")
         
     | 
| 
      
 59 
     | 
    
         
            +
                end
         
     | 
| 
      
 60 
     | 
    
         
            +
              end # it
         
     | 
| 
      
 61 
     | 
    
         
            +
            end # describe
         
     | 
    
        data/spec/mq_helper.rb
    ADDED
    
    | 
         @@ -0,0 +1,70 @@ 
     | 
|
| 
      
 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
         
     | 
    
        data/spec/spec_helper.rb
    CHANGED
    
    | 
         @@ -2,40 +2,95 @@ 
     | 
|
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            $LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
         
     | 
| 
       4 
4 
     | 
    
         | 
| 
      
 5 
     | 
    
         
            +
            require 'bundler'
         
     | 
| 
      
 6 
     | 
    
         
            +
            Bundler.setup
         
     | 
| 
      
 7 
     | 
    
         
            +
            Bundler.require :default, :test
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
       5 
9 
     | 
    
         
             
            require "mq"
         
     | 
| 
       6 
     | 
    
         
            -
             
     | 
| 
       7 
     | 
    
         
            -
             
     | 
| 
       8 
     | 
    
         
            -
             
     | 
| 
       9 
     | 
    
         
            -
             
     | 
| 
       10 
     | 
    
         
            -
             
     | 
| 
       11 
     | 
    
         
            -
             
     | 
| 
       12 
     | 
    
         
            -
             
     | 
| 
       13 
     | 
    
         
            -
             
     | 
| 
       14 
     | 
    
         
            -
             
     | 
| 
       15 
     | 
    
         
            -
             
     | 
| 
       16 
     | 
    
         
            -
             
     | 
| 
       17 
     | 
    
         
            -
             
     | 
| 
       18 
     | 
    
         
            -
             
     | 
| 
       19 
     | 
    
         
            -
               
     | 
| 
       20 
     | 
    
         
            -
               
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            amqp_config = File.dirname(__FILE__) + '/amqp.yml'
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            if File.exists? amqp_config
         
     | 
| 
      
 14 
     | 
    
         
            +
              class Hash
         
     | 
| 
      
 15 
     | 
    
         
            +
                def symbolize_keys
         
     | 
| 
      
 16 
     | 
    
         
            +
                  self.inject({}) do |result, (key, value)|
         
     | 
| 
      
 17 
     | 
    
         
            +
                    new_key = key.is_a?(String) ? key.to_sym : key
         
     | 
| 
      
 18 
     | 
    
         
            +
                    new_value = value.is_a?(Hash) ? value.symbolize_keys : value
         
     | 
| 
      
 19 
     | 
    
         
            +
                    result[new_key] = new_value
         
     | 
| 
      
 20 
     | 
    
         
            +
                    result
         
     | 
| 
      
 21 
     | 
    
         
            +
                  end
         
     | 
| 
      
 22 
     | 
    
         
            +
                end
         
     | 
| 
      
 23 
     | 
    
         
            +
              end
         
     | 
| 
      
 24 
     | 
    
         
            +
              AMQP_OPTS = YAML::load_file(amqp_config).symbolize_keys[:test]
         
     | 
| 
       21 
25 
     | 
    
         
             
            else
         
     | 
| 
       22 
     | 
    
         
            -
               
     | 
| 
      
 26 
     | 
    
         
            +
              AMQP_OPTS = {:host => 'localhost', :port => 5672}
         
     | 
| 
       23 
27 
     | 
    
         
             
            end
         
     | 
| 
       24 
28 
     | 
    
         | 
| 
       25 
     | 
    
         
            -
            # Bacon doesn't seem to have some global before hook
         
     | 
| 
       26 
     | 
    
         
            -
            Bacon::Context.class_eval do
         
     | 
| 
       27 
     | 
    
         
            -
              alias_method :__initialize__, :initialize
         
     | 
| 
       28 
29 
     | 
    
         | 
| 
       29 
     | 
    
         
            -
             
     | 
| 
       30 
     | 
    
         
            -
               
     | 
| 
       31 
     | 
    
         
            -
             
     | 
| 
       32 
     | 
    
         
            -
             
     | 
| 
      
 30 
     | 
    
         
            +
            if RUBY_VERSION == "1.8.7"
         
     | 
| 
      
 31 
     | 
    
         
            +
              module ArrayExtensions
         
     | 
| 
      
 32 
     | 
    
         
            +
                def sample
         
     | 
| 
      
 33 
     | 
    
         
            +
                  self.choice
         
     | 
| 
      
 34 
     | 
    
         
            +
                end # sample
         
     | 
| 
      
 35 
     | 
    
         
            +
              end
         
     | 
| 
       33 
36 
     | 
    
         | 
| 
       34 
     | 
    
         
            -
             
     | 
| 
       35 
     | 
    
         
            -
                 
     | 
| 
       36 
     | 
    
         
            -
                # it isn't nil) and use value = value || connect().
         
     | 
| 
       37 
     | 
    
         
            -
                self.before do
         
     | 
| 
       38 
     | 
    
         
            -
                  @connected ||= AMQP.connect(amqp_url)
         
     | 
| 
       39 
     | 
    
         
            -
                end
         
     | 
| 
      
 37 
     | 
    
         
            +
              class Array
         
     | 
| 
      
 38 
     | 
    
         
            +
                include ArrayExtensions
         
     | 
| 
       40 
39 
     | 
    
         
             
              end
         
     | 
| 
       41 
40 
     | 
    
         
             
            end
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
            # Shorthand for mocking subject's instance variable
         
     | 
| 
      
 45 
     | 
    
         
            +
            def subject_mock(name, as_null = false)
         
     | 
| 
      
 46 
     | 
    
         
            +
              mock = mock(name)
         
     | 
| 
      
 47 
     | 
    
         
            +
              mock.as_null_object if as_null
         
     | 
| 
      
 48 
     | 
    
         
            +
              subject.instance_variable_set(name.to_sym, mock)
         
     | 
| 
      
 49 
     | 
    
         
            +
              mock
         
     | 
| 
      
 50 
     | 
    
         
            +
            end
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
            # Returns Header that should be correctly parsed
         
     | 
| 
      
 53 
     | 
    
         
            +
            def basic_header(opts = {})
         
     | 
| 
      
 54 
     | 
    
         
            +
              AMQP::Frame::Header.new(
         
     | 
| 
      
 55 
     | 
    
         
            +
                  AMQP::Protocol::Header.new(
         
     | 
| 
      
 56 
     | 
    
         
            +
                      AMQP::Protocol::Basic, :priority => 1), opts[:channel] || 0)
         
     | 
| 
      
 57 
     | 
    
         
            +
            end
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
            # Returns AMQP Frame::Header frame that contains Protocol::Header header
         
     | 
| 
      
 60 
     | 
    
         
            +
            # with (pre-)defined accessors set.
         
     | 
| 
      
 61 
     | 
    
         
            +
            def test_header opts = {}
         
     | 
| 
      
 62 
     | 
    
         
            +
              AMQP::Frame::Header.new(
         
     | 
| 
      
 63 
     | 
    
         
            +
                  AMQP::Protocol::Header.new(
         
     | 
| 
      
 64 
     | 
    
         
            +
                      opts[:klass] || AMQP::Protocol::Test,
         
     | 
| 
      
 65 
     | 
    
         
            +
                      opts[:size] || 4,
         
     | 
| 
      
 66 
     | 
    
         
            +
                      opts[:weight] || 2,
         
     | 
| 
      
 67 
     | 
    
         
            +
                      opts[:properties] || {:delivery_mode => 1}))
         
     | 
| 
      
 68 
     | 
    
         
            +
            end
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
            # Returns AMQP Frame::Method frame that contains Protocol::Basic::Deliver
         
     | 
| 
      
 71 
     | 
    
         
            +
            # with (pre-)defined accessors set.
         
     | 
| 
      
 72 
     | 
    
         
            +
            def test_method_deliver opts = {}
         
     | 
| 
      
 73 
     | 
    
         
            +
              AMQP::Frame::Method.new(
         
     | 
| 
      
 74 
     | 
    
         
            +
                  AMQP::Protocol::Basic::Deliver.new(
         
     | 
| 
      
 75 
     | 
    
         
            +
                      :consumer_tag => opts[:consumer_tag] || 'test_consumer'))
         
     | 
| 
      
 76 
     | 
    
         
            +
            end
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
            require "stringio"
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
            def capture_stdout(&block)
         
     | 
| 
      
 81 
     | 
    
         
            +
              $stdout = StringIO.new
         
     | 
| 
      
 82 
     | 
    
         
            +
              block.call
         
     | 
| 
      
 83 
     | 
    
         
            +
              $stdout.rewind
         
     | 
| 
      
 84 
     | 
    
         
            +
              result = $stdout.read
         
     | 
| 
      
 85 
     | 
    
         
            +
              $stdout = STDOUT
         
     | 
| 
      
 86 
     | 
    
         
            +
              return result
         
     | 
| 
      
 87 
     | 
    
         
            +
            end
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
            def capture_stderr(&block)
         
     | 
| 
      
 90 
     | 
    
         
            +
              $stderr = StringIO.new
         
     | 
| 
      
 91 
     | 
    
         
            +
              block.call
         
     | 
| 
      
 92 
     | 
    
         
            +
              $stderr.rewind
         
     | 
| 
      
 93 
     | 
    
         
            +
              result = $stderr.read
         
     | 
| 
      
 94 
     | 
    
         
            +
              $stderr = STDOUT
         
     | 
| 
      
 95 
     | 
    
         
            +
              return result
         
     | 
| 
      
 96 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,178 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # encoding: utf-8
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require "spec_helper"
         
     | 
| 
      
 4 
     | 
    
         
            +
            require "amqp/buffer"
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            if [].map.respond_to? :with_index
         
     | 
| 
      
 8 
     | 
    
         
            +
              class Array #:nodoc:
         
     | 
| 
      
 9 
     | 
    
         
            +
                def enum_with_index
         
     | 
| 
      
 10 
     | 
    
         
            +
                  each.with_index
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
              end
         
     | 
| 
      
 13 
     | 
    
         
            +
            else
         
     | 
| 
      
 14 
     | 
    
         
            +
              require 'enumerator'
         
     | 
| 
      
 15 
     | 
    
         
            +
            end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
            describe AMQP::Buffer do
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
              #
         
     | 
| 
      
 21 
     | 
    
         
            +
              # Examples
         
     | 
| 
      
 22 
     | 
    
         
            +
              #
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
              it "has contents" do
         
     | 
| 
      
 25 
     | 
    
         
            +
                subject.contents.should == ""
         
     | 
| 
      
 26 
     | 
    
         
            +
              end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
              it "can be initialized with data" do
         
     | 
| 
      
 29 
     | 
    
         
            +
                @buffer = described_class.new("abc")
         
     | 
| 
      
 30 
     | 
    
         
            +
                @buffer.contents.should == "abc"
         
     | 
| 
      
 31 
     | 
    
         
            +
              end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
              it "can append strings" do
         
     | 
| 
      
 34 
     | 
    
         
            +
                subject << "abc"
         
     | 
| 
      
 35 
     | 
    
         
            +
                subject << "def"
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                subject.contents.should == "abcdef"
         
     | 
| 
      
 38 
     | 
    
         
            +
              end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
              it "can append other buffers" do
         
     | 
| 
      
 41 
     | 
    
         
            +
                subject << described_class.new("abc")
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                subject.data.should == "abc"
         
     | 
| 
      
 44 
     | 
    
         
            +
              end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
              it "has current position" do
         
     | 
| 
      
 47 
     | 
    
         
            +
                subject.pos.should == 0
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                subject << described_class.new("abc")
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                subject.pos.should == 0
         
     | 
| 
      
 52 
     | 
    
         
            +
              end
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
              it "has length" do
         
     | 
| 
      
 56 
     | 
    
         
            +
                subject.length.should == 0
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                subject << "abc"
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
                subject.length.should == 3
         
     | 
| 
      
 61 
     | 
    
         
            +
                # check for a crazy case when both RSpec and Bacon are loaded;
         
     | 
| 
      
 62 
     | 
    
         
            +
                # then == matcher ALWAYS PASSES. Le sigh.
         
     | 
| 
      
 63 
     | 
    
         
            +
                subject.length.should_not == 300
         
     | 
| 
      
 64 
     | 
    
         
            +
              end
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
              it "provides emptiness predicate" do
         
     | 
| 
      
 68 
     | 
    
         
            +
                subject.should be_empty
         
     | 
| 
      
 69 
     | 
    
         
            +
                subject << "xyz"
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
                subject.should_not be_empty
         
     | 
| 
      
 72 
     | 
    
         
            +
              end
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
              it "supports writing of data" do
         
     | 
| 
      
 76 
     | 
    
         
            +
                subject._write("abc")
         
     | 
| 
      
 77 
     | 
    
         
            +
                subject.pos.should == 3
         
     | 
| 
      
 78 
     | 
    
         
            +
                subject.rewind
         
     | 
| 
      
 79 
     | 
    
         
            +
                subject.pos.should == 0
         
     | 
| 
      
 80 
     | 
    
         
            +
              end
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
              it "supports reading of data" do
         
     | 
| 
      
 84 
     | 
    
         
            +
                subject._write("abc")
         
     | 
| 
      
 85 
     | 
    
         
            +
                subject.rewind
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
                subject._read(2).should == "ab"
         
     | 
| 
      
 88 
     | 
    
         
            +
                subject.pos.should == 0
         
     | 
| 
      
 89 
     | 
    
         
            +
                subject._read(1).should == "c"
         
     | 
| 
      
 90 
     | 
    
         
            +
                subject.pos.should == 0
         
     | 
| 
      
 91 
     | 
    
         
            +
              end
         
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
      
 93 
     | 
    
         
            +
             
     | 
| 
      
 94 
     | 
    
         
            +
              it "raises on overflow" do
         
     | 
| 
      
 95 
     | 
    
         
            +
                expect {
         
     | 
| 
      
 96 
     | 
    
         
            +
                  subject._read(1)
         
     | 
| 
      
 97 
     | 
    
         
            +
                }.should raise_error(described_class::Overflow)
         
     | 
| 
      
 98 
     | 
    
         
            +
              end
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
             
     | 
| 
      
 101 
     | 
    
         
            +
              it "refuses reading of unsupported types" do
         
     | 
| 
      
 102 
     | 
    
         
            +
                expect {
         
     | 
| 
      
 103 
     | 
    
         
            +
                  subject.read(:junk)
         
     | 
| 
      
 104 
     | 
    
         
            +
                }.to raise_error(described_class::InvalidType)
         
     | 
| 
      
 105 
     | 
    
         
            +
              end
         
     | 
| 
      
 106 
     | 
    
         
            +
             
     | 
| 
      
 107 
     | 
    
         
            +
             
     | 
| 
      
 108 
     | 
    
         
            +
              it "refuses writing of unsupported types" do
         
     | 
| 
      
 109 
     | 
    
         
            +
                expect {
         
     | 
| 
      
 110 
     | 
    
         
            +
                  subject.write(:junk, 1)
         
     | 
| 
      
 111 
     | 
    
         
            +
                }.to raise_error(described_class::InvalidType)
         
     | 
| 
      
 112 
     | 
    
         
            +
              end
         
     | 
| 
      
 113 
     | 
    
         
            +
             
     | 
| 
      
 114 
     | 
    
         
            +
             
     | 
| 
      
 115 
     | 
    
         
            +
              { :octet => 0b10101010,
         
     | 
| 
      
 116 
     | 
    
         
            +
                :short => 100,
         
     | 
| 
      
 117 
     | 
    
         
            +
                :long => 100_000_000,
         
     | 
| 
      
 118 
     | 
    
         
            +
                :longlong => 666_555_444_333_222_111,
         
     | 
| 
      
 119 
     | 
    
         
            +
                :shortstr => 'hello',
         
     | 
| 
      
 120 
     | 
    
         
            +
                :longstr => 'bye'*500,
         
     | 
| 
      
 121 
     | 
    
         
            +
                :timestamp => time = Time.at(Time.now.to_i),
         
     | 
| 
      
 122 
     | 
    
         
            +
                :table => { :this => 'is', :a => 'hash', :with => {:nested => 123, :and => time, :also => 123.456} },
         
     | 
| 
      
 123 
     | 
    
         
            +
                :bit => true
         
     | 
| 
      
 124 
     | 
    
         
            +
              }.each do |type, value|
         
     | 
| 
      
 125 
     | 
    
         
            +
                it "can read and write a #{type}" do
         
     | 
| 
      
 126 
     | 
    
         
            +
                  subject.write(type, value)
         
     | 
| 
      
 127 
     | 
    
         
            +
                  subject.rewind
         
     | 
| 
      
 128 
     | 
    
         
            +
             
     | 
| 
      
 129 
     | 
    
         
            +
                  subject.read(type).should == value
         
     | 
| 
      
 130 
     | 
    
         
            +
                  subject.should be_empty
         
     | 
| 
      
 131 
     | 
    
         
            +
                end # it
         
     | 
| 
      
 132 
     | 
    
         
            +
              end # each
         
     | 
| 
      
 133 
     | 
    
         
            +
             
     | 
| 
      
 134 
     | 
    
         
            +
             
     | 
| 
      
 135 
     | 
    
         
            +
              it 'can read and write multiple bits' do
         
     | 
| 
      
 136 
     | 
    
         
            +
                bits = [true, false, false, true, true, false, false, true, true, false]
         
     | 
| 
      
 137 
     | 
    
         
            +
                subject.write(:bit, bits)
         
     | 
| 
      
 138 
     | 
    
         
            +
                subject.write(:octet, 100)
         
     | 
| 
      
 139 
     | 
    
         
            +
             
     | 
| 
      
 140 
     | 
    
         
            +
                subject.rewind
         
     | 
| 
      
 141 
     | 
    
         
            +
             
     | 
| 
      
 142 
     | 
    
         
            +
                bits.map do
         
     | 
| 
      
 143 
     | 
    
         
            +
                  subject.read(:bit)
         
     | 
| 
      
 144 
     | 
    
         
            +
                end.should == bits
         
     | 
| 
      
 145 
     | 
    
         
            +
                subject.read(:octet).should == 100
         
     | 
| 
      
 146 
     | 
    
         
            +
              end
         
     | 
| 
      
 147 
     | 
    
         
            +
             
     | 
| 
      
 148 
     | 
    
         
            +
              it 'can read and write property tables' do
         
     | 
| 
      
 149 
     | 
    
         
            +
                properties = ([
         
     | 
| 
      
 150 
     | 
    
         
            +
                               [:octet, 1],
         
     | 
| 
      
 151 
     | 
    
         
            +
                               [:shortstr, 'abc'],
         
     | 
| 
      
 152 
     | 
    
         
            +
                               [:bit, true],
         
     | 
| 
      
 153 
     | 
    
         
            +
                               [:bit, false],
         
     | 
| 
      
 154 
     | 
    
         
            +
                               [:shortstr, nil],
         
     | 
| 
      
 155 
     | 
    
         
            +
                               [:timestamp, nil],
         
     | 
| 
      
 156 
     | 
    
         
            +
                               [:table, { :a => 'hash' }],
         
     | 
| 
      
 157 
     | 
    
         
            +
                              ]*5).sort_by {rand}
         
     | 
| 
      
 158 
     | 
    
         
            +
             
     | 
| 
      
 159 
     | 
    
         
            +
                subject.write(:properties, properties)
         
     | 
| 
      
 160 
     | 
    
         
            +
                subject.rewind
         
     | 
| 
      
 161 
     | 
    
         
            +
                subject.read(:properties, *properties.map { |type, _| type }).should == properties.map { |_, value| value }
         
     | 
| 
      
 162 
     | 
    
         
            +
                subject.should be_empty
         
     | 
| 
      
 163 
     | 
    
         
            +
              end
         
     | 
| 
      
 164 
     | 
    
         
            +
             
     | 
| 
      
 165 
     | 
    
         
            +
              it 'does transactional reads with #extract' do
         
     | 
| 
      
 166 
     | 
    
         
            +
                subject.write :octet, 8
         
     | 
| 
      
 167 
     | 
    
         
            +
                orig = subject.to_s
         
     | 
| 
      
 168 
     | 
    
         
            +
             
     | 
| 
      
 169 
     | 
    
         
            +
                subject.rewind
         
     | 
| 
      
 170 
     | 
    
         
            +
                subject.extract do |b|
         
     | 
| 
      
 171 
     | 
    
         
            +
                  b.read :octet
         
     | 
| 
      
 172 
     | 
    
         
            +
                  b.read :short
         
     | 
| 
      
 173 
     | 
    
         
            +
                end
         
     | 
| 
      
 174 
     | 
    
         
            +
             
     | 
| 
      
 175 
     | 
    
         
            +
                subject.pos.should == 0
         
     | 
| 
      
 176 
     | 
    
         
            +
                subject.data.should == orig
         
     | 
| 
      
 177 
     | 
    
         
            +
              end
         
     | 
| 
      
 178 
     | 
    
         
            +
            end # describe
         
     |