blather 0.3.4 → 0.4.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.
Files changed (110) hide show
  1. data/LICENSE +1 -1
  2. data/README.rdoc +41 -12
  3. data/examples/echo.rb +1 -1
  4. data/examples/execute.rb +0 -5
  5. data/examples/pubsub/cli.rb +64 -0
  6. data/examples/pubsub/ping_pong.rb +18 -0
  7. data/examples/rosterprint.rb +14 -0
  8. data/examples/xmpp4r/echo.rb +35 -0
  9. data/lib/blather.rb +35 -12
  10. data/lib/blather/client.rb +1 -1
  11. data/lib/blather/client/client.rb +19 -13
  12. data/lib/blather/client/dsl.rb +16 -0
  13. data/lib/blather/client/dsl/pubsub.rb +133 -0
  14. data/lib/blather/core_ext/active_support.rb +1 -117
  15. data/lib/blather/core_ext/active_support/inheritable_attributes.rb +117 -0
  16. data/lib/blather/core_ext/nokogiri.rb +35 -0
  17. data/lib/blather/errors.rb +3 -20
  18. data/lib/blather/errors/sasl_error.rb +3 -1
  19. data/lib/blather/errors/stanza_error.rb +10 -17
  20. data/lib/blather/errors/stream_error.rb +11 -14
  21. data/lib/blather/jid.rb +1 -0
  22. data/lib/blather/roster.rb +9 -0
  23. data/lib/blather/roster_item.rb +6 -1
  24. data/lib/blather/stanza.rb +35 -18
  25. data/lib/blather/stanza/disco.rb +7 -1
  26. data/lib/blather/stanza/disco/disco_info.rb +45 -33
  27. data/lib/blather/stanza/disco/disco_items.rb +32 -21
  28. data/lib/blather/stanza/iq.rb +13 -8
  29. data/lib/blather/stanza/iq/query.rb +16 -8
  30. data/lib/blather/stanza/iq/roster.rb +33 -22
  31. data/lib/blather/stanza/message.rb +20 -31
  32. data/lib/blather/stanza/presence.rb +3 -5
  33. data/lib/blather/stanza/presence/status.rb +13 -21
  34. data/lib/blather/stanza/presence/subscription.rb +11 -16
  35. data/lib/blather/stanza/pubsub.rb +63 -0
  36. data/lib/blather/stanza/pubsub/affiliations.rb +50 -0
  37. data/lib/blather/stanza/pubsub/create.rb +43 -0
  38. data/lib/blather/stanza/pubsub/errors.rb +9 -0
  39. data/lib/blather/stanza/pubsub/event.rb +77 -0
  40. data/lib/blather/stanza/pubsub/items.rb +63 -0
  41. data/lib/blather/stanza/pubsub/publish.rb +58 -0
  42. data/lib/blather/stanza/pubsub/retract.rb +53 -0
  43. data/lib/blather/stanza/pubsub/subscribe.rb +42 -0
  44. data/lib/blather/stanza/pubsub/subscription.rb +66 -0
  45. data/lib/blather/stanza/pubsub/subscriptions.rb +55 -0
  46. data/lib/blather/stanza/pubsub/unsubscribe.rb +42 -0
  47. data/lib/blather/stanza/pubsub_owner.rb +41 -0
  48. data/lib/blather/stanza/pubsub_owner/delete.rb +34 -0
  49. data/lib/blather/stanza/pubsub_owner/purge.rb +34 -0
  50. data/lib/blather/stream.rb +76 -168
  51. data/lib/blather/stream/client.rb +1 -2
  52. data/lib/blather/stream/component.rb +9 -5
  53. data/lib/blather/stream/features.rb +53 -0
  54. data/lib/blather/stream/features/resource.rb +63 -0
  55. data/lib/blather/stream/{sasl.rb → features/sasl.rb} +53 -52
  56. data/lib/blather/stream/features/session.rb +44 -0
  57. data/lib/blather/stream/features/tls.rb +28 -0
  58. data/lib/blather/stream/parser.rb +70 -46
  59. data/lib/blather/xmpp_node.rb +113 -52
  60. data/spec/blather/client/client_spec.rb +44 -58
  61. data/spec/blather/client/dsl/pubsub_spec.rb +465 -0
  62. data/spec/blather/client/dsl_spec.rb +19 -6
  63. data/spec/blather/core_ext/nokogiri_spec.rb +83 -0
  64. data/spec/blather/errors/sasl_error_spec.rb +8 -8
  65. data/spec/blather/errors/stanza_error_spec.rb +25 -33
  66. data/spec/blather/errors/stream_error_spec.rb +21 -16
  67. data/spec/blather/errors_spec.rb +4 -11
  68. data/spec/blather/jid_spec.rb +31 -30
  69. data/spec/blather/roster_item_spec.rb +34 -23
  70. data/spec/blather/roster_spec.rb +27 -12
  71. data/spec/blather/stanza/discos/disco_info_spec.rb +61 -42
  72. data/spec/blather/stanza/discos/disco_items_spec.rb +47 -35
  73. data/spec/blather/stanza/iq/query_spec.rb +34 -11
  74. data/spec/blather/stanza/iq/roster_spec.rb +47 -30
  75. data/spec/blather/stanza/iq_spec.rb +19 -14
  76. data/spec/blather/stanza/message_spec.rb +30 -17
  77. data/spec/blather/stanza/presence/status_spec.rb +43 -20
  78. data/spec/blather/stanza/presence/subscription_spec.rb +41 -21
  79. data/spec/blather/stanza/presence_spec.rb +34 -21
  80. data/spec/blather/stanza/pubsub/affiliations_spec.rb +57 -0
  81. data/spec/blather/stanza/pubsub/create_spec.rb +56 -0
  82. data/spec/blather/stanza/pubsub/event_spec.rb +84 -0
  83. data/spec/blather/stanza/pubsub/items_spec.rb +79 -0
  84. data/spec/blather/stanza/pubsub/publish_spec.rb +83 -0
  85. data/spec/blather/stanza/pubsub/retract_spec.rb +75 -0
  86. data/spec/blather/stanza/pubsub/subscribe_spec.rb +61 -0
  87. data/spec/blather/stanza/pubsub/subscription_spec.rb +97 -0
  88. data/spec/blather/stanza/pubsub/subscriptions_spec.rb +59 -0
  89. data/spec/blather/stanza/pubsub/unsubscribe_spec.rb +61 -0
  90. data/spec/blather/stanza/pubsub_owner/delete_spec.rb +50 -0
  91. data/spec/blather/stanza/pubsub_owner/purge_spec.rb +50 -0
  92. data/spec/blather/stanza/pubsub_owner_spec.rb +27 -0
  93. data/spec/blather/stanza/pubsub_spec.rb +62 -0
  94. data/spec/blather/stanza_spec.rb +53 -38
  95. data/spec/blather/stream/client_spec.rb +231 -88
  96. data/spec/blather/stream/component_spec.rb +14 -5
  97. data/spec/blather/stream/parser_spec.rb +145 -0
  98. data/spec/blather/xmpp_node_spec.rb +192 -96
  99. data/spec/fixtures/pubsub.rb +311 -0
  100. data/spec/spec_helper.rb +5 -4
  101. metadata +54 -18
  102. data/Rakefile +0 -139
  103. data/ext/extconf.rb +0 -65
  104. data/ext/push_parser.c +0 -209
  105. data/lib/blather/core_ext/libxml.rb +0 -28
  106. data/lib/blather/stream/resource.rb +0 -48
  107. data/lib/blather/stream/session.rb +0 -36
  108. data/lib/blather/stream/stream_handler.rb +0 -39
  109. data/lib/blather/stream/tls.rb +0 -33
  110. data/spec/blather/core_ext/libxml_spec.rb +0 -58
