qpid_proton 0.19.0 → 0.21.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.
- checksums.yaml +4 -4
 - data/examples/README.md +76 -0
 - data/examples/broker.rb +167 -0
 - data/examples/client.rb +79 -0
 - data/examples/direct_recv.rb +61 -0
 - data/examples/direct_send.rb +67 -0
 - data/examples/example_test.rb +109 -0
 - data/examples/helloworld.rb +57 -0
 - data/examples/server.rb +70 -0
 - data/examples/simple_recv.rb +57 -0
 - data/examples/simple_send.rb +63 -0
 - data/examples/ssl_certs/README.txt +24 -0
 - data/examples/ssl_certs/tclient-certificate.p12 +0 -0
 - data/examples/ssl_certs/tclient-certificate.pem +19 -0
 - data/examples/ssl_certs/tclient-full.p12 +0 -0
 - data/examples/ssl_certs/tclient-private-key.pem +30 -0
 - data/examples/ssl_certs/tserver-certificate.p12 +0 -0
 - data/examples/ssl_certs/tserver-certificate.pem +19 -0
 - data/examples/ssl_certs/tserver-full.p12 +0 -0
 - data/examples/ssl_certs/tserver-private-key.pem +30 -0
 - data/examples/ssl_send.rb +70 -0
 - data/ext/cproton/cproton.c +105 -74
 - data/lib/core/container.rb +2 -1
 - data/lib/core/ssl_domain.rb +1 -1
 - data/lib/core/uri.rb +15 -9
 - data/lib/handler/messaging_adapter.rb +20 -5
 - data/tests/old_examples/broker.rb +200 -0
 - data/tests/old_examples/client.rb +81 -0
 - data/tests/old_examples/direct_recv.rb +64 -0
 - data/tests/old_examples/direct_send.rb +63 -0
 - data/tests/old_examples/helloworld.rb +72 -0
 - data/tests/old_examples/helloworld_direct.rb +73 -0
 - data/tests/old_examples/lib/debugging.rb +25 -0
 - data/tests/old_examples/lib/driver.rb +68 -0
 - data/tests/old_examples/lib/qpid_examples.rb +26 -0
 - data/tests/old_examples/lib/selectable.rb +119 -0
 - data/tests/old_examples/lib/send_and_receive.rb +89 -0
 - data/tests/old_examples/old_example_test.rb +107 -0
 - data/tests/old_examples/recv.rb +23 -0
 - data/tests/old_examples/send.rb +21 -0
 - data/tests/old_examples/server.rb +75 -0
 - data/tests/old_examples/simple_recv.rb +57 -0
 - data/tests/old_examples/simple_send.rb +54 -0
 - data/tests/test_connection_driver.rb +134 -0
 - data/tests/test_container.rb +319 -0
 - data/tests/test_data.rb +66 -0
 - data/tests/test_delivery.rb +110 -0
 - data/tests/test_interop.rb +131 -0
 - data/tests/test_messaging_adapter.rb +223 -0
 - data/tests/test_old_adapter.rb +228 -0
 - data/tests/test_tools.rb +147 -0
 - data/tests/test_uri.rb +83 -0
 - metadata +49 -3
 
| 
         @@ -0,0 +1,134 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # Licensed to the Apache Software Foundation (ASF) under one
         
     | 
| 
      
 2 
     | 
    
         
            +
            # or more contributor license agreements.  See the NOTICE file
         
     | 
| 
      
 3 
     | 
    
         
            +
            # distributed with this work for additional information
         
     | 
| 
      
 4 
     | 
    
         
            +
            # regarding copyright ownership.  The ASF licenses this file
         
     | 
| 
      
 5 
     | 
    
         
            +
            # to you under the Apache License, Version 2.0 (the
         
     | 
| 
      
 6 
     | 
    
         
            +
            # "License"); you may not use this file except in compliance
         
     | 
| 
      
 7 
     | 
    
         
            +
            # with the License.  You may obtain a copy of the License at
         
     | 
| 
      
 8 
     | 
    
         
            +
            #
         
     | 
| 
      
 9 
     | 
    
         
            +
            #   http://www.apache.org/licenses/LICENSE-2.0
         
     | 
| 
      
 10 
     | 
    
         
            +
            #
         
     | 
| 
      
 11 
     | 
    
         
            +
            # distributed under the License is distributed on an
         
     | 
| 
      
 12 
     | 
    
         
            +
            # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
         
     | 
| 
      
 13 
     | 
    
         
            +
            # KIND, either express or implied.  See the License for the
         
     | 
| 
      
 14 
     | 
    
         
            +
            # specific language governing permissions and limitations
         
     | 
| 
      
 15 
     | 
    
         
            +
            # under the License.
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
            require 'test_tools'
         
     | 
| 
      
 19 
     | 
    
         
            +
            require 'minitest/unit'
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
            include Qpid::Proton
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
            # Test delivery of raw proton events
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
            class RawDriverTest < MiniTest::Test
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
              # Raw handler to record all on_xxx calls
         
     | 
| 
      
 28 
     | 
    
         
            +
              class RecordingHandler
         
     | 
| 
      
 29 
     | 
    
         
            +
                def initialize() @calls =[]; end
         
     | 
| 
      
 30 
     | 
    
         
            +
                def proton_adapter_class() nil; end # Raw adapter
         
     | 
| 
      
 31 
     | 
    
         
            +
                attr_reader :calls
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                def method_missing(name, *args) respond_to_missing?(name) ? @calls << name : super; end
         
     | 
| 
      
 34 
     | 
    
         
            +
                def respond_to_missing?(name, private=false); (/^on_/ =~ name); end
         
     | 
| 
      
 35 
     | 
    
         
            +
                def respond_to?(name, all=false) super || respond_to_missing?(name); end # For ruby < 1.9.2
         
     | 
| 
      
 36 
     | 
    
         
            +
              end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
              def test_send_recv
         
     | 
| 
      
 39 
     | 
    
         
            +
                send_class = Class.new do
         
     | 
| 
      
 40 
     | 
    
         
            +
                  def proton_adapter_class() nil; end # Raw adapter
         
     | 
| 
      
 41 
     | 
    
         
            +
                  attr_reader :outcome
         
     | 
| 
      
 42 
     | 
    
         
            +
                  def on_link_flow(event) event.sender.send Message.new("foo"); end
         
     | 
| 
      
 43 
     | 
    
         
            +
                  def on_delivery(event)
         
     | 
| 
      
 44 
     | 
    
         
            +
                    @outcome = event.delivery.state
         
     | 
| 
      
 45 
     | 
    
         
            +
                    event.connection.close;
         
     | 
| 
      
 46 
     | 
    
         
            +
                  end
         
     | 
| 
      
 47 
     | 
    
         
            +
                end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                recv_class = Class.new do
         
     | 
| 
      
 50 
     | 
    
         
            +
                  def proton_adapter_class() nil; end # Raw adapter
         
     | 
| 
      
 51 
     | 
    
         
            +
                  attr_reader :message
         
     | 
| 
      
 52 
     | 
    
         
            +
                  def on_connection_remote_open(event) event.context.open; end
         
     | 
| 
      
 53 
     | 
    
         
            +
                  def on_session_remote_open(event) event.context.open; end
         
     | 
| 
      
 54 
     | 
    
         
            +
                  def on_link_remote_open(event) event.link.open; event.link.flow(1); end
         
     | 
| 
      
 55 
     | 
    
         
            +
                  def on_delivery(event) @message = event.message; event.delivery.accept; end
         
     | 
| 
      
 56 
     | 
    
         
            +
                end
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                d = DriverPair.new(send_class.new, recv_class.new)
         
     | 
