services/sync/tests/unit/test_resource_async.js

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/services/sync/tests/unit/test_resource_async.js	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,730 @@
     1.4 +/* Any copyright is dedicated to the Public Domain.
     1.5 + * http://creativecommons.org/publicdomain/zero/1.0/ */
     1.6 +
     1.7 +Cu.import("resource://gre/modules/Log.jsm");
     1.8 +Cu.import("resource://services-common/observers.js");
     1.9 +Cu.import("resource://services-sync/identity.js");
    1.10 +Cu.import("resource://services-sync/resource.js");
    1.11 +Cu.import("resource://services-sync/util.js");
    1.12 +
    1.13 +let logger;
    1.14 +
    1.15 +let fetched = false;
    1.16 +function server_open(metadata, response) {
    1.17 +  let body;
    1.18 +  if (metadata.method == "GET") {
    1.19 +    fetched = true;
    1.20 +    body = "This path exists";
    1.21 +    response.setStatusLine(metadata.httpVersion, 200, "OK");
    1.22 +  } else {
    1.23 +    body = "Wrong request method";
    1.24 +    response.setStatusLine(metadata.httpVersion, 405, "Method Not Allowed");
    1.25 +  }
    1.26 +  response.bodyOutputStream.write(body, body.length);
    1.27 +}
    1.28 +
    1.29 +function server_protected(metadata, response) {
    1.30 +  let body;
    1.31 +
    1.32 +  if (basic_auth_matches(metadata, "guest", "guest")) {
    1.33 +    body = "This path exists and is protected";
    1.34 +    response.setStatusLine(metadata.httpVersion, 200, "OK, authorized");
    1.35 +    response.setHeader("WWW-Authenticate", 'Basic realm="secret"', false);
    1.36 +  } else {
    1.37 +    body = "This path exists and is protected - failed";
    1.38 +    response.setStatusLine(metadata.httpVersion, 401, "Unauthorized");
    1.39 +    response.setHeader("WWW-Authenticate", 'Basic realm="secret"', false);
    1.40 +  }
    1.41 +
    1.42 +  response.bodyOutputStream.write(body, body.length);
    1.43 +}
    1.44 +
    1.45 +function server_404(metadata, response) {
    1.46 +  let body = "File not found";
    1.47 +  response.setStatusLine(metadata.httpVersion, 404, "Not Found");
    1.48 +  response.bodyOutputStream.write(body, body.length);
    1.49 +}
    1.50 +
    1.51 +let pacFetched = false;
    1.52 +function server_pac(metadata, response) {
    1.53 +  _("Invoked PAC handler.");
    1.54 +  pacFetched = true;
    1.55 +  let body = 'function FindProxyForURL(url, host) { return "DIRECT"; }';
    1.56 +  response.setStatusLine(metadata.httpVersion, 200, "OK");
    1.57 +  response.setHeader("Content-Type", "application/x-ns-proxy-autoconfig", false);
    1.58 +  response.bodyOutputStream.write(body, body.length);
    1.59 +}
    1.60 +
    1.61 +let sample_data = {
    1.62 +  some: "sample_data",
    1.63 +  injson: "format",
    1.64 +  number: 42
    1.65 +};
    1.66 +
    1.67 +function server_upload(metadata, response) {
    1.68 +  let body;
    1.69 +
    1.70 +  let input = readBytesFromInputStream(metadata.bodyInputStream);
    1.71 +  if (input == JSON.stringify(sample_data)) {
    1.72 +    body = "Valid data upload via " + metadata.method;
    1.73 +    response.setStatusLine(metadata.httpVersion, 200, "OK");
    1.74 +  } else {
    1.75 +    body = "Invalid data upload via " + metadata.method + ': ' + input;
    1.76 +    response.setStatusLine(metadata.httpVersion, 500, "Internal Server Error");
    1.77 +  }
    1.78 +
    1.79 +  response.bodyOutputStream.write(body, body.length);
    1.80 +}
    1.81 +
    1.82 +function server_delete(metadata, response) {
    1.83 +  let body;
    1.84 +  if (metadata.method == "DELETE") {
    1.85 +    body = "This resource has been deleted";
    1.86 +    response.setStatusLine(metadata.httpVersion, 200, "OK");
    1.87 +  } else {
    1.88 +    body = "Wrong request method";
    1.89 +    response.setStatusLine(metadata.httpVersion, 405, "Method Not Allowed");
    1.90 +  }
    1.91 +  response.bodyOutputStream.write(body, body.length);
    1.92 +}
    1.93 +
    1.94 +function server_json(metadata, response) {
    1.95 +  let body = JSON.stringify(sample_data);
    1.96 +  response.setStatusLine(metadata.httpVersion, 200, "OK");
    1.97 +  response.bodyOutputStream.write(body, body.length);
    1.98 +}
    1.99 +
   1.100 +const TIMESTAMP = 1274380461;
   1.101 +
   1.102 +function server_timestamp(metadata, response) {
   1.103 +  let body = "Thank you for your request";
   1.104 +  response.setHeader("X-Weave-Timestamp", ''+TIMESTAMP, false);
   1.105 +  response.setStatusLine(metadata.httpVersion, 200, "OK");
   1.106 +  response.bodyOutputStream.write(body, body.length);
   1.107 +}
   1.108 +
   1.109 +function server_backoff(metadata, response) {
   1.110 +  let body = "Hey, back off!";
   1.111 +  response.setHeader("X-Weave-Backoff", '600', false);
   1.112 +  response.setStatusLine(metadata.httpVersion, 200, "OK");
   1.113 +  response.bodyOutputStream.write(body, body.length);
   1.114 +}
   1.115 +
   1.116 +function server_quota_notice(request, response) {
   1.117 +  let body = "You're approaching quota.";
   1.118 +  response.setHeader("X-Weave-Quota-Remaining", '1048576', false);
   1.119 +  response.setStatusLine(request.httpVersion, 200, "OK");
   1.120 +  response.bodyOutputStream.write(body, body.length);
   1.121 +}
   1.122 +
   1.123 +function server_quota_error(request, response) {
   1.124 +  let body = "14";
   1.125 +  response.setHeader("X-Weave-Quota-Remaining", '-1024', false);
   1.126 +  response.setStatusLine(request.httpVersion, 400, "OK");
   1.127 +  response.bodyOutputStream.write(body, body.length);
   1.128 +}
   1.129 +
   1.130 +function server_headers(metadata, response) {
   1.131 +  let ignore_headers = ["host", "user-agent", "accept", "accept-language",
   1.132 +                        "accept-encoding", "accept-charset", "keep-alive",
   1.133 +                        "connection", "pragma", "cache-control",
   1.134 +                        "content-length"];
   1.135 +  let headers = metadata.headers;
   1.136 +  let header_names = [];
   1.137 +  while (headers.hasMoreElements()) {
   1.138 +    let header = headers.getNext().toString();
   1.139 +    if (ignore_headers.indexOf(header) == -1) {
   1.140 +      header_names.push(header);
   1.141 +    }
   1.142 +  }
   1.143 +  header_names = header_names.sort();
   1.144 +
   1.145 +  headers = {};
   1.146 +  for each (let header in header_names) {
   1.147 +    headers[header] = metadata.getHeader(header);
   1.148 +  }
   1.149 +  let body = JSON.stringify(headers);
   1.150 +  response.setStatusLine(metadata.httpVersion, 200, "OK");
   1.151 +  response.bodyOutputStream.write(body, body.length);
   1.152 +}
   1.153 +
   1.154 +let quotaValue;
   1.155 +Observers.add("weave:service:quota:remaining",
   1.156 +              function (subject) { quotaValue = subject; });
   1.157 +
   1.158 +function run_test() {
   1.159 +  logger = Log.repository.getLogger('Test');
   1.160 +  Log.repository.rootLogger.addAppender(new Log.DumpAppender());
   1.161 +
   1.162 +  Svc.Prefs.set("network.numRetries", 1); // speed up test
   1.163 +  run_next_test();
   1.164 +}
   1.165 +
   1.166 +// This apparently has to come first in order for our PAC URL to be hit.
   1.167 +// Don't put any other HTTP requests earlier in the file!
   1.168 +add_test(function test_proxy_auth_redirect() {
   1.169 +  _("Ensure that a proxy auth redirect (which switches out our channel) " +
   1.170 +    "doesn't break AsyncResource.");
   1.171 +  let server = httpd_setup({
   1.172 +    "/open": server_open,
   1.173 +    "/pac2": server_pac
   1.174 +  });
   1.175 +
   1.176 +  PACSystemSettings.PACURI = server.baseURI + "/pac2";
   1.177 +  installFakePAC();
   1.178 +  let res = new AsyncResource(server.baseURI + "/open");
   1.179 +  res.get(function (error, result) {
   1.180 +    do_check_true(!error);
   1.181 +    do_check_true(pacFetched);
   1.182 +    do_check_true(fetched);
   1.183 +    do_check_eq("This path exists", result);
   1.184 +    pacFetched = fetched = false;
   1.185 +    uninstallFakePAC();
   1.186 +    server.stop(run_next_test);
   1.187 +  });
   1.188 +});
   1.189 +
   1.190 +add_test(function test_new_channel() {
   1.191 +  _("Ensure a redirect to a new channel is handled properly.");
   1.192 +
   1.193 +  let resourceRequested = false;
   1.194 +  function resourceHandler(metadata, response) {
   1.195 +    resourceRequested = true;
   1.196 +
   1.197 +    let body = "Test";
   1.198 +    response.setHeader("Content-Type", "text/plain");
   1.199 +    response.bodyOutputStream.write(body, body.length);
   1.200 +  }
   1.201 +
   1.202 +  let locationURL;
   1.203 +  function redirectHandler(metadata, response) {
   1.204 +    let body = "Redirecting";
   1.205 +    response.setStatusLine(metadata.httpVersion, 307, "TEMPORARY REDIRECT");
   1.206 +    response.setHeader("Location", locationURL);
   1.207 +    response.bodyOutputStream.write(body, body.length);
   1.208 +  }
   1.209 +
   1.210 +  let server = httpd_setup({"/resource": resourceHandler,
   1.211 +                            "/redirect": redirectHandler});
   1.212 +  locationURL = server.baseURI + "/resource";
   1.213 +
   1.214 +  let request = new AsyncResource(server.baseURI + "/redirect");
   1.215 +  request.get(function onRequest(error, content) {
   1.216 +    do_check_null(error);
   1.217 +    do_check_true(resourceRequested);
   1.218 +    do_check_eq(200, content.status);
   1.219 +    do_check_true("content-type" in content.headers);
   1.220 +    do_check_eq("text/plain", content.headers["content-type"]);
   1.221 +
   1.222 +    server.stop(run_next_test);
   1.223 +  });
   1.224 +});
   1.225 +
   1.226 +
   1.227 +let server;
   1.228 +
   1.229 +add_test(function setup() {
   1.230 +  server = httpd_setup({
   1.231 +    "/open": server_open,
   1.232 +    "/protected": server_protected,
   1.233 +    "/404": server_404,
   1.234 +    "/upload": server_upload,
   1.235 +    "/delete": server_delete,
   1.236 +    "/json": server_json,
   1.237 +    "/timestamp": server_timestamp,
   1.238 +    "/headers": server_headers,
   1.239 +    "/backoff": server_backoff,
   1.240 +    "/pac2": server_pac,
   1.241 +    "/quota-notice": server_quota_notice,
   1.242 +    "/quota-error": server_quota_error
   1.243 +  });
   1.244 +
   1.245 +  run_next_test();
   1.246 +});
   1.247 +
   1.248 +add_test(function test_members() {
   1.249 +  _("Resource object members");
   1.250 +  let uri = server.baseURI + "/open";
   1.251 +  let res = new AsyncResource(uri);
   1.252 +  do_check_true(res.uri instanceof Ci.nsIURI);
   1.253 +  do_check_eq(res.uri.spec, uri);
   1.254 +  do_check_eq(res.spec, uri);
   1.255 +  do_check_eq(typeof res.headers, "object");
   1.256 +  do_check_eq(typeof res.authenticator, "object");
   1.257 +  // Initially res.data is null since we haven't performed a GET or
   1.258 +  // PUT/POST request yet.
   1.259 +  do_check_eq(res.data, null);
   1.260 +
   1.261 +  run_next_test();
   1.262 +});
   1.263 +
   1.264 +add_test(function test_get() {
   1.265 +  _("GET a non-password-protected resource");
   1.266 +  let res = new AsyncResource(server.baseURI + "/open");
   1.267 +  res.get(function (error, content) {
   1.268 +    do_check_eq(error, null);
   1.269 +    do_check_eq(content, "This path exists");
   1.270 +    do_check_eq(content.status, 200);
   1.271 +    do_check_true(content.success);
   1.272 +    // res.data has been updated with the result from the request
   1.273 +    do_check_eq(res.data, content);
   1.274 +
   1.275 +    // Observe logging messages.
   1.276 +    let logger = res._log;
   1.277 +    let dbg    = logger.debug;
   1.278 +    let debugMessages = [];
   1.279 +    logger.debug = function (msg) {
   1.280 +      debugMessages.push(msg);
   1.281 +      dbg.call(this, msg);
   1.282 +    }
   1.283 +
   1.284 +    // Since we didn't receive proper JSON data, accessing content.obj
   1.285 +    // will result in a SyntaxError from JSON.parse
   1.286 +    let didThrow = false;
   1.287 +    try {
   1.288 +      content.obj;
   1.289 +    } catch (ex) {
   1.290 +      didThrow = true;
   1.291 +    }
   1.292 +    do_check_true(didThrow);
   1.293 +    do_check_eq(debugMessages.length, 1);
   1.294 +    do_check_eq(debugMessages[0],
   1.295 +                "Parse fail: Response body starts: \"\"This path exists\"\".");
   1.296 +    logger.debug = dbg;
   1.297 +
   1.298 +    run_next_test();
   1.299 +  });
   1.300 +});
   1.301 +
   1.302 +add_test(function test_basicauth() {
   1.303 +  _("Test that the BasicAuthenticator doesn't screw up header case.");
   1.304 +  let res1 = new AsyncResource(server.baseURI + "/foo");
   1.305 +  res1.setHeader("Authorization", "Basic foobar");
   1.306 +  do_check_eq(res1._headers["authorization"], "Basic foobar");
   1.307 +  do_check_eq(res1.headers["authorization"], "Basic foobar");
   1.308 +
   1.309 +  run_next_test();
   1.310 +});
   1.311 +
   1.312 +add_test(function test_get_protected_fail() {
   1.313 +  _("GET a password protected resource (test that it'll fail w/o pass, no throw)");
   1.314 +  let res2 = new AsyncResource(server.baseURI + "/protected");
   1.315 +  res2.get(function (error, content) {
   1.316 +    do_check_eq(error, null);
   1.317 +    do_check_eq(content, "This path exists and is protected - failed");
   1.318 +    do_check_eq(content.status, 401);
   1.319 +    do_check_false(content.success);
   1.320 +    run_next_test();
   1.321 +  });
   1.322 +});
   1.323 +
   1.324 +add_test(function test_get_protected_success() {
   1.325 +  _("GET a password protected resource");
   1.326 +  let identity = new IdentityManager();
   1.327 +  let auth = identity.getBasicResourceAuthenticator("guest", "guest");
   1.328 +  let res3 = new AsyncResource(server.baseURI + "/protected");
   1.329 +  res3.authenticator = auth;
   1.330 +  do_check_eq(res3.authenticator, auth);
   1.331 +  res3.get(function (error, content) {
   1.332 +    do_check_eq(error, null);
   1.333 +    do_check_eq(content, "This path exists and is protected");
   1.334 +    do_check_eq(content.status, 200);
   1.335 +    do_check_true(content.success);
   1.336 +    run_next_test();
   1.337 +  });
   1.338 +});
   1.339 +
   1.340 +add_test(function test_get_404() {
   1.341 +  _("GET a non-existent resource (test that it'll fail, but not throw)");
   1.342 +  let res4 = new AsyncResource(server.baseURI + "/404");
   1.343 +  res4.get(function (error, content) {
   1.344 +    do_check_eq(error, null);
   1.345 +    do_check_eq(content, "File not found");
   1.346 +    do_check_eq(content.status, 404);
   1.347 +    do_check_false(content.success);
   1.348 +
   1.349 +    // Check some headers of the 404 response
   1.350 +    do_check_eq(content.headers.connection, "close");
   1.351 +    do_check_eq(content.headers.server, "httpd.js");
   1.352 +    do_check_eq(content.headers["content-length"], 14);
   1.353 +
   1.354 +    run_next_test();
   1.355 +  });
   1.356 +});
   1.357 +
   1.358 +add_test(function test_put_string() {
   1.359 +  _("PUT to a resource (string)");
   1.360 +  let res_upload = new AsyncResource(server.baseURI + "/upload");
   1.361 +  res_upload.put(JSON.stringify(sample_data), function(error, content) {
   1.362 +    do_check_eq(error, null);
   1.363 +    do_check_eq(content, "Valid data upload via PUT");
   1.364 +    do_check_eq(content.status, 200);
   1.365 +    do_check_eq(res_upload.data, content);
   1.366 +    run_next_test();
   1.367 +  });
   1.368 +});
   1.369 +
   1.370 +add_test(function test_put_object() {
   1.371 +  _("PUT to a resource (object)");
   1.372 +  let res_upload = new AsyncResource(server.baseURI + "/upload");
   1.373 +  res_upload.put(sample_data, function (error, content) {
   1.374 +    do_check_eq(error, null);
   1.375 +    do_check_eq(content, "Valid data upload via PUT");
   1.376 +    do_check_eq(content.status, 200);
   1.377 +    do_check_eq(res_upload.data, content);
   1.378 +    run_next_test();
   1.379 +  });
   1.380 +});
   1.381 +
   1.382 +add_test(function test_put_data_string() {
   1.383 +  _("PUT without data arg (uses resource.data) (string)");
   1.384 +  let res_upload = new AsyncResource(server.baseURI + "/upload");
   1.385 +  res_upload.data = JSON.stringify(sample_data);
   1.386 +  res_upload.put(function (error, content) {
   1.387 +    do_check_eq(error, null);
   1.388 +    do_check_eq(content, "Valid data upload via PUT");
   1.389 +    do_check_eq(content.status, 200);
   1.390 +    do_check_eq(res_upload.data, content);
   1.391 +    run_next_test();
   1.392 +  });
   1.393 +});
   1.394 +
   1.395 +add_test(function test_put_data_object() {
   1.396 +  _("PUT without data arg (uses resource.data) (object)");
   1.397 +  let res_upload = new AsyncResource(server.baseURI + "/upload");
   1.398 +  res_upload.data = sample_data;
   1.399 +  res_upload.put(function (error, content) {
   1.400 +    do_check_eq(error, null);
   1.401 +    do_check_eq(content, "Valid data upload via PUT");
   1.402 +    do_check_eq(content.status, 200);
   1.403 +    do_check_eq(res_upload.data, content);
   1.404 +    run_next_test();
   1.405 +  });
   1.406 +});
   1.407 +
   1.408 +add_test(function test_post_string() {
   1.409 +  _("POST to a resource (string)");
   1.410 +  let res_upload = new AsyncResource(server.baseURI + "/upload");
   1.411 +  res_upload.post(JSON.stringify(sample_data), function (error, content) {
   1.412 +    do_check_eq(error, null);
   1.413 +    do_check_eq(content, "Valid data upload via POST");
   1.414 +    do_check_eq(content.status, 200);
   1.415 +    do_check_eq(res_upload.data, content);
   1.416 +    run_next_test();
   1.417 +  });
   1.418 +});
   1.419 +
   1.420 +add_test(function test_post_object() {
   1.421 +  _("POST to a resource (object)");
   1.422 +  let res_upload = new AsyncResource(server.baseURI + "/upload");
   1.423 +  res_upload.post(sample_data, function (error, content) {
   1.424 +    do_check_eq(error, null);
   1.425 +    do_check_eq(content, "Valid data upload via POST");
   1.426 +    do_check_eq(content.status, 200);
   1.427 +    do_check_eq(res_upload.data, content);
   1.428 +    run_next_test();
   1.429 +  });
   1.430 +});
   1.431 +
   1.432 +add_test(function test_post_data_string() {
   1.433 +  _("POST without data arg (uses resource.data) (string)");
   1.434 +  let res_upload = new AsyncResource(server.baseURI + "/upload");
   1.435 +  res_upload.data = JSON.stringify(sample_data);
   1.436 +  res_upload.post(function (error, content) {
   1.437 +    do_check_eq(error, null);
   1.438 +    do_check_eq(content, "Valid data upload via POST");
   1.439 +    do_check_eq(content.status, 200);
   1.440 +    do_check_eq(res_upload.data, content);
   1.441 +    run_next_test();
   1.442 +  });
   1.443 +});
   1.444 +
   1.445 +add_test(function test_post_data_object() {
   1.446 +  _("POST without data arg (uses resource.data) (object)");
   1.447 +  let res_upload = new AsyncResource(server.baseURI + "/upload");
   1.448 +  res_upload.data = sample_data;
   1.449 +  res_upload.post(function (error, content) {
   1.450 +    do_check_eq(error, null);
   1.451 +    do_check_eq(content, "Valid data upload via POST");
   1.452 +    do_check_eq(content.status, 200);
   1.453 +    do_check_eq(res_upload.data, content);
   1.454 +    run_next_test();
   1.455 +  });
   1.456 +});
   1.457 +
   1.458 +add_test(function test_delete() {
   1.459 +  _("DELETE a resource");
   1.460 +  let res6 = new AsyncResource(server.baseURI + "/delete");
   1.461 +  res6.delete(function (error, content) {
   1.462 +    do_check_eq(error, null);
   1.463 +    do_check_eq(content, "This resource has been deleted");
   1.464 +    do_check_eq(content.status, 200);
   1.465 +    run_next_test();
   1.466 +  });
   1.467 +});
   1.468 +
   1.469 +add_test(function test_json_body() {
   1.470 +  _("JSON conversion of response body");
   1.471 +  let res7 = new AsyncResource(server.baseURI + "/json");
   1.472 +  res7.get(function (error, content) {
   1.473 +    do_check_eq(error, null);
   1.474 +    do_check_eq(content, JSON.stringify(sample_data));
   1.475 +    do_check_eq(content.status, 200);
   1.476 +    do_check_eq(JSON.stringify(content.obj), JSON.stringify(sample_data));
   1.477 +    run_next_test();
   1.478 +  });
   1.479 +});
   1.480 +
   1.481 +add_test(function test_weave_timestamp() {
   1.482 +  _("X-Weave-Timestamp header updates AsyncResource.serverTime");
   1.483 +  // Before having received any response containing the
   1.484 +  // X-Weave-Timestamp header, AsyncResource.serverTime is null.
   1.485 +  do_check_eq(AsyncResource.serverTime, null);
   1.486 +  let res8 = new AsyncResource(server.baseURI + "/timestamp");
   1.487 +  res8.get(function (error, content) {
   1.488 +    do_check_eq(error, null);
   1.489 +    do_check_eq(AsyncResource.serverTime, TIMESTAMP);
   1.490 +    run_next_test();
   1.491 +  });
   1.492 +});
   1.493 +
   1.494 +add_test(function test_get_no_headers() {
   1.495 +  _("GET: no special request headers");
   1.496 +  let res_headers = new AsyncResource(server.baseURI + "/headers");
   1.497 +  res_headers.get(function (error, content) {
   1.498 +    do_check_eq(error, null);
   1.499 +    do_check_eq(content, '{}');
   1.500 +    run_next_test();
   1.501 +  });
   1.502 +});
   1.503 +
   1.504 +add_test(function test_put_default_content_type() {
   1.505 +  _("PUT: Content-Type defaults to text/plain");
   1.506 +  let res_headers = new AsyncResource(server.baseURI + "/headers");
   1.507 +  res_headers.put('data', function (error, content) {
   1.508 +    do_check_eq(error, null);
   1.509 +    do_check_eq(content, JSON.stringify({"content-type": "text/plain"}));
   1.510 +    run_next_test();
   1.511 +  });
   1.512 +});
   1.513 +
   1.514 +add_test(function test_post_default_content_type() {
   1.515 +  _("POST: Content-Type defaults to text/plain");
   1.516 +  let res_headers = new AsyncResource(server.baseURI + "/headers");
   1.517 +  res_headers.post('data', function (error, content) {
   1.518 +    do_check_eq(error, null);
   1.519 +    do_check_eq(content, JSON.stringify({"content-type": "text/plain"}));
   1.520 +    run_next_test();
   1.521 +  });
   1.522 +});
   1.523 +
   1.524 +add_test(function test_setHeader() {
   1.525 +  _("setHeader(): setting simple header");
   1.526 +  let res_headers = new AsyncResource(server.baseURI + "/headers");
   1.527 +  res_headers.setHeader('X-What-Is-Weave', 'awesome');
   1.528 +  do_check_eq(res_headers.headers['x-what-is-weave'], 'awesome');
   1.529 +  res_headers.get(function (error, content) {
   1.530 +    do_check_eq(error, null);
   1.531 +    do_check_eq(content, JSON.stringify({"x-what-is-weave": "awesome"}));
   1.532 +    run_next_test();
   1.533 +  });
   1.534 +});
   1.535 +
   1.536 +add_test(function test_setHeader_overwrite() {
   1.537 +  _("setHeader(): setting multiple headers, overwriting existing header");
   1.538 +  let res_headers = new AsyncResource(server.baseURI + "/headers");
   1.539 +  res_headers.setHeader('X-WHAT-is-Weave', 'more awesomer');
   1.540 +  res_headers.setHeader('X-Another-Header', 'hello world');
   1.541 +  do_check_eq(res_headers.headers['x-what-is-weave'], 'more awesomer');
   1.542 +  do_check_eq(res_headers.headers['x-another-header'], 'hello world');
   1.543 +  res_headers.get(function (error, content) {
   1.544 +    do_check_eq(error, null);
   1.545 +    do_check_eq(content, JSON.stringify({"x-another-header": "hello world",
   1.546 +                                         "x-what-is-weave": "more awesomer"}));
   1.547 +
   1.548 +    run_next_test();
   1.549 +  });
   1.550 +});
   1.551 +
   1.552 +add_test(function test_headers_object() {
   1.553 +  _("Setting headers object");
   1.554 +  let res_headers = new AsyncResource(server.baseURI + "/headers");
   1.555 +  res_headers.headers = {};
   1.556 +  res_headers.get(function (error, content) {
   1.557 +    do_check_eq(error, null);
   1.558 +    do_check_eq(content, "{}");
   1.559 +    run_next_test();
   1.560 +  });
   1.561 +});
   1.562 +
   1.563 +add_test(function test_put_override_content_type() {
   1.564 +  _("PUT: override default Content-Type");
   1.565 +  let res_headers = new AsyncResource(server.baseURI + "/headers");
   1.566 +  res_headers.setHeader('Content-Type', 'application/foobar');
   1.567 +  do_check_eq(res_headers.headers['content-type'], 'application/foobar');
   1.568 +  res_headers.put('data', function (error, content) {
   1.569 +    do_check_eq(error, null);
   1.570 +    do_check_eq(content, JSON.stringify({"content-type": "application/foobar"}));
   1.571 +    run_next_test();
   1.572 +  });
   1.573 +});
   1.574 +
   1.575 +add_test(function test_post_override_content_type() {
   1.576 +  _("POST: override default Content-Type");
   1.577 +  let res_headers = new AsyncResource(server.baseURI + "/headers");
   1.578 +  res_headers.setHeader('Content-Type', 'application/foobar');
   1.579 +  res_headers.post('data', function (error, content) {
   1.580 +    do_check_eq(error, null);
   1.581 +    do_check_eq(content, JSON.stringify({"content-type": "application/foobar"}));
   1.582 +    run_next_test();
   1.583 +  });
   1.584 +});
   1.585 +
   1.586 +add_test(function test_weave_backoff() {
   1.587 +  _("X-Weave-Backoff header notifies observer");
   1.588 +  let backoffInterval;
   1.589 +  function onBackoff(subject, data) {
   1.590 +    backoffInterval = subject;
   1.591 +  }
   1.592 +  Observers.add("weave:service:backoff:interval", onBackoff);
   1.593 +
   1.594 +  let res10 = new AsyncResource(server.baseURI + "/backoff");
   1.595 +  res10.get(function (error, content) {
   1.596 +    do_check_eq(error, null);
   1.597 +    do_check_eq(backoffInterval, 600);
   1.598 +    run_next_test();
   1.599 +  });
   1.600 +});
   1.601 +
   1.602 +add_test(function test_quota_error() {
   1.603 +  _("X-Weave-Quota-Remaining header notifies observer on successful requests.");
   1.604 +  let res10 = new AsyncResource(server.baseURI + "/quota-error");
   1.605 +  res10.get(function (error, content) {
   1.606 +    do_check_eq(error, null);
   1.607 +    do_check_eq(content.status, 400);
   1.608 +    do_check_eq(quotaValue, undefined); // HTTP 400, so no observer notification.
   1.609 +    run_next_test();
   1.610 +  });
   1.611 +});
   1.612 +
   1.613 +add_test(function test_quota_notice() {
   1.614 +  let res10 = new AsyncResource(server.baseURI + "/quota-notice");
   1.615 +  res10.get(function (error, content) {
   1.616 +    do_check_eq(error, null);
   1.617 +    do_check_eq(content.status, 200);
   1.618 +    do_check_eq(quotaValue, 1048576);
   1.619 +    run_next_test();
   1.620 +  });
   1.621 +});
   1.622 +
   1.623 +add_test(function test_preserve_exceptions() {
   1.624 +  _("Error handling in ChannelListener etc. preserves exception information");
   1.625 +  let res11 = new AsyncResource("http://localhost:12345/does/not/exist");
   1.626 +  res11.get(function (error, content) {
   1.627 +    do_check_neq(error, null);
   1.628 +    do_check_eq(error.result, Cr.NS_ERROR_CONNECTION_REFUSED);
   1.629 +    do_check_eq(error.message, "NS_ERROR_CONNECTION_REFUSED");
   1.630 +    run_next_test();
   1.631 +  });
   1.632 +});
   1.633 +
   1.634 +add_test(function test_xpc_exception_handling() {
   1.635 +  _("Exception handling inside fetches.");
   1.636 +  let res14 = new AsyncResource(server.baseURI + "/json");
   1.637 +  res14._onProgress = function(rec) {
   1.638 +    // Provoke an XPC exception without a Javascript wrapper.
   1.639 +    Services.io.newURI("::::::::", null, null);
   1.640 +  };
   1.641 +  let warnings = [];
   1.642 +  res14._log.warn = function(msg) { warnings.push(msg); };
   1.643 +
   1.644 +  res14.get(function (error, content) {
   1.645 +    do_check_eq(error.result, Cr.NS_ERROR_MALFORMED_URI);
   1.646 +    do_check_eq(error.message, "NS_ERROR_MALFORMED_URI");
   1.647 +    do_check_eq(content, null);
   1.648 +    do_check_eq(warnings.pop(),
   1.649 +                "Got exception calling onProgress handler during fetch of " +
   1.650 +                server.baseURI + "/json");
   1.651 +
   1.652 +    run_next_test();
   1.653 +  });
   1.654 +});
   1.655 +
   1.656 +add_test(function test_js_exception_handling() {
   1.657 +  _("JS exception handling inside fetches.");
   1.658 +  let res15 = new AsyncResource(server.baseURI + "/json");
   1.659 +  res15._onProgress = function(rec) {
   1.660 +    throw "BOO!";
   1.661 +  };
   1.662 +  let warnings = [];
   1.663 +  res15._log.warn = function(msg) { warnings.push(msg); };
   1.664 +
   1.665 +  res15.get(function (error, content) {
   1.666 +    do_check_eq(error.result, Cr.NS_ERROR_XPC_JS_THREW_STRING);
   1.667 +    do_check_eq(error.message, "NS_ERROR_XPC_JS_THREW_STRING");
   1.668 +    do_check_eq(content, null);
   1.669 +    do_check_eq(warnings.pop(),
   1.670 +                "Got exception calling onProgress handler during fetch of " +
   1.671 +                server.baseURI + "/json");
   1.672 +
   1.673 +    run_next_test();
   1.674 +  });
   1.675 +});
   1.676 +
   1.677 +add_test(function test_timeout() {
   1.678 +  _("Ensure channel timeouts are thrown appropriately.");
   1.679 +  let res19 = new AsyncResource(server.baseURI + "/json");
   1.680 +  res19.ABORT_TIMEOUT = 0;
   1.681 +  res19.get(function (error, content) {
   1.682 +    do_check_eq(error.result, Cr.NS_ERROR_NET_TIMEOUT);
   1.683 +    run_next_test();
   1.684 +  });
   1.685 +});
   1.686 +
   1.687 +add_test(function test_uri_construction() {
   1.688 +  _("Testing URI construction.");
   1.689 +  let args = [];
   1.690 +  args.push("newer=" + 1234);
   1.691 +  args.push("limit=" + 1234);
   1.692 +  args.push("sort=" + 1234);
   1.693 +
   1.694 +  let query = "?" + args.join("&");
   1.695 +
   1.696 +  let uri1 = Utils.makeURI("http://foo/" + query)
   1.697 +                  .QueryInterface(Ci.nsIURL);
   1.698 +  let uri2 = Utils.makeURI("http://foo/")
   1.699 +                  .QueryInterface(Ci.nsIURL);
   1.700 +  uri2.query = query;
   1.701 +  do_check_eq(uri1.query, uri2.query);
   1.702 +
   1.703 +  run_next_test();
   1.704 +});
   1.705 +
   1.706 +add_test(function test_not_sending_cookie() {
   1.707 +  function handler(metadata, response) {
   1.708 +    let body = "COOKIE!";
   1.709 +    response.setStatusLine(metadata.httpVersion, 200, "OK");
   1.710 +    response.bodyOutputStream.write(body, body.length);
   1.711 +    do_check_false(metadata.hasHeader("Cookie"));
   1.712 +  }
   1.713 +  let cookieSer = Cc["@mozilla.org/cookieService;1"]
   1.714 +                    .getService(Ci.nsICookieService);
   1.715 +  let uri = CommonUtils.makeURI(server.baseURI);
   1.716 +  cookieSer.setCookieString(uri, null, "test=test; path=/;", null);
   1.717 +
   1.718 +  let res = new AsyncResource(server.baseURI + "/test");
   1.719 +  res.get(function (error) {
   1.720 +    do_check_null(error);
   1.721 +    do_check_true(this.response.success);
   1.722 +    do_check_eq("COOKIE!", this.response.body);
   1.723 +    server.stop(run_next_test);
   1.724 +  });
   1.725 +});
   1.726 +
   1.727 +/**
   1.728 + * End of tests that rely on a single HTTP server.
   1.729 + * All tests after this point must begin and end their own.
   1.730 + */
   1.731 +add_test(function eliminate_server() {
   1.732 +  server.stop(run_next_test);
   1.733 +});

mercurial