jabber4r-revive 0.9.0 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. data/.gitignore +5 -4
  2. data/.rspec +3 -3
  3. data/.travis.yml +7 -7
  4. data/CHANGELOG +11 -1
  5. data/Gemfile +3 -3
  6. data/README.md +29 -29
  7. data/Rakefile +70 -70
  8. data/jabber4r-revive.gemspec +25 -25
  9. data/lib/jabber4r.rb +38 -33
  10. data/lib/jabber4r/bosh.rb +21 -0
  11. data/lib/jabber4r/bosh/authentication.rb +13 -0
  12. data/lib/jabber4r/bosh/authentication/non_sasl.rb +219 -0
  13. data/lib/jabber4r/bosh/authentication/sasl.rb +239 -0
  14. data/lib/jabber4r/bosh/session.rb +144 -0
  15. data/lib/jabber4r/connection.rb +259 -258
  16. data/lib/jabber4r/debugger.rb +60 -60
  17. data/lib/jabber4r/jid.rb +20 -19
  18. data/lib/jabber4r/protocol.rb +249 -257
  19. data/lib/jabber4r/protocol/authentication.rb +14 -0
  20. data/lib/jabber4r/protocol/authentication/non_sasl.rb +138 -0
  21. data/lib/jabber4r/protocol/authentication/sasl.rb +88 -0
  22. data/lib/jabber4r/protocol/iq.rb +259 -259
  23. data/lib/jabber4r/protocol/message.rb +245 -245
  24. data/lib/jabber4r/protocol/parsed_xml_element.rb +207 -207
  25. data/lib/jabber4r/protocol/presence.rb +160 -160
  26. data/lib/jabber4r/protocol/xml_element.rb +143 -143
  27. data/lib/jabber4r/rexml_1.8_patch.rb +15 -15
  28. data/lib/jabber4r/roster.rb +38 -38
  29. data/lib/jabber4r/session.rb +615 -615
  30. data/lib/jabber4r/version.rb +10 -3
  31. data/spec/lib/jabber4r/bosh/authentication/non_sasl_spec.rb +79 -0
  32. data/spec/lib/jabber4r/bosh/authentication/sasl_spec.rb +42 -0
  33. data/spec/lib/jabber4r/bosh/session_spec.rb +406 -0
  34. data/spec/lib/jabber4r/bosh_spec.rb +0 -0
  35. data/spec/lib/jabber4r/connection_spec.rb +174 -174
  36. data/spec/lib/jabber4r/debugger_spec.rb +35 -35
  37. data/spec/lib/jabber4r/jid_spec.rb +197 -197
  38. data/spec/lib/jabber4r/protocol/authentication/non_sasl_spec.rb +79 -0
  39. data/spec/lib/jabber4r/protocol/authentication/sasl_spec.rb +42 -0
  40. data/spec/spec_helper.rb +11 -11
  41. data/spec/support/mocks/tcp_socket_mock.rb +8 -8
  42. metadata +61 -45
  43. data/Gemfile.lock +0 -45
  44. data/lib/jabber4r/bosh_session.rb +0 -224
  45. data/spec/lib/jabber4r/bosh_session_spec.rb +0 -150