| 
      
 59 
     | 
    
         
            +
                d.client.connection.open(:container_id => __method__);
         
     | 
| 
      
 60 
     | 
    
         
            +
                d.client.connection.open_sender()
         
     | 
| 
      
 61 
     | 
    
         
            +
                d.run
         
     | 
| 
      
 62 
     | 
    
         
            +
                assert_equal(d.server.handler.message.body, "foo")
         
     | 
| 
      
 63 
     | 
    
         
            +
                assert_equal Transfer::ACCEPTED, d.client.handler.outcome
         
     | 
| 
      
 64 
     | 
    
         
            +
              end
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
              def test_idle
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
                d = DriverPair.new(RecordingHandler.new, RecordingHandler.new)
         
     | 
| 
      
 69 
     | 
    
         
            +
                ms = 444
         
     | 
| 
      
 70 
     | 
    
         
            +
                secs = Rational(ms, 1000)   # Use rationals to keep it accurate
         
     | 
| 
      
 71 
     | 
    
         
            +
                opts = {:idle_timeout => secs}
         
     | 
| 
      
 72 
     | 
    
         
            +
                d.client.transport.apply(opts)
         
     | 
| 
      
 73 
     | 
    
         
            +
                assert_equal(ms, d.client.transport.idle_timeout) # Transport converts to ms
         
     | 
| 
      
 74 
     | 
    
         
            +
                d.server.transport.set_server
         
     | 
| 
      
 75 
     | 
    
         
            +
                d.client.connection.open(opts)
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
                start = Time.at(1)          # Dummy timeline
         
     | 
| 
      
 78 
     | 
    
         
            +
                tick = d.run start          # Process all IO events
         
     | 
| 
      
 79 
     | 
    
         
            +
                assert_equal(secs/4, tick - start)
         
     | 
| 
      
 80 
     | 
    
         
            +
                assert_equal [:on_connection_init, :on_connection_local_open, :on_connection_bound], d.client.handler.calls
         
     | 
| 
      
 81 
     | 
    
         
            +
                assert_equal [:on_connection_init, :on_connection_bound, :on_connection_remote_open, :on_transport], d.server.handler.calls
         
     | 
| 
      
 82 
     | 
    
         
            +
                assert_equal (ms), d.client.transport.idle_timeout
         
     | 
| 
      
 83 
     | 
    
         
            +
                assert_equal (ms/2), d.server.transport.remote_idle_timeout # proton changes the value
         
     | 
| 
      
 84 
     | 
    
         
            +
                assert_equal (secs/2), d.server.connection.idle_timeout
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
                # Now update the time till we get connections closing
         
     | 
| 
      
 87 
     | 
    
         
            +
                d.each { |x| x.handler.calls.clear }
         
     | 
| 
      
 88 
     | 
    
         
            +
                d.run(start + secs - 0.001) # Should nothing, timeout not reached
         
     | 
| 
      
 89 
     | 
    
         
            +
                assert_equal [[],[]], d.collect { |x| x.handler.calls }
         
     | 
| 
      
 90 
     | 
    
         
            +
                d.run(start + secs*2)   # After 2x timeout, connections should close
         
     | 
| 
      
 91 
     | 
    
         
            +
                assert_equal [[:on_transport_error, :on_transport_tail_closed, :on_transport_head_closed, :on_transport_closed], [:on_connection_remote_close, :on_transport_tail_closed, :on_transport_head_closed, :on_transport_closed]], d.collect { |x| x.handler.calls }
         
     | 
| 
      
 92 
     | 
    
         
            +
              end
         
     | 
| 
      
 93 
     | 
    
         
            +
             
     | 
| 
      
 94 
     | 
    
         
            +
              # Test each_session/each_link methods both with a block and returning Enumerator
         
     | 
| 
      
 95 
     | 
    
         
            +
              def test_enumerators
         
     | 
| 
      
 96 
     | 
    
         
            +
                connection = Connection.new()
         
     | 
| 
      
 97 
     | 
    
         
            +
                (3.times.collect { connection.open_session }).each { |s|
         
     | 
| 
      
 98 
     | 
    
         
            +
                  s.open_sender; s.open_receiver
         
     | 
| 
      
 99 
     | 
    
         
            +
                }
         
     | 
| 
      
 100 
     | 
    
         
            +
             
     | 
| 
      
 101 
     | 
    
         
            +
                assert_equal 3, connection.each_session.to_a.size
         
     | 
| 
      
 102 
     | 
    
         
            +
                assert_equal 6, connection.each_link.to_a.size
         
     | 
| 
      
 103 
     | 
    
         
            +
             
     | 
| 
      
 104 
     | 
    
         
            +
                # Build Session => Set<Links> map using connection link enumerator
         
     | 
| 
      
 105 
     | 
    
         
            +
                map1 = {}
         
     | 
| 
      
 106 
     | 
    
         
            +
                connection.each_link { |l| map1[l.session] ||= Set.new; map1[l.session] << l }
         
     | 
| 
      
 107 
     | 
    
         
            +
                assert_equal 3, map1.size
         
     | 
| 
      
 108 
     | 
    
         
            +
                map1.each do |session,links|
         
     | 
| 
      
 109 
     | 
    
         
            +
                  assert_equal 2, links.size
         
     | 
| 
      
 110 
     | 
    
         
            +
                  links.each { |l| assert_equal session, l.session }
         
     | 
| 
      
 111 
     | 
    
         
            +
                end
         
     | 
| 
      
 112 
     | 
    
         
            +
             
     | 
| 
      
 113 
     | 
    
         
            +
                # Build Session => Set<Links> map using connection and session blocks
         
     | 
| 
      
 114 
     | 
    
         
            +
                map2 = {}
         
     | 
| 
      
 115 
     | 
    
         
            +
                connection.each_session do |session|
         
     | 
| 
      
 116 
     | 
    
         
            +
                  map2[session] = Set.new
         
     | 
| 
      
 117 
     | 
    
         
            +
                  session.each_link { |l| map2[session] << l }
         
     | 
| 
      
 118 
     | 
    
         
            +
                end
         
     | 
| 
      
 119 
     | 
    
         
            +
                assert_equal map1, map2
         
     | 
| 
      
 120 
     | 
    
         
            +
             
     | 
| 
      
 121 
     | 
    
         
            +
                # Build Session => Set<Links> map using connection session and session enumerators
         
     | 
| 
      
 122 
     | 
    
         
            +
                map3 = Hash[connection.each_session.collect { |s| [s, Set.new(s.each_link)] }]
         
     | 
| 
      
 123 
     | 
    
         
            +
                assert_equal map1, map3
         
     | 
| 
      
 124 
     | 
    
         
            +
             
     | 
| 
      
 125 
     | 
    
         
            +
                assert_equal [true, true, true], connection.each_sender.collect { |l| l.is_a? Sender }
         
     | 
| 
      
 126 
     | 
    
         
            +
                assert_equal [true, true, true], connection.each_receiver.collect { |l| l.is_a? Receiver }
         
     | 
| 
      
 127 
     | 
    
         
            +
                connection.each_session { |session|
         
     | 
| 
      
 128 
     | 
    
         
            +
                  assert_equal [true], session.each_sender.collect { |l| l.is_a? Sender }
         
     | 
| 
      
 129 
     | 
    
         
            +
                  assert_equal [true], session.each_receiver.collect { |l| l.is_a? Receiver }
         
     | 
| 
      
 130 
     | 
    
         
            +
                }
         
     | 
| 
      
 131 
     | 
    
         
            +
             
     | 
