blather 0.1 → 0.2
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.
- 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
|