PROTON-1537: [ruby] Fixes to Delivery and Codec
Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/72074d42 Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/72074d42 Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/72074d42 Branch: refs/heads/go1 Commit: 72074d42a444eceaac2362a55badb29314e1c615 Parents: c172383 Author: Alan Conway <[email protected]> Authored: Sat Dec 9 14:14:44 2017 -0500 Committer: Alan Conway <[email protected]> Committed: Wed Dec 13 13:16:48 2017 -0500 ---------------------------------------------------------------------- proton-c/bindings/ruby/lib/codec/data.rb | 2 +- proton-c/bindings/ruby/lib/core/delivery.rb | 31 +++--- proton-c/bindings/ruby/lib/core/tracker.rb | 14 +-- proton-c/bindings/ruby/lib/core/transfer.rb | 3 + proton-c/bindings/ruby/lib/handler/adapter.rb | 6 +- proton-c/bindings/ruby/lib/types/array.rb | 2 +- proton-c/bindings/ruby/lib/types/hash.rb | 2 +- proton-c/bindings/ruby/lib/util/wrapper.rb | 3 +- proton-c/bindings/ruby/tests/test_delivery.rb | 106 +++++++++++++++++++++ proton-c/bindings/ruby/tests/test_interop.rb | 3 +- proton-c/bindings/ruby/tests/test_tools.rb | 13 +++ 11 files changed, 157 insertions(+), 28 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/72074d42/proton-c/bindings/ruby/lib/codec/data.rb ---------------------------------------------------------------------- diff --git a/proton-c/bindings/ruby/lib/codec/data.rb b/proton-c/bindings/ruby/lib/codec/data.rb index 86af3a1..1573b5c 100644 --- a/proton-c/bindings/ruby/lib/codec/data.rb +++ b/proton-c/bindings/ruby/lib/codec/data.rb @@ -120,7 +120,7 @@ module Qpid::Proton def expect(code) unless code == self.code - raise TypeError, "expected #{Cproton.pn_type_name(code)}, got #{Cproton.pn_type_name(code)}" + raise TypeError, "expected #{Cproton.pn_type_name(code)}, got #{Cproton.pn_type_name(self.code)}" end end http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/72074d42/proton-c/bindings/ruby/lib/core/delivery.rb ---------------------------------------------------------------------- diff --git a/proton-c/bindings/ruby/lib/core/delivery.rb b/proton-c/bindings/ruby/lib/core/delivery.rb index b240784..ba89097 100644 --- a/proton-c/bindings/ruby/lib/core/delivery.rb +++ b/proton-c/bindings/ruby/lib/core/delivery.rb @@ -31,29 +31,34 @@ module Qpid::Proton # Release a message, indicating to the sender that it was not processed # but may be delivered again to this or another receiver. # - # @param mods [Hash] Instructions to the sender to modify re-delivery. + # @param opts [Hash] Instructions to the sender to modify re-delivery. # To allow re-delivery with no modifications at all use +release(nil)+ # - # @option mods [Boolean] :failed Instruct the sender to increase + # @option opts [Boolean] :failed (true) Instruct the sender to increase # {Message#delivery_count} so future receivers will know there was a # previous failed delivery. # - # @option mods [Boolean] :undeliverable Instruct the sender that this + # @option opts [Boolean] :undeliverable (false) Instruct the sender that this # message should never be re-delivered to this receiver, although it may be # delivered other receivers. # - # @option mods [Hash] :annotations Instruct the sender to update the - # {Message#annotations} with these +key=>value+ pairs before re-delivery. - def release(mods = {:failed=>true}) - mods = { :failed => true } if mods == true # Backwards compatibility - if !mods || mods.empty? - settle(RELEASED) - else + # @option opts [Hash] :annotations Instruct the sender to update the + # {Message#annotations} with these +key=>value+ pairs before re-delivery, + # replacing existing entries in {Message#annotations} with the same key. + def release(opts = nil) + opts = { :failed => false } if (opts == false) # deprecated + failed = !opts || opts.fetch(:failed, true) + undeliverable = opts && opts[:undeliverable] + annotations = opts && opts[:annotations] + annotations = nil if annotations && annotations.empty? + if failed || undeliverable || annotations d = Cproton.pn_delivery_local(@impl) - Cproton.pn_disposition_set_failed(mods[:failed]) - Cproton.pn_disposition_set_undeliverable(mods[:undeliverable]) - Data.from_object(Cproton.pn_disposition_annotations(d), mods[:annotations]) if mods.key? :annotations + Cproton.pn_disposition_set_failed(d, true) if failed + Cproton.pn_disposition_set_undeliverable(d, true) if undeliverable + Codec::Data.from_object(Cproton.pn_disposition_annotations(d), annotations) if annotations settle(MODIFIED) + else + settle(RELEASED) end end http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/72074d42/proton-c/bindings/ruby/lib/core/tracker.rb ---------------------------------------------------------------------- diff --git a/proton-c/bindings/ruby/lib/core/tracker.rb b/proton-c/bindings/ruby/lib/core/tracker.rb index 79620de..cf04be9 100644 --- a/proton-c/bindings/ruby/lib/core/tracker.rb +++ b/proton-c/bindings/ruby/lib/core/tracker.rb @@ -23,14 +23,16 @@ module Qpid::Proton # @return [Sender] The parent {Sender} link. def sender() link; end - # Re-delivery modifications provided by the receiver in {Delivery#release} - # @return [Hash] See the {Delivery#release} +mods+ parameter. + # Re-delivery modifications sent by the receiver in {Delivery#release} + # @return [Hash] See the {Delivery#release} +opts+ parameter. + # @return [nil] If no modifications were requested by the receiver. def modifications() - return {} unless (state == MODIFIED) && (d = Cproton.pn_delivery_remote(@impl)) + return nil if (state != MODIFIED) + d = Cproton.pn_delivery_remote(@impl) { - :failed => Cproton.pn_disposition_get_failed(d), - :undeliverable => Cproton.pn_disposition_get_undeliverable(d), - :annotations => Data.to_object(Cproton.pn_disposition_annotations(d)) + :failed => Cproton.pn_disposition_is_failed(d), + :undeliverable => Cproton.pn_disposition_is_undeliverable(d), + :annotations => Codec::Data.to_object(Cproton.pn_disposition_annotations(d)) } end end http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/72074d42/proton-c/bindings/ruby/lib/core/transfer.rb ---------------------------------------------------------------------- diff --git a/proton-c/bindings/ruby/lib/core/transfer.rb b/proton-c/bindings/ruby/lib/core/transfer.rb index 57e8b55..cdf3419 100644 --- a/proton-c/bindings/ruby/lib/core/transfer.rb +++ b/proton-c/bindings/ruby/lib/core/transfer.rb @@ -112,7 +112,10 @@ module Qpid::Proton def settle(state = nil) update(state) unless state.nil? Cproton.pn_delivery_settle(@impl) + @inspect = inspect # Save the inspect string, the delivery pointer will go bad. end + def inspect() @inspect || super; end + def to_s() inspect; end end end http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/72074d42/proton-c/bindings/ruby/lib/handler/adapter.rb ---------------------------------------------------------------------- diff --git a/proton-c/bindings/ruby/lib/handler/adapter.rb b/proton-c/bindings/ruby/lib/handler/adapter.rb index 8fe9bc5..25dd8c0 100644 --- a/proton-c/bindings/ruby/lib/handler/adapter.rb +++ b/proton-c/bindings/ruby/lib/handler/adapter.rb @@ -122,9 +122,8 @@ module Qpid::Proton::Handler d.release(true) end end - elsif d.updated? && d.settled? - delegate(:on_settled, event) end + delegate(:on_settled, event) if d.settled? add_credit(event) else # Outgoing message t = event.tracker @@ -132,7 +131,8 @@ module Qpid::Proton::Handler case t.remote_state when Qpid::Proton::Delivery::ACCEPTED then delegate(:on_accepted, event) when Qpid::Proton::Delivery::REJECTED then delegate(:on_rejected, event) - when Qpid::Proton::Delivery::RELEASED, Qpid::Proton::Delivery::MODIFIED then delegate(:on_released, event) + when Qpid::Proton::Delivery::RELEASED then delegate(:on_released, event) + when Qpid::Proton::Delivery::MODIFIED then delegate(:on_modified, event) end delegate(:on_settled, event) if t.settled? t.settle if @opts[:auto_settle] http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/72074d42/proton-c/bindings/ruby/lib/types/array.rb ---------------------------------------------------------------------- diff --git a/proton-c/bindings/ruby/lib/types/array.rb b/proton-c/bindings/ruby/lib/types/array.rb index 3051f31..d00a86b 100644 --- a/proton-c/bindings/ruby/lib/types/array.rb +++ b/proton-c/bindings/ruby/lib/types/array.rb @@ -18,7 +18,7 @@ #-- # Patch the Array class to provide methods for adding its contents -# to a Qpid::Proton::Data instance. +# to a Qpid::Proton::Codec::Data instance. #++ module Qpid::Proton http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/72074d42/proton-c/bindings/ruby/lib/types/hash.rb ---------------------------------------------------------------------- diff --git a/proton-c/bindings/ruby/lib/types/hash.rb b/proton-c/bindings/ruby/lib/types/hash.rb index 736bb8f..f70cbdb 100644 --- a/proton-c/bindings/ruby/lib/types/hash.rb +++ b/proton-c/bindings/ruby/lib/types/hash.rb @@ -18,7 +18,7 @@ #-- # Patch the Hash class to provide methods for adding its contents -# to a Qpid::Proton::Data instance. +# to a Qpid::Proton::Codec::Data instance. #++ # @private http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/72074d42/proton-c/bindings/ruby/lib/util/wrapper.rb ---------------------------------------------------------------------- diff --git a/proton-c/bindings/ruby/lib/util/wrapper.rb b/proton-c/bindings/ruby/lib/util/wrapper.rb index 347a9a5..08d1794 100644 --- a/proton-c/bindings/ruby/lib/util/wrapper.rb +++ b/proton-c/bindings/ruby/lib/util/wrapper.rb @@ -124,6 +124,7 @@ module Qpid::Proton attr_accessor :impl def inspect + return "#{self.class}<nil>" unless @impl pstr = Cproton.pn_string("") begin Cproton.pn_inspect(@impl, pstr) @@ -133,7 +134,7 @@ module Qpid::Proton end end - alias to_s inspect + def to_s() inspect; end def self.registry @registry ||= {} http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/72074d42/proton-c/bindings/ruby/tests/test_delivery.rb ---------------------------------------------------------------------- diff --git a/proton-c/bindings/ruby/tests/test_delivery.rb b/proton-c/bindings/ruby/tests/test_delivery.rb new file mode 100644 index 0000000..334450a --- /dev/null +++ b/proton-c/bindings/ruby/tests/test_delivery.rb @@ -0,0 +1,106 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + + +require 'minitest/autorun' +require 'qpid_proton' +require 'test_tools' +include Qpid::Proton + +# Test Delivery and Tracker +class TestDelivery < Minitest::Test + + # Duck-typed handler + class NoAutoHandler + @@options = {:auto_settle=>false, :auto_accept=>false} + def options() @@options; end + end + + class SendHandler < NoAutoHandler + def initialize(to_send) + @unsent = to_send + end + + def on_connection_opened(event) + @outcomes = [] + @sender = event.connection.open_sender("x") + @unsettled = {} # Awaiting remote settlement + end + + attr_reader :outcomes, :unsent, :unsettled + + def on_sendable(event) + return if @unsent.empty? + m = Message.new(@unsent.shift) + tracker = event.sender.send(m) + @unsettled[tracker] = m + end + + def outcome(event) + t = event.tracker + m = @unsettled.delete(t) + @outcomes << [m.body, event.method, t.id, t.state, t.modifications] + event.connection.close if @unsettled.empty? + end + + def on_accepted(event) outcome(event); end + def on_rejected(event) outcome(event); end + def on_released(event) outcome(event); end + def on_modified(event) outcome(event); end + end + + class ReceiveHandler < NoAutoHandler + def initialize + @received = [] + end + + attr_reader :received + + def on_message(event) + @received << event.message.body + case event.message.body + when "accept" then event.delivery.accept + when "reject" then event.delivery.reject + when "release-really" then event.delivery.release({:failed=>false}) # AMQP RELEASED + when "release" then event.delivery.release # AMQP MODIFIED{ :failed => true } + when "modify" then event.delivery.release({:undeliverable => true, :annotations => {:x => 42 }}) + when "modify-empty" then event.delivery.release({:failed => false, :undeliverable => false, :annotations => {}}) + when "modify-nil" then event.delivery.release({:failed => false, :undeliverable => false, :annotations => nil}) + else raise event.inspect + end + end + end + + def test_outcomes + rh = ReceiveHandler.new + sh = SendHandler.new(["accept", "reject", "release-really", "release", "modify", "modify-empty", "modify-nil"]) + c = TestContainer.new(nil, { :handler => rh }, __method__) + c.connect(c.url, {:handler => sh}) + c.run + o = sh.outcomes + assert_equal ["accept", :on_accepted, "1", Transfer::ACCEPTED, nil], o.shift + assert_equal ["reject", :on_rejected, "2", Transfer::REJECTED, nil], o.shift + assert_equal ["release-really", :on_released, "3", Transfer::RELEASED, nil], o.shift + assert_equal ["release", :on_modified, "4", Transfer::MODIFIED, {:failed=>true, :undeliverable=>false, :annotations=>nil}], o.shift + assert_equal ["modify", :on_modified, "5", Transfer::MODIFIED, {:failed=>true, :undeliverable=>true, :annotations=>{:x => 42}}], o.shift + assert_equal ["modify-empty", :on_released, "6", Transfer::RELEASED, nil], o.shift + assert_equal ["modify-nil", :on_released, "7", Transfer::RELEASED, nil], o.shift + assert_empty o + assert_equal ["accept", "reject", "release-really", "release", "modify", "modify-empty", "modify-nil"], rh.received + assert_empty sh.unsettled + end +end http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/72074d42/proton-c/bindings/ruby/tests/test_interop.rb ---------------------------------------------------------------------- diff --git a/proton-c/bindings/ruby/tests/test_interop.rb b/proton-c/bindings/ruby/tests/test_interop.rb index 0a13a3d..326b481 100755 --- a/proton-c/bindings/ruby/tests/test_interop.rb +++ b/proton-c/bindings/ruby/tests/test_interop.rb @@ -15,10 +15,9 @@ end class InteropTest < MiniTest::Test include Qpid::Proton - Data = Codec::Data def setup - @data = Data.new + @data = Codec::Data.new @message = Message.new end http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/72074d42/proton-c/bindings/ruby/tests/test_tools.rb ---------------------------------------------------------------------- diff --git a/proton-c/bindings/ruby/tests/test_tools.rb b/proton-c/bindings/ruby/tests/test_tools.rb index 2dc13b3..bc9c1d9 100644 --- a/proton-c/bindings/ruby/tests/test_tools.rb +++ b/proton-c/bindings/ruby/tests/test_tools.rb @@ -116,3 +116,16 @@ class DriverPair < Array end end + +# Container that listens on a random port for a single connection +class TestContainer < Container + + def initialize(handler, lopts=nil, id=nil) + super handler, id + @server = TCPServer.open(0) + @listener = listen_io(@server, ListenOnceHandler.new(lopts)) + end + + def port() @server.addr[1]; end + def url() "amqp://:#{port}"; end +end --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