| 
      
 132 
     | 
    
         
            +
             
     | 
| 
      
 133 
     | 
    
         
            +
              end
         
     | 
| 
      
 134 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,319 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # Licensed to the Apache Software Foundation (ASF) under one
         
     | 
| 
      
 2 
     | 
    
         
            +
            # or more contributor license agreements.  See the NOTICE file
         
     | 
| 
      
 3 
     | 
    
         
            +
            # distributed with this work for additional information
         
     | 
| 
      
 4 
     | 
    
         
            +
            # regarding copyright ownership.  The ASF licenses this file
         
     | 
| 
      
 5 
     | 
    
         
            +
            # to you under the Apache License, Version 2.0 (the
         
     | 
| 
      
 6 
     | 
    
         
            +
            # "License"); you may not use this file except in compliance
         
     | 
| 
      
 7 
     | 
    
         
            +
            # with the License.  You may obtain a copy of the License at
         
     | 
| 
      
 8 
     | 
    
         
            +
            #
         
     | 
| 
      
 9 
     | 
    
         
            +
            #   http://www.apache.org/licenses/LICENSE-2.0
         
     | 
| 
      
 10 
     | 
    
         
            +
            #
         
     | 
| 
      
 11 
     | 
    
         
            +
            # Unless required by applicable law or agreed to in writing,
         
     | 
| 
      
 12 
     | 
    
         
            +
            # software distributed under the License is distributed on an
         
     | 
| 
      
 13 
     | 
    
         
            +
            # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
         
     | 
| 
      
 14 
     | 
    
         
            +
            # KIND, either express or implied.  See the License for the
         
     | 
| 
      
 15 
     | 
    
         
            +
            # specific language governing permissions and limitations
         
     | 
| 
      
 16 
     | 
    
         
            +
            # under the License.
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
            require 'test_tools'
         
     | 
| 
      
 20 
     | 
    
         
            +
            require 'minitest/unit'
         
     | 
| 
      
 21 
     | 
    
         
            +
            require 'socket'
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
            # Container that listens on a random port
         
     | 
| 
      
 24 
     | 
    
         
            +
            class TestContainer < Qpid::Proton::Container
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
              def initialize(handler, lopts=nil, id=nil)
         
     | 
| 
      
 27 
     | 
    
         
            +
                super handler, id
         
     | 
| 
      
 28 
     | 
    
         
            +
                @listener = listen_io(TCPServer.open(0), ListenOnceHandler.new(lopts))
         
     | 
| 
      
 29 
     | 
    
         
            +
              end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
              def port() @listener.to_io.addr[1]; end
         
     | 
| 
      
 32 
     | 
    
         
            +
              def url() "amqp://:#{port}"; end#
         
     | 
| 
      
 33 
     | 
    
         
            +
            end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
            class ContainerTest < MiniTest::Test
         
     | 
| 
      
 36 
     | 
    
         
            +
              include Qpid::Proton
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
              def test_simple()
         
     | 
| 
      
 39 
     | 
    
         
            +
                send_handler = Class.new(MessagingHandler) do
         
     | 
| 
      
 40 
     | 
    
         
            +
                  attr_reader :accepted, :sent
         
     | 
| 
      
 41 
     | 
    
         
            +
                  def on_sendable(sender)
         
     | 
| 
      
 42 
     | 
    
         
            +
                    sender.send Message.new("foo") unless @sent
         
     | 
| 
      
 43 
     | 
    
         
            +
                    @sent = true
         
     | 
| 
      
 44 
     | 
    
         
            +
                  end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                  def on_tracker_accept(tracker)
         
     | 
| 
      
 47 
     | 
    
         
            +
                    @accepted = true
         
     | 
| 
      
 48 
     | 
    
         
            +
                    tracker.connection.close
         
     | 
| 
      
 49 
     | 
    
         
            +
                  end
         
     | 
| 
      
 50 
     | 
    
         
            +
                end.new
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                receive_handler = Class.new(MessagingHandler) do
         
     | 
| 
      
 53 
     | 
    
         
            +
                  attr_reader :message, :link
         
     | 
| 
      
 54 
     | 
    
         
            +
                  def on_receiver_open(link)
         
     | 
| 
      
 55 
     | 
    
         
            +
                    @link = link
         
     | 
| 
      
 56 
     | 
    
         
            +
                    @link.open
         
     | 
| 
      
 57 
     | 
    
         
            +
                    @link.flow(1)
         
     | 
| 
      
 58 
     | 
    
         
            +
                  end
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
                  def on_message(delivery, message)
         
     | 
| 
      
 61 
     | 
    
         
            +
                    @message = message;
         
     | 
| 
      
 62 
     | 
    
         
            +
                    delivery.update Disposition::ACCEPTED
         
     | 
| 
      
 63 
     | 
    
         
            +
                    delivery.settle
         
     | 
| 
      
 64 
     | 
    
         
            +
                  end
         
     | 
| 
      
 65 
     | 
    
         
            +
                end.new
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
                c = TestContainer.new(receive_handler, {}, __method__)
         
     | 
| 
      
 68 
     | 
    
         
            +
                c.connect(c.url, {:handler => send_handler}).open_sender({:name => "testlink"})
         
     | 
| 
      
 69 
     | 
    
         
            +
                c.run
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
                assert send_handler.accepted
         
     | 
| 
      
 72 
     | 
    
         
            +
                assert_equal "testlink", receive_handler.link.name
         
     | 
| 
      
 73 
     | 
    
         
            +
                assert_equal "foo", receive_handler.message.body
         
     | 
| 
      
 74 
     | 
    
         
            +
                assert_equal "test_simple", receive_handler.link.connection.container_id
         
     | 
| 
      
 75 
     | 
    
         
            +
              end
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
              class CloseOnOpenHandler < TestHandler
         
     | 
| 
      
 78 
     | 
    
         
            +
                def on_connection_open(c) super; c.close; end
         
     | 
| 
      
 79 
     | 
    
         
            +
              end
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
              def test_auto_stop_one
         
     | 
| 
      
 82 
     | 
    
         
            +
                # A listener and a connection
         
     | 
| 
      
 83 
     | 
    
         
            +
                start_stop_handler = Class.new do
         
     | 
| 
      
 84 
     | 
    
         
            +
                  def on_container_start(c) @start = c; end
         
     | 
| 
      
 85 
     | 
    
         
            +
                  def on_container_stop(c) @stop = c; end
         
     | 
| 
      
 86 
     | 
    
         
            +
                  attr_reader :start, :stop
         
     | 
| 
      
 87 
     | 
    
         
            +
                end.new
         
     | 
| 
      
 88 
     | 
    
         
            +
                c = Container.new(start_stop_handler, __method__)
         
     | 
| 
      
 89 
     | 
    
         
            +
                threads = 3.times.collect { Thread.new { c.run } }
         
     | 
| 
      
 90 
     | 
    
         
            +
                sleep(0.01) while c.running < 3
         
     | 
| 
      
 91 
     | 
    
         
            +
                assert_equal c, start_stop_handler.start
         
     | 
| 
      
 92 
     | 
    
         
            +
                l = c.listen_io(TCPServer.new(0), ListenOnceHandler.new({ :handler => CloseOnOpenHandler.new}))
         
     | 
| 
      
 93 
     | 
    
         
            +
                c.connect("amqp://:#{l.to_io.addr[1]}", { :handler => CloseOnOpenHandler.new} )
         
     | 
| 
      
 94 
     | 
    
         
            +
                threads.each { |t| assert t.join(1) }
         
     | 
