qpid_proton 0.19.0 → 0.21.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/examples/README.md +76 -0
  3. data/examples/broker.rb +167 -0
  4. data/examples/client.rb +79 -0
  5. data/examples/direct_recv.rb +61 -0
  6. data/examples/direct_send.rb +67 -0
  7. data/examples/example_test.rb +109 -0
  8. data/examples/helloworld.rb +57 -0
  9. data/examples/server.rb +70 -0
  10. data/examples/simple_recv.rb +57 -0
  11. data/examples/simple_send.rb +63 -0
  12. data/examples/ssl_certs/README.txt +24 -0
  13. data/examples/ssl_certs/tclient-certificate.p12 +0 -0
  14. data/examples/ssl_certs/tclient-certificate.pem +19 -0
  15. data/examples/ssl_certs/tclient-full.p12 +0 -0
  16. data/examples/ssl_certs/tclient-private-key.pem +30 -0
  17. data/examples/ssl_certs/tserver-certificate.p12 +0 -0
  18. data/examples/ssl_certs/tserver-certificate.pem +19 -0
  19. data/examples/ssl_certs/tserver-full.p12 +0 -0
  20. data/examples/ssl_certs/tserver-private-key.pem +30 -0
  21. data/examples/ssl_send.rb +70 -0
  22. data/ext/cproton/cproton.c +105 -74
  23. data/lib/core/container.rb +2 -1
  24. data/lib/core/ssl_domain.rb +1 -1
  25. data/lib/core/uri.rb +15 -9
  26. data/lib/handler/messaging_adapter.rb +20 -5
  27. data/tests/old_examples/broker.rb +200 -0
  28. data/tests/old_examples/client.rb +81 -0
  29. data/tests/old_examples/direct_recv.rb +64 -0
  30. data/tests/old_examples/direct_send.rb +63 -0
  31. data/tests/old_examples/helloworld.rb +72 -0
  32. data/tests/old_examples/helloworld_direct.rb +73 -0
  33. data/tests/old_examples/lib/debugging.rb +25 -0
  34. data/tests/old_examples/lib/driver.rb +68 -0
  35. data/tests/old_examples/lib/qpid_examples.rb +26 -0
  36. data/tests/old_examples/lib/selectable.rb +119 -0
  37. data/tests/old_examples/lib/send_and_receive.rb +89 -0
  38. data/tests/old_examples/old_example_test.rb +107 -0
  39. data/tests/old_examples/recv.rb +23 -0
  40. data/tests/old_examples/send.rb +21 -0
  41. data/tests/old_examples/server.rb +75 -0
  42. data/tests/old_examples/simple_recv.rb +57 -0
  43. data/tests/old_examples/simple_send.rb +54 -0
  44. data/tests/test_connection_driver.rb +134 -0
  45. data/tests/test_container.rb +319 -0
  46. data/tests/test_data.rb +66 -0
  47. data/tests/test_delivery.rb +110 -0
  48. data/tests/test_interop.rb +131 -0
  49. data/tests/test_messaging_adapter.rb +223 -0
  50. data/tests/test_old_adapter.rb +228 -0
  51. data/tests/test_tools.rb +147 -0
  52. data/tests/test_uri.rb +83 -0
  53. 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
+
@@ -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