xmpp4r 0.4 → 0.5

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.
Files changed (68) hide show
  1. data/CHANGELOG +8 -0
  2. data/README.rdoc +4 -1
  3. data/Rakefile +10 -20
  4. data/data/doc/xmpp4r/examples/advanced/versionpoll.rb +20 -1
  5. data/lib/xmpp4r/bytestreams/helper/ibb/target.rb +7 -0
  6. data/lib/xmpp4r/bytestreams/helper/socks5bytestreams/target.rb +7 -1
  7. data/lib/xmpp4r/callbacks.rb +9 -0
  8. data/lib/xmpp4r/caps/c.rb +14 -0
  9. data/lib/xmpp4r/caps/helper/helper.rb +1 -4
  10. data/lib/xmpp4r/client.rb +42 -15
  11. data/lib/xmpp4r/connection.rb +7 -3
  12. data/lib/xmpp4r/debuglog.rb +22 -1
  13. data/lib/xmpp4r/discovery.rb +1 -0
  14. data/lib/xmpp4r/discovery/helper/helper.rb +58 -0
  15. data/lib/xmpp4r/discovery/iq/discoinfo.rb +2 -2
  16. data/lib/xmpp4r/discovery/iq/discoitems.rb +2 -2
  17. data/lib/xmpp4r/errors.rb +5 -2
  18. data/lib/xmpp4r/httpbinding/client.rb +9 -19
  19. data/lib/xmpp4r/last.rb +2 -0
  20. data/lib/xmpp4r/last/helper/helper.rb +37 -0
  21. data/lib/xmpp4r/last/iq/last.rb +67 -0
  22. data/lib/xmpp4r/location.rb +2 -0
  23. data/lib/xmpp4r/location/helper/helper.rb +56 -0
  24. data/lib/xmpp4r/location/location.rb +179 -0
  25. data/lib/xmpp4r/message.rb +32 -0
  26. data/lib/xmpp4r/presence.rb +1 -1
  27. data/lib/xmpp4r/pubsub/children/configuration.rb +1 -1
  28. data/lib/xmpp4r/pubsub/children/items.rb +11 -2
  29. data/lib/xmpp4r/pubsub/children/publish.rb +14 -0
  30. data/lib/xmpp4r/pubsub/children/retract.rb +41 -0
  31. data/lib/xmpp4r/pubsub/helper/nodebrowser.rb +2 -3
  32. data/lib/xmpp4r/pubsub/helper/nodehelper.rb +4 -4
  33. data/lib/xmpp4r/pubsub/helper/oauth_service_helper.rb +90 -0
  34. data/lib/xmpp4r/pubsub/helper/servicehelper.rb +58 -19
  35. data/lib/xmpp4r/reliable.rb +168 -0
  36. data/lib/xmpp4r/rexmladdons.rb +6 -0
  37. data/lib/xmpp4r/roster/helper/roster.rb +5 -2
  38. data/lib/xmpp4r/sasl.rb +19 -8
  39. data/lib/xmpp4r/stream.rb +133 -31
  40. data/lib/xmpp4r/streamparser.rb +9 -1
  41. data/lib/xmpp4r/test/listener_mocker.rb +118 -0
  42. data/lib/xmpp4r/xmpp4r.rb +3 -1
  43. data/test/bytestreams/tc_ibb.rb +6 -4
  44. data/test/bytestreams/tc_socks5bytestreams.rb +3 -2
  45. data/test/caps/tc_helper.rb +4 -2
  46. data/test/dataforms/tc_data.rb +1 -1
  47. data/test/last/tc_helper.rb +75 -0
  48. data/test/lib/clienttester.rb +43 -14
  49. data/test/muc/tc_muc_mucclient.rb +6 -2
  50. data/test/pubsub/tc_helper.rb +131 -8
  51. data/test/pubsub/tc_nodeconfig.rb +7 -0
  52. data/test/reliable/tc_disconnect_cleanup.rb +334 -0
  53. data/test/reliable/tc_disconnect_exception.rb +37 -0
  54. data/test/reliable/tc_listener_mocked_test.rb +68 -0
  55. data/test/reliable/tc_reliable_connection.rb +31 -0
  56. data/test/roster/tc_helper.rb +21 -11
  57. data/test/rpc/tc_helper.rb +2 -2
  58. data/test/tc_callbacks.rb +3 -3
  59. data/test/tc_message.rb +15 -0
  60. data/test/tc_stream.rb +59 -121
  61. data/test/tc_streamError.rb +2 -4
  62. data/test/tc_streamparser.rb +26 -13
  63. data/test/ts_xmpp4r.rb +0 -9
  64. data/test/tune/tc_helper_recv.rb +0 -2
  65. data/test/vcard/tc_helper.rb +1 -1
  66. data/xmpp4r.gemspec +31 -84
  67. metadata +116 -167
  68. data/lib/xmpp4r/bytestreams/helper/socks5bytestreams/target.rb.orig +0 -62