@@ -0,0 +1,50 @@
1
+ require File.join(File.dirname(__FILE__), *%w[.. .. .. spec_helper])
2
+ require File.join(File.dirname(__FILE__), *%w[.. .. .. fixtures pubsub])
3
+
4
+ describe Blather::Stanza::PubSubOwner::Purge do
5
+ it 'registers itself' do
6
+ Blather::XMPPNode.class_from_registration(:purge, 'http://jabber.org/protocol/pubsub#owner').must_equal Blather::Stanza::PubSubOwner::Purge
7
+ end
8
+
9
+ it 'can be imported' do
10
+ Blather::XMPPNode.import(parse_stanza(<<-NODE).root).must_be_instance_of Blather::Stanza::PubSubOwner::Purge
11
+ <iq type='set'
12
+ from='hamlet@denmark.lit/elsinore'
13
+ to='pubsub.shakespeare.lit'
14
+ id='purge1'>
15
+ <pubsub xmlns='http://jabber.org/protocol/pubsub#owner'>
16
+ <purge node='princely_musings'/>
17
+ </pubsub>
18
+ </iq>
19
+ NODE
20
+ end
21
+
22
+ it 'ensures an purge node is present on create' do
23
+ purge = Blather::Stanza::PubSubOwner::Purge.new
24
+ purge.find('//ns:pubsub/ns:purge', :ns => Blather::Stanza::PubSubOwner.registered_ns).wont_be_empty
25
+ end
26
+
27
+ it 'ensures an purge node exists when calling #purge_node' do
28
+ purge = Blather::Stanza::PubSubOwner::Purge.new
29
+ purge.pubsub.remove_children :purge
30
+ purge.find('//ns:pubsub/ns:purge', :ns => Blather::Stanza::PubSubOwner.registered_ns).must_be_empty
31
+
32
+ purge.purge_node.wont_be_nil
33
+ purge.find('//ns:pubsub/ns:purge', :ns => Blather::Stanza::PubSubOwner.registered_ns).wont_be_empty
34
+ end
35
+
36
+ it 'defaults to a set node' do
37
+ purge = Blather::Stanza::PubSubOwner::Purge.new
38
+ purge.type.must_equal :set
39
+ end
40
+
41
+ it 'sets the host if requested' do
42
+ purge = Blather::Stanza::PubSubOwner::Purge.new :set, 'pubsub.jabber.local'
43
+ purge.to.must_equal Blather::JID.new('pubsub.jabber.local')
44
+ end
45
+
46
+ it 'sets the node' do
47
+ purge = Blather::Stanza::PubSubOwner::Purge.new :set, 'host', 'node-name'
48
+ purge.node.must_equal 'node-name'
49
+ end
50
+ end
@@ -0,0 +1,27 @@
1
+ require File.join(File.dirname(__FILE__), *%w[.. .. spec_helper])
2
+ require File.join(File.dirname(__FILE__), *%w[.. .. fixtures pubsub])
3
+
4
+ describe Blather::Stanza::PubSubOwner do
5
+ it 'registers itself' do
6
+ Blather::XMPPNode.class_from_registration(:pubsub, 'http://jabber.org/protocol/pubsub#owner').must_equal Blather::Stanza::PubSubOwner
7
+ end
8
+
9
+ it 'ensures a pubusb node is present on create' do
10
+ pubsub = Blather::Stanza::PubSubOwner.new
11
+ pubsub.find_first('/iq/ns:pubsub', :ns => Blather::Stanza::PubSubOwner.registered_ns).wont_be_nil
12
+ end
13
+
14
+ it 'ensures a pubsub node exists when calling #pubsub' do
15
+ pubsub = Blather::Stanza::PubSubOwner.new
16
+ pubsub.remove_children :pubsub
17
+ pubsub.find_first('/iq/ns:pubsub', :ns => Blather::Stanza::PubSubOwner.registered_ns).must_be_nil
18
+
19
+ pubsub.pubsub.wont_be_nil
20
+ pubsub.find_first('/iq/ns:pubsub', :ns => Blather::Stanza::PubSubOwner.registered_ns).wont_be_nil
21
+ end
22
+
23
+ it 'sets the host if requested' do
24
+ aff = Blather::Stanza::PubSubOwner.new :get, 'pubsub.jabber.local'
25
+ aff.to.must_equal Blather::JID.new('pubsub.jabber.local')
26
+ end
27
+ end
@@ -0,0 +1,62 @@
1
+ require File.join(File.dirname(__FILE__), *%w[.. .. spec_helper])
2
+ require File.join(File.dirname(__FILE__), *%w[.. .. fixtures pubsub])
3
+
4
+ describe Blather::Stanza::PubSub do
5
+ it 'registers itself' do
6
+ Blather::XMPPNode.class_from_registration(:pubsub, 'http://jabber.org/protocol/pubsub').must_equal Blather::Stanza::PubSub
7
+ end
8
+
9
+ it 'ensures a pubusb node is present on create' do
10
+ pubsub = Blather::Stanza::PubSub.new
11
+ pubsub.find_first('/iq/ns:pubsub', :ns => Blather::Stanza::PubSub.registered_ns).wont_be_nil
12
+ end
13
+
14
+ it 'ensures a pubsub node exists when calling #pubsub' do
15
+ pubsub = Blather::Stanza::PubSub.new
16
+ pubsub.remove_children :pubsub
17
+ pubsub.find_first('/iq/ns:pubsub', :ns => Blather::Stanza::PubSub.registered_ns).must_be_nil
18
+
19
+ pubsub.pubsub.wont_be_nil
20
+ pubsub.find_first('/iq/ns:pubsub', :ns => Blather::Stanza::PubSub.registered_ns).wont_be_nil
21
+ end
22
+
23
+ it 'sets the host if requested' do
24
+ aff = Blather::Stanza::PubSub.new :get, 'pubsub.jabber.local'
25
+ aff.to.must_equal Blather::JID.new('pubsub.jabber.local')
26
+ end
27
+
28
+ it 'ensures newly inherited items are PubSubItem objects' do
29
+ pubsub = Blather::XMPPNode.import(parse_stanza(items_all_nodes_xml).root)
30
+ pubsub.items.map { |i| i.class }.uniq.must_equal [Blather::Stanza::PubSub::PubSubItem]
31
+ end
32
+ end
33
+
34
+ describe Blather::Stanza::PubSub::PubSubItem do
35
+ it 'can be initialized with just an ID' do
36
+ id = 'foobarbaz'
37
+ item = Blather::Stanza::PubSub::Items::PubSubItem.new id
38
+ item.id.must_equal id
39
+ end
40
+
41
+ it 'can be initialized with a payload' do
42
+ payload = 'foobarbaz'
43
+ item = Blather::Stanza::PubSub::Items::PubSubItem.new 'foo', payload
44
+ item.payload.must_equal payload
45
+ end
46
+
47
+ it 'allows the payload to be set' do
48
+ item = Blather::Stanza::PubSub::Items::PubSubItem.new
49
+ item.payload.must_be_nil
50
+ item.payload = 'testing'
51
+ item.payload.must_equal 'testing'
52
+ item.content.must_equal 'testing'
53
+ end
54
+
55
+ it 'allows the payload to be unset' do
56
+ payload = 'foobarbaz'
57
+ item = Blather::Stanza::PubSub::Items::PubSubItem.new 'foo', payload
58
+ item.payload.must_equal payload
59
+ item.payload = nil
60
+ item.payload.must_be_nil
61
+ end
62
+ end
@@ -1,34 +1,49 @@
1
1
  require File.join(File.dirname(__FILE__), *%w[.. spec_helper])