| 
      
 95 
     | 
    
         
            +
                assert_equal c, start_stop_handler.stop
         
     | 
| 
      
 96 
     | 
    
         
            +
                assert_raises(Container::StoppedError) { c.run }
         
     | 
| 
      
 97 
     | 
    
         
            +
              end
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
      
 99 
     | 
    
         
            +
              def test_auto_stop_two
         
     | 
| 
      
 100 
     | 
    
         
            +
                # Connect between different containers
         
     | 
| 
      
 101 
     | 
    
         
            +
                c1, c2 = Container.new("#{__method__}-1"), Container.new("#{__method__}-2")
         
     | 
| 
      
 102 
     | 
    
         
            +
                threads = [ Thread.new {c1.run }, Thread.new {c2.run } ]
         
     | 
| 
      
 103 
     | 
    
         
            +
                l = c2.listen_io(TCPServer.new(0), ListenOnceHandler.new({ :handler => CloseOnOpenHandler.new}))
         
     | 
| 
      
 104 
     | 
    
         
            +
                c1.connect(l.url, { :handler => CloseOnOpenHandler.new} )
         
     | 
| 
      
 105 
     | 
    
         
            +
                assert threads.each { |t| t.join(1) }
         
     | 
| 
      
 106 
     | 
    
         
            +
                assert_raises(Container::StoppedError) { c1.run }
         
     | 
| 
      
 107 
     | 
    
         
            +
                assert_raises(Container::StoppedError) { c2.connect("") }
         
     | 
| 
      
 108 
     | 
    
         
            +
              end
         
     | 
| 
      
 109 
     | 
    
         
            +
             
     | 
| 
      
 110 
     | 
    
         
            +
              def test_auto_stop_listener_only
         
     | 
| 
      
 111 
     | 
    
         
            +
                c = Container.new(__method__)
         
     | 
| 
      
 112 
     | 
    
         
            +
                # Listener only, external close
         
     | 
| 
      
 113 
     | 
    
         
            +
                t = Thread.new { c.run }
         
     | 
| 
      
 114 
     | 
    
         
            +
                l = c.listen_io(TCPServer.new(0))
         
     | 
| 
      
 115 
     | 
    
         
            +
                l.close
         
     | 
| 
      
 116 
     | 
    
         
            +
                assert t.join(1)
         
     | 
| 
      
 117 
     | 
    
         
            +
              end
         
     | 
| 
      
 118 
     | 
    
         
            +
             
     | 
| 
      
 119 
     | 
    
         
            +
              def test_stop_empty
         
     | 
| 
      
 120 
     | 
    
         
            +
                c = Container.new(__method__)
         
     | 
| 
      
 121 
     | 
    
         
            +
                threads = 3.times.collect { Thread.new { c.run } }
         
     | 
| 
      
 122 
     | 
    
         
            +
                sleep(0.01) while c.running < 3
         
     | 
| 
      
 123 
     | 
    
         
            +
                assert_nil threads[0].join(0.001) # Not stopped
         
     | 
| 
      
 124 
     | 
    
         
            +
                c.stop
         
     | 
| 
      
 125 
     | 
    
         
            +
                assert c.stopped
         
     | 
| 
      
 126 
     | 
    
         
            +
                assert_raises(Container::StoppedError) { c.connect("") }
         
     | 
| 
      
 127 
     | 
    
         
            +
                assert_raises(Container::StoppedError) { c.run }
         
     | 
| 
      
 128 
     | 
    
         
            +
                threads.each { |t| assert t.join(1) }
         
     | 
| 
      
 129 
     | 
    
         
            +
              end
         
     | 
| 
      
 130 
     | 
    
         
            +
             
     | 
| 
      
 131 
     | 
    
         
            +
              def test_stop
         
     | 
| 
      
 132 
     | 
    
         
            +
                c = Container.new(__method__)
         
     | 
| 
      
 133 
     | 
    
         
            +
                c.auto_stop = false
         
     | 
| 
      
 134 
     | 
    
         
            +
             
     | 
| 
      
 135 
     | 
    
         
            +
                l = c.listen_io(TCPServer.new(0))
         
     | 
| 
      
 136 
     | 
    
         
            +
                threads = 3.times.collect { Thread.new { c.run } }
         
     | 
| 
      
 137 
     | 
    
         
            +
                sleep(0.01) while c.running < 3
         
     | 
| 
      
 138 
     | 
    
         
            +
                l.close
         
     | 
| 
      
 139 
     | 
    
         
            +
                assert_nil threads[0].join(0.001) # Not stopped, no auto_stop
         
     | 
| 
      
 140 
     | 
    
         
            +
             
     | 
| 
      
 141 
     | 
    
         
            +
                l = c.listen_io(TCPServer.new(0)) # New listener
         
     | 
| 
      
 142 
     | 
    
         
            +
                conn = c.connect("amqp://:#{l.to_io.addr[1]}")
         
     | 
| 
      
 143 
     | 
    
         
            +
                c.stop
         
     | 
| 
      
 144 
     | 
    
         
            +
                assert c.stopped
         
     | 
| 
      
 145 
     | 
    
         
            +
                threads.each { |t| assert t.join(1) }
         
     | 
| 
      
 146 
     | 
    
         
            +
             
     | 
| 
      
 147 
     | 
    
         
            +
                assert_raises(Container::StoppedError) { c.run }
         
     | 
| 
      
 148 
     | 
    
         
            +
                assert_equal 0, c.running
         
     | 
| 
      
 149 
     | 
    
         
            +
                assert_nil l.condition
         
     | 
| 
      
 150 
     | 
    
         
            +
                assert_nil conn.condition
         
     | 
| 
      
 151 
     | 
    
         
            +
              end
         
     | 
| 
      
 152 
     | 
    
         
            +
             
     | 
| 
      
 153 
     | 
    
         
            +
              def test_bad_host
         
     | 
| 
      
 154 
     | 
    
         
            +
                cont = Container.new(__method__)
         
     | 
| 
      
 155 
     | 
    
         
            +
                assert_raises (SocketError) { cont.listen("badlisten.example.com:999") }
         
     | 
| 
      
 156 
     | 
    
         
            +
                assert_raises (SocketError) { c = cont.connect("badconnect.example.com:999") }
         
     | 
| 
      
 157 
     | 
    
         
            +
              end
         
     | 
| 
      
 158 
     | 
    
         
            +
             
     | 
| 
      
 159 
     | 
    
         
            +
              # Verify that connection options are sent to the peer and available as Connection methods
         
     | 
| 
      
 160 
     | 
    
         
            +
              def test_connection_options
         
     | 
| 
      
 161 
     | 
    
         
            +
                # Note: user, password and sasl_xxx options are tested by ContainerSASLTest below
         
     | 
| 
      
 162 
     | 
    
         
            +
                server_handler = Class.new(MessagingHandler) do
         
     | 
| 
      
 163 
     | 
    
         
            +
                  def on_error(e) raise e.inspect; end
         
     | 
| 
      
 164 
     | 
    
         
            +
                  def on_connection_open(c)
         
     | 
| 
      
 165 
     | 
    
         
            +
                    @connection = c
         
     | 
| 
      
 166 
     | 
    
         
            +
                    c.open({
         
     | 
| 
      
 167 
     | 
    
         
            +
                            :virtual_host => "server.to.client",
         
     | 
| 
      
 168 
     | 
    
         
            +
                            :properties => { :server => :client },
         
     | 
| 
      
 169 
     | 
    
         
            +
                            :offered_capabilities => [ :s1 ],
         
     | 
| 
      
 170 
     | 
    
         
            +
                            :desired_capabilities => [ :s2 ],
         
     | 
| 
      
 171 
     | 
    
         
            +
                            :container_id => "box",
         
     | 
| 
      
 172 
     | 
    
         
            +
                           })
         
     | 
