xmpp4r 0.4 → 0.5

Sign up to get free protection for your applications and to get access to all the features.
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