2
2
 
3
- describe 'Blather::Stanza' do
3
+ describe Blather::Stanza do
4
4
  it 'provides .next_id helper for generating new IDs' do
5
- proc { Stanza.next_id }.must_change 'Stanza.next_id'
5
+ proc { Blather::Stanza.next_id }.must_change 'Blather::Stanza.next_id'
6
6
  end
7
7
 
8
- it 'can import a node' do
9
- s = Stanza.import XMPPNode.new('foo')
10
- s.element_name.must_equal 'foo'
8
+ it 'provides a handler registration mechanism' do
9
+ class Registration < Blather::Stanza; register :handler_test, :handler, 'test:namespace'; end
10
+ Registration.handler_heirarchy.must_include :handler_test
11
+ Blather::Stanza.handler_list.must_include :handler_test
12
+ end
13
+
14
+ it 'can register based on handler' do
15
+ class RegisterHandler < Blather::Stanza; register :register_handler; end
16
+ Blather::Stanza.class_from_registration(:register_handler, nil).must_equal RegisterHandler
17
+ end
18
+
19
+ it 'can register based on given name' do
20
+ class RegisterName < Blather::Stanza; register :handler, :registered_name; end
21
+ Blather::Stanza.class_from_registration(:registered_name, nil).must_equal RegisterName
11
22
  end
12
23
 
13
- it 'sets the ID when created' do
14
- Stanza.new('message').id.wont_be_nil
24
+ it 'can register subclass handlers' do
25
+ class SuperClassRegister < Blather::Stanza; register :super_class; end
26
+ class SubClassRegister < SuperClassRegister; register :sub_class; end
27
+ SuperClassRegister.handler_heirarchy.wont_include :sub_class
28
+ SubClassRegister.handler_heirarchy.must_include :super_class
15
29
  end
16
30
 
17
- it 'sets the document when created' do
18
- Stanza.new('message').doc.wont_be_nil
31
+ it 'can import a node' do
32
+ s = Blather::Stanza.import Blather::XMPPNode.new('foo')
33
+ s.element_name.must_equal 'foo'
19
34
  end
20
35
 
21
36
  it 'provides an #error? helper' do
22
- s = Stanza.new('message')
37
+ s = Blather::Stanza.new('message')
23
38
  s.error?.must_equal false
24
39
  s.type = :error
25
40
  s.error?.must_equal true
26
41
  end
27
42
 
28
43
  it 'will generate a reply' do
29
- s = Stanza.new('message')
30
- s.from = f = JID.new('n@d/r')
31
- s.to = t = JID.new('d@n/r')
44
+ s = Blather::Stanza.new('message')
45
+ s.from = f = Blather::JID.new('n@d/r')
46
+ s.to = t = Blather::JID.new('d@n/r')
32
47
 
