зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1084525 - Part 4: Add listPromises method to PromisesActor r=fitzgen
This commit is contained in:
Родитель
78acd7471f
Коммит
d721f8d0e5
|
@ -6,7 +6,16 @@
|
|||
|
||||
const protocol = require("devtools/server/protocol");
|
||||
const { method, RetVal, Arg, types } = protocol;
|
||||
const { expectState } = require("devtools/server/actors/common");
|
||||
const { expectState, ActorPool } = require("devtools/server/actors/common");
|
||||
const { ObjectActor, createValueGrip } = require("devtools/server/actors/object");
|
||||
const DevToolsUtils = require("devtools/toolkit/DevToolsUtils");
|
||||
loader.lazyRequireGetter(this, "events", "sdk/event/core");
|
||||
|
||||
// Teach protocol.js how to deal with legacy actor types
|
||||
types.addType("ObjectActor", {
|
||||
write: actor => actor.grip(),
|
||||
read: grip => grip
|
||||
});
|
||||
|
||||
/**
|
||||
* The Promises Actor provides support for getting the list of live promises and
|
||||
|
@ -22,13 +31,19 @@ let PromisesActor = protocol.ActorClass({
|
|||
initialize: function(conn, parent) {
|
||||
protocol.Actor.prototype.initialize.call(this, conn);
|
||||
|
||||
this.conn = conn;
|
||||
this.parent = parent;
|
||||
this.state = "detached";
|
||||
this._dbg = null;
|
||||
this._gripDepth = 0;
|
||||
this._navigationLifetimePool = null;
|
||||
|
||||
this.objectGrip = this.objectGrip.bind(this);
|
||||
this._onWindowReady = this._onWindowReady.bind(this);
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
protocol.Actor.prototype.destroy.call(this, conn);
|
||||
protocol.Actor.prototype.destroy.call(this, this.conn);
|
||||
|
||||
if (this.state === "attached") {
|
||||
this.detach();
|
||||
|
@ -47,6 +62,12 @@ let PromisesActor = protocol.ActorClass({
|
|||
*/
|
||||
attach: method(expectState("detached", function() {
|
||||
this.dbg.addDebuggees();
|
||||
|
||||
this._navigationLifetimePool = this._createActorPool();
|
||||
this.conn.addActorPool(this._navigationLifetimePool);
|
||||
|
||||
events.on(this.parent, "window-ready", this._onWindowReady);
|
||||
|
||||
this.state = "attached";
|
||||
}, `attaching to the PromisesActor`), {
|
||||
request: {},
|
||||
|
@ -60,11 +81,93 @@ let PromisesActor = protocol.ActorClass({
|
|||
this.dbg.removeAllDebuggees();
|
||||
this.dbg.enabled = false;
|
||||
this._dbg = null;
|
||||
|
||||
if (this._navigationLifetimePool) {
|
||||
this.conn.removeActorPool(this._navigationLifetimePool);
|
||||
this._navigationLifetimePool = null;
|
||||
}
|
||||
|
||||
events.off(this.parent, "window-ready", this._onWindowReady);
|
||||
|
||||
this.state = "detached";
|
||||
}, `detaching from the PromisesActor`), {
|
||||
request: {},
|
||||
response: {}
|
||||
}),
|
||||
|
||||
_createActorPool: function() {
|
||||
let pool = new ActorPool(this.conn);
|
||||
pool.objectActors = new WeakMap();
|
||||
return pool;
|
||||
},
|
||||
|
||||
/**
|
||||
* Create an ObjectActor for the given Promise object.
|
||||
*
|
||||
* @param object promise
|
||||
* The promise object
|
||||
* @return object
|
||||
* An ObjectActor object that wraps the given Promise object
|
||||
*/
|
||||
_createObjectActorForPromise: function(promise) {
|
||||
let object = new ObjectActor(promise, {
|
||||
getGripDepth: () => this._gripDepth,
|
||||
incrementGripDepth: () => this._gripDepth++,
|
||||
decrementGripDepth: () => this._gripDepth--,
|
||||
createValueGrip: v =>
|
||||
createValueGrip(v, this._navigationLifetimePool, this.objectGrip),
|
||||
sources: () => DevToolsUtils.reportException("PromisesActor",
|
||||
Error("sources not yet implemented")),
|
||||
createEnvironmentActor: () => DevToolsUtils.reportException(
|
||||
"PromisesActor", Error("createEnvironmentActor not yet implemented"))
|
||||
});
|
||||
this._navigationLifetimePool.addActor(object);
|
||||
return object;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get a grip for the given Promise object.
|
||||
*
|
||||
* @param object value
|
||||
* The Promise object
|
||||
* @return object
|
||||
* The grip for the given Promise object
|
||||
*/
|
||||
objectGrip: function(value) {
|
||||
let pool = this._navigationLifetimePool;
|
||||
|
||||
if (pool.objectActors.has(value)) {
|
||||
return pool.objectActors.get(value).grip();
|
||||
}
|
||||
|
||||
let actor = this._createObjectActorForPromise(value);
|
||||
pool.objectActors.set(value, actor);
|
||||
return actor.grip();
|
||||
},
|
||||
|
||||
/**
|
||||
* Get a list of ObjectActors for all live Promise Objects.
|
||||
*/
|
||||
listPromises: method(function() {
|
||||
let promises = this.dbg.findObjects({ class: "Promise" });
|
||||
return promises.map(p => this._createObjectActorForPromise(p));
|
||||
}, {
|
||||
request: {
|
||||
},
|
||||
response: {
|
||||
promises: RetVal("array:ObjectActor")
|
||||
}
|
||||
}),
|
||||
|
||||
_onWindowReady: expectState("attached", function({ isTopLevel }) {
|
||||
if (!isTopLevel) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._navigationLifetimePool.cleanup();
|
||||
this.dbg.removeAllDebuggees();
|
||||
this.dbg.addDebuggees();
|
||||
})
|
||||
});
|
||||
|
||||
exports.PromisesActor = PromisesActor;
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Test that we can get the list of all live Promise objects from the
|
||||
* PromisesActor.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const { PromisesFront } = devtools.require("devtools/server/actors/promises");
|
||||
const SECRET = "MyLittleSecret";
|
||||
|
||||
add_task(function*() {
|
||||
let client = yield startTestDebuggerServer("promises-actor-test");
|
||||
let chromeActors = yield getChromeActors(client);
|
||||
|
||||
yield testListPromises(client, chromeActors, v =>
|
||||
new Promise(resolve => resolve(v)));
|
||||
|
||||
let response = yield listTabs(client);
|
||||
let targetTab = findTab(response.tabs, "promises-actor-test");
|
||||
ok(targetTab, "Found our target tab.");
|
||||
|
||||
yield testListPromises(client, targetTab, v => {
|
||||
const debuggee = DebuggerServer.getTestGlobal("promises-actor-test");
|
||||
return debuggee.Promise.resolve(v);
|
||||
});
|
||||
|
||||
yield close(client);
|
||||
});
|
||||
|
||||
function* testListPromises(client, form, makePromise) {
|
||||
let resolution = SECRET + Math.random();
|
||||
let promise = makePromise(resolution);
|
||||
let front = PromisesFront(client, form);
|
||||
|
||||
yield front.attach();
|
||||
|
||||
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");
|
||||
|
||||
if (p.promiseState.state === "fulfilled" &&
|
||||
p.promiseState.value === resolution) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
ok(found, "Found our promise");
|
||||
yield front.detach();
|
||||
// Appease eslint
|
||||
void promise;
|
||||
}
|
|
@ -9,11 +9,21 @@ const { TabSources } = require("devtools/server/actors/utils/TabSources");
|
|||
const promise = require("promise");
|
||||
const makeDebugger = require("devtools/server/actors/utils/make-debugger");
|
||||
|
||||
var gTestGlobals = [];
|
||||
let gTestGlobals = [];
|
||||
DebuggerServer.addTestGlobal = function(aGlobal) {
|
||||
gTestGlobals.push(aGlobal);
|
||||
};
|
||||
|
||||
DebuggerServer.getTestGlobal = function(name) {
|
||||
for (let g of gTestGlobals) {
|
||||
if (g.__name == name) {
|
||||
return g;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// A mock tab list, for use by tests. This simply presents each global in
|
||||
// gTestGlobals as a tab, and the list is fixed: it never calls its
|
||||
// onListChanged handler.
|
||||
|
|
|
@ -82,6 +82,7 @@ support-files =
|
|||
[test_eval-05.js]
|
||||
[test_promises_actor_attach.js]
|
||||
[test_promises_actor_exist.js]
|
||||
[test_promises_actor_list_promises.js]
|
||||
[test_protocol_abort.js]
|
||||
[test_protocol_async.js]
|
||||
[test_protocol_children.js]
|
||||
|
|
Загрузка…
Ссылка в новой задаче