@@ -1,3 +1,10 @@
1
- module Jabber
2
- VERSION = "0.9.0"
3
- end
1
+ # coding: utf-8
2
+
3
+ # License: see LICENSE
4
+ # Jabber4R - Jabber Instant Messaging Library for Ruby
5
+ # Copyright (C) 2002 Rich Kilmer <rich@infoether.com>
6
+ # Copyright (C) 2013 Sergey Fedorov <strech_ftf@mail.ru>
7
+
8
+ module Jabber
9
+ VERSION = "0.10.0"
10
+ end
@@ -0,0 +1,79 @@
1
+ # coding: utf-8
2
+ require "spec_helper"
3
+
4
+ describe Jabber::Bosh::Authentication::NonSASL::Query do
5
+ let(:jid) { Jabber::JID.new("strech@localhost/my-resource") }
6
+
7
+ describe "#initialize" do
8
+ context "when create plain non-sasl authentication" do
9
+ let(:auth) { described_class.new(jid, "my-password") }
10
+
11
+ it { expect(auth.stream_id).to be_nil }
12
+ end
13
+
14
+ context "when jid is a String" do
15
+ let(:auth) { described_class.new("hello@localhost/my-res", "my-password") }
16
+
17
+ it { expect { auth }.not_to raise_error TypeError }
18
+ end
19
+
20
+ context "when jid is not instance of Jabber::JID or String" do
21
+ let(:auth) { described_class.new(:hello, "my-password") }
22
+
23
+ it { expect { auth }.to raise_error TypeError }
24
+ end
25
+
26
+ context "when mechanism doesn't exists" do
27
+ let(:auth) { described_class.new("hello@localhost/my-res", "my-password", mechanism: :unknown) }
28
+
29
+ it { expect { auth }.to raise_error ArgumentError }
30
+ end
31
+
32
+ context "when mechanism is digest and no stream_id is given" do
33
+ let(:auth) { described_class.new("hello@localhost/my-res", "my-password", mechanism: :digest) }
34
+
35
+ it { expect { auth }.to raise_error KeyError }
36
+ end
37
+ end
38
+
39
+ describe "#plain" do
40
+ let(:auth) { described_class.new(jid, "my-password") }
41
+ let(:auth_xml) { auth.dump.strip.gsub(/[\r\n]+|\s{2,}/, "") }
42
+ let(:correct_xml) do
43
+ '<iq xmlns="jabber:client" type="set" id="auth2"><query xmlns="jabber:iq:auth">' +
44
+ '<username>strech</username><password>my-password</password>' +
45
+ '<resource>my-resource</resource></query></iq>'
46
+ end
47
+
48
+ before { Jabber.stub(:gen_random_id).and_return "auth2" }
49
+
50
+ it { expect(auth_xml).to eq correct_xml }
51
+ end
52
+
53
+ describe "#digest" do
54
+ let(:auth) { described_class.new(jid, "my-password", stream_id: 1, mechanism: :digest) }
55
+ let(:auth_xml) { auth.dump.strip.gsub(/[\r\n]+|\s{2,}/, "") }
56
+ let(:correct_xml) do
57
+ '<iq xmlns="jabber:client" type="set" id="auth2"><query xmlns="jabber:iq:auth">' +
58
+ '<username>strech</username><digest>0123456789</digest>' +
59
+ '<resource>my-resource</resource></query></iq>'
60
+ end
61
+
62
+ before { Jabber.stub(:gen_random_id).and_return "auth2" }
63
+ before { described_class.stub(:generate_digest).and_return "0123456789" }
64
+
65
+ it { expect(auth_xml).to eq correct_xml }
66
+ end
67
+
68
+ describe "#plain?" do
69
+ let(:auth) { described_class.new(jid, "my-password") }
70
+
71
+ it { expect(auth).to be_plain }
72
+ end
73
+
74
+ describe "#digest?" do
75
+ let(:auth) { described_class.new(jid, "my-password", mechanism: :digest, stream_id: 1) }
76
+
77
+ it { expect(auth).to be_digest }
78
+ end
79
+ end
@@ -0,0 +1,42 @@
1
+ # coding: utf-8
2
+ require "spec_helper"
3
+
4
+ describe Jabber::Bosh::Authentication::SASL::Query do
5
+ let(:jid) { Jabber::JID.new("strech@localhost/my-resource") }
6
+
7
+ describe "#initialize" do
8
+ context "when jid is a String" do
9
+ let(:auth) { described_class.new("hello@localhost/my-res", "my-password") }
10
+
11
+ it { expect { auth }.not_to raise_error TypeError }
12
+ end
13
+
14
+ context "when jid is not instance of Jabber::JID or String" do
15
+ let(:auth) { described_class.new(:hello, "my-password") }
16
+
17
+ it { expect { auth }.to raise_error TypeError }
18
+ end
19
+
20
+ context "when mechanism doesn't exists" do
21
+ let(:auth) { described_class.new("hello@localhost/my-res", "my-password", mechanism: :unknown) }
22
+
23
+ it { expect { auth }.to raise_error ArgumentError }
24
+ end
25
+ end
26
+
27
+ describe "#plain" do
28
+ let(:auth) { described_class.new(jid, "my-password") }
29
+ let(:auth_xml) { auth.dump.strip.gsub(/[\r\n]+|\s{2,}/, "") }
30
+ let(:correct_xml) { '<auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" mechanism="PLAIN">0123456789</auth>' }
31
+
32
+ before { described_class.stub(:generate_plain).and_return "0123456789" }
33
+
34
+ it { expect(auth_xml).to eq correct_xml }
35
+ end
36
+
37
+ describe "#plain?" do
38
+ let(:auth) { described_class.new(jid, "my-password") }
39
+
40
+ it { expect(auth).to be_plain }
41
+ end
42
+ end
@@ -0,0 +1,406 @@
1
+ # coding: utf-8
2
+ require "spec_helper"
3
+
4
+ describe Jabber::Bosh::Session do
5
+ before { described_class.any_instance.stub(:rand).and_return 1 }
6
+
7
+ describe "#bind" do
8
+ context "when server accept sasl authentication" do
9
+ let(:bosh_session) { described_class.bind("strech@localhost/resource", "password") }
10
+
11
+ let(:successful_login) { '<body xmlns="http://jabber.org/protocol/httpbind"><success xmlns="urn:ietf:params:xml:ns:xmpp-sasl"/></body>' }
12
+ let(:successful_open_stream) do
13
+ [
14
+ '<body xmlns="http://jabber.org/protocol/httpbind" xmlns:xmpp="urn:xmpp:xbosh" xmlns:stream="http://etherx.jabber.org/streams"' +
15
+ 'charsets="UTF-8" from="localhost" hold="1" inactivity="20" polling="5" requests="2" sid="67d63e06-4159-43e2-9cb8-544de83eae58"' +
16
+ 'ver="1.6" wait="60" xmpp:version="1.0"><stream:features><mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><mechanism>PLAIN</mechanism>' +
17
+ '</mechanisms></stream:features></body>'
18
+ ].join " "
19
+ end
20
+ let(:successful_restart) do
21
+ [
22
+ '<body xmlns="http://jabber.org/protocol/httpbind" xmlns:stream="http://etherx.jabber.org/streams">' +
23
+ '<stream:features><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"/></stream:features></body>'
24
+ ].join " "
25
+ end
26
+ let(:successful_bind) do
27
+ [
28
+ '<body xmlns="http://jabber.org/protocol/httpbind"><iq id="Jabber4R_f7e7fc2a10013070" type="result">' +
29
+ '<bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"><jid>strech@localhost/resource</jid></bind></iq></body>'
30
+ ].join " "
31
+ end
32
+
33
+ let(:is_open_stream?) { ->(data) { x = Ox.parse(data); "2" == x[:rid] } }
34
+ let(:is_login?) { ->(data) { x = Ox.parse(data); "3" == x[:rid] && !x.locate("auth").empty? } }
35
+ let(:is_restart?) { ->(data) { x = Ox.parse(data); "4" == x[:rid] && x["xmpp:restart"] = "true" } }
36
+ let(:is_bind?) { ->(data) { x = Ox.parse(data); "5" == x[:rid] && !x.locate("iq/bind").empty? } }
37
+
38
+ context "when session successfuly binded" do
39
+ before do
40
+ stub_request(:post, "http://localhost:5280/http-bind")
41
+ .with(body: is_open_stream?)
42
+ .to_return(body: successful_open_stream)
43
+
44
+ stub_request(:post, "http://localhost:5280/http-bind")
45
+ .with(body: is_login?)
46
+ .to_return(body: successful_login)
47
+
48
+ stub_request(:post, "http://localhost:5280/http-bind")
49
+ .with(body: is_restart?)
50
+ .to_return(body: successful_restart)
51
+
52
+ stub_request(:post, "http://localhost:5280/http-bind")
53
+ .with(body: is_bind?)
54
+ .to_return(body: successful_bind)
55
+ end
56
+
57
+ it { expect(bosh_session).to be_alive }
58
+ end
59
+
60
+ context "when couldn't open stream" do
61
+ context "when response body missed sid attribute" do
62
+ let(:malformed_body) { '<body xmlns="http://jabber.org/protocol/httpbind" xmlns:xmpp="urn:xmpp:xbosh" xmlns:stream="http://etherx.jabber.org/streams"/>' }
63
+
64
+ before do
65
+ stub_request(:post, "http://localhost:5280/http-bind")
66
+ .with(body: is_open_stream?)
67
+ .to_return(body: malformed_body)
68
+
69
+ WebMock.should_not have_requested(:post, "http://localhost:5280/http-bind")
70
+ .with(body: is_login?)
71
+
72
+ WebMock.should_not have_requested(:post, "http://localhost:5280/http-bind")
73
+ .with(body: is_restart?)
74
+
75
+ WebMock.should_not have_requested(:post, "http://localhost:5280/http-bind")
76
+ .with(body: is_bind?)
77
+ end
78
+
79
+ it { expect { bosh_session }.to raise_error Jabber::XMLMalformedError, "Couldn't find <body /> attribute [sid]" }
80
+ end
81
+
82
+ context "when response was not 200 OK" do
83
+ before do
84
+ stub_request(:post, "http://localhost:5280/http-bind")
85
+ .with(body: is_open_stream?)
86
+ .to_return(body: "Foo", status: 401)
87
+
88
+ WebMock.should_not have_requested(:post, "http://localhost:5280/http-bind")
89
+ .with(body: is_login?)
90
+
91
+ WebMock.should_not have_requested(:post, "http://localhost:5280/http-bind")
92
+ .with(body: is_restart?)
93
+
94
+ WebMock.should_not have_requested(:post, "http://localhost:5280/http-bind")
95
+ .with(body: is_bind?)
96
+ end
97
+
98
+ it { expect { bosh_session }.to raise_error Net::HTTPBadResponse }
99
+ end
100
+ end
101
+
102
+ context "when couldn't login in opened stream" do
103
+ context "when response has no auth mechanisms" do
104
+ let(:malformed_body) do
105
+ [
106
+ '<body xmlns="http://jabber.org/protocol/httpbind" xmlns:xmpp="urn:xmpp:xbosh" xmlns:stream="http://etherx.jabber.org/streams"' +
107
+ 'charsets="UTF-8" from="localhost" hold="1" inactivity="20" polling="5" requests="2" sid="67d63e06-4159-43e2-9cb8-544de83eae58"' +
108
+ 'ver="1.6" wait="60" xmpp:version="1.0"/>'
109
+ ].join " "
110
+ end
111
+
112
+ before do
113
+ stub_request(:post, "http://localhost:5280/http-bind")
114
+ .with(body: is_open_stream?)
115
+ .to_return(body: malformed_body)
116
+
117
+ WebMock.should_not have_requested(:post, "http://localhost:5280/http-bind")
118
+ .with(body: is_login?)
119
+
120
+ WebMock.should_not have_requested(:post, "http://localhost:5280/http-bind")
121
+ .with(body: is_restart?)
122
+
123
+ WebMock.should_not have_requested(:post, "http://localhost:5280/http-bind")
124
+ .with(body: is_bind?)
125
+ end
126
+
127
+ it { expect { bosh_session }.to raise_error TypeError, "Server SASL mechanisms not include PLAIN mechanism" }
128
+ end
129
+
130
+ context "when response has type not equal 'success'" do
131
+ let(:malformed_body) { '<body xmlns="http://jabber.org/protocol/httpbind"><error xmlns="urn:ietf:params:xml:ns:xmpp-sasl"/></body>' }
132
+
133
+ before do
134
+ stub_request(:post, "http://localhost:5280/http-bind")
135
+ .with(body: is_open_stream?)
136
+ .to_return(body: successful_open_stream)
137
+
138
+ stub_request(:post, "http://localhost:5280/http-bind")
139
+ .with(body: is_login?)
140
+ .to_return(body: malformed_body)
141
+
142
+ WebMock.should_not have_requested(:post, "http://localhost:5280/http-bind")
143
+ .with(body: is_restart?)
144
+
145
+ WebMock.should_not have_requested(:post, "http://localhost:5280/http-bind")
146
+ .with(body: is_bind?)
147
+ end
148
+
149
+ it { expect { bosh_session }.to raise_error Jabber::AuthenticationError, "Failed to login" }
150
+ end
151
+
152
+ context "when response was not 200 OK" do
153
+ before do
154
+ stub_request(:post, "http://localhost:5280/http-bind")
155
+ .with(body: is_open_stream?)
156
+ .to_return(body: successful_open_stream)
157
+
158
+ stub_request(:post, "http://localhost:5280/http-bind")
159
+ .with(body: is_login?)
160
+ .to_return(body: "Foo", status: 401)
161
+
162
+ WebMock.should_not have_requested(:post, "http://localhost:5280/http-bind")
163
+ .with(body: is_restart?)
164
+
165
+ WebMock.should_not have_requested(:post, "http://localhost:5280/http-bind")
166
+ .with(body: is_bind?)
167
+ end
168
+
169
+ it { expect { bosh_session }.to raise_error Net::HTTPBadResponse }
170
+ end
171
+ end
172
+
173
+ context "when cann't restart opened stream" do
174
+ let(:malformed_body) { '<body xmlns="http://jabber.org/protocol/httpbind" xmlns:stream="http://etherx.jabber.org/streams"><error xmlns="urn:ietf:params:xml:ns:xmpp-sasl"/></body>' }
175
+
176
+ before do
177
+ stub_request(:post, "http://localhost:5280/http-bind")
178
+ .with(body: is_open_stream?)
179
+ .to_return(body: successful_open_stream)
180
+
181
+ stub_request(:post, "http://localhost:5280/http-bind")
182
+ .with(body: is_login?)
183
+ .to_return(body: successful_login)
184
+
185
+ stub_request(:post, "http://localhost:5280/http-bind")
186
+ .with(body: is_restart?)
187
+ .to_return(body: malformed_body)
188
+
189
+ WebMock.should_not have_requested(:post, "http://localhost:5280/http-bind")
190
+ .with(body: is_bind?)
191
+ end
192
+
193
+ it { expect { bosh_session }.to raise_error Jabber::AuthenticationError, "Failed to login" }
194
+ end
195
+
196
+ context "when cann't bind resource on opened stream" do
197
+ context "when response is a malformed xml without IQ tag" do
198
+ let(:malformed_body) { '<body xmlns="http://jabber.org/protocol/httpbind"></body>' }
199
+
200
+ before do
201
+ stub_request(:post, "http://localhost:5280/http-bind")
202
+ .with(body: is_open_stream?)
203
+ .to_return(body: successful_open_stream)
204
+
205
+ stub_request(:post, "http://localhost:5280/http-bind")
206
+ .with(body: is_login?)
207
+ .to_return(body: successful_login)
208
+
209
+ stub_request(:post, "http://localhost:5280/http-bind")
210
+ .with(body: is_restart?)
211
+ .to_return(body: successful_restart)
212
+
213
+ stub_request(:post, "http://localhost:5280/http-bind")
214
+ .with(body: is_bind?)
215
+ .to_return(body: malformed_body)
216
+ end
217
+
218
+ it { expect { bosh_session }.to raise_error Jabber::XMLMalformedError, "Couldn't find xml tag <iq/>" }
219
+ end
220
+
221
+ context "when response has type not equal 'result'" do
222
+ let(:malformed_body) { '<body xmlns="http://jabber.org/protocol/httpbind"><iq id="Jabber4R_f7e7fc2a10013070" type="error"/></body>' }
223
+
224
+ before do
225
+ stub_request(:post, "http://localhost:5280/http-bind")
226
+ .with(body: is_open_stream?)
227
+ .to_return(body: successful_open_stream)
228
+
229
+ stub_request(:post, "http://localhost:5280/http-bind")
230
+ .with(body: is_login?)
231
+ .to_return(body: successful_login)
232
+
233
+ stub_request(:post, "http://localhost:5280/http-bind")
234
+ .with(body: is_restart?)
235
+ .to_return(body: successful_restart)
236
+
237
+ stub_request(:post, "http://localhost:5280/http-bind")
238
+ .with(body: is_bind?)
239
+ .to_return(body: malformed_body)
240
+ end
241
+
242
+ it { expect { bosh_session }.to raise_error Jabber::AuthenticationError, "Failed to login" }
243
+ end
244
+ end
245
+ end
246
+
247
+ # REFACTOR ALL
248
+
249
+ context "when server accept non-sasl authentication" do
250
+ let(:bosh_session) { described_class.bind("strech@localhost/resource", "password", use_sasl: false) }
251
+
252
+ let(:successful_login) { '<body xmlns="http://jabber.org/protocol/httpbind"><iq type="result" xmlns="jabber:client" id="2034"/></body>' }
253
+ let(:successful_open_stream) do
254
+ [
255
+ '<body xmlns="http://jabber.org/protocol/httpbind" xmlns:xmpp="urn:xmpp:xbosh" xmlns:stream="http://etherx.jabber.org/streams"',
256
+ 'authid="3780309894" sid="ce21410" from="localhost" xmpp:version="1.0"',
257
+ 'wait="60" requests="2" inactivity="30" maxpause="120" polling="2" ver="1.8" secure="true" />'
258
+ ].join " "
259
+ end
260
+ let(:is_open_stream?) { ->(data) { x = Ox.parse(data); ["2", "localhost"] == [x[:rid], x[:to]] } }
261
+ let(:is_login?) { ->(data) { x = Ox.parse(data); ["3", "ce21410"] == [x[:rid], x[:sid]] } }
262
+
263
+ context "when session successfuly binded" do
264
+ before do
265
+ stub_request(:post, "http://localhost:5280/http-bind")
266
+ .with(body: is_open_stream?)
267
+ .to_return(body: successful_open_stream)
268
+
269
+ stub_request(:post, "http://localhost:5280/http-bind")
270
+ .with(body: is_login?)
271
+ .to_return(body: successful_login)
272
+ end
273
+
274
+ it { expect(bosh_session).to be_alive }
275
+ end
276
+
277
+ context "when couldn't open stream" do
278
+ context "when response body missed authid attribute" do
279
+ let(:malformed_body) { '<body xmlns="http://jabber.org/protocol/httpbind" sid="ce21410" />' }
280
+
281
+ before do
282
+ stub_request(:post, "http://localhost:5280/http-bind")
283
+ .with(body: is_open_stream?)
284
+ .to_return(body: malformed_body)
285
+
286
+ WebMock.should_not have_requested(:post, "http://localhost:5280/http-bind")
287
+ .with(body: is_login?)
288
+ end
289
+
290
+ it { expect { bosh_session }.to raise_error Jabber::XMLMalformedError, "Couldn't find <body /> attribute [authid]" }
291
+ end
292
+
293
+ context "when response body missed sid attribute" do
294
+ let(:malformed_body) { '<body xmlns="http://jabber.org/protocol/httpbind" authid="3780309894" />' }
295
+
296
+ before do
297
+ stub_request(:post, "http://localhost:5280/http-bind")
298
+ .with(body: is_open_stream?)
299
+ .to_return(body: malformed_body)
300
+
301
+ WebMock.should_not have_requested(:post, "http://localhost:5280/http-bind")
302
+ .with(body: is_login?)
303
+ end
304
+
305
+ it { expect { bosh_session }.to raise_error Jabber::XMLMalformedError, "Couldn't find <body /> attribute [sid]" }
306
+ end
307
+
308
+ context "when response was not 200 OK" do
309
+ before do
310
+ stub_request(:post, "http://localhost:5280/http-bind")
311
+ .with(body: is_open_stream?)
312
+ .to_return(body: "Foo", status: 401)
313
+
314
+ WebMock.should_not have_requested(:post, "http://localhost:5280/http-bind")
315
+ .with(body: is_login?)
316
+ end
317
+
318
+ it { expect { bosh_session }.to raise_error Net::HTTPBadResponse }
319
+ end
320
+ end
321
+
322
+ context "when couldn't login in opened stream" do
323
+ context "when response is a malformed xml without IQ tag" do
324
+ let(:malformed_body) { '<body xmlns="http://jabber.org/protocol/httpbind"></body>' }
325
+
326
+ before do
327
+ stub_request(:post, "http://localhost:5280/http-bind")
328
+ .with(body: is_open_stream?)
329
+ .to_return(body: successful_open_stream)
330
+
331
+ stub_request(:post, "http://localhost:5280/http-bind")
332
+ .with(body: is_login?)
333
+ .to_return(body: malformed_body)
334
+ end
335
+
336
+ it { expect { bosh_session }.to raise_error Jabber::XMLMalformedError, "Couldn't find xml tag <iq/>" }
337
+ end
338
+
339
+ context "when response has type not equal 'result'" do
340
+ let(:malformed_body) { '<body xmlns="http://jabber.org/protocol/httpbind"><iq type="error" xmlns="jabber:client" id="2034"/></body>' }
341
+
342
+ before do
343
+ stub_request(:post, "http://localhost:5280/http-bind")
344
+ .with(body: is_open_stream?)
345
+ .to_return(body: successful_open_stream)
346
+
347
+ stub_request(:post, "http://localhost:5280/http-bind")
348
+ .with(body: is_login?)
349
+ .to_return(body: malformed_body)
350
+ end
351
+
352
+ it { expect { bosh_session }.to raise_error Jabber::AuthenticationError, "Failed to login" }
353
+ end
354
+
355
+ context "when response was not 200 OK" do
356
+ before do
357
+ stub_request(:post, "http://localhost:5280/http-bind")
358
+ .with(body: is_open_stream?)
359
+ .to_return(body: successful_open_stream)
360
+
361
+ stub_request(:post, "http://localhost:5280/http-bind")
362
+ .with(body: is_login?)
363
+ .to_return(body: "Foo", status: 401)
364
+ end
365
+
366
+ it { expect { bosh_session }.to raise_error Net::HTTPBadResponse }
367
+ end
368
+ end
369
+ end
370
+ end
371
+
372
+ describe "#to_json" do
373
+ let(:bosh_session) { described_class.bind("strech@localhost/resource", "password", use_sasl: false) }
374
+ let(:successful_login) { '<body xmlns="http://jabber.org/protocol/httpbind"><iq type="result" xmlns="jabber:client" id="2034"/></body>' }
375
+ let(:successful_open_stream) do
376
+ [
377
+ '<body xmlns="http://jabber.org/protocol/httpbind" xmlns:xmpp="urn:xmpp:xbosh" xmlns:stream="http://etherx.jabber.org/streams"',
378
+ 'authid="3780309894" sid="ce21410" from="localhost" xmpp:version="1.0"',
379
+ 'wait="60" requests="2" inactivity="30" maxpause="120" polling="2" ver="1.8" secure="true" />'
380
+ ].join " "
381
+ end
382
+ let(:is_open_stream?) { ->(data) { x = Ox.parse(data); ["2", "localhost"] == [x[:rid], x[:to]] } }
383
+ let(:is_login?) { ->(data) { x = Ox.parse(data); ["3", "ce21410"] == [x[:rid], x[:sid]] } }
384
+
385
+ let(:json) { JSON.parse(bosh_session.to_json) }
386
+
387
+ before do
388
+ stub_request(:post, "http://localhost:5280/http-bind")
389
+ .with(body: is_open_stream?)
390
+ .to_return(body: successful_open_stream)
391
+
392
+
393
+ stub_request(:post, "http://localhost:5280/http-bind")
394
+ .with(body: is_login?)
395
+ .to_return(body: successful_login)
396
+ end
397
+
398
+ it { expect(json).to have_key "jid" }
399
+ it { expect(json).to have_key "rid" }
400
+ it { expect(json).to have_key "sid" }
401
+
402
+ it { expect(json["jid"]).to eq "strech@localhost/resource"}
403
+ it { expect(json["rid"]).to eq 3}
404
+ it { expect(json["sid"]).to eq "ce21410"}
405
+ end
406
+ end