|
1 /* Any copyright is dedicated to the Public Domain. |
|
2 * http://creativecommons.org/publicdomain/zero/1.0/ */ |
|
3 |
|
4 Cu.import("resource://services-common/async.js"); |
|
5 Cu.import("resource://services-common/tokenserverclient.js"); |
|
6 |
|
7 function run_test() { |
|
8 initTestLogging("Trace"); |
|
9 |
|
10 run_next_test(); |
|
11 } |
|
12 |
|
13 add_test(function test_working_bid_exchange() { |
|
14 _("Ensure that working BrowserID token exchange works as expected."); |
|
15 |
|
16 let service = "http://example.com/foo"; |
|
17 let duration = 300; |
|
18 |
|
19 let server = httpd_setup({ |
|
20 "/1.0/foo/1.0": function(request, response) { |
|
21 do_check_true(request.hasHeader("accept")); |
|
22 do_check_false(request.hasHeader("x-conditions-accepted")); |
|
23 do_check_eq("application/json", request.getHeader("accept")); |
|
24 |
|
25 response.setStatusLine(request.httpVersion, 200, "OK"); |
|
26 response.setHeader("Content-Type", "application/json"); |
|
27 |
|
28 let body = JSON.stringify({ |
|
29 id: "id", |
|
30 key: "key", |
|
31 api_endpoint: service, |
|
32 uid: "uid", |
|
33 duration: duration, |
|
34 }); |
|
35 response.bodyOutputStream.write(body, body.length); |
|
36 } |
|
37 }); |
|
38 |
|
39 let client = new TokenServerClient(); |
|
40 let cb = Async.makeSpinningCallback(); |
|
41 let url = server.baseURI + "/1.0/foo/1.0"; |
|
42 client.getTokenFromBrowserIDAssertion(url, "assertion", cb); |
|
43 let result = cb.wait(); |
|
44 do_check_eq("object", typeof(result)); |
|
45 do_check_attribute_count(result, 5); |
|
46 do_check_eq(service, result.endpoint); |
|
47 do_check_eq("id", result.id); |
|
48 do_check_eq("key", result.key); |
|
49 do_check_eq("uid", result.uid); |
|
50 do_check_eq(duration, result.duration); |
|
51 server.stop(run_next_test); |
|
52 }); |
|
53 |
|
54 add_test(function test_invalid_arguments() { |
|
55 _("Ensure invalid arguments to APIs are rejected."); |
|
56 |
|
57 let args = [ |
|
58 [null, "assertion", function() {}], |
|
59 ["http://example.com/", null, function() {}], |
|
60 ["http://example.com/", "assertion", null] |
|
61 ]; |
|
62 |
|
63 for each (let arg in args) { |
|
64 try { |
|
65 let client = new TokenServerClient(); |
|
66 client.getTokenFromBrowserIDAssertion(arg[0], arg[1], arg[2]); |
|
67 do_throw("Should never get here."); |
|
68 } catch (ex) { |
|
69 do_check_true(ex instanceof TokenServerClientError); |
|
70 } |
|
71 } |
|
72 |
|
73 run_next_test(); |
|
74 }); |
|
75 |
|
76 add_test(function test_conditions_required_response_handling() { |
|
77 _("Ensure that a conditions required response is handled properly."); |
|
78 |
|
79 let description = "Need to accept conditions"; |
|
80 let tosURL = "http://example.com/tos"; |
|
81 |
|
82 let server = httpd_setup({ |
|
83 "/1.0/foo/1.0": function(request, response) { |
|
84 do_check_false(request.hasHeader("x-conditions-accepted")); |
|
85 |
|
86 response.setStatusLine(request.httpVersion, 403, "Forbidden"); |
|
87 response.setHeader("Content-Type", "application/json"); |
|
88 |
|
89 let body = JSON.stringify({ |
|
90 errors: [{description: description, location: "body", name: ""}], |
|
91 urls: {tos: tosURL} |
|
92 }); |
|
93 response.bodyOutputStream.write(body, body.length); |
|
94 } |
|
95 }); |
|
96 |
|
97 let client = new TokenServerClient(); |
|
98 let url = server.baseURI + "/1.0/foo/1.0"; |
|
99 |
|
100 function onResponse(error, token) { |
|
101 do_check_true(error instanceof TokenServerClientServerError); |
|
102 do_check_eq(error.cause, "conditions-required"); |
|
103 do_check_null(token); |
|
104 |
|
105 do_check_eq(error.urls.tos, tosURL); |
|
106 |
|
107 server.stop(run_next_test); |
|
108 } |
|
109 |
|
110 client.getTokenFromBrowserIDAssertion(url, "assertion", onResponse); |
|
111 }); |
|
112 |
|
113 add_test(function test_invalid_403_no_content_type() { |
|
114 _("Ensure that a 403 without content-type is handled properly."); |
|
115 |
|
116 let server = httpd_setup({ |
|
117 "/1.0/foo/1.0": function(request, response) { |
|
118 response.setStatusLine(request.httpVersion, 403, "Forbidden"); |
|
119 // No Content-Type header by design. |
|
120 |
|
121 let body = JSON.stringify({ |
|
122 errors: [{description: "irrelevant", location: "body", name: ""}], |
|
123 urls: {foo: "http://bar"} |
|
124 }); |
|
125 response.bodyOutputStream.write(body, body.length); |
|
126 } |
|
127 }); |
|
128 |
|
129 let client = new TokenServerClient(); |
|
130 let url = server.baseURI + "/1.0/foo/1.0"; |
|
131 |
|
132 function onResponse(error, token) { |
|
133 do_check_true(error instanceof TokenServerClientServerError); |
|
134 do_check_eq(error.cause, "malformed-response"); |
|
135 do_check_null(token); |
|
136 |
|
137 do_check_null(error.urls); |
|
138 |
|
139 server.stop(run_next_test); |
|
140 } |
|
141 |
|
142 client.getTokenFromBrowserIDAssertion(url, "assertion", onResponse); |
|
143 }); |
|
144 |
|
145 add_test(function test_invalid_403_bad_json() { |
|
146 _("Ensure that a 403 with JSON that isn't proper is handled properly."); |
|
147 |
|
148 let server = httpd_setup({ |
|
149 "/1.0/foo/1.0": function(request, response) { |
|
150 response.setStatusLine(request.httpVersion, 403, "Forbidden"); |
|
151 response.setHeader("Content-Type", "application/json; charset=utf-8"); |
|
152 |
|
153 let body = JSON.stringify({ |
|
154 foo: "bar" |
|
155 }); |
|
156 response.bodyOutputStream.write(body, body.length); |
|
157 } |
|
158 }); |
|
159 |
|
160 let client = new TokenServerClient(); |
|
161 let url = server.baseURI + "/1.0/foo/1.0"; |
|
162 |
|
163 function onResponse(error, token) { |
|
164 do_check_true(error instanceof TokenServerClientServerError); |
|
165 do_check_eq(error.cause, "malformed-response"); |
|
166 do_check_null(token); |
|
167 do_check_null(error.urls); |
|
168 |
|
169 server.stop(run_next_test); |
|
170 } |
|
171 |
|
172 client.getTokenFromBrowserIDAssertion(url, "assertion", onResponse); |
|
173 }); |
|
174 |
|
175 add_test(function test_403_no_urls() { |
|
176 _("Ensure that a 403 without a urls field is handled properly."); |
|
177 |
|
178 let server = httpd_setup({ |
|
179 "/1.0/foo/1.0": function(request, response) { |
|
180 response.setStatusLine(request.httpVersion, 403, "Forbidden"); |
|
181 response.setHeader("Content-Type", "application/json; charset=utf-8"); |
|
182 |
|
183 let body = "{}"; |
|
184 response.bodyOutputStream.write(body, body.length); |
|
185 } |
|
186 }); |
|
187 |
|
188 let client = new TokenServerClient(); |
|
189 let url = server.baseURI + "/1.0/foo/1.0"; |
|
190 |
|
191 client.getTokenFromBrowserIDAssertion(url, "assertion", |
|
192 function onResponse(error, result) { |
|
193 do_check_true(error instanceof TokenServerClientServerError); |
|
194 do_check_eq(error.cause, "malformed-response"); |
|
195 do_check_null(result); |
|
196 |
|
197 server.stop(run_next_test); |
|
198 |
|
199 }); |
|
200 }); |
|
201 |
|
202 add_test(function test_send_extra_headers() { |
|
203 _("Ensures that the condition acceptance header is sent when asked."); |
|
204 |
|
205 let duration = 300; |
|
206 let server = httpd_setup({ |
|
207 "/1.0/foo/1.0": function(request, response) { |
|
208 do_check_true(request.hasHeader("x-foo")); |
|
209 do_check_eq(request.getHeader("x-foo"), "42"); |
|
210 |
|
211 do_check_true(request.hasHeader("x-bar")); |
|
212 do_check_eq(request.getHeader("x-bar"), "17"); |
|
213 |
|
214 response.setStatusLine(request.httpVersion, 200, "OK"); |
|
215 response.setHeader("Content-Type", "application/json"); |
|
216 |
|
217 let body = JSON.stringify({ |
|
218 id: "id", |
|
219 key: "key", |
|
220 api_endpoint: "http://example.com/", |
|
221 uid: "uid", |
|
222 duration: duration, |
|
223 }); |
|
224 response.bodyOutputStream.write(body, body.length); |
|
225 } |
|
226 }); |
|
227 |
|
228 let client = new TokenServerClient(); |
|
229 let url = server.baseURI + "/1.0/foo/1.0"; |
|
230 |
|
231 function onResponse(error, token) { |
|
232 do_check_null(error); |
|
233 |
|
234 // Other tests validate other things. |
|
235 |
|
236 server.stop(run_next_test); |
|
237 } |
|
238 |
|
239 let extra = { |
|
240 "X-Foo": 42, |
|
241 "X-Bar": 17 |
|
242 }; |
|
243 client.getTokenFromBrowserIDAssertion(url, "assertion", onResponse, extra); |
|
244 }); |
|
245 |
|
246 add_test(function test_error_404_empty() { |
|
247 _("Ensure that 404 responses without proper response are handled properly."); |
|
248 |
|
249 let server = httpd_setup(); |
|
250 |
|
251 let client = new TokenServerClient(); |
|
252 let url = server.baseURI + "/foo"; |
|
253 client.getTokenFromBrowserIDAssertion(url, "assertion", function(error, r) { |
|
254 do_check_true(error instanceof TokenServerClientServerError); |
|
255 do_check_eq(error.cause, "malformed-response"); |
|
256 |
|
257 do_check_neq(null, error.response); |
|
258 do_check_null(r); |
|
259 |
|
260 server.stop(run_next_test); |
|
261 }); |
|
262 }); |
|
263 |
|
264 add_test(function test_error_404_proper_response() { |
|
265 _("Ensure that a Cornice error report for 404 is handled properly."); |
|
266 |
|
267 let server = httpd_setup({ |
|
268 "/1.0/foo/1.0": function(request, response) { |
|
269 response.setStatusLine(request.httpVersion, 404, "Not Found"); |
|
270 response.setHeader("Content-Type", "application/json; charset=utf-8"); |
|
271 |
|
272 let body = JSON.stringify({ |
|
273 status: 404, |
|
274 errors: [{description: "No service", location: "body", name: ""}], |
|
275 }); |
|
276 |
|
277 response.bodyOutputStream.write(body, body.length); |
|
278 } |
|
279 }); |
|
280 |
|
281 function onResponse(error, token) { |
|
282 do_check_true(error instanceof TokenServerClientServerError); |
|
283 do_check_eq(error.cause, "unknown-service"); |
|
284 do_check_null(token); |
|
285 |
|
286 server.stop(run_next_test); |
|
287 } |
|
288 |
|
289 let client = new TokenServerClient(); |
|
290 let url = server.baseURI + "/1.0/foo/1.0"; |
|
291 client.getTokenFromBrowserIDAssertion(url, "assertion", onResponse); |
|
292 }); |
|
293 |
|
294 add_test(function test_bad_json() { |
|
295 _("Ensure that malformed JSON is handled properly."); |
|
296 |
|
297 let server = httpd_setup({ |
|
298 "/1.0/foo/1.0": function(request, response) { |
|
299 response.setStatusLine(request.httpVersion, 200, "OK"); |
|
300 response.setHeader("Content-Type", "application/json"); |
|
301 |
|
302 let body = '{"id": "id", baz}' |
|
303 response.bodyOutputStream.write(body, body.length); |
|
304 } |
|
305 }); |
|
306 |
|
307 let client = new TokenServerClient(); |
|
308 let url = server.baseURI + "/1.0/foo/1.0"; |
|
309 client.getTokenFromBrowserIDAssertion(url, "assertion", function(error, r) { |
|
310 do_check_neq(null, error); |
|
311 do_check_eq("TokenServerClientServerError", error.name); |
|
312 do_check_eq(error.cause, "malformed-response"); |
|
313 do_check_neq(null, error.response); |
|
314 do_check_eq(null, r); |
|
315 |
|
316 server.stop(run_next_test); |
|
317 }); |
|
318 }); |
|
319 |
|
320 add_test(function test_400_response() { |
|
321 _("Ensure HTTP 400 is converted to malformed-request."); |
|
322 |
|
323 let server = httpd_setup({ |
|
324 "/1.0/foo/1.0": function(request, response) { |
|
325 response.setStatusLine(request.httpVersion, 400, "Bad Request"); |
|
326 response.setHeader("Content-Type", "application/json; charset=utf-8"); |
|
327 |
|
328 let body = "{}"; // Actual content may not be used. |
|
329 response.bodyOutputStream.write(body, body.length); |
|
330 } |
|
331 }); |
|
332 |
|
333 let client = new TokenServerClient(); |
|
334 let url = server.baseURI + "/1.0/foo/1.0"; |
|
335 client.getTokenFromBrowserIDAssertion(url, "assertion", function(error, r) { |
|
336 do_check_neq(null, error); |
|
337 do_check_eq("TokenServerClientServerError", error.name); |
|
338 do_check_neq(null, error.response); |
|
339 do_check_eq(error.cause, "malformed-request"); |
|
340 |
|
341 server.stop(run_next_test); |
|
342 }); |
|
343 }); |
|
344 |
|
345 add_test(function test_401_with_error_cause() { |
|
346 _("Ensure 401 cause is specified in body.status"); |
|
347 |
|
348 let server = httpd_setup({ |
|
349 "/1.0/foo/1.0": function(request, response) { |
|
350 response.setStatusLine(request.httpVersion, 401, "Unauthorized"); |
|
351 response.setHeader("Content-Type", "application/json; charset=utf-8"); |
|
352 |
|
353 let body = JSON.stringify({status: "no-soup-for-you"}); |
|
354 response.bodyOutputStream.write(body, body.length); |
|
355 } |
|
356 }); |
|
357 |
|
358 let client = new TokenServerClient(); |
|
359 let url = server.baseURI + "/1.0/foo/1.0"; |
|
360 client.getTokenFromBrowserIDAssertion(url, "assertion", function(error, r) { |
|
361 do_check_neq(null, error); |
|
362 do_check_eq("TokenServerClientServerError", error.name); |
|
363 do_check_neq(null, error.response); |
|
364 do_check_eq(error.cause, "no-soup-for-you"); |
|
365 |
|
366 server.stop(run_next_test); |
|
367 }); |
|
368 }); |
|
369 |
|
370 add_test(function test_unhandled_media_type() { |
|
371 _("Ensure that unhandled media types throw an error."); |
|
372 |
|
373 let server = httpd_setup({ |
|
374 "/1.0/foo/1.0": function(request, response) { |
|
375 response.setStatusLine(request.httpVersion, 200, "OK"); |
|
376 response.setHeader("Content-Type", "text/plain"); |
|
377 |
|
378 let body = "hello, world"; |
|
379 response.bodyOutputStream.write(body, body.length); |
|
380 } |
|
381 }); |
|
382 |
|
383 let url = server.baseURI + "/1.0/foo/1.0"; |
|
384 let client = new TokenServerClient(); |
|
385 client.getTokenFromBrowserIDAssertion(url, "assertion", function(error, r) { |
|
386 do_check_neq(null, error); |
|
387 do_check_eq("TokenServerClientServerError", error.name); |
|
388 do_check_neq(null, error.response); |
|
389 do_check_eq(null, r); |
|
390 |
|
391 server.stop(run_next_test); |
|
392 }); |
|
393 }); |
|
394 |
|
395 add_test(function test_rich_media_types() { |
|
396 _("Ensure that extra tokens in the media type aren't rejected."); |
|
397 |
|
398 let duration = 300; |
|
399 let server = httpd_setup({ |
|
400 "/foo": function(request, response) { |
|
401 response.setStatusLine(request.httpVersion, 200, "OK"); |
|
402 response.setHeader("Content-Type", "application/json; foo=bar; bar=foo"); |
|
403 |
|
404 let body = JSON.stringify({ |
|
405 id: "id", |
|
406 key: "key", |
|
407 api_endpoint: "foo", |
|
408 uid: "uid", |
|
409 duration: duration, |
|
410 }); |
|
411 response.bodyOutputStream.write(body, body.length); |
|
412 } |
|
413 }); |
|
414 |
|
415 let url = server.baseURI + "/foo"; |
|
416 let client = new TokenServerClient(); |
|
417 client.getTokenFromBrowserIDAssertion(url, "assertion", function(error, r) { |
|
418 do_check_eq(null, error); |
|
419 |
|
420 server.stop(run_next_test); |
|
421 }); |
|
422 }); |
|
423 |
|
424 add_test(function test_exception_during_callback() { |
|
425 _("Ensure that exceptions thrown during callback handling are handled."); |
|
426 |
|
427 let duration = 300; |
|
428 let server = httpd_setup({ |
|
429 "/foo": function(request, response) { |
|
430 response.setStatusLine(request.httpVersion, 200, "OK"); |
|
431 response.setHeader("Content-Type", "application/json"); |
|
432 |
|
433 let body = JSON.stringify({ |
|
434 id: "id", |
|
435 key: "key", |
|
436 api_endpoint: "foo", |
|
437 uid: "uid", |
|
438 duration: duration, |
|
439 }); |
|
440 response.bodyOutputStream.write(body, body.length); |
|
441 } |
|
442 }); |
|
443 |
|
444 let url = server.baseURI + "/foo"; |
|
445 let client = new TokenServerClient(); |
|
446 let cb = Async.makeSpinningCallback(); |
|
447 let callbackCount = 0; |
|
448 |
|
449 client.getTokenFromBrowserIDAssertion(url, "assertion", function(error, r) { |
|
450 do_check_eq(null, error); |
|
451 |
|
452 cb(); |
|
453 |
|
454 callbackCount += 1; |
|
455 throw new Error("I am a bad function!"); |
|
456 }); |
|
457 |
|
458 cb.wait(); |
|
459 // This relies on some heavy event loop magic. The error in the main |
|
460 // callback should already have been raised at this point. |
|
461 do_check_eq(callbackCount, 1); |
|
462 |
|
463 server.stop(run_next_test); |
|
464 }); |