@@ -107,7 +107,7 @@ class PubSub::ServiceHelperTest < Test::Unit::TestCase
107
107
  <subscription node='#{iq.pubsub.children.first.attributes['node']}' jid='#{iq.from.strip}'
108
108
  subid='ba49252aaa4f5d320c24d3766f0bdcade78c78d3'
109
109
  subscription='pending'/>
110
-
110
+
111
111
  </pubsub>
112
112
  </iq>")
113
113
  }
@@ -336,7 +336,7 @@ class PubSub::ServiceHelperTest < Test::Unit::TestCase
336
336
  assert_equal(1, iq.pubsub.children[0].children.size)
337
337
  assert_equal('item', iq.pubsub.children[0].children[0].name)
338
338
  assert_equal(1, iq.pubsub.children[0].children[0].children.size)
339
- assert_equal(item1.children.to_s, iq.pubsub.children[0].children[0].children[0].to_s)
339
+ assert_equal(item1.children[0].to_s, iq.pubsub.children[0].children[0].children[0].to_s)
340
340
  send("<iq type='result' to='#{iq.from}' from='#{iq.to}' id='#{iq.id}'/>")
341
341
  }
342
342
  assert_nothing_raised { h.publish_item_to(node, item1) }
@@ -362,7 +362,7 @@ class PubSub::ServiceHelperTest < Test::Unit::TestCase
362
362
  assert_equal('item', iq.pubsub.children[0].children[0].name)
363
363
  assert_equal('blubb', iq.pubsub.children[0].children[0].attributes['id'] )
364
364
  assert_equal(1, iq.pubsub.children[0].children[0].children.size)
365
- assert_equal(item1.children.to_s, iq.pubsub.children[0].children[0].children[0].to_s)
365
+ assert_equal(item1.children[0].to_s, iq.pubsub.children[0].children[0].children[0].to_s)
366
366
  send("<iq type='result' to='#{iq.from}' from='#{iq.to}' id='#{iq.id}'/>")
367
367
  }
368
368
  assert_nothing_raised { h.publish_item_with_id_to('mynode', item1,"blubb") }
@@ -379,7 +379,7 @@ class PubSub::ServiceHelperTest < Test::Unit::TestCase
379
379
 
380
380
  assert_raise RuntimeError do h.publish_item_with_id_to('mynode', item1,"blubb") end
381
381
  end
382
-
382
+
383
383
  ##
384
384
  # publish item and trap server-side error
385
385
  # examples 88 from
@@ -401,7 +401,7 @@ class PubSub::ServiceHelperTest < Test::Unit::TestCase
401
401
  assert_equal('item', iq.pubsub.children[0].children[0].name)
402
402
  assert_equal('blubb', iq.pubsub.children[0].children[0].attributes['id'] )
403
403
  assert_equal(1, iq.pubsub.children[0].children[0].children.size)