33
48
  r = s.reply
34
49
  r.object_id.wont_equal s.object_id
@@ -37,9 +52,9 @@ describe 'Blather::Stanza' do
37
52
  end
38
53
 
39
54
  it 'convert to a reply' do
40
- s = Stanza.new('message')
41
- s.from = f = JID.new('n@d/r')
42
- s.to = t = JID.new('d@n/r')
55
+ s = Blather::Stanza.new('message')
56
+ s.from = f = Blather::JID.new('n@d/r')
57
+ s.to = t = Blather::JID.new('d@n/r')
43
58
 
44
59
  r = s.reply!
45
60
  r.object_id.must_equal s.object_id
@@ -48,53 +63,53 @@ describe 'Blather::Stanza' do
48
63
  end
49
64
 
50
65
  it 'provides "attr_accessor" for id' do
51
- s = Stanza.new('message')
52
- s.id.wont_be_nil
53
- s['id'].wont_be_nil
54
-
55
- s.id = nil
66
+ s = Blather::Stanza.new('message')
56
67
  s.id.must_be_nil
57
- s['id'].must_be_nil
68
+ s[:id].must_be_nil
69
+
70
+ s.id = '123'
71
+ s.id.must_equal '123'
72
+ s[:id].must_equal '123'
58
73
  end
59
74
 
60
75
  it 'provides "attr_accessor" for to' do
61
- s = Stanza.new('message')
76
+ s = Blather::Stanza.new('message')
62
77
  s.to.must_be_nil
63
- s['to'].must_be_nil
78
+ s[:to].must_be_nil
64
79
 
65
- s.to = JID.new('n@d/r')
80
+ s.to = Blather::JID.new('n@d/r')
66
81
  s.to.wont_be_nil
67
- s.to.must_be_kind_of JID
82
+ s.to.must_be_kind_of Blather::JID
68
83
 
69
- s['to'].wont_be_nil
70
- s['to'].must_equal 'n@d/r'
84
+ s[:to].wont_be_nil
85
+ s[:to].must_equal 'n@d/r'
71
86
  end
72
87
 
73
88
  it 'provides "attr_accessor" for from' do
74
- s = Stanza.new('message')
89
+ s = Blather::Stanza.new('message')
75
90
  s.from.must_be_nil
76
- s['from'].must_be_nil
91
+ s[:from].must_be_nil
77
92
 
78
- s.from = JID.new('n@d/r')
93
+ s.from = Blather::JID.new('n@d/r')
79
94
  s.from.wont_be_nil
80
- s.from.must_be_kind_of JID
95
+ s.from.must_be_kind_of Blather::JID
81
96
 
82
- s['from'].wont_be_nil
83
- s['from'].must_equal 'n@d/r'
97
+ s[:from].wont_be_nil
98
+ s[:from].must_equal 'n@d/r'
84
99
  end
85
100
 
86
101
  it 'provides "attr_accessor" for type' do
87
- s = Stanza.new('message')
102
+ s = Blather::Stanza.new('message')
88
103
  s.type.must_be_nil
89
- s['type'].must_be_nil
104
+ s[:type].must_be_nil
90
105
 
91
106
  s.type = 'testing'
92
107
  s.type.wont_be_nil
93
- s['type'].wont_be_nil
108
+ s[:type].wont_be_nil
94
109
  end
95
110
 
96
111
  it 'can be converted into an error by error name' do
97
- s = Stanza.new('message')
112
+ s = Blather::Stanza.new('message')
98
113
  err = s.as_error 'internal-server-error', 'cancel'
99
114
  err.name.must_equal :internal_server_error
100
115
  end
@@ -1,6 +1,7 @@
1
+ require 'resolv'
1
2
  require File.join(File.dirname(__FILE__), *%w[.. .. spec_helper])
2
3
 
3
- describe 'Blather::Stream::Client' do
4
+ describe Blather::Stream::Client do
4
5
  class MockServer; end
5
6
  module ServerMock
6
7
  def receive_data(data)
@@ -12,44 +13,102 @@ describe 'Blather::Stream::Client' do
12
13
  def mocked_server(times = nil, &block)
13
14
  @client ||= mock()
14
15
  @client.stubs(:unbind) unless @client.respond_to?(:unbind)
16
+ @client.stubs(:post_init) unless @client.respond_to?(:post_init)
15
17
  @client.stubs(:jid=) unless @client.respond_to?(:jid=)
16
18
 
17
19
  MockServer.any_instance.expects(:receive_data).send(*(times ? [:times, times] : [:at_least, 1])).with &block
18
20
  EventMachine::run {
21
+ EM.add_timer(0.5) { EM.stop if EM.reactor_running? }
22
+
19
23
  # Mocked server
20
24
  EventMachine::start_server '127.0.0.1', 12345, ServerMock
21
25
 
22
- # Stream connection
23
- EM.connect('127.0.0.1', 12345, Stream::Client, @client, @jid || JID.new('n@d/r'), 'pass') { |c| @stream = c }
26
+ # Blather::Stream connection
27
+ EM.connect('127.0.0.1', 12345, Blather::Stream::Client, @client, @jid || Blather::JID.new('n@d/r'), 'pass') { |c| @stream = c }
24
28
  }
25
29
  end
26
30
 
31
+
27
32
  it 'can be started' do
28
33
  client = mock()
29
34
  params = [client, 'n@d/r', 'pass', 'host', 1234]
30
35
  EM.expects(:connect).with do |*parms|