| 
      
 173 
     | 
    
         
            +
                    c.close
         
     | 
| 
      
 174 
     | 
    
         
            +
                  end
         
     | 
| 
      
 175 
     | 
    
         
            +
                  attr_reader :connection
         
     | 
| 
      
 176 
     | 
    
         
            +
                end.new
         
     | 
| 
      
 177 
     | 
    
         
            +
                # Transport options must be provided to the listener, by Connection#open it is too late
         
     | 
| 
      
 178 
     | 
    
         
            +
                cont = TestContainer.new(nil, {
         
     | 
| 
      
 179 
     | 
    
         
            +
                                               :handler => server_handler,
         
     | 
| 
      
 180 
     | 
    
         
            +
                                               :idle_timeout => 88,
         
     | 
| 
      
 181 
     | 
    
         
            +
                                               :max_sessions =>1000,
         
     | 
| 
      
 182 
     | 
    
         
            +
                                               :max_frame_size => 8888,
         
     | 
| 
      
 183 
     | 
    
         
            +
                                              })
         
     | 
| 
      
 184 
     | 
    
         
            +
                client = cont.connect(cont.url,
         
     | 
| 
      
 185 
     | 
    
         
            +
                                      {:virtual_host => "client.to.server",
         
     | 
| 
      
 186 
     | 
    
         
            +
                                       :properties => { :foo => :bar, "str" => "str" },
         
     | 
| 
      
 187 
     | 
    
         
            +
                                       :offered_capabilities => [:c1 ],
         
     | 
| 
      
 188 
     | 
    
         
            +
                                       :desired_capabilities => ["c2" ],
         
     | 
| 
      
 189 
     | 
    
         
            +
                                       :idle_timeout => 42,
         
     | 
| 
      
 190 
     | 
    
         
            +
                                       :max_sessions =>100,
         
     | 
| 
      
 191 
     | 
    
         
            +
                                       :max_frame_size => 4096,
         
     | 
| 
      
 192 
     | 
    
         
            +
                                       :container_id => "bowl"
         
     | 
| 
      
 193 
     | 
    
         
            +
                                      })
         
     | 
| 
      
 194 
     | 
    
         
            +
                cont.run
         
     | 
| 
      
 195 
     | 
    
         
            +
                c = server_handler.connection
         
     | 
| 
      
 196 
     | 
    
         
            +
                assert_equal "client.to.server", c.virtual_host
         
     | 
| 
      
 197 
     | 
    
         
            +
                assert_equal({ :foo => :bar, :str => "str" }, c.properties)
         
     | 
| 
      
 198 
     | 
    
         
            +
                assert_equal([:c1], c.offered_capabilities)
         
     | 
| 
      
 199 
     | 
    
         
            +
                assert_equal([:c2], c.desired_capabilities)
         
     | 
| 
      
 200 
     | 
    
         
            +
                assert_equal 21, c.idle_timeout # Proton divides by 2
         
     | 
| 
      
 201 
     | 
    
         
            +
                assert_equal 100, c.max_sessions
         
     | 
| 
      
 202 
     | 
    
         
            +
                assert_equal 4096, c.max_frame_size
         
     | 
| 
      
 203 
     | 
    
         
            +
                assert_equal "bowl", c.container_id
         
     | 
| 
      
 204 
     | 
    
         
            +
             
     | 
| 
      
 205 
     | 
    
         
            +
                c = client
         
     | 
| 
      
 206 
     | 
    
         
            +
                assert_equal "server.to.client", c.virtual_host
         
     | 
| 
      
 207 
     | 
    
         
            +
                assert_equal({ :server => :client }, c.properties)
         
     | 
| 
      
 208 
     | 
    
         
            +
                assert_equal([:s1], c.offered_capabilities)
         
     | 
| 
      
 209 
     | 
    
         
            +
                assert_equal([:s2], c.desired_capabilities)
         
     | 
| 
      
 210 
     | 
    
         
            +
                assert_equal "box", c.container_id
         
     | 
| 
      
 211 
     | 
    
         
            +
                assert_equal 8888, c.max_frame_size
         
     | 
| 
      
 212 
     | 
    
         
            +
                assert_equal 44, c.idle_timeout # Proton divides by 2
         
     | 
| 
      
 213 
     | 
    
         
            +
                assert_equal 100, c.max_sessions
         
     | 
| 
      
 214 
     | 
    
         
            +
              end
         
     | 
| 
      
 215 
     | 
    
         
            +
            end
         
     | 
| 
      
 216 
     | 
    
         
            +
             
     | 
| 
      
 217 
     | 
    
         
            +
             
     | 
| 
      
 218 
     | 
    
         
            +
            class ContainerSASLTest < MiniTest::Test
         
     | 
| 
      
 219 
     | 
    
         
            +
              include Qpid::Proton
         
     | 
| 
      
 220 
     | 
    
         
            +
             
     | 
| 
      
 221 
     | 
    
         
            +
              # Handler for test client/server that sets up server and client SASL options
         
     | 
| 
      
 222 
     | 
    
         
            +
              class SASLHandler < TestHandler
         
     | 
| 
      
 223 
     | 
    
         
            +
             
     | 
| 
      
 224 
     | 
    
         
            +
                def initialize(url="amqp://", opts=nil)
         
     | 
| 
      
 225 
     | 
    
         
            +
                  super()
         
     | 
| 
      
 226 
     | 
    
         
            +
                  @url, @opts = url, opts
         
     | 
| 
      
 227 
     | 
    
         
            +
                end
         
     | 
| 
      
 228 
     | 
    
         
            +
             
     | 
| 
      
 229 
     | 
    
         
            +
                def on_container_start(container)
         
     | 
| 
      
 230 
     | 
    
         
            +
                  @client = container.connect("#{@url}:#{container.port}", @opts)
         
     | 
| 
      
 231 
     | 
    
         
            +
                end
         
     | 
| 
      
 232 
     | 
    
         
            +
             
     | 
| 
      
 233 
     | 
    
         
            +
                attr_reader :auth_user
         
     | 
| 
      
 234 
     | 
    
         
            +
             
     | 
| 
      
 235 
     | 
    
         
            +
                def on_connection_open(connection)
         
     | 
| 
      
 236 
     | 
    
         
            +
                  super
         
     | 
| 
      
 237 
     | 
    
         
            +
                  if connection == @client
         
     | 
| 
      
 238 
     | 
    
         
            +
                    connection.close
         
     | 
| 
      
 239 
     | 
    
         
            +
                  else
         
     | 
| 
      
 240 
     | 
    
         
            +
                    @auth_user = connection.user
         
     | 
| 
      
 241 
     | 
    
         
            +
                  end
         
     | 
| 
      
 242 
     | 
    
         
            +
                end
         
     | 
| 
      
 243 
     | 
    
         
            +
              end
         
     | 
| 
      
 244 
     | 
    
         
            +
             
     | 
| 
      
 245 
     | 
    
         
            +
              # Generate SASL server configuration files and database, initialize proton SASL
         
     | 
| 
      
 246 
     | 
    
         
            +
              class SASLConfig
         
     | 
| 
      
 247 
     | 
    
         
            +
                include Qpid::Proton
         
     | 
| 
      
 248 
     | 
    
         
            +
                attr_reader :conf_dir, :conf_file, :conf_name, :database
         
     | 
| 
      
 249 
     | 
    
         
            +
             
     | 