404
- assert_equal(item1.children.to_s, iq.pubsub.children[0].children[0].children[0].to_s)
404
+ assert_equal(item1.children[0].to_s, iq.pubsub.children[0].children[0].children[0].to_s)
405
405
  send("<iq type='error' to='#{iq.from}' from='#{iq.to}' id='#{iq.id}'/>
406
406
  <pubsub xmlns='http://jabber.org/protocol/pubsub'>
407
407
  <publish node='#{iq.pubsub.children[0].attributes['node']}'>
@@ -419,7 +419,7 @@ class PubSub::ServiceHelperTest < Test::Unit::TestCase
419
419
  ##
420
420
  # retrieve all items
421
421
  # examples 70 and 71 from
422
- # http://www.xmpp.org/extensions/xep-0060.html#subscriber-retrieve-returnall
422
+ # http://www.xmpp.org/extensions/xep-0060.html#subscriber-retrieve-returnall
423
423
  def test_items
424
424
  item1 = Jabber::PubSub::Item.new("1")
425
425
  item1.text = 'foobar'
@@ -427,7 +427,7 @@ class PubSub::ServiceHelperTest < Test::Unit::TestCase
427
427
  item2.text = 'barfoo'
428
428
 
429
429
  h = PubSub::ServiceHelper.new(@client,'pubsub.example.org')
430
-
430
+
431
431
  state { |iq|
432
432
  assert_kind_of(Jabber::Iq, iq)
433
433
  assert_equal(:get, iq.type)
@@ -453,6 +453,30 @@ class PubSub::ServiceHelperTest < Test::Unit::TestCase
453
453
  wait_state
454
454
  end
455
455
 
456
+ ##
457
+ # retrieve some items
458
+ # example 76 from
459
+ # http://xmpp.org/extensions/xep-0060.html#subscriber-retrieve-requestsome
460
+ def test_items_with_max_items
461
+ node_name = "mynode"
462
+ max_items = 2
463
+ h = PubSub::ServiceHelper.new(@client,'pubsub.example.org')
464
+
465
+ state { |iq|
466
+ assert_kind_of(Jabber::Iq, iq)
467
+ assert_equal(:get, iq.type)
468
+ assert_equal(1, iq.pubsub.children.size)
469
+ assert_equal('items', iq.pubsub.children.first.name)
470
+ assert_equal(node_name, iq.pubsub.children.first.attributes['node'])
471
+ assert_equal(max_items.to_s, iq.pubsub.children.first.attributes['max_items'])
472
+ # response doesn't matter; was previously tested, so send a simple result
473
+ send("<iq type='result' to='#{iq.from}' from='#{iq.to}' id='#{iq.id}' />")
474
+ }
475
+
476
+ h.get_items_from(node_name, max_items)
477
+ wait_state
478
+ end
479
+
456
480
  ##
457
481
  # get affiliation
458
482
  # example 184 and 185 from
@@ -487,6 +511,25 @@ class PubSub::ServiceHelperTest < Test::Unit::TestCase
487
511
  wait_state
488
512
  end
489
513
 
514
+ # http://xmpp.org/extensions/xep-0060.html#owner-affiliations-modify
515
+ def test_set_affiliations
516
+ h = PubSub::ServiceHelper.new(@client,'pubsub.shakespeare.lit')
517
+
518
+ state { |iq|
519
+ assert_kind_of(Jabber::Iq, iq)
520
+ assert_equal(:set, iq.type)
521
+ assert_equal(1, iq.pubsub.children.size)
522
+ assert_equal('affiliations', iq.pubsub.children[0].name)
523
+ assert_equal('affiliation', iq.pubsub.children[0].children[0].name)
524
+ assert_equal('bard@shakespeare.lit', iq.pubsub.children[0].children[0].attributes['jid'])
525
+ assert_equal('publisher', iq.pubsub.children[0].children[0].attributes['affiliation'])
526
+ send("<iq type='result' to='#{iq.from}' from='#{iq.to}' id='#{iq.id}'/>")
527
+ }
528
+
529
+ a = h.set_affiliations('princely_musings', 'bard@shakespeare.lit', :publisher)
530
+ wait_state
531
+ end
532
+
490
533
  ##
491
534
  # get_subscriptions_from
492
535
  # example 171 and 172 from
@@ -596,7 +639,7 @@ class PubSub::ServiceHelperTest < Test::Unit::TestCase
596
639
  end
597
640
 
598
641
  ##
599
- # get all subscriptions with no subscriptions
642
+ # get all subscriptions with no subscriptions
600
643
  def test_get_all_subscriptions_with_no_subscriptions
601
644
  h = PubSub::ServiceHelper.new(@client,'pubsub.example.org')
602
645
 
@@ -655,6 +698,86 @@ class PubSub::ServiceHelperTest < Test::Unit::TestCase
655
698
  wait_state
656
699
  end
657
700
 
701
+ ##
702
+ # owner set configuration for a node
703
+ # example 133
704
+ # http://xmpp.org/extensions/xep-0060.html#owner-configure
705
+ def test_set_node_config
706
+ node = 'princely_musings'
707
+ pubsub = 'pubsub.shakespeare.lit'
708
+ h = PubSub::ServiceHelper.new(@client,pubsub)
709
+
710
+ state { |iq|
711
+ assert_kind_of(Jabber::Iq,iq)
712
+ assert_equal(:set, iq.type)
713
+ assert_equal(pubsub, iq.to.to_s)
714
+
715
+ config = iq.pubsub.first_element('configure')
716
+ assert_kind_of(Jabber::PubSub::OwnerNodeConfig, config)
717
+ assert_kind_of(Jabber::Dataforms::XData, config.form)
718
+
719
+ assert_equal(config.options["pubsub#title"], "Princely Musings (Atom)")
720
+ assert_equal(config.options["pubsub#deliver_notifications"], "1")
721
+ assert_equal(config.options["pubsub#deliver_payloads"], "1")
722
+ assert_equal(config.options["pubsub#persist_items"], "1")
723
+ assert_equal(config.options["pubsub#max_items"], "10")
724
+ assert_equal(config.options["pubsub#access_model"], "open")
725
+ assert_equal(config.options["pubsub#publish_model"], "publishers")
726
+ assert_equal(config.options["pubsub#send_last_published_item"], "never")
727
+ assert_equal(config.options["pubsub#presence_based_delivery"], "false")
728
+ assert_equal(config.options["pubsub#notify_config"], "0")
729
+ assert_equal(config.options["pubsub#notify_delete"], "0")
730
+ assert_equal(config.options["pubsub#notify_retract"], "0")
731
+ assert_equal(config.options["pubsub#notify_sub"], "0")
732
+ assert_equal(config.options["pubsub#max_payload_size"], "1028")
733
+ assert_equal(config.options["pubsub#type"], "http://www.w3.org/2005/Atom")
734
+ assert_equal(config.options["pubsub#body_xslt"], "http://jabxslt.jabberstudio.org/atom_body.xslt")
735
+
736
+ send("<iq type='result' from='#{iq.to}' to='#{iq.from}' id='#{iq.id}'/>")
737
+ }
738
+
739
+ config = Jabber::PubSub::OwnerNodeConfig.new(node)
740
+ config.options = {
741
+ "pubsub#title" => "Princely Musings (Atom)",
742
+ "pubsub#deliver_notifications" => "1",
743
+ "pubsub#deliver_payloads" => "1",
744
+ "pubsub#persist_items" => "1",
745
+ "pubsub#max_items" => "10",
746
+ "pubsub#access_model" => "open",
747
+ "pubsub#publish_model" => "publishers",
748
+ "pubsub#send_last_published_item" => "never",
749
+ "pubsub#presence_based_delivery" => "false",
750
+ "pubsub#notify_config" => "0",
751
+ "pubsub#notify_delete" => "0",
752
+ "pubsub#notify_retract" => "0",
753
+ "pubsub#notify_sub" => "0",
754
+ "pubsub#max_payload_size" => "1028",
755
+ "pubsub#type" => "http://www.w3.org/2005/Atom",
756
+ "pubsub#body_xslt" => "http://jabxslt.jabberstudio.org/atom_body.xslt"
757
+ }
758
+
759
+ assert_kind_of(Jabber::PubSub::OwnerNodeConfig, config)
760
+ h.set_config_for(node, config)
761
+ wait_state
762
+ end
763
+
764
+ def test_delete_item
765
+ pubsub = 'pubsub.example.org'
766
+ h = PubSub::ServiceHelper.new(@client, pubsub)
767
+
768
+ state { |iq|
769
+ assert_kind_of(Jabber::Iq, iq)
770
+ assert_kind_of(Jabber::PubSub::IqPubSub, iq.pubsub)
771
+ assert_kind_of(Jabber::PubSub::Retract, iq.pubsub.first_element('retract'))
772
+ assert_equal(1, iq.pubsub.first_element('retract').items.size)
773
+ assert_equal('ae890ac52d0df67ed7cfdf51b644e901', iq.pubsub.first_element('retract').items[0].id)
774
+ send(iq.answer.set_type(:result))
775
+ }
776
+
777
+ h.delete_item_from('princely_musings', 'ae890ac52d0df67ed7cfdf51b644e901')
778
+ wait_state
779
+ end
780
+
658
781
  def test_to_s
659
782
  h = PubSub::ServiceHelper.new(@client,'pubsub.example.org')
660
783
  assert_equal('pubsub.example.org',h.to_s)
@@ -51,4 +51,11 @@ class PubSub::NodeConfigTest < Test::Unit::TestCase
51
51
  assert_kind_of(Jabber::Dataforms::XData, config.form)
52
52
  assert_equal(options, config.options)
53
53
  end
54
+
55
+ def test_create_with_array_in_options
56
+ options = {'pubsub#collection'=>['parent1','parent2']}
57
+ config = PubSub::OwnerNodeConfig.new(nil, options)
58
+
59
+ assert_equal(options, config.options)
60
+ end
54
61
  end
@@ -0,0 +1,334 @@
1
+ #!/usr/bin/ruby
2
+
3
+ $:.unshift "#{File.dirname(__FILE__)}/../../lib"
4
+
5
+ require 'test/unit'
6
+ require 'xmpp4r'
7
+
8
+ # Jabber::debug = true
9
+ # Jabber::warnings = true
10
+
11
+ class ClientDisconnectCleanupTest < Test::Unit::TestCase
12
+ class ControledClient < Jabber::Client
13
+ attr_accessor :tcpserver, :socket_override
14
+ def connect
15
+ begin
16
+ @port = 1024 + rand(32768 - 1024)
17
+ @tcpserver = TCPServer.new("127.0.0.1", @port)
18
+ rescue Errno::EADDRINUSE, Errno::EACCES
19
+ @tcpserver.close rescue nil
20
+ retry
21
+ end
22
+ super("127.0.0.1", @port)
23
+ end
24
+ def start
25
+ @socket = socket_override
26
+ super
27
+ end
28
+ end
29
+
30
+ def test_regular_stream_end
31
+ rd, wr = IO.pipe
32
+ rd.instance_eval do
33
+ def write(*args)
34
+ end
35
+ def flush
36
+ end
37
+ end
38
+ client = ControledClient.new("test@localhost")
39
+ @exceptions_caught = 0
40
+ client.on_exception do |e, connection, where_failed|
41
+ @exceptions_caught += 1
42
+ end
43
+
44
+ Thread.new do
45
+ client.socket_override = rd
46
+ client.instance_eval{ @keepalive_interval = 0.1 }
47
+ client.connect
48
+ client.auth_nonsasl("password", false)
49
+ end
50
+ sleep(0.1)
51
+ assert client.is_connected?
52
+
53
+ wr.write('<stream:stream xmlns:stream="http://etherx.jabber.org/streams">')
54
+ wr.write("</stream:stream>")
55
+ sleep(0.2)
56
+
57
+ assert !client.is_connected?
58
+ assert client.instance_eval{ @parser_thread.nil? || !@parser_thread.alive? }
59
+ assert client.instance_eval{ @keepaliveThread.nil? || !@keepaliveThread.alive? }
60
+ assert @exceptions_caught > 0
61
+ end
62
+
63
+ def test_error_on_send
64
+ rd, wr = IO.pipe
65
+ rd.instance_eval do
66
+ def write(*args)
67
+ end
68
+ def flush
69
+ end
70
+ end
71
+ client = ControledClient.new("test@localhost")
72
+ @exceptions_caught = 0
73
+ client.on_exception do |e, connection, where_failed|
74
+ @exceptions_caught += 1
75
+ end
76
+
77
+ Thread.new do
78
+ client.socket_override = rd
79
+ client.connect
80
+ client.auth_nonsasl("password", false)
81
+ end
82
+ sleep(0.1)
83
+ assert client.is_connected?
84
+
85
+ rd.instance_eval do
86
+ def write(*args)
87
+ raise "No writting for you, you disconnect now"
88
+ end
89
+ end
90
+ wr.write(%Q{<stream:stream from='localhost' id="acecf234be084aecdc16509077573c7d7200912f" version='1.0' xmlns:stream="http://etherx.jabber.org/streams" xmlns="jabber:client"><stream:features><auth xmlns='http://jabber.org/features/iq-auth'/></stream:features> })
91
+ sleep(0.1)
92
+
93
+ assert !client.is_connected?
94
+ assert client.instance_eval{ @parser_thread.nil? || !@parser_thread.alive? }
95
+ assert client.instance_eval{ @keepaliveThread.nil? || !@keepaliveThread.alive? }
96
+ assert @exceptions_caught > 0
97
+ end
98
+
99
+ def test_client_disconnect
100
+ rd, wr = IO.pipe
101
+ rd.instance_eval do
102
+ def write(*args)
103
+ end
104
+ def flush
105
+ end
106
+ end
107
+ client = ControledClient.new("test@localhost")
108
+ @exceptions_caught = 0
109
+ client.on_exception do |e, connection, where_failed|
110
+ @exceptions_caught += 1
111
+ end
112
+
113
+ Thread.new do
114
+ client.socket_override = rd
115
+ client.connect
116
+ client.auth_nonsasl("password", false)
117
+ end
118
+ wr.write(%Q{<stream:stream from='localhost' id="acecf234be084aecdc16509077573c7d7200912f" version='1.0' xmlns:stream="http://etherx.jabber.org/streams" xmlns="jabber:client"><stream:features><auth xmlns='http://jabber.org/features/iq-auth'/></stream:features> })
119
+ sleep(0.1)
120
+ assert client.is_connected?
121
+ assert client.instance_eval{ @parser_thread.alive? }
122
+ assert client.instance_eval{ @keepaliveThread.alive? }
123
+
124
+ wr.close
125
+ sleep(0.1)
126
+
127
+ assert !client.is_connected?
128
+ assert client.instance_eval{ @parser_thread.nil? || !@parser_thread.alive? }
129
+ assert client.instance_eval{ @keepaliveThread.nil? || !@keepaliveThread.alive? }
130
+ assert @exceptions_caught > 0
131
+ end
132
+
133
+ end
134
+
135
+ class ConnectionDisconnectCleanupTest < Test::Unit::TestCase
136
+ class PipeConnection < Jabber::Connection
137
+ attr_accessor :socket_override
138
+ def connect
139
+ begin
140
+ @port = 1024 + rand(32768 - 1024)
141
+ tcpsocket = TCPServer.new("127.0.0.1", @port)
142
+ rescue Errno::EADDRINUSE, Errno::EACCES
143
+ tcpsocket.close rescue nil
144
+ retry
145
+ end
146
+ super("127.0.0.1", @port)
147
+ end
148
+ def accept_features
149
+ #do nothing
150
+ end
151
+ def start
152
+ @socket = self.socket_override
153
+ super
154
+ end
155
+ end
156
+
157
+ def test_cleanup_when_disconnected_during_keepalive
158
+ rd, wr = IO.pipe
159
+ conn = PipeConnection.new
160
+ @exceptions_caught = 0
161
+ conn.on_exception do |e, connection, where_failed|
162
+ @exceptions_caught += 1
163
+ end
164
+
165
+ Thread.new do
166
+ conn.socket_override = rd
167
+ #this will raise exception in keepalive thread, when attempts to send blank space shortly after connect
168
+ conn.instance_eval{ @keepalive_interval = 0.1 }
169
+ conn.connect
170
+ end
171
+
172
+ sleep(0.2)
173
+
174
+ assert rd.closed?
175
+ assert !conn.is_connected?
176
+ assert !conn.instance_eval{ @parser_thread }.alive?
177
+ assert !conn.instance_eval{ @keepaliveThread }.alive?
178
+ assert @exceptions_caught > 0
179
+ end
180
+
181
+ def test_cleanup_after_stream_close
182
+ rd, wr = IO.pipe
183
+ conn = PipeConnection.new
184
+ @exceptions_caught = 0
185
+ conn.on_exception do |e, connection, where_failed|
186
+ @exceptions_caught += 1
187
+ end
188
+
189
+ Thread.new do
190
+ conn.socket_override = rd
191
+ conn.connect
192
+ end
193
+
194
+ wr.write("<hi/>")
195
+ wr.close
196
+ sleep(0.1)
197
+
198
+ assert rd.closed?
199
+ assert !conn.is_connected?
200
+ assert !conn.instance_eval{ @parser_thread }.alive?
201
+ assert !conn.instance_eval{ @keepaliveThread }.alive?
202
+ assert @exceptions_caught > 0
203
+ end
204
+
205
+ def test_cleanup_after_stream_end
206
+ rd, wr = IO.pipe
207
+ conn = PipeConnection.new
208
+ @exceptions_caught = 0
209
+ conn.on_exception do |e, connection, where_failed|
210
+ @exceptions_caught += 1
211
+ end
212
+
213
+ Thread.new do
214
+ conn.socket_override = rd
215
+ conn.connect
216
+ end
217
+
218
+ wr.write('<stream:stream xmlns:stream="http://etherx.jabber.org/streams">')
219
+ wr.write("</stream:stream>")
220
+ # wr.close
221
+ sleep(0.1)
222
+
223
+ assert rd.closed?
224
+ assert !conn.is_connected?
225
+ assert !conn.instance_eval{ @parser_thread }.alive?
226
+ assert !conn.instance_eval{ @keepaliveThread }.alive?
227
+ assert @exceptions_caught > 0
228
+ end
229
+
230
+ end
231
+
232
+ class StreamDisconnectCleanupTest < Test::Unit::TestCase
233
+
234
+ def test_cleanup_when_errors_on_send
235
+ rd, wr = IO.pipe
236
+
237
+ stream = Jabber::Stream.new
238
+ @exceptions_caught = 0
239
+ stream.on_exception do |e, connection, where_failed|
240
+ @exceptions_caught += 1
241
+ end
242
+
243
+ assert !stream.is_connected?
244
+
245
+ stream.start(rd)
246
+ wr.write("<hi/>")
247
+ assert stream.is_connected?
248
+ #should raise error trying to write to stream that can't be written to, and catch should close it.
249
+ begin
250
+ stream.send("<hi/>")
251
+ rescue
252
+ end
253
+ sleep(0.1)
254
+
255
+ assert rd.closed?
256
+ assert !stream.is_connected?
257
+ assert !stream.instance_eval{ @parser_thread }.alive?
258
+ assert @exceptions_caught > 0
259
+ end
260
+
261
+ def test_cleanup_after_stream_close
262
+ rd, wr = IO.pipe
263
+
264
+ stream = Jabber::Stream.new
265
+ @exceptions_caught = 0
266
+ stream.on_exception do |e, connection, where_failed|
267
+ @exceptions_caught += 1
268
+ end
269
+
270
+ assert !stream.is_connected?
271
+
272
+ stream.start(rd)
273
+ wr.write("<hi/>")
274
+ assert stream.is_connected?
275
+
276
+ wr.close
277
+ sleep(0.1)
278
+
279
+ assert rd.closed?
280
+ assert !stream.is_connected?
281
+ assert !stream.instance_eval{ @parser_thread }.alive?
282
+ assert @exceptions_caught > 0
283
+ end
284
+
285
+ def test_cleanup_after_stream_end
286
+ rd, wr = IO.pipe
287
+
288
+ stream = Jabber::Stream.new
289
+ @exceptions_caught = 0
290
+ stream.on_exception do |e, connection, where_failed|
291
+ @exceptions_caught += 1
292
+ end
293
+
294
+ assert !stream.is_connected?
295
+
296
+ stream.start(rd)
297
+ wr.write('<stream:stream xmlns:stream="http://etherx.jabber.org/streams">')
298
+ wr.write("</stream:stream>")
299
+ assert stream.is_connected?
300
+
301
+ # wr.close
302
+ sleep(0.1)
303
+
304
+ assert rd.closed?
305
+ assert !stream.is_connected?
306
+ assert !stream.instance_eval{ @parser_thread }.alive?
307
+ assert @exceptions_caught > 0
308
+ end
309
+
310
+ def test_cleanup_after_parse_failure
311
+ rd, wr = IO.pipe
312
+
313
+ stream = Jabber::Stream.new
314
+ @exceptions_caught = 0
315
+ stream.on_exception do |e, connection, where_failed|
316
+ @exceptions_caught += 1
317
+ end
318
+
319
+ assert !stream.is_connected?
320
+
321
+ stream.start(rd)
322
+ wr.write('<this is bad xml>>')
323
+ wr.close
324
+ assert stream.is_connected?
325
+
326
+ sleep(0.1)
327
+
328
+ assert rd.closed?
329
+ assert !stream.is_connected?
330
+ assert !stream.instance_eval{ @parser_thread }.alive?
331
+ assert @exceptions_caught > 0
332
+ end
333
+
334
+ end