31
- parms[0] == 'host' &&
32
- parms[1] == 1234 &&
33
- parms[3] == client &&
34
- parms[5] == 'pass' &&
35
- parms[4] == JID.new('n@d/r')
36
+ parms[0].must_equal 'host'
37
+ parms[1].must_equal 1234
38
+ parms[3].must_equal client
39
+ parms[5].must_equal 'pass'
40
+ parms[4].must_equal Blather::JID.new('n@d/r')
41
+ end
42
+
43
+ Blather::Stream::Client.start *params
44
+ end
45
+
46
+ it 'attempts to find the SRV record if a host is not provided' do
47
+ dns = mock(:sort! => nil, :empty? => false)
48
+ dns.expects(:each).yields(mock({
49
+ :target => 'd',
50
+ :port => 5222
51
+ }))
52
+ Resolv::DNS.expects(:open).yields(mock(:getresources => dns))
53
+
54
+ client = Class.new
55
+ EM.expects(:connect).with do |*parms|
56
+ parms[0].must_equal 'd'
57
+ parms[1].must_equal 5222
58
+ parms[3].must_equal client
59
+ parms[5].must_equal 'pass'
60
+ parms[4].must_equal Blather::JID.new('n@d/r')
36
61
  end
37
62
 
38
- Stream::Client.start *(params)
63
+ Blather::Stream::Client.start client, 'n@d/r', 'pass'
64
+ end
65
+
66
+ it 'will attempt as many connections as it takes' do
67
+ dns = [mock(:target => 'd', :port => 5222), mock(:target => 'g', :port => 1234)]
68
+ dns.stubs(:sort!) #ignore sorting
69
+ Resolv::DNS.expects(:open).yields(mock(:getresources => dns))
70
+
71
+ client = Class.new
72
+ EM.expects(:connect).with do |*parms|
73
+ raise Blather::Stream::NoConnection if parms[0] == 'd'
74
+ parms[0].must_equal 'g'
75
+ parms[1].must_equal 1234
76
+ parms[3].must_equal client
77
+ parms[5].must_equal 'pass'
78
+ parms[4].must_equal Blather::JID.new('n@d/r')
79
+ end
80
+ Blather::Stream::Client.start client, 'n@d/r', 'pass'
81
+ end
82
+
83
+ it 'will not attempt to connect more often than necessary' do
84
+ dns = [mock(:target => 'd', :port => 5222), mock()]
85
+ dns.stubs(:sort!) #ignore sorting
86
+ Resolv::DNS.expects(:open).yields(mock(:getresources => dns))
87
+
88
+ client = Class.new
89
+ EM.expects(:connect).with do |*parms|
90
+ parms[0].must_equal 'd'
91
+ parms[1].must_equal 5222
92
+ parms[3].must_equal client
93
+ parms[5].must_equal 'pass'
94
+ parms[4].must_equal Blather::JID.new('n@d/r')
95
+ end
96
+ Blather::Stream::Client.start client, 'n@d/r', 'pass'
39
97
  end
40
98
 
41
99
  it 'can figure out the host to use based on the jid' do
42
- client = mock()
43
- params = [client, 'n@d/r', 'pass', 'd', 5222]
100
+ Resolv::DNS.expects(:open).yields(mock(:getresources => mock(:empty? => true)))
101
+ client = Class.new
102
+ params = [client, 'n@d/r', 'pass', nil, 5222]
44
103
  EM.expects(:connect).with do |*parms|
45
- parms[0] == 'd' &&
46
- parms[1] == 5222 &&
47
- parms[3] == client &&
48
- parms[5] == 'pass' &&
49
- parms[4] == JID.new('n@d/r')
104
+ parms[0].must_equal 'd'
105
+ parms[1].must_equal 5222
106
+ parms[3].must_equal client
107
+ parms[5].must_equal 'pass'
108
+ parms[4].must_equal Blather::JID.new('n@d/r')
50
109
  end
51
110
 
52
- Stream::Client.start client, 'n@d/r', 'pass'
111
+ Blather::Stream::Client.start client, 'n@d/r', 'pass'
53
112
  end
54
113
 
55
114
  it 'starts the stream once the connection is complete' do
@@ -60,7 +119,7 @@ describe 'Blather::Stream::Client' do
60
119
  @client = mock()
61
120
  @client.expects(:receive_data).with do |n|
62
121
  EM.stop
63
- n.kind_of?(Stanza::Message) && @stream.ready?.must_equal(true)
122
+ n.must_be_kind_of Blather::Stanza::Message
64
123
  end
65
124
 
66
125
  mocked_server(1) do |val, server|
@@ -70,7 +129,7 @@ describe 'Blather::Stream::Client' do
70
129
  end
71
130
  end
72
131
 
73
- it 'puts itself in the stopped state and calls @client.stopped when stopped' do
132
+ it 'puts itself in the stopped state and calls @client.unbind when unbound' do
74
133
  @client = mock()
75
134
  @client.expects(:unbind).at_least_once
76
135
 
@@ -95,7 +154,6 @@ describe 'Blather::Stream::Client' do
95
154
  it 'will be in the negotiating state during feature negotiations' do
96
155
  state = nil
97
156
  @client = mock()
98
- @client.stubs(:post_init)
99
157
  @client.expects(:receive_data).with do |n|
100
158
  EM.stop
101
159
  state.must_equal(:negotiated) && @stream.negotiating?.must_equal(false)
@@ -111,7 +169,7 @@ describe 'Blather::Stream::Client' do
111
169
 
112
170
  when :started
113
171
  state = :negotiated
114
- @stream.negotiating?.must_equal(true)
172
+ @stream.negotiating?.must_equal true
115
173
  server.send_data "<iq from='d' type='result' id='#{val[/id="([^"]+)"/,1]}' />"
116
174
  server.send_data "<message to='a@b/c' from='d@e/f' type='chat' xml:lang='en'><body>Message!</body></message>"
117
175
  true
@@ -186,13 +244,36 @@ describe 'Blather::Stream::Client' do
186
244
  end
187
245
  end
188
246
 
247
+ it 'skips features it is unable to handle' do
248
+ state = nil
249
+ mocked_server() do |val, server|
250
+ case state
251
+ when nil
252
+ state = :started
253
+ server.send_data "<?xml version='1.0'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'>"
254
+ server.send_data "<stream:features><auth xmlns='http://jabber.org/features/iq-auth'/><starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls' /></stream:features>"
255
+ val.must_match(/stream:stream/)
256
+
257
+ when :started
258
+ EM.stop
259
+ val.must_match(/starttls/)
260
+
261
+ else
262
+ EM.stop
263
+ false
264
+
265
+ end
266
+ end
267
+ end
268
+
189
269
  it 'starts TLS when asked' do
