Bug 1084525 - Part 8: Expose Promise time to settle in object grip r=fitzgen
authorGabriel Luong <gabriel.luong@gmail.com>
Wed, 10 Jun 2015 00:18:46 -0700
changeset 248116 ae4f4b3fd22f0ff16501329eb980afce496aafa0
parent 248115 f0c15d17566f5639ed85954ca24a64352407e6d9
child 248117 57ec499fafb57645f5aa26ab8a9e2247a258cfb2
push id60888
push userkwierso@gmail.com
push dateThu, 11 Jun 2015 01:38:38 +0000
treeherdermozilla-inbound@39e638ed06bf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfitzgen
bugs1084525
milestone41.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1084525 - Part 8: Expose Promise time to settle in object grip r=fitzgen
toolkit/devtools/server/actors/object.js
toolkit/devtools/server/tests/unit/test_promises_actor_list_promises.js
toolkit/devtools/server/tests/unit/test_promises_actor_onpromisesettled.js
toolkit/devtools/server/tests/unit/test_promises_object_timetosettle-01.js
toolkit/devtools/server/tests/unit/test_promises_object_timetosettle-02.js
toolkit/devtools/server/tests/unit/xpcshell.ini
--- a/toolkit/devtools/server/actors/object.js
+++ b/toolkit/devtools/server/actors/object.js
@@ -140,16 +140,22 @@ ObjectActor.prototype = {
       promiseState.value = this.hooks.createValueGrip(value);
     } else if (state == "rejected") {
       promiseState.reason = this.hooks.createValueGrip(reason);
     }
 
     promiseState.creationTimestamp = Date.now() -
       PromiseDebugging.getPromiseLifetime(rawPromise);
 
