michael@0: /* Any copyright is dedicated to the Public Domain. michael@0: * http://creativecommons.org/publicdomain/zero/1.0/ */ michael@0: michael@0: Cu.import("resource://services-common/async.js"); michael@0: Cu.import("resource://services-common/tokenserverclient.js"); michael@0: michael@0: function run_test() { michael@0: initTestLogging("Trace"); michael@0: michael@0: run_next_test(); michael@0: } michael@0: michael@0: add_test(function test_working_bid_exchange() { michael@0: _("Ensure that working BrowserID token exchange works as expected."); michael@0: michael@0: let service = "http://example.com/foo"; michael@0: let duration = 300; michael@0: michael@0: let server = httpd_setup({ michael@0: "/1.0/foo/1.0": function(request, response) { michael@0: do_check_true(request.hasHeader("accept")); michael@0: do_check_false(request.hasHeader("x-conditions-accepted")); michael@0: do_check_eq("application/json", request.getHeader("accept")); michael@0: michael@0: response.setStatusLine(request.httpVersion, 200, "OK"); michael@0: response.setHeader("Content-Type", "application/json"); michael@0: michael@0: let body = JSON.stringify({ michael@0: id: "id", michael@0: key: "key", michael@0: api_endpoint: service, michael@0: uid: "uid", michael@0: duration: duration, michael@0: }); michael@0: response.bodyOutputStream.write(body, body.length); michael@0: } michael@0: }); michael@0: michael@0: let client = new TokenServerClient(); michael@0: let cb = Async.makeSpinningCallback(); michael@0: let url = server.baseURI + "/1.0/foo/1.0"; michael@0: client.getTokenFromBrowserIDAssertion(url, "assertion", cb); michael@0: let result = cb.wait(); michael@0: do_check_eq("object", typeof(result)); michael@0: do_check_attribute_count(result, 5); michael@0: do_check_eq(service, result.endpoint); michael@0: do_check_eq("id", result.id); michael@0: do_check_eq("key", result.key); michael@0: do_check_eq("uid", result.uid); michael@0: do_check_eq(duration, result.duration); michael@0: server.stop(run_next_test); michael@0: }); michael@0: michael@0: add_test(function test_invalid_arguments() { michael@0: _("Ensure invalid arguments to APIs are rejected."); michael@0: michael@0: let args = [ michael@0: [null, "assertion", function() {}], michael@0: ["http://example.com/", null, function() {}], michael@0: ["http://example.com/", "assertion", null] michael@0: ]; michael@0: michael@0: for each (let arg in args) { michael@0: try { michael@0: let client = new TokenServerClient(); michael@0: client.getTokenFromBrowserIDAssertion(arg[0], arg[1], arg[2]); michael@0: do_throw("Should never get here."); michael@0: } catch (ex) { michael@0: do_check_true(ex instanceof TokenServerClientError); michael@0: } michael@0: } michael@0: michael@0: run_next_test(); michael@0: }); michael@0: michael@0: add_test(function test_conditions_required_response_handling() { michael@0: _("Ensure that a conditions required response is handled properly."); michael@0: michael@0: let description = "Need to accept conditions"; michael@0: let tosURL = "http://example.com/tos"; michael@0: michael@0: let server = httpd_setup({ michael@0: "/1.0/foo/1.0": function(request, response) { michael@0: do_check_false(request.hasHeader("x-conditions-accepted")); michael@0: michael@0: response.setStatusLine(request.httpVersion, 403, "Forbidden"); michael@0: response.setHeader("Content-Type", "application/json"); michael@0: michael@0: let body = JSON.stringify({ michael@0: errors: [{description: description, location: "body", name: ""}], michael@0: urls: {tos: tosURL} michael@0: }); michael@0: response.bodyOutputStream.write(body, body.length); michael@0: } michael@0: }); michael@0: michael@0: let client = new TokenServerClient(); michael@0: let url = server.baseURI + "/1.0/foo/1.0"; michael@0: michael@0: function onResponse(error, token) { michael@0: do_check_true(error instanceof TokenServerClientServerError); michael@0: do_check_eq(error.cause, "conditions-required"); michael@0: do_check_null(token); michael@0: michael@0: do_check_eq(error.urls.tos, tosURL); michael@0: michael@0: server.stop(run_next_test); michael@0: } michael@0: michael@0: client.getTokenFromBrowserIDAssertion(url, "assertion", onResponse); michael@0: }); michael@0: michael@0: add_test(function test_invalid_403_no_content_type() { michael@0: _("Ensure that a 403 without content-type is handled properly."); michael@0: michael@0: let server = httpd_setup({ michael@0: "/1.0/foo/1.0": function(request, response) { michael@0: response.setStatusLine(request.httpVersion, 403, "Forbidden"); michael@0: // No Content-Type header by design. michael@0: michael@0: let body = JSON.stringify({ michael@0: errors: [{description: "irrelevant", location: "body", name: ""}], michael@0: urls: {foo: "http://bar"} michael@0: }); michael@0: response.bodyOutputStream.write(body, body.length); michael@0: } michael@0: }); michael@0: michael@0: let client = new TokenServerClient(); michael@0: let url = server.baseURI + "/1.0/foo/1.0"; michael@0: michael@0: function onResponse(error, token) { michael@0: do_check_true(error instanceof TokenServerClientServerError); michael@0: do_check_eq(error.cause, "malformed-response"); michael@0: do_check_null(token); michael@0: michael@0: do_check_null(error.urls); michael@0: michael@0: server.stop(run_next_test); michael@0: } michael@0: michael@0: client.getTokenFromBrowserIDAssertion(url, "assertion", onResponse); michael@0: }); michael@0: michael@0: add_test(function test_invalid_403_bad_json() { michael@0: _("Ensure that a 403 with JSON that isn't proper is handled properly."); michael@0: michael@0: let server = httpd_setup({ michael@0: "/1.0/foo/1.0": function(request, response) { michael@0: response.setStatusLine(request.httpVersion, 403, "Forbidden"); michael@0: response.setHeader("Content-Type", "application/json; charset=utf-8"); michael@0: michael@0: let body = JSON.stringify({ michael@0: foo: "bar" michael@0: }); michael@0: response.bodyOutputStream.write(body, body.length); michael@0: } michael@0: }); michael@0: michael@0: let client = new TokenServerClient(); michael@0: let url = server.baseURI + "/1.0/foo/1.0"; michael@0: michael@0: function onResponse(error, token) { michael@0: do_check_true(error instanceof TokenServerClientServerError); michael@0: do_check_eq(error.cause, "malformed-response"); michael@0: do_check_null(token); michael@0: do_check_null(error.urls); michael@0: michael@0: server.stop(run_next_test); michael@0: } michael@0: michael@0: client.getTokenFromBrowserIDAssertion(url, "assertion", onResponse); michael@0: }); michael@0: michael@0: add_test(function test_403_no_urls() { michael@0: _("Ensure that a 403 without a urls field is handled properly."); michael@0: michael@0: let server = httpd_setup({ michael@0: "/1.0/foo/1.0": function(request, response) { michael@0: response.setStatusLine(request.httpVersion, 403, "Forbidden"); michael@0: response.setHeader("Content-Type", "application/json; charset=utf-8"); michael@0: michael@0: let body = "{}"; michael@0: response.bodyOutputStream.write(body, body.length); michael@0: } michael@0: }); michael@0: michael@0: let client = new TokenServerClient(); michael@0: let url = server.baseURI + "/1.0/foo/1.0"; michael@0: michael@0: client.getTokenFromBrowserIDAssertion(url, "assertion", michael@0: function onResponse(error, result) { michael@0: do_check_true(error instanceof TokenServerClientServerError); michael@0: do_check_eq(error.cause, "malformed-response"); michael@0: do_check_null(result); michael@0: michael@0: server.stop(run_next_test); michael@0: michael@0: }); michael@0: }); michael@0: michael@0: add_test(function test_send_extra_headers() { michael@0: _("Ensures that the condition acceptance header is sent when asked."); michael@0: michael@0: let duration = 300; michael@0: let server = httpd_setup({ michael@0: "/1.0/foo/1.0": function(request, response) { michael@0: do_check_true(request.hasHeader("x-foo")); michael@0: do_check_eq(request.getHeader("x-foo"), "42"); michael@0: michael@0: do_check_true(request.hasHeader("x-bar")); michael@0: do_check_eq(request.getHeader("x-bar"), "17"); michael@0: michael@0: response.setStatusLine(request.httpVersion, 200, "OK"); michael@0: response.setHeader("Content-Type", "application/json"); michael@0: michael@0: let body = JSON.stringify({ michael@0: id: "id", michael@0: key: "key", michael@0: api_endpoint: "http://example.com/", michael@0: uid: "uid", michael@0: duration: duration, michael@0: }); michael@0: response.bodyOutputStream.write(body, body.length); michael@0: } michael@0: }); michael@0: michael@0: let client = new TokenServerClient(); michael@0: let url = server.baseURI + "/1.0/foo/1.0"; michael@0: michael@0: function onResponse(error, token) { michael@0: do_check_null(error); michael@0: michael@0: // Other tests validate other things. michael@0: michael@0: server.stop(run_next_test); michael@0: } michael@0: michael@0: let extra = { michael@0: "X-Foo": 42, michael@0: "X-Bar": 17 michael@0: }; michael@0: client.getTokenFromBrowserIDAssertion(url, "assertion", onResponse, extra); michael@0: }); michael@0: michael@0: add_test(function test_error_404_empty() { michael@0: _("Ensure that 404 responses without proper response are handled properly."); michael@0: michael@0: let server = httpd_setup(); michael@0: michael@0: let client = new TokenServerClient(); michael@0: let url = server.baseURI + "/foo"; michael@0: client.getTokenFromBrowserIDAssertion(url, "assertion", function(error, r) { michael@0: do_check_true(error instanceof TokenServerClientServerError); michael@0: do_check_eq(error.cause, "malformed-response"); michael@0: michael@0: do_check_neq(null, error.response); michael@0: do_check_null(r); michael@0: michael@0: server.stop(run_next_test); michael@0: }); michael@0: }); michael@0: michael@0: add_test(function test_error_404_proper_response() { michael@0: _("Ensure that a Cornice error report for 404 is handled properly."); michael@0: michael@0: let server = httpd_setup({ michael@0: "/1.0/foo/1.0": function(request, response) { michael@0: response.setStatusLine(request.httpVersion, 404, "Not Found"); michael@0: response.setHeader("Content-Type", "application/json; charset=utf-8"); michael@0: michael@0: let body = JSON.stringify({ michael@0: status: 404, michael@0: errors: [{description: "No service", location: "body", name: ""}], michael@0: }); michael@0: michael@0: response.bodyOutputStream.write(body, body.length); michael@0: } michael@0: }); michael@0: michael@0: function onResponse(error, token) { michael@0: do_check_true(error instanceof TokenServerClientServerError); michael@0: do_check_eq(error.cause, "unknown-service"); michael@0: do_check_null(token); michael@0: michael@0: server.stop(run_next_test); michael@0: } michael@0: michael@0: let client = new TokenServerClient(); michael@0: let url = server.baseURI + "/1.0/foo/1.0"; michael@0: client.getTokenFromBrowserIDAssertion(url, "assertion", onResponse); michael@0: }); michael@0: michael@0: add_test(function test_bad_json() { michael@0: _("Ensure that malformed JSON is handled properly."); michael@0: michael@0: let server = httpd_setup({ michael@0: "/1.0/foo/1.0": function(request, response) { michael@0: response.setStatusLine(request.httpVersion, 200, "OK"); michael@0: response.setHeader("Content-Type", "application/json"); michael@0: michael@0: let body = '{"id": "id", baz}' michael@0: response.bodyOutputStream.write(body, body.length); michael@0: } michael@0: }); michael@0: michael@0: let client = new TokenServerClient(); michael@0: let url = server.baseURI + "/1.0/foo/1.0"; michael@0: client.getTokenFromBrowserIDAssertion(url, "assertion", function(error, r) { michael@0: do_check_neq(null, error); michael@0: do_check_eq("TokenServerClientServerError", error.name); michael@0: do_check_eq(error.cause, "malformed-response"); michael@0: do_check_neq(null, error.response); michael@0: do_check_eq(null, r); michael@0: michael@0: server.stop(run_next_test); michael@0: }); michael@0: }); michael@0: michael@0: add_test(function test_400_response() { michael@0: _("Ensure HTTP 400 is converted to malformed-request."); michael@0: michael@0: let server = httpd_setup({ michael@0: "/1.0/foo/1.0": function(request, response) { michael@0: response.setStatusLine(request.httpVersion, 400, "Bad Request"); michael@0: response.setHeader("Content-Type", "application/json; charset=utf-8"); michael@0: michael@0: let body = "{}"; // Actual content may not be used. michael@0: response.bodyOutputStream.write(body, body.length); michael@0: } michael@0: }); michael@0: michael@0: let client = new TokenServerClient(); michael@0: let url = server.baseURI + "/1.0/foo/1.0"; michael@0: client.getTokenFromBrowserIDAssertion(url, "assertion", function(error, r) { michael@0: do_check_neq(null, error); michael@0: do_check_eq("TokenServerClientServerError", error.name); michael@0: do_check_neq(null, error.response); michael@0: do_check_eq(error.cause, "malformed-request"); michael@0: michael@0: server.stop(run_next_test); michael@0: }); michael@0: }); michael@0: michael@0: add_test(function test_401_with_error_cause() { michael@0: _("Ensure 401 cause is specified in body.status"); michael@0: michael@0: let server = httpd_setup({ michael@0: "/1.0/foo/1.0": function(request, response) { michael@0: response.setStatusLine(request.httpVersion, 401, "Unauthorized"); michael@0: response.setHeader("Content-Type", "application/json; charset=utf-8"); michael@0: michael@0: let body = JSON.stringify({status: "no-soup-for-you"}); michael@0: response.bodyOutputStream.write(body, body.length); michael@0: } michael@0: }); michael@0: michael@0: let client = new TokenServerClient(); michael@0: let url = server.baseURI + "/1.0/foo/1.0"; michael@0: client.getTokenFromBrowserIDAssertion(url, "assertion", function(error, r) { michael@0: do_check_neq(null, error); michael@0: do_check_eq("TokenServerClientServerError", error.name); michael@0: do_check_neq(null, error.response); michael@0: do_check_eq(error.cause, "no-soup-for-you"); michael@0: michael@0: server.stop(run_next_test); michael@0: }); michael@0: }); michael@0: michael@0: add_test(function test_unhandled_media_type() { michael@0: _("Ensure that unhandled media types throw an error."); michael@0: michael@0: let server = httpd_setup({ michael@0: "/1.0/foo/1.0": function(request, response) { michael@0: response.setStatusLine(request.httpVersion, 200, "OK"); michael@0: response.setHeader("Content-Type", "text/plain"); michael@0: michael@0: let body = "hello, world"; michael@0: response.bodyOutputStream.write(body, body.length); michael@0: } michael@0: }); michael@0: michael@0: let url = server.baseURI + "/1.0/foo/1.0"; michael@0: let client = new TokenServerClient(); michael@0: client.getTokenFromBrowserIDAssertion(url, "assertion", function(error, r) { michael@0: do_check_neq(null, error); michael@0: do_check_eq("TokenServerClientServerError", error.name); michael@0: do_check_neq(null, error.response); michael@0: do_check_eq(null, r); michael@0: michael@0: server.stop(run_next_test); michael@0: }); michael@0: }); michael@0: michael@0: add_test(function test_rich_media_types() { michael@0: _("Ensure that extra tokens in the media type aren't rejected."); michael@0: michael@0: let duration = 300; michael@0: let server = httpd_setup({ michael@0: "/foo": function(request, response) { michael@0: response.setStatusLine(request.httpVersion, 200, "OK"); michael@0: response.setHeader("Content-Type", "application/json; foo=bar; bar=foo"); michael@0: michael@0: let body = JSON.stringify({ michael@0: id: "id", michael@0: key: "key", michael@0: api_endpoint: "foo", michael@0: uid: "uid", michael@0: duration: duration, michael@0: }); michael@0: response.bodyOutputStream.write(body, body.length); michael@0: } michael@0: }); michael@0: michael@0: let url = server.baseURI + "/foo"; michael@0: let client = new TokenServerClient(); michael@0: client.getTokenFromBrowserIDAssertion(url, "assertion", function(error, r) { michael@0: do_check_eq(null, error); michael@0: michael@0: server.stop(run_next_test); michael@0: }); michael@0: }); michael@0: michael@0: add_test(function test_exception_during_callback() { michael@0: _("Ensure that exceptions thrown during callback handling are handled."); michael@0: michael@0: let duration = 300; michael@0: let server = httpd_setup({ michael@0: "/foo": function(request, response) { michael@0: response.setStatusLine(request.httpVersion, 200, "OK"); michael@0: response.setHeader("Content-Type", "application/json"); michael@0: michael@0: let body = JSON.stringify({ michael@0: id: "id", michael@0: key: "key", michael@0: api_endpoint: "foo", michael@0: uid: "uid", michael@0: duration: duration, michael@0: }); michael@0: response.bodyOutputStream.write(body, body.length); michael@0: } michael@0: }); michael@0: michael@0: let url = server.baseURI + "/foo"; michael@0: let client = new TokenServerClient(); michael@0: let cb = Async.makeSpinningCallback(); michael@0: let callbackCount = 0; michael@0: michael@0: client.getTokenFromBrowserIDAssertion(url, "assertion", function(error, r) { michael@0: do_check_eq(null, error); michael@0: michael@0: cb(); michael@0: michael@0: callbackCount += 1; michael@0: throw new Error("I am a bad function!"); michael@0: }); michael@0: michael@0: cb.wait(); michael@0: // This relies on some heavy event loop magic. The error in the main michael@0: // callback should already have been raised at this point. michael@0: do_check_eq(callbackCount, 1); michael@0: michael@0: server.stop(run_next_test); michael@0: });