190
270
  state = nil
191
271
  mocked_server(3) do |val, server|
192
272
  case state
193
273
  when nil
194
274
  state = :started
195
- server.send_data "<?xml version='1.0'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'><stream:features><starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls' /></stream:features>"
275
+ server.send_data "<?xml version='1.0'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'>"
276
+ server.send_data "<stream:features><starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls' /></stream:features>"
196
277
  val.must_match(/stream:stream/)
197
278
 
198
279
  when :started
@@ -216,7 +297,7 @@ describe 'Blather::Stream::Client' do
216
297
  it 'will fail if TLS negotiation fails' do
217
298
  state = nil
218
299
  @client = mock()
219
- @client.expects(:receive_data).with { |v| v.must_be_kind_of TLSFailure }
300
+ @client.expects(:receive_data).with { |v| v.must_be_kind_of Blather::Stream::TLS::TLSFailure }
220
301
  mocked_server(3) do |val, server|
221
302
  case state
222
303
  when nil
@@ -246,14 +327,14 @@ describe 'Blather::Stream::Client' do
246
327
  state = nil
247
328
  @client = mock()
248
329
  @client.expects(:receive_data).with do |v|
249
- v.must_be_kind_of UnknownResponse
250
- v.node.element_name.must_equal 'foo-bar'
330
+ v.must_be_kind_of Blather::Stream::TLS::TLSFailure
251
331
  end
252
332
  mocked_server(3) do |val, server|
253
333
  case state
254
334
  when nil
255
335
  state = :started
256
- server.send_data "<?xml version='1.0'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'><stream:features><starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls' /></stream:features>"
336
+ server.send_data "<?xml version='1.0'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'>"
337
+ server.send_data "<stream:features><starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls' /></stream:features>"
257
338
  val.must_match(/stream:stream/)
258
339
 
259
340
  when :started
@@ -368,9 +449,9 @@ describe 'Blather::Stream::Client' do
368
449
  end
369
450
  end
370
451
 
371
- it 'connects via ANONYMOUS if the JID has a blank node' do
452
+ it 'connects via ANONYMOUS if the Blather::JID has a blank node' do
372
453
  state = nil
373
- @jid = JID.new '@d'
454
+ @jid = Blather::JID.new '@d'
374
455
 
375
456
  mocked_server(3) do |val, server|
376
457
  case state
@@ -397,11 +478,37 @@ describe 'Blather::Stream::Client' do
397
478
  end
398
479
  end
399
480
 
481
+ it 'fails if asked to connect via ANONYMOUS but the server does not support it' do
482
+ state = nil
483
+ @jid = Blather::JID.new '@d'
484
+ @client = mock()
485
+ @client.expects(:receive_data).with { |s| s.must_be_instance_of Blather::BlatherError }
486
+
487
+ mocked_server(2) do |val, server|
488
+ case state
489
+ when nil
490
+ state = :started
491
+ server.send_data "<?xml version='1.0'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'>"
492
+ server.send_data "<stream:features><mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><mechanism>DIGEST-MD5</mechanism><mechanism>PLAIN</mechanism></mechanisms></stream:features>"
493
+ val.must_match(/stream:stream/)
494
+
495
+ when :started
496
+ EM.stop
497
+ val.must_match(/stream:stream/)
498
+
499
+ else
500
+ EM.stop
501
+ false
502
+
503
+ end
504
+ end
505
+ end
506
+
400
507
  it 'tries each possible mechanism until it fails completely' do
401
508
  state = nil
402
509
  @client = mock()
403
510
  @client.expects(:receive_data).with do |n|
404
- n.must_be_kind_of(SASLError)
511
+ n.must_be_kind_of(Blather::SASLError)
405
512
  n.name.must_equal :not_authorized
406
513
  end
407
514
 
@@ -409,7 +516,8 @@ describe 'Blather::Stream::Client' do
409
516
  case state
410
517
  when nil
411
518
  state = :started
412
- server.send_data "<?xml version='1.0'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'><stream:features><mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><mechanism>DIGEST-MD5</mechanism><mechanism>PLAIN</mechanism><mechanism>ANONYMOUS</mechanism></mechanisms></stream:features>"
519
+ server.send_data "<?xml version='1.0'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'>"
520
+ server.send_data "<stream:features><mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><mechanism>DIGEST-MD5</mechanism><mechanism>PLAIN</mechanism><mechanism>ANONYMOUS</mechanism></mechanisms></stream:features>"
413
521
  val.must_match(/stream:stream/)
414
522
 
415
523
  when :started
@@ -471,9 +579,37 @@ describe 'Blather::Stream::Client' do
471
579
  end
472
580
  end
473
581
 
582
+ it 'will ignore methods it does not understand' do
583
+ state = nil
584
+ mocked_server(3) do |val, server|
585
+ case state
586
+ when nil
587
+ state = :started
588
+ server.send_data "<?xml version='1.0'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'>"
589
+ server.send_data "<stream:features><mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><mechanism>CRAM-MD5</mechanism><mechanism>PLAIN</mechanism></mechanisms></stream:features>"
590
+ val.must_match(/stream:stream/)
591
+
592
+ when :started
593
+ state = :auth_sent
594
+ server.send_data "<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl' />"
595
+ val.must_equal('<auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" mechanism="PLAIN">bkBkAG4AcGFzcw==</auth>')
596
+
597
+ when :auth_sent
598
+ EM.stop
599
+ state = :complete
600
+ val.must_match(/stream:stream/)
601
+
602
+ else
603
+ EM.stop
604
+ false
605
+
606
+ end
607
+ end
608
+ end
609
+ =begin
474
610
  it 'sends client an error when an unknown mechanism is sent' do
475
611
  @client = mock()
476
- @client.expects(:receive_data).with { |v| v.must_be_kind_of(Stream::SASL::UnknownMechanism) }
612
+ @client.expects(:receive_data).with { |v| v.must_be_kind_of(Blather::Stream::SASL::UnknownMechanism) }
477
613
  started = false