+    // If the promise is not settled, avoid adding the timeToSettle property
+    // and catch the error thrown by PromiseDebugging.getTimeToSettle.
+    try {
+      promiseState.timeToSettle = PromiseDebugging.getTimeToSettle(rawPromise);
+    } catch(e) {}
+
     return promiseState;
   },
 
   /**
    * Releases this actor from the pool.
    */
   release: function() {
     if (this.registeredPool.objectActors) {
--- a/toolkit/devtools/server/tests/unit/test_promises_actor_list_promises.js
+++ b/toolkit/devtools/server/tests/unit/test_promises_actor_list_promises.js
@@ -40,16 +40,18 @@ function* testListPromises(client, form,
   let promises = yield front.listPromises();
 
   let found = false;
   for (let p of promises) {
     equal(p.type, "object", "Expect type to be Object");
     equal(p.class, "Promise", "Expect class to be Promise");
     equal(typeof p.promiseState.creationTimestamp, "number",
       "Expect creation timestamp to be a number");
+    equal(typeof p.promiseState.timeToSettle, "number",
+      "Expect time to settle to be a number");
 
     if (p.promiseState.state === "fulfilled" &&
         p.promiseState.value === resolution) {
       found = true;
     }
   }
 
   ok(found, "Found our promise");
--- a/toolkit/devtools/server/tests/unit/test_promises_actor_onpromisesettled.js
+++ b/toolkit/devtools/server/tests/unit/test_promises_actor_onpromisesettled.js
@@ -64,22 +64,28 @@ function* testPromisesSettled(client, fo
 function oncePromiseSettled(front, resolution, resolveValue, rejectValue) {
   return new Promise(resolve => {
     events.on(front, "promises-settled", promises => {
       for (let p of promises) {
         equal(p.type, "object", "Expect type to be Object");
         equal(p.class, "Promise", "Expect class to be Promise");
         equal(typeof p.promiseState.creationTimestamp, "number",
           "Expect creation timestamp to be a number");
+        equal(typeof p.promiseState.timeToSettle, "number",
+          "Expect time to settle to be a number");
 
         if (p.promiseState.state === "fulfilled" &&
             p.promiseState.value === resolution) {
+          equal(Math.floor(p.promiseState.timeToSettle), 0,
+            "Expect time to settle for resolved promise to be 0.");
           resolve(resolveValue);
         } else if (p.promiseState.state === "rejected" &&
                    p.promiseState.reason === resolution) {
+          equal(Math.floor(p.promiseState.timeToSettle), 0,
+            "Expect time to settle for rejected promise to be 0.");
           resolve(rejectValue);
         } else {
           dump("Found non-target promise\n");
         }
       }
     });
   });
 }
new file mode 100644
--- /dev/null
+++ b/toolkit/devtools/server/tests/unit/test_promises_object_timetosettle-01.js
@@ -0,0 +1,78 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Test whether or not we get the time to settle depending on the state of the
+ * promise.
+ */
+
+"use strict";
+
+const { PromisesFront } = devtools.require("devtools/server/actors/promises");
+
+let events = devtools.require("sdk/event/core");
+
+add_task(function*() {
+  let client = yield startTestDebuggerServer("test-promises-timetosettle");
+  let chromeActors = yield getChromeActors(client);
+
+  ok(Promise.toString().contains("native code"), "Expect native DOM Promise.");
+
+  yield testGetTimeToSettle(client, chromeActors, () => {
+    let p = new Promise(() => {});
+    p.name = "p";
+    let q = p.then();
+    q.name = "q";
+
+    return p;
+  });
+
+  let response = yield listTabs(client);
+  let targetTab = findTab(response.tabs, "test-promises-timetosettle");
+  ok(targetTab, "Found our target tab.");
+
+  yield testGetTimeToSettle(client, targetTab, () => {
+    const debuggee =
+      DebuggerServer.getTestGlobal("test-promises-timetosettle");
+
+    let p = new debuggee.Promise(() => {});
+    p.name = "p";
+    let q = p.then();
+    q.name = "q";
+
+    return p;
+  });
+
+  yield close(client);
+});
+
+function* testGetTimeToSettle(client, form, makePromises) {
+  let front = PromisesFront(client, form);
+
+  yield front.attach();
+  yield front.listPromises();
+
+  let onNewPromise = new Promise(resolve => {
+    events.on(front, "new-promises", promises => {
+      for (let p of promises) {
+        if (p.promiseState.state === "pending") {
+          ok(!p.promiseState.timeToSettle,
+            "Expect no time to settle for unsettled promise.");
+        } else {
+          ok(p.promiseState.timeToSettle,
+            "Expect time to settle for settled promise.");
+          equal(typeof p.promiseState.timeToSettle, "number",
+            "Expect time to settle to be a number.");
+        }
+      }
+      resolve();
+    });
+  });
+
+  let promise = makePromises();
+
+  yield onNewPromise;
+  yield front.detach();
+  // Appease eslint
+  void promise;
+}
new file mode 100644
--- /dev/null
+++ b/toolkit/devtools/server/tests/unit/test_promises_object_timetosettle-02.js
@@ -0,0 +1,69 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Test that we get the expected settlement time for promise time to settle.
+ */
+
+"use strict";
+
+const { PromisesFront } = devtools.require("devtools/server/actors/promises");
+const { setTimeout } = devtools.require("sdk/timers");
+
+let events = devtools.require("sdk/event/core");
+
+add_task(function*() {
+  let client = yield startTestDebuggerServer("test-promises-timetosettle");
+  let chromeActors = yield getChromeActors(client);
+
+  ok(Promise.toString().contains("native code"), "Expect native DOM Promise.");
+
+  yield testGetTimeToSettle(client, chromeActors,
+    v => new Promise(resolve => setTimeout(() => resolve(v), 100)));
+
+  let response = yield listTabs(client);
+  let targetTab = findTab(response.tabs, "test-promises-timetosettle");
+  ok(targetTab, "Found our target tab.");
+
+  yield testGetTimeToSettle(client, targetTab, v => {
+    const debuggee =
+      DebuggerServer.getTestGlobal("test-promises-timetosettle");
+    return new debuggee.Promise(resolve => setTimeout(() => resolve(v), 100));
+  });
+
+  yield close(client);
+});
+
+function* testGetTimeToSettle(client, form, makePromise) {
+  let front = PromisesFront(client, form);
+  let resolution = "MyLittleSecret" + Math.random();
+  let found = false;
+
+  yield front.attach();
+  yield front.listPromises();
+
+  let onNewPromise = new Promise(resolve => {
+    events.on(front, "promises-settled", promises => {
+      for (let p of promises) {
+        if (p.promiseState.state === "fulfilled" &&
+            p.promiseState.value === resolution) {
+          equal(Math.floor(p.promiseState.timeToSettle / 100) * 100, 100,
+            "Expect time to settle for resolved promise to be " +
+            "approximately 100ms.");
+          found = true;
+          resolve();
+        } else {
+          dump("Found non-target promise.\n");
+        }
+      }
+    });
+  });
+
+  let promise = makePromise(resolution);
+
+  yield onNewPromise;
+  ok(found, "Found our new promise.");
+  yield front.detach();
+  // Appease eslint
+  void promise;
+}
--- a/toolkit/devtools/server/tests/unit/xpcshell.ini
+++ b/toolkit/devtools/server/tests/unit/xpcshell.ini
@@ -81,16 +81,18 @@ support-files =
 [test_eval-04.js]
 [test_eval-05.js]
 [test_promises_actor_attach.js]
 [test_promises_actor_exist.js]
 [test_promises_actor_list_promises.js]
 [test_promises_actor_onnewpromise.js]
 [test_promises_actor_onpromisesettled.js]
 [test_promises_object_creationtimestamp.js]
+[test_promises_object_timetosettle-01.js]
+[test_promises_object_timetosettle-02.js]
 [test_protocol_abort.js]
 [test_protocol_async.js]
 [test_protocol_children.js]
 [test_protocol_formtype.js]
 [test_protocol_longstring.js]
 [test_protocol_simple.js]
 [test_protocol_unregister.js]
 [test_breakpoint-01.js]