| 
      
 250 
     | 
    
         
            +
                def initialize()
         
     | 
| 
      
 251 
     | 
    
         
            +
                  if SASL.extended? # Configure cyrus SASL
         
     | 
| 
      
 252 
     | 
    
         
            +
                    @conf_dir = File.expand_path('sasl_conf')
         
     | 
| 
      
 253 
     | 
    
         
            +
                    @conf_name = "proton-server"
         
     | 
| 
      
 254 
     | 
    
         
            +
                    @database = File.join(@conf_dir, "proton.sasldb")
         
     | 
| 
      
 255 
     | 
    
         
            +
                    @conf_file = File.join(conf_dir,"#{@conf_name}.conf")
         
     | 
| 
      
 256 
     | 
    
         
            +
                    Dir::mkdir(@conf_dir) unless File.directory?(@conf_dir)
         
     | 
| 
      
 257 
     | 
    
         
            +
                    # Same user name in different realms
         
     | 
| 
      
 258 
     | 
    
         
            +
                    make_user("user", "password", "proton") # proton realm
         
     | 
| 
      
 259 
     | 
    
         
            +
                    make_user("user", "default_password") # Default realm
         
     | 
| 
      
 260 
     | 
    
         
            +
                    File.open(@conf_file, 'w') do |f|
         
     | 
