blather 0.1 → 0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +2 -0
- data/Manifest +36 -33
- data/README.rdoc +11 -17
- data/Rakefile +4 -3
- data/blather.gemspec +9 -9
- data/examples/drb_client.rb +7 -0
- data/examples/echo.rb +9 -18
- data/lib/blather.rb +140 -31
- data/lib/blather/{core/errors.rb → errors.rb} +0 -0
- data/lib/blather/{core/jid.rb → jid.rb} +0 -0
- data/lib/blather/{core/roster.rb → roster.rb} +0 -0
- data/lib/blather/{core/roster_item.rb → roster_item.rb} +0 -0
- data/lib/blather/{core/stanza.rb → stanza.rb} +6 -14
- data/lib/blather/stanza/error.rb +31 -0
- data/lib/blather/{core/stanza → stanza}/iq.rb +2 -2
- data/lib/blather/stanza/iq/query.rb +50 -0
- data/lib/blather/{core/stanza → stanza}/iq/roster.rb +3 -3
- data/lib/blather/{core/stanza → stanza}/message.rb +6 -2
- data/lib/blather/{core/stanza → stanza}/presence.rb +10 -0
- data/lib/blather/{core/stanza → stanza}/presence/status.rb +8 -6
- data/lib/blather/{core/stanza → stanza}/presence/subscription.rb +1 -1
- data/lib/blather/{core/stream.rb → stream.rb} +1 -1
- data/lib/blather/{core/stream → stream}/parser.rb +0 -5
- data/lib/blather/{core/stream → stream}/resource.rb +0 -0
- data/lib/blather/{core/stream → stream}/sasl.rb +16 -5
- data/lib/blather/{core/stream → stream}/session.rb +0 -0
- data/lib/blather/{core/stream → stream}/tls.rb +0 -0
- data/lib/blather/{core/sugar.rb → sugar.rb} +4 -0
- data/lib/blather/{core/xmpp_node.rb → xmpp_node.rb} +1 -3
- data/spec/blather/{core/jid_spec.rb → jid_spec.rb} +16 -1
- data/spec/blather/{core/roster_item_spec.rb → roster_item_spec.rb} +1 -1
- data/spec/blather/{core/roster_spec.rb → roster_spec.rb} +11 -1
- data/spec/blather/stanza/iq/query_spec.rb +34 -0
- data/spec/blather/stanza/iq/roster_spec.rb +7 -0
- data/spec/blather/stanza/iq_spec.rb +11 -0
- data/spec/blather/stanza/message_spec.rb +52 -0
- data/spec/blather/stanza/presence/status_spec.rb +102 -0
- data/spec/blather/stanza/presence/subscription_spec.rb +74 -0
- data/spec/blather/stanza/presence_spec.rb +24 -0
- data/spec/blather/{core/stanza_spec.rb → stanza_spec.rb} +1 -1
- data/spec/blather/{core/stream_spec.rb → stream_spec.rb} +208 -9
- data/spec/blather/{core/xmpp_node_spec.rb → xmpp_node_spec.rb} +1 -1
- metadata +75 -69
- data/examples/shell_client.rb +0 -28
- data/lib/blather/callback.rb +0 -24
- data/lib/blather/client.rb +0 -81
- data/lib/blather/core/stanza/iq/query.rb +0 -42
- data/lib/blather/extensions.rb +0 -4
- data/lib/blather/extensions/last_activity.rb +0 -55
- data/lib/blather/extensions/version.rb +0 -85
@@ -0,0 +1,52 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), *%w[.. .. spec_helper])
|
2
|
+
|
3
|
+
describe 'Blather::Stanza::Message' do
|
4
|
+
it 'registers itself' do
|
5
|
+
XMPPNode.class_from_registration(:message, nil).must_equal Stanza::Message
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'provides "attr_accessor" for body' do
|
9
|
+
s = Stanza::Message.new
|
10
|
+
s.body.must_be_nil
|
11
|
+
s.detect { |n| n.element_name == 'body' }.must_be_nil
|
12
|
+
|
13
|
+
s.body = 'test message'
|
14
|
+
s.body.wont_be_nil
|
15
|
+
s.detect { |n| n.element_name == 'body' }.wont_be_nil
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'provides "attr_accessor" for subject' do
|
19
|
+
s = Stanza::Message.new
|
20
|
+
s.subject.must_be_nil
|
21
|
+
s.detect { |n| n.element_name == 'subject' }.must_be_nil
|
22
|
+
|
23
|
+
s.subject = 'test subject'
|
24
|
+
s.subject.wont_be_nil
|
25
|
+
s.detect { |n| n.element_name == 'subject' }.wont_be_nil
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'provides "attr_accessor" for thread' do
|
29
|
+
s = Stanza::Message.new
|
30
|
+
s.thread.must_be_nil
|
31
|
+
s.detect { |n| n.element_name == 'thread' }.must_be_nil
|
32
|
+
|
33
|
+
s.thread = 1234
|
34
|
+
s.thread.wont_be_nil
|
35
|
+
s.detect { |n| n.element_name == 'thread' }.wont_be_nil
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'ensures type is one of Stanza::Message::VALID_TYPES' do
|
39
|
+
lambda { Stanza::Message.new nil, nil, :invalid_type_name }.must_raise(Blather::ArgumentError)
|
40
|
+
|
41
|
+
Stanza::Message::VALID_TYPES.each do |valid_type|
|
42
|
+
msg = Stanza::Message.new nil, nil, valid_type
|
43
|
+
msg.type.must_equal valid_type
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
Stanza::Message::VALID_TYPES.each do |valid_type|
|
48
|
+
it "provides a helper (#{valid_type}?) for type #{valid_type}" do
|
49
|
+
Stanza::Message.new.must_respond_to :"#{valid_type}?"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), *%w[.. .. .. spec_helper])
|
2
|
+
|
3
|
+
describe 'Blather::Stanza::Presence::Status' do
|
4
|
+
it 'registers itself' do
|
5
|
+
XMPPNode.class_from_registration(:status, nil).must_equal Stanza::Presence::Status
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'can set state on creation' do
|
9
|
+
status = Stanza::Presence::Status.new :away
|
10
|
+
status.state.must_equal :away
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'can set a message on creation' do
|
14
|
+
status = Stanza::Presence::Status.new nil, 'Say hello!'
|
15
|
+
status.message.must_equal 'Say hello!'
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'ensures type is nil or :unavailable' do
|
19
|
+
status = Stanza::Presence::Status.new
|
20
|
+
lambda { status.type = :invalid_type_name }.must_raise(Blather::ArgumentError)
|
21
|
+
|
22
|
+
[nil, :unavailable].each do |valid_type|
|
23
|
+
status.type = valid_type
|
24
|
+
status.type.must_equal valid_type
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'ensures state is one of Presence::Status::VALID_STATES' do
|
29
|
+
status = Stanza::Presence::Status.new
|
30
|
+
lambda { status.state = :invalid_type_name }.must_raise(Blather::ArgumentError)
|
31
|
+
|
32
|
+
Stanza::Presence::Status::VALID_STATES.each do |valid_state|
|
33
|
+
status.state = valid_state
|
34
|
+
status.state.must_equal valid_state
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'returns :available if state is nil' do
|
39
|
+
Stanza::Presence::Status.new.state.must_equal :available
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'returns :unavailable if type is :unavailable' do
|
43
|
+
status = Stanza::Presence::Status.new
|
44
|
+
status.type = :unavailable
|
45
|
+
status.state.must_equal :unavailable
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'ensures priority is not greater than 127' do
|
49
|
+
lambda { Stanza::Presence::Status.new.priority = 128 }.must_raise(Blather::ArgumentError)
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'ensures priority is not less than -128' do
|
53
|
+
lambda { Stanza::Presence::Status.new.priority = -129 }.must_raise(Blather::ArgumentError)
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'has "attr_accessor" for priority' do
|
57
|
+
status = Stanza::Presence::Status.new
|
58
|
+
status.priority.must_equal 0
|
59
|
+
|
60
|
+
status.priority = 10
|
61
|
+
status.children.detect { |n| n.element_name == 'priority' }.wont_be_nil
|
62
|
+
status.priority.must_equal 10
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'has "attr_accessor" for message' do
|
66
|
+
status = Stanza::Presence::Status.new
|
67
|
+
status.message.must_be_nil
|
68
|
+
|
69
|
+
status.message = 'new message'
|
70
|
+
status.children.detect { |n| n.element_name == 'status' }.wont_be_nil
|
71
|
+
status.message.must_equal 'new message'
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'must be comparable by priority' do
|
75
|
+
jid = JID.new 'a@b/c'
|
76
|
+
|
77
|
+
status1 = Stanza::Presence::Status.new
|
78
|
+
status1.from = jid
|
79
|
+
|
80
|
+
status2 = Stanza::Presence::Status.new
|
81
|
+
status2.from = jid
|
82
|
+
|
83
|
+
status1.priority = 1
|
84
|
+
status2.priority = -1
|
85
|
+
(status1 <=> status2).must_equal 1
|
86
|
+
(status2 <=> status1).must_equal -1
|
87
|
+
|
88
|
+
status2.priority = 1
|
89
|
+
(status1 <=> status2).must_equal 0
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'raises an argument error if compared to a status with a different JID' do
|
93
|
+
status1 = Stanza::Presence::Status.new
|
94
|
+
status1.from = 'a@b/c'
|
95
|
+
|
96
|
+
status2 = Stanza::Presence::Status.new
|
97
|
+
status2.from = 'd@e/f'
|
98
|
+
|
99
|
+
lambda { status1 <=> status2 }.must_raise(Blather::ArgumentError)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), *%w[.. .. .. spec_helper])
|
2
|
+
|
3
|
+
describe 'Blather::Stanza::Presence::Subscription' do
|
4
|
+
it 'registers itself' do
|
5
|
+
XMPPNode.class_from_registration(:subscription, nil).must_equal Stanza::Presence::Subscription
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'can set to on creation' do
|
9
|
+
sub = Stanza::Presence::Subscription.new 'a@b'
|
10
|
+
sub.to.to_s.must_equal 'a@b'
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'can set a type on creation' do
|
14
|
+
sub = Stanza::Presence::Subscription.new nil, :subscribed
|
15
|
+
sub.type.must_equal :subscribed
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'strips JIDs when setting #to' do
|
19
|
+
sub = Stanza::Presence::Subscription.new 'a@b/c'
|
20
|
+
sub.to.to_s.must_equal 'a@b'
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'generates an approval using #approve!' do
|
24
|
+
jid = JID.new 'a@b'
|
25
|
+
sub = Stanza::Presence::Subscription.new
|
26
|
+
sub.from = jid
|
27
|
+
sub.approve!
|
28
|
+
sub.to.must_equal jid
|
29
|
+
sub.type.must_equal :subscribed
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'generates a refusal using #refuse!' do
|
33
|
+
jid = JID.new 'a@b'
|
34
|
+
sub = Stanza::Presence::Subscription.new
|
35
|
+
sub.from = jid
|
36
|
+
sub.refuse!
|
37
|
+
sub.to.must_equal jid
|
38
|
+
sub.type.must_equal :unsubscribed
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'generates an unsubscript using #unsubscribe!' do
|
42
|
+
jid = JID.new 'a@b'
|
43
|
+
sub = Stanza::Presence::Subscription.new
|
44
|
+
sub.from = jid
|
45
|
+
sub.unsubscribe!
|
46
|
+
sub.to.must_equal jid
|
47
|
+
sub.type.must_equal :unsubscribe
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'generates a cancellation using #cancel!' do
|
51
|
+
jid = JID.new 'a@b'
|
52
|
+
sub = Stanza::Presence::Subscription.new
|
53
|
+
sub.from = jid
|
54
|
+
sub.cancel!
|
55
|
+
sub.to.must_equal jid
|
56
|
+
sub.type.must_equal :unsubscribed
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'generates a request using #request!' do
|
60
|
+
jid = JID.new 'a@b'
|
61
|
+
sub = Stanza::Presence::Subscription.new
|
62
|
+
sub.from = jid
|
63
|
+
sub.request!
|
64
|
+
sub.to.must_equal jid
|
65
|
+
sub.type.must_equal :subscribe
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'has a #request? helper' do
|
69
|
+
sub = Stanza::Presence::Subscription.new
|
70
|
+
sub.must_respond_to :request?
|
71
|
+
sub.type = :subscribe
|
72
|
+
sub.request?.must_equal true
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), *%w[.. .. spec_helper])
|
2
|
+
|
3
|
+
describe 'Blather::Stanza::Presence' do
|
4
|
+
it 'registers itself' do
|
5
|
+
XMPPNode.class_from_registration(:presence, nil).must_equal Stanza::Presence
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'ensures type is one of Stanza::Presence::VALID_TYPES' do
|
9
|
+
presence = Stanza::Presence.new
|
10
|
+
lambda { presence.type = :invalid_type_name }.must_raise(Blather::ArgumentError)
|
11
|
+
|
12
|
+
Stanza::Presence::VALID_TYPES.each do |valid_type|
|
13
|
+
presence.type = valid_type
|
14
|
+
presence.type.must_equal valid_type
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
Stanza::Presence::VALID_TYPES.each do |valid_type|
|
19
|
+
it "provides a helper (#{valid_type}?) for type #{valid_type}" do
|
20
|
+
Stanza::Presence.new.must_respond_to :"#{valid_type}?"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), *%w[..
|
1
|
+
require File.join(File.dirname(__FILE__), *%w[.. spec_helper])
|
2
2
|
|
3
3
|
describe 'Blather::Stream' do
|
4
4
|
class MockStream; include Stream; end
|
@@ -44,17 +44,108 @@ describe 'Blather::Stream' do
|
|
44
44
|
s.connection_completed
|
45
45
|
end
|
46
46
|
|
47
|
+
it 'sends stanzas to the client when the stream is ready' do
|
48
|
+
client = mock()
|
49
|
+
client.stubs(:jid=)
|
50
|
+
client.expects(:call)
|
51
|
+
stream = MockStream.new client, JID.new('n@d/r'), 'pass'
|
52
|
+
|
53
|
+
stream.expects(:send_data).with do |val|
|
54
|
+
val.must_match(/stream:stream/)
|
55
|
+
stream.receive_data "<stream:stream><message to='a@b/c' from='d@e/f' type='chat' xml:lang='en'><body>Message!</body></message>"
|
56
|
+
end
|
57
|
+
stream.connection_completed
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'puts itself in the stopped state when unbound' do
|
61
|
+
stream = mock_stream do |val|
|
62
|
+
val.must_match(/stream:stream/)
|
63
|
+
stream.receive_data "<stream:stream>"
|
64
|
+
|
65
|
+
stream.stopped?.wont_equal true
|
66
|
+
stream.unbind
|
67
|
+
stream.stopped?.must_equal true
|
68
|
+
end
|
69
|
+
stream.connection_completed
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'stops when sent </stream:stream>' do
|
73
|
+
state = nil
|
74
|
+
stream = mock_stream do |val|
|
75
|
+
case state
|
76
|
+
when nil
|
77
|
+
val.must_match(/stream:stream/)
|
78
|
+
state = :started
|
79
|
+
|
80
|
+
when :started
|
81
|
+
stream.stopped?.wont_equal true
|
82
|
+
state = :stopped
|
83
|
+
stream.receive_data "</stream:stream>"
|
84
|
+
true
|
85
|
+
|
86
|
+
when :stopped
|
87
|
+
stream.stopped?.must_equal true
|
88
|
+
val.must_equal "</stream:stream>"
|
89
|
+
true
|
90
|
+
|
91
|
+
else
|
92
|
+
false
|
93
|
+
|
94
|
+
end
|
95
|
+
end
|
96
|
+
stream.connection_completed
|
97
|
+
stream.receive_data "<stream:stream><stream:features><starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls' /></stream:features>"
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'raises an error when it receives stream:error' do
|
101
|
+
lambda do
|
102
|
+
state = nil
|
103
|
+
stream = mock_stream do |val|
|
104
|
+
case state
|
105
|
+
when nil
|
106
|
+
val.must_match(/stream:stream/)
|
107
|
+
state = :started
|
108
|
+
|
109
|
+
when :started
|
110
|
+
stream.stopped?.wont_equal true
|
111
|
+
state = :stopped
|
112
|
+
stream.receive_data "<stream:error><conflict xmlns='urn:ietf:params:xml:ns:xmpp-streams'/></stream:error>"
|
113
|
+
true
|
114
|
+
|
115
|
+
when :stopped
|
116
|
+
stream.stopped?.must_equal true
|
117
|
+
val.must_equal "</stream:stream>"
|
118
|
+
true
|
119
|
+
|
120
|
+
else
|
121
|
+
false
|
122
|
+
|
123
|
+
end
|
124
|
+
end
|
125
|
+
stream.connection_completed
|
126
|
+
stream.receive_data "<stream:stream><stream:features><starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls' /></stream:features>"
|
127
|
+
end.must_raise(StreamError)
|
128
|
+
end
|
129
|
+
|
47
130
|
it 'starts TLS when asked' do
|
48
131
|
state = nil
|
49
|
-
|
50
|
-
case
|
51
|
-
when
|
52
|
-
|
53
|
-
|
132
|
+
stream = mock_stream do |val|
|
133
|
+
case state
|
134
|
+
when nil
|
135
|
+
val.must_match(/stream:stream/)
|
136
|
+
state = :started
|
137
|
+
|
138
|
+
when :started
|
139
|
+
val.must_match(/starttls/)
|
140
|
+
true
|
141
|
+
|
142
|
+
else
|
143
|
+
false
|
144
|
+
|
54
145
|
end
|
55
146
|
end
|
56
|
-
|
57
|
-
|
147
|
+
stream.connection_completed
|
148
|
+
stream.receive_data "<stream:stream><stream:features><starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls' /></stream:features>"
|
58
149
|
end
|
59
150
|
|
60
151
|
it 'connects via SASL MD5 when asked' do
|
@@ -80,7 +171,7 @@ describe 'Blather::Stream' do
|
|
80
171
|
true
|
81
172
|
|
82
173
|
when :auth_sent
|
83
|
-
val.must_equal('<response xmlns="urn:ietf:params:xml:ns:xmpp-sasl">
|
174
|
+
val.must_equal('<response xmlns="urn:ietf:params:xml:ns:xmpp-sasl">bm9uY2U9Ik9BNk1HOXRFUUdtMmhoIixjaGFyc2V0PXV0Zi04LHVzZXJuYW1lPSJuIixyZWFsbT0ic29tZXJlYWxtIixjbm9uY2U9Ijc3N2Q0NWJiYmNkZjUwZDQ5YzQyYzcwYWQ3YWNmNWZlIixuYz0wMDAwMDAwMSxxb3A9YXV0aCxkaWdlc3QtdXJpPSJ4bXBwL2QiLHJlc3BvbnNlPTZiNTlhY2Q1ZWJmZjhjZTA0NTYzMGFiMDU2Zjg3MTdm</response>')
|
84
175
|
state = :response1_sent
|
85
176
|
stream.receive_data "<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>cnNwYXV0aD1lYTQwZjYwMzM1YzQyN2I1NTI3Yjg0ZGJhYmNkZmZmZAo=</challenge>"
|
86
177
|
true
|
@@ -170,6 +261,112 @@ describe 'Blather::Stream' do
|
|
170
261
|
stream.connection_completed
|
171
262
|
end
|
172
263
|
|
264
|
+
it 'tried each possible mechanism until it fails completely' do
|
265
|
+
state = nil
|
266
|
+
client = mock()
|
267
|
+
client.stubs(:jid=)
|
268
|
+
stream = MockStream.new client, JID.new('n@d/r'), 'pass'
|
269
|
+
|
270
|
+
stream.expects(:send_data).times(5).with do |val|
|
271
|
+
case state
|
272
|
+
when nil
|
273
|
+
val.must_match(/stream:stream/)
|
274
|
+
state = :started
|
275
|
+
stream.receive_data "<stream:stream><stream:features><mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><mechanism>DIGEST-MD5</mechanism><mechanism>PLAIN</mechanism><mechanism>ANONYMOUS</mechanism></mechanisms></stream:features>"
|
276
|
+
true
|
277
|
+
|
278
|
+
when :started
|
279
|
+
val.must_match(/mechanism="DIGEST-MD5"/)
|
280
|
+
state = :failed_md5
|
281
|
+
stream.receive_data "<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><not-authorized/></failure>"
|
282
|
+
true
|
283
|
+
|
284
|
+
when :failed_md5
|
285
|
+
val.must_match(/mechanism="PLAIN"/)
|
286
|
+
state = :failed_plain
|
287
|
+
stream.receive_data "<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><not-authorized/></failure>"
|
288
|
+
true
|
289
|
+
|
290
|
+
when :failed_plain
|
291
|
+
val.must_match(/mechanism="ANONYMOUS"/)
|
292
|
+
state = :failed_anon
|
293
|
+
stream.receive_data "<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><not-authorized/></failure>"
|
294
|
+
true
|
295
|
+
|
296
|
+
when :failed_anon
|
297
|
+
val.must_match(/\/stream:stream/)
|
298
|
+
state = :complete
|
299
|
+
true
|
300
|
+
|
301
|
+
else
|
302
|
+
false
|
303
|
+
|
304
|
+
end
|
305
|
+
end
|
306
|
+
stream.connection_completed
|
307
|
+
end
|
308
|
+
|
309
|
+
it 'tries each mechanism until it succeeds' do
|
310
|
+
state = nil
|
311
|
+
client = mock()
|
312
|
+
client.stubs(:jid=)
|
313
|
+
stream = MockStream.new client, JID.new('n@d/r'), 'pass'
|
314
|
+
|
315
|
+
stream.expects(:send_data).times(4).with do |val|
|
316
|
+
case state
|
317
|
+
when nil
|
318
|
+
val.must_match(/stream:stream/)
|
319
|
+
state = :started
|
320
|
+
stream.receive_data "<stream:stream><stream:features><mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><mechanism>DIGEST-MD5</mechanism><mechanism>PLAIN</mechanism><mechanism>ANONYMOUS</mechanism></mechanisms></stream:features>"
|
321
|
+
true
|
322
|
+
|
323
|
+
when :started
|
324
|
+
val.must_match(/mechanism="DIGEST-MD5"/)
|
325
|
+
state = :failed_md5
|
326
|
+
stream.receive_data "<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><not-authorized/></failure>"
|
327
|
+
true
|
328
|
+
|
329
|
+
when :failed_md5
|
330
|
+
val.must_match(/mechanism="PLAIN"/)
|
331
|
+
state = :plain_sent
|
332
|
+
stream.receive_data "<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>"
|
333
|
+
true
|
334
|
+
|
335
|
+
when :plain_sent
|
336
|
+
val.must_match(/stream:stream/)
|
337
|
+
state = :complete
|
338
|
+
true
|
339
|
+
|
340
|
+
else
|
341
|
+
false
|
342
|
+
|
343
|
+
end
|
344
|
+
end
|
345
|
+
stream.connection_completed
|
346
|
+
end
|
347
|
+
|
348
|
+
it 'raises an exception when an unknown mechanism is sent' do
|
349
|
+
state = nil
|
350
|
+
client = mock()
|
351
|
+
client.stubs(:jid=)
|
352
|
+
stream = MockStream.new client, JID.new('n@d/r'), 'pass'
|
353
|
+
|
354
|
+
stream.expects(:send_data).times(2).with do |val|
|
355
|
+
if !state
|
356
|
+
state = :started
|
357
|
+
val.must_match(/stream:stream/)
|
358
|
+
lambda do
|
359
|
+
stream.receive_data "<stream:stream><stream:features><mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><mechanism>UNKNOWN</mechanism></mechanisms></stream:features>"
|
360
|
+
end.must_raise(Stream::SASL::UnknownMechanism)
|
361
|
+
|
362
|
+
else
|
363
|
+
val.must_match(/failure(.*)invalid\-mechanism/)
|
364
|
+
|
365
|
+
end
|
366
|
+
end
|
367
|
+
stream.connection_completed
|
368
|
+
end
|
369
|
+
|
173
370
|
it 'will bind to a resource set by the server' do
|
174
371
|
state = nil
|
175
372
|
class Client; attr_accessor :jid; end
|
@@ -240,6 +437,7 @@ describe 'Blather::Stream' do
|
|
240
437
|
client.stubs(:jid=)
|
241
438
|
stream = MockStream.new client, JID.new('n@d/r'), 'pass'
|
242
439
|
|
440
|
+
client.expects(:stream_started)
|
243
441
|
stream.expects(:send_data).times(2).with do |val|
|
244
442
|
case state
|
245
443
|
when nil
|
@@ -251,6 +449,7 @@ describe 'Blather::Stream' do
|
|
251
449
|
when :started
|
252
450
|
val.must_match('<iq id="[^"]+" type="set" to="d"><session xmlns="urn:ietf:params:xml:ns:xmpp-session"/></iq>')
|
253
451
|
state = :completed
|
452
|
+
stream.receive_data "<iq from='d' type='result' id='#{val[/id="([^"]+)"/,1]}'/>"
|
254
453
|
true
|
255
454
|
|
256
455
|
else
|