478
614
  mocked_server(2) do |val, server|
479
615
  if !started
@@ -489,7 +625,7 @@ describe 'Blather::Stream::Client' do
489
625
  end
490
626
  end
491
627
  end
492
-
628
+ =end
493
629
  %w[ aborted
494
630
  incorrect-encoding
495
631
  invalid-authzid
@@ -533,7 +669,7 @@ describe 'Blather::Stream::Client' do
533
669
  it 'fails when an unkown node comes through during SASL negotiation' do
534
670
  @client = mock()
535
671
  @client.expects(:receive_data).with do |n|
536
- n.must_be_instance_of UnknownResponse
672
+ n.must_be_instance_of Blather::UnknownResponse
537
673
  n.node.element_name.must_equal 'foo-bar'
538
674
  end
539
675
  state = nil
@@ -566,13 +702,14 @@ describe 'Blather::Stream::Client' do
566
702
  state = nil
567
703
  class Client; attr_accessor :jid; end
568
704
  @client = Client.new
569
- @jid = JID.new('n@d')
705
+ @jid = Blather::JID.new('n@d')
570
706
 
571
707
  mocked_server(3) do |val, server|
572
708
  case state
573
709
  when nil
574
710
  state = :started
575
- server.send_data "<?xml version='1.0'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'><stream:features><bind xmlns='urn:ietf:params:xml:ns:xmpp-bind' /></stream:features>"
711
+ server.send_data "<?xml version='1.0'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'>"
712
+ server.send_data "<stream:features><bind xmlns='urn:ietf:params:xml:ns:xmpp-bind' /></stream:features>"
576
713
  val.must_match(/stream:stream/)
577
714
 
578
715
  when :started
@@ -584,7 +721,7 @@ describe 'Blather::Stream::Client' do
584
721
 
585
722
  when :complete
586
723
  EM.stop
587
- @client.jid.must_equal JID.new('n@d/server_resource')
724
+ @client.jid.must_equal Blather::JID.new('n@d/server_resource')
588
725
 
589
726
  else
590
727
  EM.stop
@@ -598,7 +735,7 @@ describe 'Blather::Stream::Client' do
598
735
  state = nil
599
736
  class Client; attr_accessor :jid; end
600
737
  @client = Client.new
601
- @jid = JID.new('n@d/r')
738
+ @jid = Blather::JID.new('n@d/r')
602
739
 
603
740
  mocked_server(3) do |val, server|
604
741
  case state
@@ -609,14 +746,47 @@ describe 'Blather::Stream::Client' do
609
746
 
610
747
  when :started
611
748
  state = :complete
612
- val =~ %r{<iq[^>]+id="([^"]+)"}
613
- server.send_data "<iq type='result' id='#{$1}'><bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><jid>#{@jid}</jid></bind></iq>"
749
+ doc = parse_stanza val
750
+ doc.xpath('/iq/bind_ns:bind/bind_ns:resource[.="r"]', :bind_ns => Blather::Stream::Resource::BIND_NS).wont_be_empty
751
+
752
+ server.send_data "<iq type='result' id='#{doc.find_first('iq')['id']}'><bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><jid>#{@jid}</jid></bind></iq>"
614
753
  server.send_data "<stream:features><bind xmlns='urn:ietf:params:xml:ns:xmpp-bind' /></stream:features>"