| 
      
 261 
     | 
    
         
            +
                      f.write("
         
     | 
| 
      
 262 
     | 
    
         
            +
            sasldb_path: #{database}
         
     | 
| 
      
 263 
     | 
    
         
            +
            mech_list: EXTERNAL DIGEST-MD5 SCRAM-SHA-1 CRAM-MD5 PLAIN ANONYMOUS
         
     | 
| 
      
 264 
     | 
    
         
            +
                              ")
         
     | 
| 
      
 265 
     | 
    
         
            +
                    end
         
     | 
| 
      
 266 
     | 
    
         
            +
                    # Tell proton library to use the new configuration
         
     | 
| 
      
 267 
     | 
    
         
            +
                    SASL.config_path =  conf_dir
         
     | 
| 
      
 268 
     | 
    
         
            +
                    SASL.config_name = conf_name
         
     | 
| 
      
 269 
     | 
    
         
            +
                  end
         
     | 
| 
      
 270 
     | 
    
         
            +
                end
         
     | 
| 
      
 271 
     | 
    
         
            +
             
     | 
| 
      
 272 
     | 
    
         
            +
                private
         
     | 
| 
      
 273 
     | 
    
         
            +
             
     | 
| 
      
 274 
     | 
    
         
            +
                SASLPASSWD = (ENV['SASLPASSWD'] or 'saslpasswd2')
         
     | 
| 
      
 275 
     | 
    
         
            +
             
     | 
| 
      
 276 
     | 
    
         
            +
                def make_user(user, password, realm=nil)
         
     | 
| 
      
 277 
     | 
    
         
            +
                  realm_opt = (realm ? "-u #{realm}" : "")
         
     | 
| 
      
 278 
     | 
    
         
            +
                  cmd = "echo '#{password}' | #{SASLPASSWD} -c -p -f #{database} #{realm_opt} #{user}"
         
     | 
| 
      
 279 
     | 
    
         
            +
                  system(cmd) or raise RuntimeError.new("saslpasswd2 failed: #{makepw_cmd}")
         
     | 
| 
      
 280 
     | 
    
         
            +
                end
         
     | 
| 
      
 281 
     | 
    
         
            +
                DEFAULT = SASLConfig.new
         
     | 
| 
      
 282 
     | 
    
         
            +
              end
         
     | 
| 
      
 283 
     | 
    
         
            +
             
     | 
| 
      
 284 
     | 
    
         
            +
              def test_sasl_anonymous()
         
     | 
| 
      
 285 
     | 
    
         
            +
                s = SASLHandler.new("amqp://",  {:sasl_allowed_mechs => "ANONYMOUS"})
         
     | 
| 
      
 286 
     | 
    
         
            +
                TestContainer.new(s, {:sasl_allowed_mechs => "ANONYMOUS"}, __method__).run
         
     | 
| 
      
 287 
     | 
    
         
            +
                assert_equal "anonymous", s.connections[0].user
         
     | 
| 
      
 288 
     | 
    
         
            +
              end
         
     | 
| 
      
 289 
     | 
    
         
            +
             
     | 
| 
      
 290 
     | 
    
         
            +
              def test_sasl_plain_url()
         
     | 
| 
      
 291 
     | 
    
         
            +
                skip unless SASL.extended?
         
     | 
| 
      
 292 
     | 
    
         
            +
                # Use default realm with URL, should authenticate with "default_password"
         
     | 
| 
      
 293 
     | 
    
         
            +
                opts = {:sasl_allowed_mechs => "PLAIN", :sasl_allow_insecure_mechs => true}
         
     | 
| 
      
 294 
     | 
    
         
            +
                s = SASLHandler.new("amqp://user:default_password@",  opts)
         
     | 
| 
      
 295 
     | 
    
         
            +
                TestContainer.new(s, opts, __method__).run
         
     | 
| 
      
 296 
     | 
    
         
            +
                assert_equal(2, s.connections.size)
         
     | 
| 
      
 297 
     | 
    
         
            +
                assert_equal("user", s.auth_user)
         
     | 
| 
      
 298 
     | 
    
         
            +
              end
         
     | 
| 
      
 299 
     | 
    
         
            +
             
     | 
| 
      
 300 
     | 
    
         
            +
              def test_sasl_plain_options()
         
     | 
| 
      
 301 
     | 
    
         
            +
                skip unless SASL.extended?
         
     | 
| 
      
 302 
     | 
    
         
            +
                # Use default realm with connection options, should authenticate with "default_password"
         
     | 
| 
      
 303 
     | 
    
         
            +
                opts = {:sasl_allowed_mechs => "PLAIN",:sasl_allow_insecure_mechs => true,
         
     | 
| 
      
 304 
     | 
    
         
            +
                        :user => 'user', :password => 'default_password' }
         
     | 
| 
      
 305 
     | 
    
         
            +
                s = SASLHandler.new("amqp://", opts)
         
     | 
| 
      
 306 
     | 
    
         
            +
                TestContainer.new(s, {:sasl_allowed_mechs => "PLAIN",:sasl_allow_insecure_mechs => true}, __method__).run
         
     | 
| 
      
 307 
     | 
    
         
            +
                assert_equal(2, s.connections.size)
         
     | 
| 
      
 308 
     | 
    
         
            +
                assert_equal("user", s.auth_user)
         
     | 
| 
      
 309 
     | 
    
         
            +
              end
         
     | 
| 
      
 310 
     | 
    
         
            +
             
     | 
| 
      
 311 
     | 
    
         
            +
              # Ensure we don't allow PLAIN if allow_insecure_mechs = true is not explicitly set
         
     | 
| 
      
 312 
     | 
    
         
            +
              def test_disallow_insecure()
         
     | 
| 
      
 313 
     | 
    
         
            +
                # Don't set allow_insecure_mechs, but try to use PLAIN
         
     | 
| 
      
 314 
     | 
    
         
            +
                s = SASLHandler.new("amqp://user:password@", {:sasl_allowed_mechs => "PLAIN", :sasl_allow_insecure_mechs => true})
         
     | 
| 
      
 315 
     | 
    
         
            +
                e = assert_raises(TestError) { TestContainer.new(s, {:sasl_allowed_mechs => "PLAIN"}, __method__).run }
         
     | 
| 
      
 316 
     | 
    
         
            +
                assert_match(/amqp:unauthorized-access.*Authentication failed/, e.to_s)
         
     | 
| 
      
 317 
     | 
    
         
            +
              end
         
     | 
| 
      
 318 
     | 
    
         
            +
            end
         
     | 
| 
      
 319 
     | 
    
         
            +
             
     | 
    
        data/tests/test_data.rb
    ADDED
    
    | 
         @@ -0,0 +1,66 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # Licensed to the Apache Software Foundation (ASF) under one
         
     | 
| 
      
 2 
     | 
    
         
            +
            # or more contributor license agreements.  See the NOTICE file
         
     | 
| 
      
 3 
     | 
    
         
            +
            # distributed with this work for additional information
         
     | 
| 
      
 4 
     | 
    
         
            +
            # regarding copyright ownership.  The ASF licenses this file
         
     | 
| 
      
 5 
     | 
    
         
            +
            # to you under the Apache License, Version 2.0 (the
         
     | 
| 
      
 6 
     | 
    
         
            +
            # "License"); you may not use this file except in compliance
         
     | 
| 
      
 7 
     | 
    
         
            +
            # with the License.  You may obtain a copy of the License at
         
     | 
| 
      
 8 
     | 
    
         
            +
            #
         
     | 
| 
      
 9 
     | 
    
         
            +
            #   http://www.apache.org/licenses/LICENSE-2.0
         
     | 
| 
      
 10 
     | 
    
         
            +
            #
         
     | 
| 
      
 11 
     | 
    
         
            +
            # Unless required by applicable law or agreed to in writing,
         
     | 
| 
      
 12 
     | 
    
         
            +
            # software distributed under the License is distributed on an
         
     | 
| 
      
 13 
     | 
    
         
            +
            # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
         
     | 
| 
      
 14 
     | 
    
         
            +
            # KIND, either express or implied.  See the License for the
         
     | 
| 
      
 15 
     | 
    
         
            +
            # specific language governing permissions and limitations
         
     | 
| 
      
 16 
     | 
    
         
            +
            # under the License.
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
            require 'test_tools'
         
     | 
| 
      
 20 
     | 
    
         
            +
            require "securerandom"
         
     | 
| 
      
 21 
     | 
    
         
            +
            require 'qpid_proton'
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
            class TestData < MiniTest::Test
         
     | 
| 
      
 24 
     | 
    
         
            +
              include Qpid::Proton
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
              def assert_from_to(*values)
         
     | 
| 
      
 27 
     | 
    
         
            +
                d = Codec::Data.new
         
     | 
| 
      
 28 
     | 
    
         
            +
                values.each do |x|
         
     | 
| 
      
 29 
     | 
    
         
            +
                  Codec::Data.from_object(d.impl, x)
         
     | 
| 
      
 30 
     | 
    
         
            +
                  assert_equal x, Codec::Data.to_object(d.impl)
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
              end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
              def test_from_to
         
     | 
| 
      
 35 
     | 
    
         
            +
                assert_from_to({ 1 => :one, 2=>:two })
         
     | 
| 
      
 36 
     | 
    
         
            +
                assert_from_to([{:a => 1, "b" => 2}, 3, 4.4, :five])
         
     | 
| 
      
 37 
     | 
    
         
            +
                assert_from_to(Types::UniformArray.new(Types::INT, [1, 2, 3, 4]))
         
     | 
| 
      
 38 
     | 
    
         
            +
              end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
              def rnum(*arg) SecureRandom.random_number(*arg); end
         
     | 
| 
      
 41 
     | 
    
         
            +
              def rstr(*arg) SecureRandom.base64(*arg); end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
              def test_nil()
         
     | 
| 
      
 44 
     | 
    
         
            +
                assert_nil((Codec::Data.new << nil).object)
         
     | 
| 
      
 45 
     | 
    
         
            +
              end
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
              def assert_convert(*values)
         
     | 
| 
      
 48 
     | 
    
         
            +
                values.each { |x| assert_equal x, ((Codec::Data.new << x).object) }
         
     | 
| 
      
 49 
     | 
    
         
            +
              end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
              def test_bool()
         
     | 
| 
      
 52 
     | 
    
         
            +
                assert_convert(true, false)
         
     | 
| 
      
 53 
     | 
    
         
            +
              end
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
              def test_float()
         
     | 
| 
      
 56 
     | 
    
         
            +
                assert_convert(0.0, 1.0, -1.0, 1.23e123, rnum(), rnum(), rnum(), rnum())
         
     | 
| 
      
 57 
     | 
    
         
            +
              end
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
              def test_string()
         
     | 
| 
      
 60 
     | 
    
         
            +
                assert_convert("", "foo", rstr(100000), rstr(rnum(1000)), rstr(rnum(1000)))
         
     | 
| 
      
 61 
     | 
    
         
            +
              end
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
              def test_symbol()
         
     | 
| 
      
 64 
     | 
    
         
            +
                assert_convert(:"", :foo, rstr(256).to_sym)
         
     | 
| 
      
 65 
     | 
    
         
            +
              end
         
     | 
| 
      
 66 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,110 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # Licensed to the Apache Software Foundation (ASF) under one
         
     | 
| 
      
 2 
     | 
    
         
            +
            # or more contributor license agreements.  See the NOTICE file
         
     | 
| 
      
 3 
     | 
    
         
            +
            # distributed with this work for additional information
         
     | 
| 
      
 4 
     | 
    
         
            +
            # regarding copyright ownership.  The ASF licenses this file
         
     | 
| 
      
 5 
     | 
    
         
            +
            # to you under the Apache License, Version 2.0 (the
         
     | 
| 
      
 6 
     | 
    
         
            +
            # "License"); you may not use this file except in compliance
         
     | 
| 
      
 7 
     | 
    
         
            +
            # with the License.  You may obtain a copy of the License at
         
     | 
| 
      
 8 
     | 
    
         
            +
            #
         
     | 
| 
      
 9 
     | 
    
         
            +
            #   http://www.apache.org/licenses/LICENSE-2.0
         
     | 
| 
      
 10 
     | 
    
         
            +
            #
         
     | 
| 
      
 11 
     | 
    
         
            +
            # Unless required by applicable law or agreed to in writing,
         
     | 
| 
      
 12 
     | 
    
         
            +
            # software distributed under the License is distributed on an
         
     | 
| 
      
 13 
     | 
    
         
            +
            # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
         
     | 
| 
      
 14 
     | 
    
         
            +
            # KIND, either express or implied.  See the License for the
         
     | 
| 
      
 15 
     | 
    
         
            +
            # specific language governing permissions and limitations
         
     | 
| 
      
 16 
     | 
    
         
            +
            # under the License.
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
            require 'minitest/autorun'
         
     | 
| 
      
 20 
     | 
    
         
            +
            require 'qpid_proton'
         
     | 
| 
      
 21 
     | 
    
         
            +
            require 'test_tools'
         
     | 
| 
      
 22 
     | 
    
         
            +
            include Qpid::Proton
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
            # Test Delivery and Tracker
         
     | 
| 
      
 25 
     | 
    
         
            +
            class TestDelivery < MiniTest::Test
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
              class NoAutoHandler < MessagingHandler
         
     | 
| 
      
 28 
     | 
    
         
            +
                def on_sender_open(l) l.open({:auto_settle=>false, :auto_accept=>false}); end
         
     | 
| 
      
 29 
     | 
    
         
            +
                def on_receiver_open(l) l.open({:auto_settle=>false, :auto_accept=>false}); end
         
     | 
| 
      
 30 
     | 
    
         
            +
              end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
              class SendHandler < NoAutoHandler
         
     | 
| 
      
 33 
     | 
    
         
            +
                def initialize(to_send)
         
     | 
| 
      
 34 
     | 
    
         
            +
                  @unsent = to_send
         
     | 
| 
      
 35 
     | 
    
         
            +
                end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                def on_connection_open(connection)
         
     | 
| 
      
 38 
     | 
    
         
            +
                  @outcomes = []
         
     | 
| 
      
 39 
     | 
    
         
            +
                  @sender = connection.open_sender("x")
         
     | 
| 
      
 40 
     | 
    
         
            +
                  @unsettled = {}           # Awaiting remote settlement
         
     | 
| 
      
 41 
     | 
    
         
            +
                end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                attr_reader :outcomes, :unsent, :unsettled
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                def on_sendable(sender)
         
     | 
| 
      
 46 
     | 
    
         
            +
                  return if @unsent.empty?
         
     | 
| 
      
 47 
     | 
    
         
            +
                  m = Message.new(@unsent.shift)
         
     | 
| 
      
 48 
     | 
    
         
            +
                  tracker = sender.send(m)
         
     | 
| 
      
 49 
     | 
    
         
            +
                  @unsettled[tracker] = m
         
     | 
| 
      
 50 
     | 
    
         
            +
                end
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                def outcome(method, tracker)
         
     | 
| 
      
 53 
     | 
    
         
            +
                  t = tracker
         
     | 
| 
      
 54 
     | 
    
         
            +
                  m = @unsettled.delete(t)
         
     | 
| 
      
 55 
     | 
    
         
            +
                  @outcomes << [m.body, method, t.id, t.state, t.modifications]
         
     | 
| 
      
 56 
     | 
    
         
            +
                  tracker.connection.close if @unsettled.empty?
         
     | 
| 
      
 57 
     | 
    
         
            +
                end
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                def on_tracker_accept(tracker) outcome(__method__, tracker); end
         
     | 
| 
      
 60 
     | 
    
         
            +
                def on_tracker_reject(tracker) outcome(__method__, tracker); end
         
     | 
| 
      
 61 
     | 
    
         
            +
                def on_tracker_release(tracker) outcome(__method__, tracker); end
         
     | 
| 
      
 62 
     | 
    
         
            +
                def on_tracker_modify(tracker) outcome(__method__, tracker); end
         
     | 
| 
      
 63 
     | 
    
         
            +
              end
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
              class ReceiveHandler < NoAutoHandler
         
     | 
| 
      
 66 
     | 
    
         
            +
                def initialize
         
     | 
| 
      
 67 
     | 
    
         
            +
                  @received = []
         
     | 
| 
      
 68 
     | 
    
         
            +
                end
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
                attr_reader :received
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                def on_message(delivery, message)
         
     | 
| 
      
 73 
     | 
    
         
            +
                  @received << message.body
         
     | 
| 
      
 74 
     | 
    
         
            +
                  case message.body
         
     | 
| 
      
 75 
     | 
    
         
            +
                  when "accept" then delivery.accept
         
     | 
| 
      
 76 
     | 
    
         
            +
                  when "reject" then delivery.reject
         
     | 
| 
      
 77 
     | 
    
         
            +
                  when "release-really" then delivery.release({:failed=>false}) # AMQP RELEASED
         
     | 
| 
      
 78 
     | 
    
         
            +
                  when "release" then delivery.release # AMQP MODIFIED{ :failed => true }
         
     | 
| 
      
 79 
     | 
    
         
            +
                  when "modify" then delivery.release({:undeliverable => true, :annotations => {:x => 42 }})
         
     | 
| 
      
 80 
     | 
    
         
            +
                  when "modify-empty" then delivery.release({:failed => false, :undeliverable => false, :annotations => {}})
         
     | 
| 
      
 81 
     | 
    
         
            +
                  when "modify-nil" then delivery.release({:failed => false, :undeliverable => false, :annotations => nil})
         
     | 
| 
      
 82 
     | 
    
         
            +
                  when "reject-raise" then raise Reject
         
     | 
| 
      
 83 
     | 
    
         
            +
                  when "release-raise" then raise Release
         
     | 
| 
      
 84 
     | 
    
         
            +
                  else raise inspect
         
     | 
| 
      
 85 
     | 
    
         
            +
                  end
         
     | 
| 
      
 86 
     | 
    
         
            +
                end
         
     | 
| 
      
 87 
     | 
    
         
            +
              end
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
              def test_outcomes
         
     | 
| 
      
 90 
     | 
    
         
            +
                rh = ReceiveHandler.new
         
     | 
| 
      
 91 
     | 
    
         
            +
                sh = SendHandler.new(["accept", "reject", "release-really", "release", "modify", "modify-empty", "modify-nil", "reject-raise", "release-raise"])
         
     | 
| 
      
 92 
     | 
    
         
            +
                c = Container.new(nil, __method__)
         
     | 
| 
      
 93 
     | 
    
         
            +
                l = c.listen_io(TCPServer.new(0), ListenOnceHandler.new({ :handler => rh }))
         
     | 
| 
      
 94 
     | 
    
         
            +
                c.connect(l.url, {:handler => sh})
         
     | 
| 
      
 95 
     | 
    
         
            +
                c.run
         
     | 
| 
      
 96 
     | 
    
         
            +
                o = sh.outcomes
         
     | 
| 
      
 97 
     | 
    
         
            +
                assert_equal ["accept", :on_tracker_accept, "1", Transfer::ACCEPTED, nil], o.shift
         
     | 
| 
      
 98 
     | 
    
         
            +
                assert_equal ["reject", :on_tracker_reject, "2", Transfer::REJECTED, nil], o.shift
         
     | 
| 
      
 99 
     | 
    
         
            +
                assert_equal ["release-really", :on_tracker_release, "3", Transfer::RELEASED, nil], o.shift
         
     | 
| 
      
 100 
     | 
    
         
            +
                assert_equal ["release", :on_tracker_modify, "4", Transfer::MODIFIED, {:failed=>true, :undeliverable=>false, :annotations=>nil}], o.shift
         
     | 
| 
      
 101 
     | 
    
         
            +
                assert_equal ["modify", :on_tracker_modify, "5", Transfer::MODIFIED, {:failed=>true, :undeliverable=>true, :annotations=>{:x => 42}}], o.shift
         
     | 
| 
      
 102 
     | 
    
         
            +
                assert_equal ["modify-empty", :on_tracker_release, "6", Transfer::RELEASED, nil], o.shift
         
     | 
| 
      
 103 
     | 
    
         
            +
                assert_equal ["modify-nil", :on_tracker_release, "7", Transfer::RELEASED, nil], o.shift
         
     | 
| 
      
 104 
     | 
    
         
            +
                assert_equal ["reject-raise", :on_tracker_reject, "8", Transfer::REJECTED, nil], o.shift
         
     | 
| 
      
 105 
     | 
    
         
            +
                assert_equal ["release-raise", :on_tracker_modify, "9", Transfer::MODIFIED, {:failed=>true, :undeliverable=>false, :annotations=>nil}], o.shift
         
     | 
| 
      
 106 
     | 
    
         
            +
                assert_empty o
         
     | 
| 
      
 107 
     | 
    
         
            +
                assert_equal ["accept", "reject", "release-really", "release", "modify", "modify-empty", "modify-nil", "reject-raise", "release-raise"], rh.received
         
     | 
| 
      
 108 
     | 
    
         
            +
                assert_empty sh.unsettled
         
     | 
| 
      
 109 
     | 
    
         
            +
              end
         
     | 
| 
      
 110 
     | 
    
         
            +
            end
         
     |