/* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ const { TokenServerClient, TokenServerClientError, TokenServerClientServerError, } = ChromeUtils.importESModule( "resource://services-common/tokenserverclient.sys.mjs" ); initTestLogging("Trace"); add_task(async function test_working_token_exchange() { _("Ensure that working OAuth token exchange works as expected."); let service = "http://example.com/foo"; let duration = 300; let server = httpd_setup({ "/1.0/foo/1.0": function (request, response) { Assert.ok(request.hasHeader("accept")); Assert.equal("application/json", request.getHeader("accept")); response.setStatusLine(request.httpVersion, 200, "OK"); response.setHeader("Content-Type", "application/json"); let body = JSON.stringify({ id: "id", key: "key", api_endpoint: service, uid: "uid", duration, }); response.bodyOutputStream.write(body, body.length); }, }); let client = new TokenServerClient(); let url = server.baseURI + "/1.0/foo/1.0"; let result = await client.getTokenUsingOAuth(url, "access_token"); Assert.equal("object", typeof result); do_check_attribute_count(result, 7); Assert.equal(service, result.endpoint); Assert.equal("id", result.id); Assert.equal("key", result.key); Assert.equal("uid", result.uid); Assert.equal(duration, result.duration); Assert.deepEqual(undefined, result.node_type); await promiseStopServer(server); }); add_task(async function test_working_token_exchange_with_nodetype() { _("Ensure that a token response with a node type as expected."); let service = "http://example.com/foo"; let duration = 300; let nodeType = "the-node-type"; let server = httpd_setup({ "/1.0/foo/1.0": function (request, response) { Assert.ok(request.hasHeader("accept")); Assert.equal("application/json", request.getHeader("accept")); response.setStatusLine(request.httpVersion, 200, "OK"); response.setHeader("Content-Type", "application/json"); let body = JSON.stringify({ id: "id", key: "key", api_endpoint: service, uid: "uid", duration, node_type: nodeType, }); response.bodyOutputStream.write(body, body.length); }, }); let client = new TokenServerClient(); let url = server.baseURI + "/1.0/foo/1.0"; let result = await client.getTokenUsingOAuth(url, "access_token"); Assert.equal("object", typeof result); do_check_attribute_count(result, 7); Assert.equal(service, result.endpoint); Assert.equal("id", result.id); Assert.equal("key", result.key); Assert.equal("uid", result.uid); Assert.equal(duration, result.duration); Assert.equal(nodeType, result.node_type); await promiseStopServer(server); }); add_task(async function test_invalid_arguments() { _("Ensure invalid arguments to APIs are rejected."); let args = [ [null, "access_token"], ["http://example.com/", null], ]; for (let arg of args) { let client = new TokenServerClient(); await Assert.rejects(client.getTokenUsingOAuth(arg[0], arg[1]), ex => { Assert.ok(ex instanceof TokenServerClientError); return true; }); } }); add_task(async function test_invalid_403_no_content_type() { _("Ensure that a 403 without content-type is handled properly."); let server = httpd_setup({ "/1.0/foo/1.0": function (request, response) { response.setStatusLine(request.httpVersion, 403, "Forbidden"); // No Content-Type header by design. let body = JSON.stringify({ errors: [{ description: "irrelevant", location: "body", name: "" }], urls: { foo: "http://bar" }, }); response.bodyOutputStream.write(body, body.length); }, }); let client = new TokenServerClient(); let url = server.baseURI + "/1.0/foo/1.0"; await Assert.rejects( client.getTokenUsingOAuth(url, "access_token"), error => { Assert.ok(error instanceof TokenServerClientServerError); Assert.equal(error.cause, "malformed-response"); Assert.equal(null, error.urls); return true; } ); await promiseStopServer(server); }); add_task(async function test_send_extra_headers() { _("Ensures that the condition acceptance header is sent when asked."); let duration = 300; let server = httpd_setup({ "/1.0/foo/1.0": function (request, response) { Assert.ok(request.hasHeader("x-foo")); Assert.equal(request.getHeader("x-foo"), "42"); Assert.ok(request.hasHeader("x-bar")); Assert.equal(request.getHeader("x-bar"), "17"); response.setStatusLine(request.httpVersion, 200, "OK"); response.setHeader("Content-Type", "application/json"); let body = JSON.stringify({ id: "id", key: "key", api_endpoint: "http://example.com/", uid: "uid", duration, }); response.bodyOutputStream.write(body, body.length); }, }); let client = new TokenServerClient(); let url = server.baseURI + "/1.0/foo/1.0"; let extra = { "X-Foo": 42, "X-Bar": 17, }; await client.getTokenUsingOAuth(url, "access_token", extra); // Other tests validate other things. await promiseStopServer(server); }); add_task(async function test_error_404_empty() { _("Ensure that 404 responses without proper response are handled properly."); let server = httpd_setup(); let client = new TokenServerClient(); let url = server.baseURI + "/foo"; await Assert.rejects( client.getTokenUsingOAuth(url, "access_token"), error => { Assert.ok(error instanceof TokenServerClientServerError); Assert.equal(error.cause, "malformed-response"); Assert.notEqual(null, error.response); return true; } ); await promiseStopServer(server); }); add_task(async function test_error_404_proper_response() { _("Ensure that a Cornice error report for 404 is handled properly."); let server = httpd_setup({ "/1.0/foo/1.0": function (request, response) { response.setStatusLine(request.httpVersion, 404, "Not Found"); response.setHeader("Content-Type", "application/json; charset=utf-8"); let body = JSON.stringify({ status: 404, errors: [{ description: "No service", location: "body", name: "" }], }); response.bodyOutputStream.write(body, body.length); }, }); let client = new TokenServerClient(); let url = server.baseURI + "/1.0/foo/1.0"; await Assert.rejects( client.getTokenUsingOAuth(url, "access_token"), error => { Assert.ok(error instanceof TokenServerClientServerError); Assert.equal(error.cause, "unknown-service"); return true; } ); await promiseStopServer(server); }); add_task(async function test_bad_json() { _("Ensure that malformed JSON is handled properly."); let server = httpd_setup({ "/1.0/foo/1.0": function (request, response) { response.setStatusLine(request.httpVersion, 200, "OK"); response.setHeader("Content-Type", "application/json"); let body = '{"id": "id", baz}'; response.bodyOutputStream.write(body, body.length); }, }); let client = new TokenServerClient(); let url = server.baseURI + "/1.0/foo/1.0"; await Assert.rejects( client.getTokenUsingOAuth(url, "access_token"), error => { Assert.notEqual(null, error); Assert.equal("TokenServerClientServerError", error.name); Assert.equal(error.cause, "malformed-response"); Assert.notEqual(null, error.response); return true; } ); await promiseStopServer(server); }); add_task(async function test_400_response() { _("Ensure HTTP 400 is converted to malformed-request."); let server = httpd_setup({ "/1.0/foo/1.0": function (request, response) { response.setStatusLine(request.httpVersion, 400, "Bad Request"); response.setHeader("Content-Type", "application/json; charset=utf-8"); let body = "{}"; // Actual content may not be used. response.bodyOutputStream.write(body, body.length); }, }); let client = new TokenServerClient(); let url = server.baseURI + "/1.0/foo/1.0"; await Assert.rejects( client.getTokenUsingOAuth(url, "access_token"), error => { Assert.notEqual(null, error); Assert.equal("TokenServerClientServerError", error.name); Assert.notEqual(null, error.response); Assert.equal(error.cause, "malformed-request"); return true; } ); await promiseStopServer(server); }); add_task(async function test_401_with_error_cause() { _("Ensure 401 cause is specified in body.status"); let server = httpd_setup({ "/1.0/foo/1.0": function (request, response) { response.setStatusLine(request.httpVersion, 401, "Unauthorized"); response.setHeader("Content-Type", "application/json; charset=utf-8"); let body = JSON.stringify({ status: "no-soup-for-you" }); response.bodyOutputStream.write(body, body.length); }, }); let client = new TokenServerClient(); let url = server.baseURI + "/1.0/foo/1.0"; await Assert.rejects( client.getTokenUsingOAuth(url, "access_token"), error => { Assert.notEqual(null, error); Assert.equal("TokenServerClientServerError", error.name); Assert.notEqual(null, error.response); Assert.equal(error.cause, "no-soup-for-you"); return true; } ); await promiseStopServer(server); }); add_task(async function test_unhandled_media_type() { _("Ensure that unhandled media types throw an error."); let server = httpd_setup({ "/1.0/foo/1.0": function (request, response) { response.setStatusLine(request.httpVersion, 200, "OK"); response.setHeader("Content-Type", "text/plain"); let body = "hello, world"; response.bodyOutputStream.write(body, body.length); }, }); let url = server.baseURI + "/1.0/foo/1.0"; let client = new TokenServerClient(); await Assert.rejects( client.getTokenUsingOAuth(url, "access_token"), error => { Assert.notEqual(null, error); Assert.equal("TokenServerClientServerError", error.name); Assert.notEqual(null, error.response); return true; } ); await promiseStopServer(server); }); add_task(async function test_rich_media_types() { _("Ensure that extra tokens in the media type aren't rejected."); let duration = 300; let server = httpd_setup({ "/foo": function (request, response) { response.setStatusLine(request.httpVersion, 200, "OK"); response.setHeader("Content-Type", "application/json; foo=bar; bar=foo"); let body = JSON.stringify({ id: "id", key: "key", api_endpoint: "foo", uid: "uid", duration, }); response.bodyOutputStream.write(body, body.length); }, }); let url = server.baseURI + "/foo"; let client = new TokenServerClient(); await client.getTokenUsingOAuth(url, "access_token"); await promiseStopServer(server); });