615
- val.must_match(%r{<bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"><resource>r</resource></bind>})
616
754
 
617
755
  when :complete
618
756
  EM.stop
619
- @client.jid.must_equal JID.new('n@d/r')
757
+ @client.jid.must_equal Blather::JID.new('n@d/r')
758
+
759
+ else
760
+ EM.stop
761
+ false
762
+
763
+ end
764
+ end
765
+ end
766
+
767
+ it 'will error out if the bind ID mismatches' do
768
+ state = nil
769
+ @jid = Blather::JID.new('n@d')
770
+ @client = mock()
771
+
772
+ mocked_server(3) do |val, server|
773
+ case state
774
+ when nil
775
+ state = :started
776
+ server.send_data "<?xml version='1.0'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'>"
777
+ server.send_data "<stream:features><bind xmlns='urn:ietf:params:xml:ns:xmpp-bind' /></stream:features>"
778
+ val.must_match(/stream:stream/)
779
+
780
+ when :started
781
+ state = :complete
782
+ val =~ %r{<iq[^>]+id="([^"]+)"}
783
+ @client.expects(:receive_data).with("BIND result ID mismatch. Expected: #{$1}. Received: #{$1}-bad")
784
+ server.send_data "<iq type='result' id='#{$1}-bad'><bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><jid>#{@jid}/server_resource</jid></bind></iq>"
785
+ val.must_match(%r{<bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"\s?/>})
786
+
787
+ when :complete
788
+ EM.stop
789
+ true
620
790
 
621
791
  else
622
792
  EM.stop
@@ -641,9 +811,9 @@ describe 'Blather::Stream::Client' do
641
811
 
642
812
  when :started
643
813
  state = :complete
644
- val =~ %r{<iq[^>]+id="([^"]+)"}
645
- server.send_data "<iq type='error' id='#{$1}'><bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><resource>r</resource></bind><error type='modify'><bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/></error></iq>"
646
- val.must_match(%r{<bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"><resource>r</resource></bind>})
814
+ doc = parse_stanza val
815
+ doc.xpath('/iq/bind_ns:bind/bind_ns:resource[.="r"]', :bind_ns => Blather::Stream::Resource::BIND_NS).wont_be_empty
816
+ server.send_data "<iq type='error' id='#{doc.find_first('iq')['id']}'><bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><resource>r</resource></bind><error type='modify'><bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/></error></iq>"
647
817
 
648
818
  when :complete
649
819
  EM.stop
@@ -661,21 +831,22 @@ describe 'Blather::Stream::Client' do
661
831
  state = nil
662
832
  @client = mock()
663
833
  @client.expects(:receive_data).with do |n|
664
- n.must_be_instance_of UnknownResponse
834
+ n.must_be_instance_of Blather::UnknownResponse
665
835
  n.node.element_name.must_equal 'foo-bar'
666
836
  end
667
837
  mocked_server(3) do |val, server|
668
838
  case state
669
839
  when nil
670
840
  state = :started
671
- server.send_data "<?xml version='1.0'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'><stream:features><bind xmlns='urn:ietf:params:xml:ns:xmpp-bind' /></stream:features>"
841
+ server.send_data "<?xml version='1.0'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'>"
842
+ server.send_data "<stream:features><bind xmlns='urn:ietf:params:xml:ns:xmpp-bind' /></stream:features>"
672
843
  val.must_match(/stream:stream/)
673
844
 
674
845
  when :started
675
846
  state = :complete
676
- val =~ %r{<iq[^>]+id="([^"]+)"}
847
+ doc = parse_stanza val
848
+ doc.xpath('/iq/bind_ns:bind/bind_ns:resource[.="r"]', :bind_ns => Blather::Stream::Resource::BIND_NS).wont_be_empty
677
849
  server.send_data "<foo-bar />"
678
- val.must_match(%r{<bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"><resource>r</resource></bind>})
679
850
 
680
851
  when :complete
681
852
  EM.stop
@@ -704,9 +875,10 @@ describe 'Blather::Stream::Client' do
704
875
 
705
876
  when :started
706
877
  state = :completed
707
- server.send_data "<iq from='d' type='result' id='#{val[/id="([^"]+)"/,1]}' />"
878
+ doc = parse_stanza val
879
+ doc.find('/iq[@type="set" and @to="d"]/sess_ns:session', :sess_ns => Blather::Stream::Session::SESSION_NS).wont_be_empty
880
+ server.send_data "<iq from='d' type='result' id='#{doc.find_first('iq')['id']}' />"
708
881
  server.send_data "<stream:features><bind xmlns='urn:ietf:params:xml:ns:xmpp-bind' /></stream:features>"
709
- val.must_match(%r{<iq id="[^"]+" type="set" to="d"><session xmlns="urn:ietf:params:xml:ns:xmpp-session"\s?/></iq>})
710
882
 
711
883
  when :completed
712
884
  EM.stop
@@ -736,8 +908,9 @@ describe 'Blather::Stream::Client' do
736
908
 
737
909
  when :started
738
910
  state = :completed
739
- server.send_data "<iq from='d' type='error' id='#{val[/id="([^"]+)"/,1]}'><session xmlns='urn:ietf:params:xml:ns:xmpp-session'/><error type='wait'><internal-server-error xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/></error></iq>"
740
- val.must_match(%r{<iq id="[^"]+" type="set" to="d"><session xmlns="urn:ietf:params:xml:ns:xmpp-session"\s?/></iq>})
911
+ doc = parse_stanza val
912
+ doc.find('/iq[@type="set" and @to="d"]/sess_ns:session', :sess_ns => Blather::Stream::Session::SESSION_NS).wont_be_empty
913
+ server.send_data "<iq from='d' type='error' id='#{doc.find_first('iq')['id']}'><session xmlns='urn:ietf:params:xml:ns:xmpp-session'/><error type='wait'><internal-server-error xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/></error></iq>"
741
914
 
742
915
  when :completed
743
916
  EM.stop
@@ -755,7 +928,7 @@ describe 'Blather::Stream::Client' do
755
928
  state = nil
756
929
  @client = mock()
757
930
  @client.expects(:receive_data).with do |n|
758
- n.must_be_instance_of UnknownResponse
931
+ n.must_be_instance_of Blather::UnknownResponse
759
932
  n.node.element_name.must_equal 'foo-bar'
760
933
  end
761
934
  mocked_server(3) do |val, server|
@@ -768,8 +941,9 @@ describe 'Blather::Stream::Client' do
768
941
 
769
942
  when :started
770
943
  state = :completed
944
+ doc = parse_stanza val
945
+ doc.find('/iq[@type="set" and @to="d"]/sess_ns:session', :sess_ns => Blather::Stream::Session::SESSION_NS).wont_be_empty
771
946
  server.send_data '<foo-bar />'
772
- val.must_match(%r{<iq id="[^"]+" type="set" to="d"><session xmlns="urn:ietf:params:xml:ns:xmpp-session"\s?/></iq>})
773
947
 
774
948
  when :completed
775
949
  EM.stop
@@ -783,42 +957,10 @@ describe 'Blather::Stream::Client' do
783
957
  end
784
958
  end
785
959
 
786
- it 'sends the client a warning on parse warning' do
787
- @client = mock()
788
- @client.expects(:receive_data).with do |v|
789
- EM.stop
790
- v.must_be_kind_of ParseWarning
791
- v.message.must_match(/vcard\-temp/)
792
- end
793
- state = nil
794
- mocked_server(2) do |val, server|
795
- case state
796
- when nil
797
- state = :started
798
- server.send_data "<?xml version='1.0'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' version='1.0'>"
799
- server.send_data "<stream:features><bind xmlns='urn:ietf:params:xml:ns:xmpp-bind' /></stream:features>"
800
- val.must_match(/stream:stream/)
801
-
802
- when :started
803
- server.send_data <<-XML
804
- <iq xmlns="jabber:client" to="utterance.localhost" type="get" id="2590">
805
- <vCard xmlns="vcard-temp" />
806
- </iq>
807
- XML
808
- true
809
-
810
- else
811
- EM.stop
812
- false
813
-
814
- end
815
- end
816
- end
817
-
818
- it 'sends client an error on parse error' do
960
+ it 'sends client an error and reply to the server on parse error' do
819
961
  @client = mock()
820
962
  @client.expects(:receive_data).with do |v|
821
- v.must_be_kind_of ParseError
963
+ v.must_be_kind_of Blather::ParseError
822
964
  v.message.must_match(/generate\-parse\-error/)
823
965
  end
824
966
  state = nil
@@ -845,4 +987,5 @@ describe 'Blather::Stream::Client' do
845
987
  end
846
988
  end
847
989
  end
990
+
848
991
  end