зеркало из https://github.com/mozilla/gecko-dev.git
Merge fx-team to m-c a=merge
This commit is contained in:
Коммит
f71f3c9a6a
|
@ -1613,7 +1613,7 @@ pref("loop.soft_start_hostname", "soft-start.loop.services.mozilla.com");
|
|||
pref("loop.server", "https://loop.services.mozilla.com");
|
||||
pref("loop.seenToS", "unseen");
|
||||
pref("loop.learnMoreUrl", "https://www.firefox.com/hello/");
|
||||
pref("loop.legal.ToS_url", "https://call.mozilla.com/legal/terms/");
|
||||
pref("loop.legal.ToS_url", "https://hello.firefox.com/legal/terms/");
|
||||
pref("loop.legal.privacy_url", "https://www.mozilla.org/privacy/");
|
||||
pref("loop.do_not_disturb", false);
|
||||
pref("loop.ringtone", "chrome://browser/content/loop/shared/sounds/Firefox-Long.ogg");
|
||||
|
|
|
@ -16,20 +16,11 @@ XPCOMUtils.defineLazyModuleGetter(this, "LOOP_SESSION_TYPE",
|
|||
XPCOMUtils.defineLazyModuleGetter(this, "MozLoopPushHandler",
|
||||
"resource:///modules/loop/MozLoopPushHandler.jsm");
|
||||
|
||||
// Create a new instance of the ConsoleAPI so we can control the maxLogLevel with a pref.
|
||||
XPCOMUtils.defineLazyGetter(this, "log", () => {
|
||||
let ConsoleAPI = Cu.import("resource://gre/modules/devtools/Console.jsm", {}).ConsoleAPI;
|
||||
let consoleOptions = {
|
||||
maxLogLevel: Services.prefs.getCharPref(PREF_LOG_LEVEL).toLowerCase(),
|
||||
prefix: "Loop",
|
||||
};
|
||||
return new ConsoleAPI(consoleOptions);
|
||||
});
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["LoopRooms", "roomsPushNotification"];
|
||||
|
||||
let gRoomsListFetched = false;
|
||||
let gRooms = new Map();
|
||||
let gCallbacks = new Map();
|
||||
|
||||
/**
|
||||
* Callback used to indicate changes to rooms data on the LoopServer.
|
||||
|
@ -59,7 +50,7 @@ let LoopRoomsInternal = {
|
|||
// identifier.
|
||||
for (let room of rooms) {
|
||||
let id = MozLoopService.generateLocalID();
|
||||
room.localRoomID = id;
|
||||
room.localRoomId = id;
|
||||
// Next, request the detailed information for each room.
|
||||
// If the request fails the room data will not be added to the map.
|
||||
try {
|
||||
|
@ -67,22 +58,24 @@ let LoopRoomsInternal = {
|
|||
for (let attr in details) {
|
||||
room[attr] = details[attr]
|
||||
}
|
||||
delete room.currSize; //This attribute will be eliminated in the next revision.
|
||||
gRooms.set(id, room);
|
||||
}
|
||||
catch (error) {log.warn("failed GETing room details for roomToken = " + room.roomToken + ": ", error)}
|
||||
catch (error) {MozLoopService.log.warn(
|
||||
"failed GETing room details for roomToken = " + room.roomToken + ": ", error)}
|
||||
}
|
||||
callback(null, [...gRooms.values()]);
|
||||
return;
|
||||
}.bind(this)).catch((error) => {log.error("getAll error:", error);
|
||||
}.bind(this)).catch((error) => {MozLoopService.log.error("getAll error:", error);
|
||||
callback(error)});
|
||||
return;
|
||||
},
|
||||
|
||||
getRoomData: function(roomID, callback) {
|
||||
if (gRooms.has(roomID)) {
|
||||
callback(null, gRooms.get(roomID));
|
||||
getRoomData: function(localRoomId, callback) {
|
||||
if (gRooms.has(localRoomId)) {
|
||||
callback(null, gRooms.get(localRoomId));
|
||||
} else {
|
||||
callback(new Error("Room data not found or not fetched yet for room with ID " + roomID));
|
||||
callback(new Error("Room data not found or not fetched yet for room with ID " + localRoomId));
|
||||
}
|
||||
return;
|
||||
},
|
||||
|
@ -130,6 +123,150 @@ let LoopRoomsInternal = {
|
|||
onNotification: function(version, channelID) {
|
||||
return;
|
||||
},
|
||||
|
||||
createRoom: function(props, callback) {
|
||||
// Always create a basic room record and launch the window, attaching
|
||||
// the localRoomId. Later errors will be returned via the registered callback.
|
||||
let localRoomId = MozLoopService.generateLocalID((id) => {gRooms.has(id)})
|
||||
let room = {localRoomId : localRoomId};
|
||||
for (let prop in props) {
|
||||
room[prop] = props[prop]
|
||||
}
|
||||
|
||||
gRooms.set(localRoomId, room);
|
||||
this.addCallback(localRoomId, "RoomCreated", callback);
|
||||
MozLoopService.openChatWindow(null, "", "about:loopconversation#room/" + localRoomId);
|
||||
|
||||
if (!"roomName" in props ||
|
||||
!"expiresIn" in props ||
|
||||
!"roomOwner" in props ||
|
||||
!"maxSize" in props) {
|
||||
this.postCallback(localRoomId, "RoomCreated",
|
||||
new Error("missing required room create property"));
|
||||
return localRoomId;
|
||||
}
|
||||
|
||||
let sessionType = MozLoopService.userProfile ? LOOP_SESSION_TYPE.FXA :
|
||||
LOOP_SESSION_TYPE.GUEST;
|
||||
|
||||
MozLoopService.hawkRequest(sessionType, "/rooms", "POST", props).then(
|
||||
(response) => {
|
||||
let data = JSON.parse(response.body);
|
||||
for (let attr in data) {
|
||||
room[attr] = data[attr]
|
||||
}
|
||||
delete room.expiresIn; //Do not keep this value - it is a request to the server
|
||||
this.postCallback(localRoomId, "RoomCreated", null, room);
|
||||
},
|
||||
(error) => {
|
||||
this.postCallback(localRoomId, "RoomCreated", error);
|
||||
});
|
||||
|
||||
return localRoomId;
|
||||
},
|
||||
|
||||
/**
|
||||
* Send an update to the callbacks registered for a specific localRoomId
|
||||
* for a callback type.
|
||||
*
|
||||
* The result set is always saved. Then each
|
||||
* callback function that has been registered when this function is
|
||||
* called will be called with the result set. Any new callback that
|
||||
* is regsitered via addCallback will receive a copy of the last
|
||||
* saved result set when registered. This allows the posting operation
|
||||
* to complete before the callback is registered in an asynchronous
|
||||
* operation.
|
||||
*
|
||||
* Callbacsk must be of the form:
|
||||
* function (error, success) {...}
|
||||
*
|
||||
* @param {String} localRoomId Local room identifier.
|
||||
* @param {String} callbackName callback type
|
||||
* @param {?Error} error result or null.
|
||||
* @param {?Object} success result if error argument is null.
|
||||
*/
|
||||
postCallback: function(localRoomId, callbackName, error, success) {
|
||||
let roomCallbacks = gCallbacks.get(localRoomId);
|
||||
if (!roomCallbacks) {
|
||||
// No callbacks have been registered or results posted for this room.
|
||||
// Initialize a record for this room and callbackName, saving the
|
||||
// result set.
|
||||
gCallbacks.set(localRoomId, new Map([[
|
||||
callbackName,
|
||||
{ callbackList: [], result: { error: error, success: success } }]]));
|
||||
return;
|
||||
}
|
||||
|
||||
let namedCallback = roomCallbacks.get(callbackName);
|
||||
// A callback of this name has not been registered.
|
||||
if (!namedCallback) {
|
||||
roomCallbacks.set(
|
||||
callbackName,
|
||||
{callbackList: [], result: {error: error, success: success}});
|
||||
return;
|
||||
}
|
||||
|
||||
// Record the latest result set.
|
||||
namedCallback.result = {error: error, success: success};
|
||||
|
||||
// Call each registerd callback passing the new result posted.
|
||||
namedCallback.callbackList.forEach((callback) => {
|
||||
callback(error, success);
|
||||
});
|
||||
},
|
||||
|
||||
addCallback: function(localRoomId, callbackName, callback) {
|
||||
let roomCallbacks = gCallbacks.get(localRoomId);
|
||||
if (!roomCallbacks) {
|
||||
// No callbacks have been registered or results posted for this room.
|
||||
// Initialize a record for this room and callbackName.
|
||||
gCallbacks.set(localRoomId, new Map([[
|
||||
callbackName,
|
||||
{callbackList: [callback]}]]));
|
||||
return;
|
||||
}
|
||||
|
||||
let namedCallback = roomCallbacks.get(callbackName);
|
||||
// A callback of this name has not been registered.
|
||||
if (!namedCallback) {
|
||||
roomCallbacks.set(
|
||||
callbackName,
|
||||
{callbackList: [callback]});
|
||||
return;
|
||||
}
|
||||
|
||||
// Add this callback if not already in the array
|
||||
if (namedCallback.callbackList.indexOf(callback) >= 0) {
|
||||
return;
|
||||
}
|
||||
namedCallback.callbackList.push(callback);
|
||||
|
||||
// If a result has been posted for this callback
|
||||
// send it using this new callback function.
|
||||
let result = namedCallback.result;
|
||||
if (result) {
|
||||
callback(result.error, result.success);
|
||||
}
|
||||
},
|
||||
|
||||
deleteCallback: function(localRoomId, callbackName, callback) {
|
||||
let roomCallbacks = gCallbacks.get(localRoomId);
|
||||
if (!roomCallbacks) {
|
||||
return;
|
||||
}
|
||||
|
||||
let namedCallback = roomCallbacks.get(callbackName);
|
||||
if (!namedCallback) {
|
||||
return;
|
||||
}
|
||||
|
||||
let i = namedCallback.callbackList.indexOf(callback);
|
||||
if (i >= 0) {
|
||||
namedCallback.callbackList.splice(i, 1);
|
||||
}
|
||||
|
||||
return;
|
||||
},
|
||||
};
|
||||
Object.freeze(LoopRoomsInternal);
|
||||
|
||||
|
@ -156,15 +293,51 @@ this.LoopRooms = {
|
|||
/**
|
||||
* Return the current stored version of the data for the indicated room.
|
||||
*
|
||||
* @param {String} roomID Local room identifier
|
||||
* @param {String} localRoomId Local room identifier
|
||||
* @param {Function} callback Function that will be invoked once the operation
|
||||
* finished. The first argument passed will be an
|
||||
* `Error` object or `null`. The second argument will
|
||||
* be the list of rooms, if it was fetched successfully.
|
||||
*/
|
||||
getRoomData: function(roomID, callback) {
|
||||
return LoopRoomsInternal.getRoomData(roomID, callback);
|
||||
getRoomData: function(localRoomId, callback) {
|
||||
return LoopRoomsInternal.getRoomData(localRoomId, callback);
|
||||
},
|
||||
|
||||
/**
|
||||
* Create a room. Will both open a chat window for the new room
|
||||
* and perform an exchange with the LoopServer to create the room.
|
||||
* for a callback type. Callback must be of the form:
|
||||
* function (error, success) {...}
|
||||
*
|
||||
* @param {Object} room properties to be sent to the LoopServer
|
||||
* @param {Function} callback Must be of the form: function (error, success) {...}
|
||||
*
|
||||
* @returns {String} localRoomId assigned to this new room.
|
||||
*/
|
||||
createRoom: function(roomProps, callback) {
|
||||
return LoopRoomsInternal.createRoom(roomProps, callback);
|
||||
},
|
||||
|
||||
/**
|
||||
* Register a callback of a specified type with a localRoomId.
|
||||
*
|
||||
* @param {String} localRoomId Local room identifier.
|
||||
* @param {String} callbackName callback type
|
||||
* @param {Function} callback Must be of the form: function (error, success) {...}
|
||||
*/
|
||||
addCallback: function(localRoomId, callbackName, callback) {
|
||||
return LoopRoomsInternal.addCallback(localRoomId, callbackName, callback);
|
||||
},
|
||||
|
||||
/**
|
||||
* Un-register and delete a callback of a specified type for a localRoomId.
|
||||
*
|
||||
* @param {String} localRoomId Local room identifier.
|
||||
* @param {String} callbackName callback type
|
||||
* @param {Function} callback Previously passed to addCallback().
|
||||
*/
|
||||
deleteCallback: function(localRoomId, callbackName, callback) {
|
||||
return LoopRoomsInternal.deleteCallback(localRoomId, callbackName, callback);
|
||||
},
|
||||
};
|
||||
Object.freeze(LoopRooms);
|
||||
|
||||
|
|
|
@ -178,6 +178,35 @@ loop.conversation = (function(mozL10n) {
|
|||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Incoming Call failed view. Displayed when a call fails.
|
||||
*
|
||||
* XXX Based on CallFailedView, but built specially until we flux-ify the
|
||||
* incoming call views (bug 1088672).
|
||||
*/
|
||||
var IncomingCallFailedView = React.createClass({displayName: 'IncomingCallFailedView',
|
||||
propTypes: {
|
||||
cancelCall: React.PropTypes.func.isRequired
|
||||
},
|
||||
|
||||
render: function() {
|
||||
document.title = mozL10n.get("generic_failure_title");
|
||||
|
||||
return (
|
||||
React.DOM.div({className: "call-window"},
|
||||
React.DOM.h2(null, mozL10n.get("generic_failure_title")),
|
||||
|
||||
React.DOM.div({className: "btn-group call-action-group"},
|
||||
React.DOM.button({className: "btn btn-cancel",
|
||||
onClick: this.props.cancelCall},
|
||||
mozL10n.get("cancel_button")
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* This view manages the incoming conversation views - from
|
||||
* call initiation through to the actual conversation and call end.
|
||||
|
@ -254,11 +283,13 @@ loop.conversation = (function(mozL10n) {
|
|||
case "end": {
|
||||
// XXX To be handled with the "failed" view state when bug 1047410 lands
|
||||
if (this.state.callFailed) {
|
||||
document.title = mozL10n.get("generic_failure_title");
|
||||
} else {
|
||||
document.title = mozL10n.get("conversation_has_ended");
|
||||
return IncomingCallFailedView({
|
||||
cancelCall: this.closeWindow.bind(this)}
|
||||
)
|
||||
}
|
||||
|
||||
document.title = mozL10n.get("conversation_has_ended");
|
||||
|
||||
var feebackAPIBaseUrl = navigator.mozLoop.getLoopCharPref(
|
||||
"feedback.baseUrl");
|
||||
|
||||
|
@ -394,19 +425,25 @@ loop.conversation = (function(mozL10n) {
|
|||
if (progressData.state !== "terminated")
|
||||
return;
|
||||
|
||||
if (progressData.reason === "cancel" ||
|
||||
progressData.reason === "closed") {
|
||||
// XXX This would be nicer in the _abortIncomingCall function, but we need to stop
|
||||
// it here for now due to server-side issues that are being fixed in bug 1088351.
|
||||
// This is before the abort call to ensure that it happens before the window is
|
||||
// closed.
|
||||
navigator.mozLoop.stopAlerting();
|
||||
|
||||
// If we hit any of the termination reasons, and the user hasn't accepted
|
||||
// then it seems reasonable to close the window/abort the incoming call.
|
||||
//
|
||||
// If the user has accepted the call, and something's happened, display
|
||||
// the call failed view.
|
||||
//
|
||||
// https://wiki.mozilla.org/Loop/Architecture/MVP#Termination_Reasons
|
||||
if (previousState === "init" || previousState === "alerting") {
|
||||
this._abortIncomingCall();
|
||||
return;
|
||||
} else {
|
||||
this.setState({callFailed: true, callStatus: "end"});
|
||||
}
|
||||
|
||||
if (progressData.reason === "timeout") {
|
||||
if (previousState === "init" || previousState === "alerting") {
|
||||
this._abortIncomingCall();
|
||||
} else {
|
||||
this.setState({callFailed: true, callStatus: "end"});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -414,7 +451,6 @@ loop.conversation = (function(mozL10n) {
|
|||
* closes the websocket.
|
||||
*/
|
||||
_abortIncomingCall: function() {
|
||||
navigator.mozLoop.stopAlerting();
|
||||
this._websocket.close();
|
||||
// Having a timeout here lets the logging for the websocket complete and be
|
||||
// displayed on the console if both are on.
|
||||
|
@ -644,6 +680,7 @@ loop.conversation = (function(mozL10n) {
|
|||
AppControllerView: AppControllerView,
|
||||
IncomingConversationView: IncomingConversationView,
|
||||
IncomingCallView: IncomingCallView,
|
||||
IncomingCallFailedView: IncomingCallFailedView,
|
||||
init: init
|
||||
};
|
||||
})(document.mozL10n);
|
||||
|
|
|
@ -178,6 +178,35 @@ loop.conversation = (function(mozL10n) {
|
|||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Incoming Call failed view. Displayed when a call fails.
|
||||
*
|
||||
* XXX Based on CallFailedView, but built specially until we flux-ify the
|
||||
* incoming call views (bug 1088672).
|
||||
*/
|
||||
var IncomingCallFailedView = React.createClass({
|
||||
propTypes: {
|
||||
cancelCall: React.PropTypes.func.isRequired
|
||||
},
|
||||
|
||||
render: function() {
|
||||
document.title = mozL10n.get("generic_failure_title");
|
||||
|
||||
return (
|
||||
<div className="call-window">
|
||||
<h2>{mozL10n.get("generic_failure_title")}</h2>
|
||||
|
||||
<div className="btn-group call-action-group">
|
||||
<button className="btn btn-cancel"
|
||||
onClick={this.props.cancelCall}>
|
||||
{mozL10n.get("cancel_button")}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* This view manages the incoming conversation views - from
|
||||
* call initiation through to the actual conversation and call end.
|
||||
|
@ -254,11 +283,13 @@ loop.conversation = (function(mozL10n) {
|
|||
case "end": {
|
||||
// XXX To be handled with the "failed" view state when bug 1047410 lands
|
||||
if (this.state.callFailed) {
|
||||
document.title = mozL10n.get("generic_failure_title");
|
||||
} else {
|
||||
document.title = mozL10n.get("conversation_has_ended");
|
||||
return <IncomingCallFailedView
|
||||
cancelCall={this.closeWindow.bind(this)}
|
||||
/>
|
||||
}
|
||||
|
||||
document.title = mozL10n.get("conversation_has_ended");
|
||||
|
||||
var feebackAPIBaseUrl = navigator.mozLoop.getLoopCharPref(
|
||||
"feedback.baseUrl");
|
||||
|
||||
|
@ -394,19 +425,25 @@ loop.conversation = (function(mozL10n) {
|
|||
if (progressData.state !== "terminated")
|
||||
return;
|
||||
|
||||
if (progressData.reason === "cancel" ||
|
||||
progressData.reason === "closed") {
|
||||
// XXX This would be nicer in the _abortIncomingCall function, but we need to stop
|
||||
// it here for now due to server-side issues that are being fixed in bug 1088351.
|
||||
// This is before the abort call to ensure that it happens before the window is
|
||||
// closed.
|
||||
navigator.mozLoop.stopAlerting();
|
||||
|
||||
// If we hit any of the termination reasons, and the user hasn't accepted
|
||||
// then it seems reasonable to close the window/abort the incoming call.
|
||||
//
|
||||
// If the user has accepted the call, and something's happened, display
|
||||
// the call failed view.
|
||||
//
|
||||
// https://wiki.mozilla.org/Loop/Architecture/MVP#Termination_Reasons
|
||||
if (previousState === "init" || previousState === "alerting") {
|
||||
this._abortIncomingCall();
|
||||
return;
|
||||
} else {
|
||||
this.setState({callFailed: true, callStatus: "end"});
|
||||
}
|
||||
|
||||
if (progressData.reason === "timeout") {
|
||||
if (previousState === "init" || previousState === "alerting") {
|
||||
this._abortIncomingCall();
|
||||
} else {
|
||||
this.setState({callFailed: true, callStatus: "end"});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -414,7 +451,6 @@ loop.conversation = (function(mozL10n) {
|
|||
* closes the websocket.
|
||||
*/
|
||||
_abortIncomingCall: function() {
|
||||
navigator.mozLoop.stopAlerting();
|
||||
this._websocket.close();
|
||||
// Having a timeout here lets the logging for the websocket complete and be
|
||||
// displayed on the console if both are on.
|
||||
|
@ -644,6 +680,7 @@ loop.conversation = (function(mozL10n) {
|
|||
AppControllerView: AppControllerView,
|
||||
IncomingConversationView: IncomingConversationView,
|
||||
IncomingCallView: IncomingCallView,
|
||||
IncomingCallFailedView: IncomingCallFailedView,
|
||||
init: init
|
||||
};
|
||||
})(document.mozL10n);
|
||||
|
|
|
@ -431,87 +431,7 @@ describe("loop.conversation", function() {
|
|||
sandbox.stub(window, "close");
|
||||
});
|
||||
|
||||
describe("progress - terminated - cancel", function() {
|
||||
it("should stop alerting", function(done) {
|
||||
promise.then(function() {
|
||||
icView._websocket.trigger("progress", {
|
||||
state: "terminated",
|
||||
reason: "cancel"
|
||||
});
|
||||
|
||||
sinon.assert.calledOnce(navigator.mozLoop.stopAlerting);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it("should close the websocket", function(done) {
|
||||
promise.then(function() {
|
||||
icView._websocket.trigger("progress", {
|
||||
state: "terminated",
|
||||
reason: "cancel"
|
||||
});
|
||||
|
||||
sinon.assert.calledOnce(icView._websocket.close);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it("should close the window", function(done) {
|
||||
promise.then(function() {
|
||||
icView._websocket.trigger("progress", {
|
||||
state: "terminated",
|
||||
reason: "cancel"
|
||||
});
|
||||
|
||||
sandbox.clock.tick(1);
|
||||
|
||||
sinon.assert.calledOnce(window.close);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("progress - terminated - closed", function() {
|
||||
it("should stop alerting", function(done) {
|
||||
promise.then(function() {
|
||||
icView._websocket.trigger("progress", {
|
||||
state: "terminated",
|
||||
reason: "closed"
|
||||
});
|
||||
|
||||
sinon.assert.calledOnce(navigator.mozLoop.stopAlerting);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it("should close the websocket", function(done) {
|
||||
promise.then(function() {
|
||||
icView._websocket.trigger("progress", {
|
||||
state: "terminated",
|
||||
reason: "closed"
|
||||
});
|
||||
|
||||
sinon.assert.calledOnce(icView._websocket.close);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it("should close the window", function(done) {
|
||||
promise.then(function() {
|
||||
icView._websocket.trigger("progress", {
|
||||
state: "terminated",
|
||||
reason: "closed"
|
||||
});
|
||||
|
||||
sandbox.clock.tick(1);
|
||||
|
||||
sinon.assert.calledOnce(window.close);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("progress - terminated - timeout (previousState = alerting)", function() {
|
||||
describe("progress - terminated (previousState = alerting)", function() {
|
||||
it("should stop alerting", function(done) {
|
||||
promise.then(function() {
|
||||
icView._websocket.trigger("progress", {
|
||||
|
@ -528,7 +448,7 @@ describe("loop.conversation", function() {
|
|||
promise.then(function() {
|
||||
icView._websocket.trigger("progress", {
|
||||
state: "terminated",
|
||||
reason: "timeout"
|
||||
reason: "closed"
|
||||
}, "alerting");
|
||||
|
||||
sinon.assert.calledOnce(icView._websocket.close);
|
||||
|
@ -540,7 +460,7 @@ describe("loop.conversation", function() {
|
|||
promise.then(function() {
|
||||
icView._websocket.trigger("progress", {
|
||||
state: "terminated",
|
||||
reason: "timeout"
|
||||
reason: "answered-elsewhere"
|
||||
}, "alerting");
|
||||
|
||||
sandbox.clock.tick(1);
|
||||
|
@ -551,21 +471,33 @@ describe("loop.conversation", function() {
|
|||
});
|
||||
});
|
||||
|
||||
describe("progress - terminated - timeout (previousState not init" +
|
||||
describe("progress - terminated (previousState not init" +
|
||||
" nor alerting)",
|
||||
function() {
|
||||
it("should set the state to end", function(done) {
|
||||
promise.then(function() {
|
||||
icView._websocket.trigger("progress", {
|
||||
state: "terminated",
|
||||
reason: "timeout"
|
||||
reason: "media-fail"
|
||||
}, "connecting");
|
||||
|
||||
expect(icView.state.callStatus).eql("end");
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("should stop alerting", function(done) {
|
||||
promise.then(function() {
|
||||
icView._websocket.trigger("progress", {
|
||||
state: "terminated",
|
||||
reason: "media-fail"
|
||||
}, "connecting");
|
||||
|
||||
sinon.assert.calledOnce(navigator.mozLoop.stopAlerting);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -761,12 +693,12 @@ describe("loop.conversation", function() {
|
|||
});
|
||||
|
||||
describe("session:network-disconnected", function() {
|
||||
it("should navigate to call/feedback when network disconnects",
|
||||
it("should navigate to call failed when network disconnects",
|
||||
function() {
|
||||
conversation.trigger("session:network-disconnected");
|
||||
|
||||
TestUtils.findRenderedComponentWithType(icView,
|
||||
sharedView.FeedbackView);
|
||||
loop.conversation.IncomingCallFailedView);
|
||||
});
|
||||
|
||||
it("should update the conversation window toolbar title",
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
Cu.import("resource://services-common/utils.js");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Chat",
|
||||
"resource:///modules/Chat.jsm");
|
||||
let hasTheseProps = function(a, b) {
|
||||
for (let prop in a) {
|
||||
if (a[prop] != b[prop]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
let openChatOrig = Chat.open;
|
||||
|
||||
add_test(function test_openRoomsWindow() {
|
||||
let roomProps = {roomName: "UX Discussion",
|
||||
expiresIn: 5,
|
||||
roomOwner: "Alexis",
|
||||
maxSize: 2}
|
||||
|
||||
let roomData = {roomToken: "_nxD4V4FflQ",
|
||||
roomUrl: "http://localhost:3000/rooms/_nxD4V4FflQ",
|
||||
expiresAt: 1405534180}
|
||||
|
||||
loopServer.registerPathHandler("/rooms", (request, response) => {
|
||||
if (!request.bodyInputStream) {
|
||||
do_throw("empty request body");
|
||||
}
|
||||
let body = CommonUtils.readBytesFromInputStream(request.bodyInputStream);
|
||||
let data = JSON.parse(body);
|
||||
do_check_true(hasTheseProps(roomProps, data));
|
||||
|
||||
response.setStatusLine(null, 200, "OK");
|
||||
response.write(JSON.stringify(roomData));
|
||||
response.processAsync();
|
||||
response.finish();
|
||||
});
|
||||
|
||||
MozLoopService.register(mockPushHandler).then(() => {
|
||||
let opened = false;
|
||||
let created = false;
|
||||
let urlPieces = [];
|
||||
|
||||
Chat.open = function(contentWindow, origin, title, url) {
|
||||
urlPieces = url.split('/');
|
||||
do_check_eq(urlPieces[0], "about:loopconversation#room");
|
||||
opened = true;
|
||||
};
|
||||
|
||||
let returnedID = LoopRooms.createRoom(roomProps, (error, data) => {
|
||||
do_check_false(error);
|
||||
do_check_true(data);
|
||||
do_check_true(hasTheseProps(roomData, data));
|
||||
do_check_eq(data.localRoomId, urlPieces[1]);
|
||||
created = true;
|
||||
});
|
||||
|
||||
waitForCondition(function() created && opened).then(() => {
|
||||
do_check_true(opened, "should open a chat window");
|
||||
do_check_eq(returnedID, urlPieces[1]);
|
||||
|
||||
// Verify that a delayed callback, when attached,
|
||||
// received the same data.
|
||||
LoopRooms.addCallback(
|
||||
urlPieces[1], "RoomCreated",
|
||||
(error, data) => {
|
||||
do_check_false(error);
|
||||
do_check_true(data);
|
||||
do_check_true(hasTheseProps(roomData, data));
|
||||
do_check_eq(data.localRoomId, urlPieces[1]);
|
||||
});
|
||||
|
||||
run_next_test();
|
||||
}, () => {
|
||||
do_throw("should have opened a chat window");
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
function run_test()
|
||||
{
|
||||
setupFakeLoopServer();
|
||||
mockPushHandler.registrationPushURL = kEndPointUrl;
|
||||
|
||||
loopServer.registerPathHandler("/registration", (request, response) => {
|
||||
response.setStatusLine(null, 200, "OK");
|
||||
response.processAsync();
|
||||
response.finish();
|
||||
});
|
||||
|
||||
do_register_cleanup(function() {
|
||||
// Revert original Chat.open implementation
|
||||
Chat.open = openChatOrig;
|
||||
});
|
||||
|
||||
run_next_test();
|
||||
}
|
|
@ -94,14 +94,16 @@ add_test(function test_getAllRooms() {
|
|||
do_check_eq(rooms[2].roomName, "Third Room Name");
|
||||
|
||||
let room = rooms[0];
|
||||
do_check_true(room.localRoomID);
|
||||
do_check_true(room.localRoomId);
|
||||
do_check_false(room.currSize);
|
||||
delete roomList[0].currSize;
|
||||
do_check_true(hasTheseProps(roomList[0], room));
|
||||
delete roomDetail.roomName;
|
||||
delete room.participants;
|
||||
delete roomDetail.participants;
|
||||
do_check_true(hasTheseProps(roomDetail, room));
|
||||
|
||||
LoopRooms.getRoomData(room.localRoomID, (error, roomData) => {
|
||||
LoopRooms.getRoomData(room.localRoomId, (error, roomData) => {
|
||||
do_check_false(error);
|
||||
do_check_true(hasTheseProps(room, roomData));
|
||||
|
||||
|
|
|
@ -22,3 +22,4 @@ skip-if = toolkit == 'gonk'
|
|||
[test_loopservice_token_validation.js]
|
||||
[test_loopservice_busy.js]
|
||||
[test_rooms_getdata.js]
|
||||
[test_rooms_create.js]
|
||||
|
|
|
@ -1623,11 +1623,25 @@ BrowserGlue.prototype = {
|
|||
// Reset homepage pref for users who have it set to start.mozilla.org
|
||||
// or google.com/firefox.
|
||||
const HOMEPAGE_PREF = "browser.startup.homepage";
|
||||
let uri = Services.prefs.getComplexValue(HOMEPAGE_PREF,
|
||||
Ci.nsIPrefLocalizedString).data;
|
||||
if (uri && (uri.startsWith("http://start.mozilla.org") ||
|
||||
/^https?:\/\/(www\.)?google\.[a-z.]+\/firefox/i.test(uri))) {
|
||||
Services.prefs.clearUserPref(HOMEPAGE_PREF);
|
||||
if (Services.prefs.prefHasUserValue(HOMEPAGE_PREF)) {
|
||||
const DEFAULT =
|
||||
Services.prefs.getDefaultBranch(HOMEPAGE_PREF)
|
||||
.getComplexValue("", Ci.nsIPrefLocalizedString).data;
|
||||
let value =
|
||||
Services.prefs.getComplexValue(HOMEPAGE_PREF, Ci.nsISupportsString);
|
||||
let updated =
|
||||
value.data.replace(/https?:\/\/start\.mozilla\.org[^|]*/i, DEFAULT)
|
||||
.replace(/https?:\/\/(www\.)?google\.[a-z.]+\/firefox[^|]*/i,
|
||||
DEFAULT);
|
||||
if (updated != value.data) {
|
||||
if (updated == DEFAULT) {
|
||||
Services.prefs.clearUserPref(HOMEPAGE_PREF);
|
||||
} else {
|
||||
value.data = updated;
|
||||
Services.prefs.setComplexValue(HOMEPAGE_PREF,
|
||||
Ci.nsISupportsString, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -92,6 +92,7 @@ function parseDeclarations(inputString) {
|
|||
case "FUNCTION":
|
||||
current += token.value + "(";
|
||||
break;
|
||||
case "(":
|
||||
case ")":
|
||||
current += token.tokenType;
|
||||
break;
|
||||
|
|
|
@ -163,7 +163,9 @@ const TEST_DATA = [
|
|||
{name: "content", value: '"a not s\
|
||||
o very long title"', priority: ""}
|
||||
]
|
||||
}
|
||||
},
|
||||
// Test calc with nested parentheses
|
||||
{input: "width: calc((100% - 3em) / 2)", expected: [{name: "width", value: "calc((100% - 3em) / 2)", priority: ""}]},
|
||||
];
|
||||
|
||||
function run_test() {
|
||||
|
|
|
@ -23,7 +23,7 @@ def main(file):
|
|||
appdata = dict(("%s:%s" % (s, o), config.get(s, o)) for s in config.sections() for o in config.options(s))
|
||||
appdata['flags'] = ' | '.join(flags) if flags else '0'
|
||||
appdata['App:profile'] = '"%s"' % appdata['App:profile'] if 'App:profile' in appdata else 'NULL'
|
||||
expected = ('App:vendor', 'App:name', 'App:version', 'App:buildid',
|
||||
expected = ('App:vendor', 'App:name', 'App:remotingname', 'App:version', 'App:buildid',
|
||||
'App:id', 'Gecko:minversion', 'Gecko:maxversion')
|
||||
missing = [var for var in expected if var not in appdata]
|
||||
if missing:
|
||||
|
@ -40,6 +40,7 @@ def main(file):
|
|||
NULL, // directory
|
||||
"%(App:vendor)s",
|
||||
"%(App:name)s",
|
||||
"%(App:remotingname)s",
|
||||
"%(App:version)s",
|
||||
"%(App:buildid)s",
|
||||
"%(App:id)s",
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
[App]
|
||||
Vendor=@MOZ_APP_VENDOR@
|
||||
Name=@MOZ_APP_BASENAME@
|
||||
RemotingName=@MOZ_APP_REMOTINGNAME@
|
||||
#ifdef MOZ_APP_DISPLAYNAME
|
||||
CodeName=@MOZ_APP_DISPLAYNAME@
|
||||
#endif
|
||||
|
|
|
@ -27,7 +27,7 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
|
|||
|
||||
for var in ('GRE_MILESTONE', 'MOZ_APP_VERSION', 'MOZ_APP_BASENAME',
|
||||
'MOZ_APP_VENDOR', 'MOZ_APP_ID', 'MAR_CHANNEL_ID',
|
||||
'ACCEPTED_MAR_CHANNEL_IDS'):
|
||||
'ACCEPTED_MAR_CHANNEL_IDS', 'MOZ_APP_REMOTINGNAME'):
|
||||
DEFINES[var] = CONFIG[var]
|
||||
|
||||
if CONFIG['MOZ_APP_DISPLAYNAME'] != CONFIG['MOZ_APP_BASENAME']:
|
||||
|
|
12
configure.in
12
configure.in
|
@ -8683,6 +8683,8 @@ AC_SUBST(MOZ_CHILD_PROCESS_BUNDLE)
|
|||
# - MOZ_APP_VERSION: Defines the application version number.
|
||||
# - MOZ_APP_NAME: Used for e.g. the binary program file name. If not set,
|
||||
# defaults to a lowercase form of MOZ_APP_BASENAME.
|
||||
# - MOZ_APP_REMOTINGNAME: Used for the internal program name, which affects
|
||||
# profile name and remoting. If not set, defaults to MOZ_APP_NAME.
|
||||
# - MOZ_APP_PROFILE: When set, used for application.ini's
|
||||
# "Profile" field, which controls profile location.
|
||||
# - MOZ_APP_ID: When set, used for application.ini's "ID" field, and
|
||||
|
@ -8693,6 +8695,10 @@ if test -z "$MOZ_APP_NAME"; then
|
|||
MOZ_APP_NAME=`echo $MOZ_APP_BASENAME | tr A-Z a-z`
|
||||
fi
|
||||
|
||||
if test -z "$MOZ_APP_REMOTINGNAME"; then
|
||||
MOZ_APP_REMOTINGNAME=$MOZ_APP_NAME
|
||||
fi
|
||||
|
||||
# For extensions and langpacks, we require a max version that is compatible
|
||||
# across security releases. MOZ_APP_MAXVERSION is our method for doing that.
|
||||
# 24.0a1 and 24.0a2 aren't affected
|
||||
|
@ -8712,6 +8718,7 @@ AC_DEFINE_UNQUOTED(MOZ_B2G_VERSION,"$MOZ_B2G_VERSION")
|
|||
AC_DEFINE_UNQUOTED(MOZ_B2G_OS_NAME,"$MOZ_B2G_OS_NAME")
|
||||
|
||||
AC_SUBST(MOZ_APP_NAME)
|
||||
AC_SUBST(MOZ_APP_REMOTINGNAME)
|
||||
AC_SUBST(MOZ_APP_DISPLAYNAME)
|
||||
AC_SUBST(MOZ_APP_BASENAME)
|
||||
AC_SUBST(MOZ_APP_VENDOR)
|
||||
|
@ -9004,6 +9011,10 @@ if test "$ACCESSIBILITY" -a "$MOZ_ENABLE_GTK" ; then
|
|||
AC_DEFINE_UNQUOTED(ATK_REV_VERSION, $ATK_REV_VERSION)
|
||||
fi
|
||||
|
||||
if test "$MOZ_UPDATE_CHANNEL" = "aurora"; then
|
||||
AC_DEFINE(MOZ_DEV_EDITION)
|
||||
fi
|
||||
|
||||
if test "$MOZ_DEBUG"; then
|
||||
A11Y_LOG=1
|
||||
fi
|
||||
|
@ -9308,6 +9319,7 @@ export MOZ_NATIVE_ZLIB
|
|||
export MOZ_ZLIB_CFLAGS
|
||||
export MOZ_ZLIB_LIBS
|
||||
export MOZ_APP_NAME
|
||||
export MOZ_APP_REMOTINGNAME
|
||||
export DONT_POPULATE_VIRTUALENV=1
|
||||
export PYTHON
|
||||
export MOZILLA_CENTRAL_PATH=$_topsrcdir
|
||||
|
|
|
@ -588,6 +588,7 @@ skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s #bug 775227
|
|||
[test_htmlcopyencoder.html]
|
||||
[test_htmlcopyencoder.xhtml]
|
||||
[test_ipc_messagemanager_blob.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 936226
|
||||
[test_meta_viewport0.html]
|
||||
[test_meta_viewport1.html]
|
||||
[test_meta_viewport2.html]
|
||||
|
|
|
@ -58,6 +58,7 @@ skip-if = (toolkit == 'gonk' && debug) #debug-only failure; bug 926546
|
|||
skip-if = buildapp == 'mulet' || (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
|
||||
[test_input_sanitization.html]
|
||||
[test_input_textarea_set_value_no_scroll.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only
|
||||
[test_input_typing_sanitization.html]
|
||||
skip-if = buildapp == 'mulet'
|
||||
[test_input_untrusted_key_events.html]
|
||||
|
|
|
@ -306,20 +306,27 @@ skip-if = buildapp == 'b2g' && toolkit != 'gonk' # bug 1082984
|
|||
[test_aspectratio_mp4.html]
|
||||
[test_audio1.html]
|
||||
[test_audio2.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
[test_audioDocumentTitle.html]
|
||||
skip-if = true # bug 475110 - disabled since we don't play Wave files standalone
|
||||
[test_autoplay.html]
|
||||
[test_autoplay_contentEditable.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only
|
||||
[test_buffered.html]
|
||||
[test_bug448534.html]
|
||||
skip-if = buildapp == 'mulet' || os == 'win' # bug 894922
|
||||
skip-if = buildapp == 'mulet' || os == 'win' || (toolkit == 'android' && processor == 'x86') # bug 894922 #x86 only bug 914439
|
||||
[test_bug463162.xhtml]
|
||||
[test_bug465498.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86')
|
||||
[test_bug493187.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
[test_bug495145.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
[test_bug495300.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
[test_bug654550.html]
|
||||
[test_bug686942.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
[test_bug726904.html]
|
||||
[test_bug874897.html]
|
||||
[test_bug883173.html]
|
||||
|
@ -330,12 +337,13 @@ skip-if = buildapp == 'mulet' || os == 'win' # bug 894922
|
|||
[test_bug1018933.html]
|
||||
[test_can_play_type.html]
|
||||
[test_can_play_type_mpeg.html]
|
||||
skip-if = buildapp == 'b2g' # bug 1021675
|
||||
skip-if = buildapp == 'b2g' || (toolkit == 'android' && processor == 'x86') # bug 1021675 #x86 only bug 914439
|
||||
[test_can_play_type_no_ogg.html]
|
||||
[test_can_play_type_ogg.html]
|
||||
[test_chaining.html]
|
||||
skip-if = toolkit == 'gonk' && debug
|
||||
[test_clone_media_element.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
[test_closing_connections.html]
|
||||
[test_constants.html]
|
||||
[test_contentDuration1.html]
|
||||
|
@ -358,6 +366,7 @@ skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s # bug 1043403, bug 1
|
|||
skip-if = toolkit == 'android' # bug 608634
|
||||
[test_error_on_404.html]
|
||||
[test_fastSeek.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
[test_fastSeek-forwards.html]
|
||||
[test_imagecapture.html]
|
||||
[test_info_leak.html]
|
||||
|
@ -365,12 +374,18 @@ skip-if = toolkit == 'android' # bug 608634
|
|||
[test_invalid_reject_play.html]
|
||||
[test_invalid_seek.html]
|
||||
[test_load.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
[test_load_candidates.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
[test_load_same_resource.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
[test_load_source.html]
|
||||
[test_loop.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
[test_media_selection.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
[test_media_sniffer.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
[test_mediarecorder_avoid_recursion.html]
|
||||
[test_mediarecorder_creation.html]
|
||||
[test_mediarecorder_creation_fail.html]
|
||||
|
@ -408,18 +423,25 @@ skip-if = true # bug 567954 and intermittent leaks
|
|||
[test_mozHasAudio.html]
|
||||
[test_networkState.html]
|
||||
[test_new_audio.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
[test_no_load_event.html]
|
||||
[test_paused.html]
|
||||
[test_paused_after_ended.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
[test_play_events.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
[test_play_events_2.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
[test_play_twice.html]
|
||||
# Seamonkey: Bug 598252, B2G: Bug 982100, Android: Bug 758476, bug 981086
|
||||
skip-if = appname == "seamonkey" || toolkit == 'gonk' || toolkit == 'android'
|
||||
[test_playback.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
[test_playback_errors.html]
|
||||
[test_playback_rate.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #bug 845162
|
||||
[test_playback_rate_playpause.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
[test_played.html]
|
||||
skip-if = true # bug 1021794
|
||||
[test_preload_actions.html]
|
||||
|
@ -427,15 +449,20 @@ skip-if = true # bug 1021794
|
|||
[test_preload_suspend.html]
|
||||
skip-if = true # bug 493692
|
||||
[test_progress.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
[test_reactivate.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
[test_readyState.html]
|
||||
[test_referer.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only
|
||||
[test_replay_metadata.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
[test_reset_events_async.html]
|
||||
[test_reset_src.html]
|
||||
[test_resume.html]
|
||||
skip-if = true # bug 1021673
|
||||
[test_seek_out_of_range.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
[test_seek-1.html]
|
||||
[test_seek-2.html]
|
||||
[test_seek-3.html]
|
||||
|
@ -450,6 +477,7 @@ skip-if = true # bug 1021673
|
|||
[test_seek-12.html]
|
||||
[test_seek-13.html]
|
||||
[test_seekable1.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #timeout x86 only bug 914439
|
||||
[test_seekable2.html]
|
||||
[test_seekable3.html]
|
||||
[test_seekLies.html]
|
||||
|
@ -458,9 +486,12 @@ skip-if = true # bug 1021673
|
|||
[test_source_null.html]
|
||||
[test_source_write.html]
|
||||
[test_standalone.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
[test_streams_autoplay.html]
|
||||
[test_streams_element_capture.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
[test_streams_element_capture_createObjectURL.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
[test_streams_element_capture_playback.html]
|
||||
[test_streams_element_capture_reset.html]
|
||||
[test_streams_gc.html]
|
||||
|
@ -472,10 +503,13 @@ skip-if = buildapp == 'b2g' # bug 1021682
|
|||
[test_texttracklist.html]
|
||||
[test_texttrackregion.html]
|
||||
[test_timeupdate_small_files.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
[test_trackelementevent.html]
|
||||
[test_trackevent.html]
|
||||
[test_unseekable.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only
|
||||
[test_video_to_canvas.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
|
||||
[test_video_in_audio_element.html]
|
||||
[test_videoDocumentTitle.html]
|
||||
[test_VideoPlaybackQuality.html]
|
||||
|
|
|
@ -35,6 +35,7 @@ support-files =
|
|||
[test_audioBufferSourceNodeLoopStartEnd.html]
|
||||
[test_audioBufferSourceNodeLoopStartEndSame.html]
|
||||
[test_audioBufferSourceNodeNeutered.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only
|
||||
[test_audioBufferSourceNodeNoStart.html]
|
||||
[test_audioBufferSourceNodeNullBuffer.html]
|
||||
[test_audioBufferSourceNodeOffset.html]
|
||||
|
|
|
@ -38,7 +38,7 @@ skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) || toolkit == 'and
|
|||
[test_child.html]
|
||||
[test_grandchild.html]
|
||||
[test_not-opener.html]
|
||||
skip-if = buildapp == 'b2g'
|
||||
skip-if = buildapp == 'b2g' || (toolkit == 'android' && processor == 'x86') #x86 only
|
||||
[test_opener.html]
|
||||
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage
|
||||
[test_popup-navigates-children.html]
|
||||
|
|
|
@ -31,7 +31,9 @@ support-files =
|
|||
[test_marketplace_pkg_install.html]
|
||||
skip-if = buildapp == "b2g" || toolkit == "android" # see bug 989806
|
||||
[test_packaged_app_install.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only
|
||||
[test_packaged_app_update.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only
|
||||
[test_receipt_operations.html]
|
||||
[test_signed_pkg_install.html]
|
||||
[test_uninstall_errors.html]
|
||||
|
|
|
@ -153,6 +153,7 @@ disabled = bug 1022281
|
|||
[test_browserElement_inproc_FrameWrongURI.html]
|
||||
skip-if = (toolkit == 'gonk' && !debug)
|
||||
[test_browserElement_inproc_GetScreenshot.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only
|
||||
[test_browserElement_inproc_GetScreenshotDppx.html]
|
||||
[test_browserElement_inproc_Iconchange.html]
|
||||
[test_browserElement_inproc_KeyEvents.html]
|
||||
|
@ -200,6 +201,7 @@ skip-if = (toolkit == 'gonk' && !debug)
|
|||
[test_browserElement_inproc_XFrameOptionsDeny.html]
|
||||
[test_browserElement_inproc_XFrameOptionsSameOrigin.html]
|
||||
[test_browserElement_oop_NextPaint.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 936226
|
||||
# Disabled due to https://bugzilla.mozilla.org/show_bug.cgi?id=774100
|
||||
[test_browserElement_inproc_Reload.html]
|
||||
disabled = bug 774100
|
||||
|
|
|
@ -25,27 +25,49 @@ support-files =
|
|||
[test_2d.clearRect.image.offscreen.html]
|
||||
[test_2d.clip.winding.html]
|
||||
[test_2d.composite.canvas.color-burn.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
[test_2d.composite.canvas.color-dodge.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
[test_2d.composite.canvas.color.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
[test_2d.composite.canvas.darken.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
[test_2d.composite.canvas.destination-atop.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
[test_2d.composite.canvas.destination-in.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
[test_2d.composite.canvas.difference.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
[test_2d.composite.canvas.exclusion.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
[test_2d.composite.canvas.hard-light.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
[test_2d.composite.canvas.hue.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
[test_2d.composite.canvas.lighten.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
[test_2d.composite.canvas.luminosity.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
[test_2d.composite.canvas.multiply.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
[test_2d.composite.canvas.overlay.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
[test_2d.composite.canvas.saturation.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
[test_2d.composite.canvas.screen.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
[test_2d.composite.canvas.soft-light.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
[test_2d.composite.canvas.source-in.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
[test_2d.composite.canvas.source-out.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
[test_2d.composite.image.destination-atop.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
[test_2d.composite.image.destination-in.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
[test_2d.composite.image.source-in.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
[test_2d.composite.image.source-out.html]
|
||||
# xor and lighter aren't well handled by cairo; they mostly work, but we don't want
|
||||
# to test that
|
||||
|
@ -112,8 +134,11 @@ skip-if = toolkit != 'cocoa'
|
|||
[test_2d.composite.uncovered.fill.destination-atop.html]
|
||||
skip-if = toolkit != 'cocoa'
|
||||
[test_2d.composite.uncovered.image.destination-in.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
[test_2d.composite.uncovered.image.source-in.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
[test_2d.composite.uncovered.image.source-out.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 913662
|
||||
# Tests that fail on non-Mac (bug 407107)
|
||||
[test_2d.composite.uncovered.pattern.source-in.html]
|
||||
skip-if = toolkit != 'cocoa'
|
||||
|
|
|
@ -35,12 +35,15 @@ support-files =
|
|||
|
||||
[test_app_install.html]
|
||||
[test_readonly.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 936226
|
||||
[test_basic.html]
|
||||
[test_basic_worker.html]
|
||||
[test_changes.html]
|
||||
[test_arrays.html]
|
||||
[test_oop.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 936226
|
||||
[test_sync.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 936226
|
||||
[test_sync_worker.html]
|
||||
[test_bug924104.html]
|
||||
[test_certifiedApp.html]
|
||||
|
|
|
@ -66,21 +66,27 @@ support-files =
|
|||
# [test_bug478398.html]
|
||||
# disabled - See bug 579139
|
||||
[test_bug490949.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only
|
||||
[test_bug496292.html]
|
||||
[test_bug497665.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only
|
||||
[test_bug512435.html]
|
||||
[test_bug552605-1.html]
|
||||
[test_bug552605-2.html]
|
||||
[test_bug553982.html]
|
||||
[test_bug601470.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only
|
||||
[test_bug614392.html]
|
||||
[test_bug657191.html]
|
||||
[test_bug671906.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only
|
||||
[test_bug733553.html]
|
||||
[test_bug767779.html]
|
||||
[test_bug865919.html]
|
||||
[test_bug89419-1.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only
|
||||
[test_bug89419-2.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only
|
||||
[test_animation_operators.html]
|
||||
[test_drawDiscardedImage.html]
|
||||
skip-if = toolkit == "gonk" #Bug 997034 - canvas.toDataURL() often causes lost connection to device.
|
||||
|
|
|
@ -9,6 +9,6 @@
|
|||
# project structure.
|
||||
|
||||
# Project target.
|
||||
target=@ANDROID_TARGET_SDK@
|
||||
target=android-@ANDROID_TARGET_SDK@
|
||||
@IDE_PROJECT_LIBRARY_SETTING@
|
||||
@IDE_PROJECT_LIBRARY_REFERENCES@
|
||||
|
|
|
@ -1,89 +1,17 @@
|
|||
{
|
||||
"runtests": {},
|
||||
"excludetests": {
|
||||
"content/base/test/test_ipc_messagemanager_blob.html": "x86 only bug 936226",
|
||||
"content/base/test/test_copypaste.xul": "bug 904183",
|
||||
"content/html/content/test/forms/test_input_textarea_set_value_no_scroll.html": "x86 only",
|
||||
"content/media/test/test_clone_media_element.html": "x86 only bug 914439",
|
||||
"content/media/test/test_fastSeek.html": "x86 only bug 914439",
|
||||
"content/media/test/test_media_selection.html": "x86 only bug 914439",
|
||||
"content/media/test/test_bug495300.html": "x86 only bug 914439",
|
||||
"content/media/test/test_new_audio.html": "x86 only bug 914439",
|
||||
"content/media/test/test_seeked.html": "x86 only bug 914439",
|
||||
"content/media/test/test_played.html": "bug 751539",
|
||||
"content/media/test/test_playback_rate.html": "bug 845162",
|
||||
"content/media/test/test_playback_rate_playpause.html": "x86 only bug 914439",
|
||||
"content/media/test/test_loop.html": "x86 only bug 914439",
|
||||
"content/media/test/test_play_twice.html": "x86 only bug 914439",
|
||||
"content/media/test/test_bug495145.html": "x86 only bug 914439",
|
||||
"content/media/test/test_bug465498.html": "",
|
||||
"content/media/test/test_play_events_2.html": "x86 only bug 914439",
|
||||
"content/media/test/test_media_sniffer.html": "x86 only bug 914439",
|
||||
"content/media/test/test_seek_out_of_range.html": "x86 only bug 914439",
|
||||
"content/media/test/test_load_same_resource.html": "x86 only bug 914439",
|
||||
"content/media/test/test_bug493187.html": "x86 only bug 914439",
|
||||
"content/media/test/test_autoplay_contentEditable.html": "x86 only",
|
||||
"content/media/test/test_audio2.html": "x86 only bug 914439",
|
||||
"content/media/test/test_can_play_type_mpeg.html": "x86 only bug 914439",
|
||||
"content/media/test/test_bug686942.html": "x86 only bug 914439",
|
||||
"content/media/test/test_standalone.html": "x86 only bug 914439",
|
||||
"content/media/test/test_bug448534.html": "x86 only bug 914439",
|
||||
"content/media/test/test_video_to_canvas.html": "x86 only bug 914439",
|
||||
"content/media/test/test_load_candidates.html": "x86 only bug 914439",
|
||||
"content/media/test/test_streams_element_capture_createObjectURL.html": "x86 only bug 914439",
|
||||
"content/media/test/test_progress.html": "x86 only bug 914439",
|
||||
"content/media/test/test_seekable1.html": "timeout x86 only bug 914439",
|
||||
"content/media/test/test_play_events.html": "x86 only bug 914439",
|
||||
"content/media/test/test_reactivate.html": "x86 only bug 914439",
|
||||
"content/media/test/test_referer.html": "x86 only",
|
||||
"content/media/webaudio/test/test_audioBufferSourceNodeNeutered.html": "x86 only",
|
||||
"content/media/test/test_load.html": "x86 only bug 914439",
|
||||
"content/media/test/test_streams_element_capture.html": "x86 only bug 914439",
|
||||
"content/media/test/test_replay_metadata.html": "x86 only bug 914439",
|
||||
"content/media/test/test_unseekable.html": "x86 only",
|
||||
"content/media/test/test_paused_after_ended.html": "x86 only bug 914439",
|
||||
"content/media/test/test_timeupdate_small_files.html": "x86 only bug 914439",
|
||||
"content/media/test/test_playback.html": "x86 only bug 914439",
|
||||
"docshell/test/navigation/test_not-opener.html": "x86 only",
|
||||
"dom/apps/tests/test_packaged_app_update.html": "x86 only",
|
||||
"dom/apps/tests/test_packaged_app_install.html": "x86 only",
|
||||
"dom/browser-element/mochitest/test_browserElement_oop_NextPaint.html": "x86 only bug 936226",
|
||||
"dom/browser-element/mochitest/test_browserElement_inproc_GetScreenshot.html": "x86 only",
|
||||
"dom/browser-element/mochitest/test_browserElement_NoWhitelist.html": "x86 only bug 936226",
|
||||
"dom/browser-element/mochitest/test_browserElement_oop_SecurityChange.html": "TIMED_OUT, bug 766586",
|
||||
"dom/canvas/test/webgl-conformance": "bug 865443 - separate suite -- mochitest-gl",
|
||||
"dom/canvas/test/test_2d.composite.canvas.luminosity.html": "x86 only bug 913662",
|
||||
"dom/canvas/test/test_2d.composite.canvas.source-in.html": "x86 only bug 913662",
|
||||
"dom/canvas/test/test_2d.composite.uncovered.image.destination-atop.html": "x86 only bug 913662",
|
||||
"dom/canvas/test/test_2d.composite.image.source-in.html": "x86 only bug 913662",
|
||||
"dom/canvas/test/test_2d.composite.canvas.multiply.html": "x86 only bug 913662",
|
||||
"dom/canvas/test/test_2d.composite.canvas.lighten.html": "x86 only bug 913662",
|
||||
"dom/canvas/test/test_2d.composite.canvas.color-dodge.html": "x86 only bug 913662",
|
||||
"dom/canvas/test/test_2d.composite.canvas.destination-in.html": "x86 only bug 913662",
|
||||
"dom/canvas/test/test_2d.composite.canvas.screen.html": "x86 only bug 913662",
|
||||
"dom/canvas/test/test_2d.composite.image.source-out.html": "x86 only bug 913662",
|
||||
"dom/canvas/test/test_2d.composite.canvas.exclusion.html": "x86 only bug 913662",
|
||||
"dom/canvas/test/test_2d.composite.canvas.source-out.html": "x86 only bug 913662",
|
||||
"dom/canvas/test/test_2d.composite.canvas.soft-light.html": "x86 only bug 913662",
|
||||
"dom/canvas/test/test_2d.composite.canvas.destination-atop.html": "x86 only bug 913662",
|
||||
"dom/canvas/test/test_canvas.html": "x86 only bug 913662",
|
||||
"dom/canvas/test/test_2d.composite.canvas.overlay.html": "x86 only bug 913662",
|
||||
"dom/canvas/test/test_2d.composite.canvas.darken.html": "x86 only bug 913662",
|
||||
"dom/canvas/test/test_2d.composite.uncovered.image.source-in.html": "x86 only bug 913662",
|
||||
"dom/canvas/test/test_2d.composite.canvas.saturation.html": "x86 only bug 913662",
|
||||
"dom/canvas/test/test_2d.composite.image.destination-atop.html": "x86 only bug 913662",
|
||||
"dom/canvas/test/test_2d.composite.uncovered.image.source-out.html": "x86 only bug 913662",
|
||||
"dom/canvas/test/test_2d.composite.canvas.color.html": "x86 only bug 913662",
|
||||
"dom/canvas/test/test_2d.composite.image.destination-in.html": "x86 only bug 913662",
|
||||
"dom/canvas/test/test_2d.composite.canvas.hue.html": "x86 only bug 913662",
|
||||
"dom/canvas/test/test_2d.composite.canvas.difference.html": "x86 only bug 913662",
|
||||
"dom/canvas/test/test_2d.composite.canvas.color-burn.html": "x86 only bug 913662",
|
||||
"dom/canvas/test/test_2d.composite.uncovered.image.destination-in.html": "x86 only bug 913662",
|
||||
"dom/canvas/test/test_2d.composite.canvas.hard-light.html": "x86 only bug 913662",
|
||||
"dom/contacts/tests/test_contacts_getall.html": "x86 only",
|
||||
"dom/datastore/tests/test_oop.html": "x86 only bug 936226",
|
||||
"dom/datastore/tests/test_sync.html": "x86 only bug 936226",
|
||||
"dom/datastore/tests/test_readonly.html": "x86 only bug 936226",
|
||||
"dom/devicestorage": "bug 781789 & bug 782275",
|
||||
"dom/imptests/editing/selecttest/test_addRange.html": "bug 775227",
|
||||
"dom/imptests/editing/conformancetest/test_runtest.html": "",
|
||||
|
@ -93,18 +21,9 @@
|
|||
"dom/tests/mochitest/geolocation/test_timeoutWatch.html": "TIMED_OUT",
|
||||
"editor/libeditor/tests/test_bug569988.html": "TIMED_OUT",
|
||||
"editor/libeditor/tests/test_texteditor_keyevent_handling.html": "",
|
||||
"Harness_sanity/test_sanityWindowSnapshot.html": "x86 only",
|
||||
"image/test/mochitest/test_bug671906.html": "x86 only",
|
||||
"image/test/mochitest/test_bug89419-2.html": "x86 only",
|
||||
"image/test/mochitest/test_bug490949.html": "x86 only",
|
||||
"image/test/mochitest/test_bug497665.html": "x86 only",
|
||||
"image/test/mochitest/test_bug601470.html": "x86 only",
|
||||
"image/test/mochitest/test_bug89419-1.html": "x86 only",
|
||||
"layout/generic": "CRASH_DUMP, RANDOM, ONLY IN CHUNK 10",
|
||||
"MochiKit-1.4.2/tests/test_MochiKit-Async.html": "x86 only",
|
||||
"robocop": "TIMED_OUT",
|
||||
"toolkit/components/satchel/test/test_form_autocomplete.html": "TIMED_OUT",
|
||||
"toolkit/components/alerts/test/test_alerts_noobserve.html": "x86 only",
|
||||
"toolkit/components/places/tests/test_bug_411966.html": "RANDOM",
|
||||
"toolkit/components/passwordmgr/test/test_privbrowsing_perwindowpb.html": "",
|
||||
"toolkit/content/tests/widgets/test_menubar.xul": "W/SharedBufferStack(21799",
|
||||
|
|
|
@ -7,6 +7,7 @@ skip-if = true #depends on fix for bug 1048446
|
|||
[test_sanityException2.html]
|
||||
[test_sanityParams.html]
|
||||
[test_sanityWindowSnapshot.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only
|
||||
[test_SpecialPowersExtension.html]
|
||||
[test_SpecialPowersExtension2.html]
|
||||
support-files = file_SpecialPowersFrame1.html
|
||||
|
|
|
@ -13,6 +13,7 @@ support-files =
|
|||
test_Signal.js
|
||||
|
||||
[test_MochiKit-Async.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only
|
||||
[test_MochiKit-Base.html]
|
||||
[test_MochiKit-Color.html]
|
||||
[test_MochiKit-DateTime.html]
|
||||
|
|
|
@ -6,4 +6,5 @@ skip-if = buildapp == 'b2g' || e10s
|
|||
[test_alerts.html]
|
||||
skip-if = toolkit == 'android'
|
||||
[test_alerts_noobserve.html]
|
||||
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only
|
||||
[test_multiple_alerts.html]
|
||||
|
|
|
@ -14,11 +14,11 @@
|
|||
* following properties:
|
||||
* - guid: (string)
|
||||
* The globally unique id of the page.
|
||||
* - uri: (URL)
|
||||
* - url: (URL)
|
||||
* or (nsIURI)
|
||||
* or (string)
|
||||
* The full URI of the page. Note that `PageInfo` values passed as
|
||||
* argument may hold `nsIURI` or `string` values for property `uri`,
|
||||
* argument may hold `nsIURI` or `string` values for property `url`,
|
||||
* but `PageInfo` objects returned by this module always hold `URL`
|
||||
* values.
|
||||
* - title: (string)
|
||||
|
@ -75,7 +75,33 @@ XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
|||
"resource://gre/modules/Task.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Sqlite",
|
||||
"resource://gre/modules/Sqlite.jsm");
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "gNotifier",
|
||||
"@mozilla.org/browser/nav-history-service;1",
|
||||
Ci.nsPIPlacesHistoryListenersNotifier);
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
|
||||
"resource://gre/modules/PlacesUtils.jsm");
|
||||
Cu.importGlobalProperties(["URL"]);
|
||||
|
||||
/**
|
||||
* Shared connection
|
||||
*/
|
||||
XPCOMUtils.defineLazyGetter(this, "DBConnPromised",
|
||||
() => new Promise((resolve) => {
|
||||
Sqlite.wrapStorageConnection({ connection: PlacesUtils.history.DBConnection } )
|
||||
.then(db => {
|
||||
try {
|
||||
Sqlite.shutdown.addBlocker("Places History.jsm: Closing database wrapper",
|
||||
() => db.close());
|
||||
} catch (ex) {
|
||||
// It's too late to block shutdown of Sqlite, so close the connection
|
||||
// immediately.
|
||||
db.close();
|
||||
throw ex;
|
||||
}
|
||||
resolve(db);
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
this.History = Object.freeze({
|
||||
/**
|
||||
|
@ -111,7 +137,7 @@ this.History = Object.freeze({
|
|||
*
|
||||
* @param infos: (PageInfo)
|
||||
* Information on a page. This `PageInfo` MUST contain
|
||||
* - either a property `guid` or a property `uri`, as specified
|
||||
* - either a property `guid` or a property `url`, as specified
|
||||
* by the definition of `PageInfo`;
|
||||
* - a property `visits`, as specified by the definition of
|
||||
* `PageInfo`, which MUST contain at least one visit.
|
||||
|
@ -135,14 +161,14 @@ this.History = Object.freeze({
|
|||
* (i.e. if page entries were updated but not created).
|
||||
*
|
||||
* @throws (Error)
|
||||
* If the `uri` specified was for a protocol that should not be
|
||||
* If the `url` specified was for a protocol that should not be
|
||||
* stored (e.g. "chrome:", "mailbox:", "about:", "imap:", "news:",
|
||||
* "moz-anno:", "view-source:", "resource:", "data:", "wyciwyg:",
|
||||
* "javascript:", "blob:").
|
||||
* @throws (Error)
|
||||
* If `infos` has an unexpected type.
|
||||
* @throws (Error)
|
||||
* If a `PageInfo` has neither `guid` nor `uri`,
|
||||
* If a `PageInfo` has neither `guid` nor `url`.
|
||||
* @throws (Error)
|
||||
* If a `guid` property provided is not a valid GUID.
|
||||
* @throws (Error)
|
||||
|
@ -177,12 +203,42 @@ this.History = Object.freeze({
|
|||
* A promise resoled once the operation is complete.
|
||||
* @resolve (bool)
|
||||
* `true` if at least one page was removed, `false` otherwise.
|
||||
* @throws (Error)
|
||||
* @throws (TypeError)
|
||||
* If `pages` has an unexpected type or if a string provided
|
||||
* is neither a valid GUID nor a valid URI.
|
||||
* is neither a valid GUID nor a valid URI or if `pages`
|
||||
* is an empty array.
|
||||
*/
|
||||
remove: function (pages, onResult) {
|
||||
throw new Error("Method not implemented");
|
||||
remove: function (pages, onResult = null) {
|
||||
// Normalize and type-check arguments
|
||||
if (Array.isArray(pages)) {
|
||||
if (pages.length == 0) {
|
||||
throw new TypeError("Expected at least one page");
|
||||
}
|
||||
} else {
|
||||
pages = [pages];
|
||||
}
|
||||
|
||||
let guids = [];
|
||||
let urls = [];
|
||||
for (let page of pages) {
|
||||
// Normalize to URL or GUID, or throw if `page` cannot
|
||||
// be normalized.
|
||||
let normalized = normalizeToURLOrGUID(page);
|
||||
if (typeof normalized === "string") {
|
||||
guids.push(normalized);
|
||||
} else {
|
||||
urls.push(normalized.href);
|
||||
}
|
||||
}
|
||||
// At this stage, we know that either `guids` is not-empty
|
||||
// or `urls` is not-empty.
|
||||
|
||||
if (onResult && typeof onResult != "function") {
|
||||
throw new TypeError("Invalid function: " + onResult);
|
||||
}
|
||||
|
||||
// Now perform queries
|
||||
return remove({guids: guids, urls: urls}, onResult);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -257,3 +313,154 @@ this.History = Object.freeze({
|
|||
TRANSITION_FRAMED_LINK: Ci.nsINavHistoryService.TRANSITION_FRAMED_LINK,
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* Normalize a key to either a string (if it is a valid GUID) or an
|
||||
* instance of `URL` (if it is a `URL`, `nsIURI`, or a string
|
||||
* representing a valid url).
|
||||
*
|
||||
* @throws (TypeError)
|
||||
* If the key is neither a valid guid nor a valid url.
|
||||
*/
|
||||
function normalizeToURLOrGUID(key) {
|
||||
if (typeof key === "string") {
|
||||
// A string may be a URL or a guid
|
||||
if (/^[a-zA-Z0-9\-_]{12}$/.test(key)) {
|
||||
return key;
|
||||
}
|
||||
return new URL(key);
|
||||
}
|
||||
if (key instanceof URL) {
|
||||
return key;
|
||||
}
|
||||
if (key instanceof Ci.nsIURI) {
|
||||
return new URL(key.spec);
|
||||
}
|
||||
throw new TypeError("Invalid url or guid: " + key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a list of strings or numbers to its SQL
|
||||
* representation as a string.
|
||||
*/
|
||||
function sqlList(list) {
|
||||
return list.map(JSON.stringify).join();
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate and recompute the frecency of a list of pages,
|
||||
* informing frecency observers.
|
||||
*
|
||||
* @param db: (Sqlite connection)
|
||||
* @param idList: (Array)
|
||||
* The `moz_places` identifiers for the places to invalidate.
|
||||
* @return (Promise)
|
||||
*/
|
||||
let invalidateFrecencies = Task.async(function*(db, idList) {
|
||||
if (idList.length == 0) {
|
||||
return;
|
||||
}
|
||||
let ids = sqlList(idList);
|
||||
yield db.execute(
|
||||
`UPDATE moz_places
|
||||
SET frecency = NOTIFY_FRECENCY(
|
||||
CALCULATE_FRECENCY(id), url, guid, hidden, last_visit_date
|
||||
) WHERE id in (${ ids })`
|
||||
);
|
||||
yield db.execute(
|
||||
`UPDATE moz_places
|
||||
SET hidden = 0
|
||||
WHERE id in (${ ids })
|
||||
AND frecency <> 0`
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
// Inner implementation of History.remove.
|
||||
let remove = Task.async(function*({guids, urls}, onResult = null) {
|
||||
let db = yield DBConnPromised;
|
||||
|
||||
// 1. Find out what needs to be removed
|
||||
let query =
|
||||
`SELECT id, url, guid, foreign_count, title, frecency FROM moz_places
|
||||
WHERE guid IN (${ sqlList(guids) })
|
||||
OR url IN (${ sqlList(urls) })
|
||||
`;
|
||||
|
||||
let pages = [];
|
||||
let hasPagesToKeep = false;
|
||||
let hasPagesToRemove = false;
|
||||
yield db.execute(query, null, Task.async(function*(row) {
|
||||
let toRemove = row.getResultByName("foreign_count") == 0;
|
||||
if (toRemove) {
|
||||
hasPagesToRemove = true;
|
||||
} else {
|
||||
hasPagesToKeep = true;
|
||||
}
|
||||
let id = row.getResultByName("id");
|
||||
let guid = row.getResultByName("guid");
|
||||
let url = row.getResultByName("url");
|
||||
let page = {
|
||||
id: id,
|
||||
guid: guid,
|
||||
toRemove: toRemove,
|
||||
uri: NetUtil.newURI(url),
|
||||
};
|
||||
pages.push(page);
|
||||
if (onResult) {
|
||||
let pageInfo = {
|
||||
guid: guid,
|
||||
title: row.getResultByName("title"),
|
||||
frecency: row.getResultByName("frecency"),
|
||||
url: new URL(url)
|
||||
};
|
||||
try {
|
||||
yield onResult(pageInfo);
|
||||
} catch (ex) {
|
||||
// Errors should be reported but should not stop `remove`.
|
||||
Promise.reject(ex);
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
if (pages.length == 0) {
|
||||
// Nothing to do
|
||||
return false;
|
||||
}
|
||||
|
||||
yield db.executeTransaction(function*() {
|
||||
// 2. Remove all visits to these pages.
|
||||
yield db.execute(`DELETE FROM moz_historyvisits
|
||||
WHERE place_id IN (${ sqlList([p.id for (p of pages)]) })
|
||||
`);
|
||||
|
||||
// 3. For pages that should not be removed, invalidate frecencies.
|
||||
if (hasPagesToKeep) {
|
||||
yield invalidateFrecencies(db, [p.id for (p of pages) if (!p.toRemove)]);
|
||||
}
|
||||
|
||||
// 4. For pages that should be removed, remove page.
|
||||
if (hasPagesToRemove) {
|
||||
let ids = [p.id for (p of pages) if (p.toRemove)];
|
||||
yield db.execute(`DELETE FROM moz_places
|
||||
WHERE id IN (${ sqlList(ids) })
|
||||
`);
|
||||
}
|
||||
|
||||
// 5. Notify observers.
|
||||
for (let {guid, uri, toRemove} of pages) {
|
||||
gNotifier.notifyOnPageExpired(
|
||||
uri, // uri
|
||||
0, // visitTime - There are no more visits
|
||||
toRemove, // wholeEntry
|
||||
guid, // guid
|
||||
Ci.nsINavHistoryObserver.REASON_DELETED, // reason
|
||||
-1 // transition
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
PlacesUtils.history.clearEmbedVisits();
|
||||
|
||||
return hasPagesToRemove;
|
||||
});
|
||||
|
|
|
@ -1176,7 +1176,7 @@ interface nsINavHistoryQueryOptions : nsISupports
|
|||
nsINavHistoryQueryOptions clone();
|
||||
};
|
||||
|
||||
[scriptable, uuid(4b6963bf-763a-4f39-9fec-25670d354dd9)]
|
||||
[scriptable, uuid(47f7b08b-71e0-492e-a2be-9a9fbfc75250)]
|
||||
interface nsINavHistoryService : nsISupports
|
||||
{
|
||||
/**
|
||||
|
@ -1391,6 +1391,11 @@ interface nsINavHistoryService : nsISupports
|
|||
* history is disabled if the places.history.enabled pref is false.
|
||||
*/
|
||||
readonly attribute boolean historyDisabled;
|
||||
|
||||
/**
|
||||
* Clear all TRANSITION_EMBED visits.
|
||||
*/
|
||||
void clearEmbedVisits();
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -3757,6 +3757,12 @@ nsNavHistory::clearEmbedVisits() {
|
|||
mEmbedVisits.Clear();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNavHistory::ClearEmbedVisits() {
|
||||
clearEmbedVisits();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsNavHistory::CheckIsRecentEvent
|
||||
//
|
||||
// Sees if this URL happened "recently."
|
||||
|
|
|
@ -16,6 +16,7 @@ XPCSHELL_TESTS_MANIFESTS += [
|
|||
'network/xpcshell.ini',
|
||||
'queries/xpcshell.ini',
|
||||
'unifiedcomplete/xpcshell.ini',
|
||||
'unit/history/xpcshell.ini',
|
||||
'unit/xpcshell.ini',
|
||||
'xpcshell.ini',
|
||||
]
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const Ci = Components.interfaces;
|
||||
const Cc = Components.classes;
|
||||
const Cr = Components.results;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
// Import common head.
|
||||
let (commonFile = do_get_file("../../head_common.js", false)) {
|
||||
let uri = Services.io.newFileURI(commonFile);
|
||||
Services.scriptloader.loadSubScript(uri.spec, this);
|
||||
};
|
||||
|
|
@ -0,0 +1,342 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// Tests for `History.remove`, as implemented in History.jsm
|
||||
|
||||
"use strict";
|
||||
|
||||
Cu.importGlobalProperties(["URL"]);
|
||||
|
||||
|
||||
// Test removing a single page
|
||||
add_task(function* test_remove_single() {
|
||||
let WITNESS_URI = NetUtil.newURI("http://mozilla.com/test_browserhistory/test_remove/" + Math.random());
|
||||
yield promiseAddVisits(WITNESS_URI);
|
||||
Assert.ok(page_in_database(WITNESS_URI));
|
||||
|
||||
let remover = Task.async(function*(name, filter, options) {
|
||||
do_print(name);
|
||||
do_print(JSON.stringify(options));
|
||||
do_print("Setting up visit");
|
||||
|
||||
let uri = NetUtil.newURI("http://mozilla.com/test_browserhistory/test_remove/" + Math.random());
|
||||
let title = "Visit " + Math.random();
|
||||
yield promiseAddVisits({uri: uri, title: title});
|
||||
Assert.ok(visits_in_database(uri), "History entry created");
|
||||
|
||||
let removeArg = yield filter(uri);
|
||||
|
||||
if (options.addBookmark) {
|
||||
PlacesUtils.bookmarks.insertBookmark(
|
||||
PlacesUtils.unfiledBookmarksFolderId,
|
||||
uri,
|
||||
PlacesUtils.bookmarks.DEFAULT_INDEX,
|
||||
"test bookmark");
|
||||
}
|
||||
|
||||
let shouldRemove = !options.addBookmark;
|
||||
let observer;
|
||||
let promiseObserved = new Promise((resolve, reject) => {
|
||||
observer = {
|
||||
onBeginUpdateBatch: function() {},
|
||||
onEndUpdateBatch: function() {},
|
||||
onVisit: function(uri) {
|
||||
reject(new Error("Unexpected call to onVisit " + uri.spec));
|
||||
},
|
||||
onTitleChanged: function(uri) {
|
||||
reject(new Error("Unexpected call to onTitleChanged " + uri.spec));
|
||||
},
|
||||
onClearHistory: function() {
|
||||
reject("Unexpected call to onClearHistory");
|
||||
},
|
||||
onPageChanged: function(uri) {
|
||||
reject(new Error("Unexpected call to onPageChanged " + uri.spec));
|
||||
},
|
||||
onFrecencyChanged: function(aURI) {
|
||||
try {
|
||||
Assert.ok(!shouldRemove, "Observing onFrecencyChanged");
|
||||
Assert.equal(aURI.spec, uri.spec, "Observing effect on the right uri");
|
||||
} finally {
|
||||
resolve();
|
||||
}
|
||||
},
|
||||
onManyFrecenciesChanged: function() {
|
||||
try {
|
||||
Assert.ok(!shouldRemove, "Observing onManyFrecenciesChanged");
|
||||
} finally {
|
||||
resolve();
|
||||
}
|
||||
},
|
||||
onDeleteURI: function(aURI) {
|
||||
try {
|
||||
Assert.ok(shouldRemove, "Observing onDeleteURI");
|
||||
Assert.equal(aURI.spec, uri.spec, "Observing effect on the right uri");
|
||||
} finally {
|
||||
resolve();
|
||||
}
|
||||
},
|
||||
onDeleteVisits: function(aURI) {
|
||||
Assert.equal(aURI.spec, uri.spec, "Observing onDeleteVisits on the right uri");
|
||||
}
|
||||
};
|
||||
});
|
||||
PlacesUtils.history.addObserver(observer, false);
|
||||
|
||||
do_print("Performing removal");
|
||||
let removed = false;
|
||||
if (options.useCallback) {
|
||||
let onRowCalled = false;
|
||||
removed = yield PlacesUtils.history.remove(removeArg, page => {
|
||||
Assert.equal(onRowCalled, false, "Callback has not been called yet");
|
||||
onRowCalled = true;
|
||||
Assert.equal(page.url.href, uri.spec, "Callback provides the correct url");
|
||||
Assert.equal(page.guid, do_get_guid_for_uri(uri), "Callback provides the correct guid");
|
||||
Assert.equal(page.title, title, "Callback provides the correct title");
|
||||
Assert.equal(page.frecency, frecencyForUrl(uri), "Callback provides the correct frecency");
|
||||
});
|
||||
Assert.ok(onRowCalled, "Callback has been called");
|
||||
} else {
|
||||
removed = yield PlacesUtils.history.remove(removeArg);
|
||||
}
|
||||
|
||||
yield promiseObserved;
|
||||
PlacesUtils.history.removeObserver(observer);
|
||||
|
||||
Assert.equal(visits_in_database(uri), 0, "History entry has disappeared");
|
||||
Assert.notEqual(visits_in_database(WITNESS_URI), 0, "Witness URI still has visits");
|
||||
Assert.notEqual(page_in_database(WITNESS_URI), 0, "Witness URI is still here");
|
||||
if (shouldRemove) {
|
||||
Assert.ok(removed, "Something was removed");
|
||||
Assert.equal(page_in_database(uri), 0, "Page has disappeared");
|
||||
} else {
|
||||
Assert.ok(!removed, "The page was not removed, as there was a bookmark");
|
||||
Assert.notEqual(page_in_database(uri), 0, "The page is still present");
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
for (let useCallback of [false, true]) {
|
||||
for (let addBookmark of [false, true]) {
|
||||
let options = { useCallback: useCallback, addBookmark: addBookmark };
|
||||
yield remover("Testing History.remove() with a single URI", x => x, options);
|
||||
yield remover("Testing History.remove() with a single string url", x => x.spec, options);
|
||||
yield remover("Testing History.remove() with a single string guid", x => do_get_guid_for_uri(x), options);
|
||||
yield remover("Testing History.remove() with a single URI in an array", x => [x], options);
|
||||
yield remover("Testing History.remove() with a single string url in an array", x => [x.spec], options);
|
||||
yield remover("Testing History.remove() with a single string guid in an array", x => [do_get_guid_for_uri(x)], options);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
yield promiseClearHistory();
|
||||
}
|
||||
return;
|
||||
});
|
||||
|
||||
// Test removing a list of pages
|
||||
add_task(function* test_remove_many() {
|
||||
const SIZE = 10;
|
||||
|
||||
do_print("Adding a witness page");
|
||||
let WITNESS_URI = NetUtil.newURI("http://mozilla.com/test_browserhistory/test_remove/" + Math.random());;
|
||||
yield promiseAddVisits(WITNESS_URI);
|
||||
Assert.ok(page_in_database(WITNESS_URI), "Witness page added");
|
||||
|
||||
do_print("Generating samples");
|
||||
let pages = [];
|
||||
for (let i = 0; i < SIZE; ++i) {
|
||||
let uri = NetUtil.newURI("http://mozilla.com/test_browserhistory/test_remove?sample=" + i + "&salt=" + Math.random());
|
||||
let title = "Visit " + i + ", " + Math.random();
|
||||
let hasBookmark = i % 3 == 0;
|
||||
let resolve;
|
||||
let page = {
|
||||
uri: uri,
|
||||
title: title,
|
||||
hasBookmark: hasBookmark,
|
||||
// `true` once `onResult` has been called for this page
|
||||
onResultCalled: false,
|
||||
// `true` once `onDeleteVisits` has been called for this page
|
||||
onDeleteVisitsCalled: false,
|
||||
// `true` once `onFrecencyChangedCalled` has been called for this page
|
||||
onFrecencyChangedCalled: false,
|
||||
// `true` once `onDeleteURI` has been called for this page
|
||||
onDeleteURICalled: false,
|
||||
};
|
||||
do_print("Pushing: " + uri.spec);
|
||||
pages.push(page);
|
||||
|
||||
yield promiseAddVisits(page);
|
||||
page.guid = do_get_guid_for_uri(uri);
|
||||
if (hasBookmark) {
|
||||
PlacesUtils.bookmarks.insertBookmark(
|
||||
PlacesUtils.unfiledBookmarksFolderId,
|
||||
uri,
|
||||
PlacesUtils.bookmarks.DEFAULT_INDEX,
|
||||
"test bookmark " + i);
|
||||
}
|
||||
Assert.ok(page_in_database(uri), "Page added");
|
||||
}
|
||||
|
||||
do_print("Mixing key types and introducing dangling keys");
|
||||
let keys = [];
|
||||
for (let i = 0; i < SIZE; ++i) {
|
||||
if (i % 4 == 0) {
|
||||
keys.push(pages[i].uri);
|
||||
keys.push(NetUtil.newURI("http://example.org/dangling/nsIURI/" + i));
|
||||
} else if (i % 4 == 1) {
|
||||
keys.push(new URL(pages[i].uri.spec));
|
||||
keys.push(new URL("http://example.org/dangling/URL/" + i));
|
||||
} else if (i % 4 == 2) {
|
||||
keys.push(pages[i].uri.spec);
|
||||
keys.push("http://example.org/dangling/stringuri/" + i);
|
||||
} else {
|
||||
keys.push(pages[i].guid);
|
||||
keys.push(("guid_" + i + "_01234567890").substr(0, 12));
|
||||
}
|
||||
}
|
||||
|
||||
let observer = {
|
||||
onBeginUpdateBatch: function() {},
|
||||
onEndUpdateBatch: function() {},
|
||||
onVisit: function(aURI) {
|
||||
Assert.ok(false, "Unexpected call to onVisit " + aURI.spec);
|
||||
},
|
||||
onTitleChanged: function(aURI) {
|
||||
Assert.ok(false, "Unexpected call to onTitleChanged " + aURI.spec);
|
||||
},
|
||||
onClearHistory: function() {
|
||||
Assert.ok(false, "Unexpected call to onClearHistory");
|
||||
},
|
||||
onPageChanged: function(aURI) {
|
||||
Assert.ok(false, "Unexpected call to onPageChanged " + aURI.spec);
|
||||
},
|
||||
onFrecencyChanged: function(aURI) {
|
||||
let origin = pages.find(x => x.uri.spec == aURI.spec);
|
||||
Assert.ok(origin);
|
||||
Assert.ok(origin.hasBookmark, "Observing onFrecencyChanged on a page with a bookmark");
|
||||
origin.onFrecencyChangedCalled = true;
|
||||
// We do not make sure that `origin.onFrecencyChangedCalled` is `false`, as
|
||||
},
|
||||
onManyFrecenciesChanged: function() {
|
||||
Assert.ok(false, "Observing onManyFrecenciesChanges, this is most likely correct but not covered by this test");
|
||||
},
|
||||
onDeleteURI: function(aURI) {
|
||||
let origin = pages.find(x => x.uri.spec == aURI.spec);
|
||||
Assert.ok(origin);
|
||||
Assert.ok(!origin.hasBookmark, "Observing onDeleteURI on a page without a bookmark");
|
||||
Assert.ok(!origin.onDeleteURICalled, "Observing onDeleteURI for the first time");
|
||||
origin.onDeleteURICalled = true;
|
||||
},
|
||||
onDeleteVisits: function(aURI) {
|
||||
let origin = pages.find(x => x.uri.spec == aURI.spec);
|
||||
Assert.ok(origin);
|
||||
Assert.ok(!origin.onDeleteVisitsCalled, "Observing onDeleteVisits for the first time");
|
||||
origin.onDeleteVisitsCalled = true;
|
||||
}
|
||||
};
|
||||
PlacesUtils.history.addObserver(observer, false);
|
||||
|
||||
do_print("Removing the pages and checking the callbacks");
|
||||
let removed = yield PlacesUtils.history.remove(keys, page => {
|
||||
let origin = pages.find(candidate => candidate.uri.spec == page.url.href);
|
||||
|
||||
Assert.ok(origin, "onResult has a valid page");
|
||||
Assert.ok(!origin.onResultCalled, "onResult has not seen this page yet");
|
||||
origin.onResultCalled = true;
|
||||
Assert.equal(page.guid, origin.guid, "onResult has the right guid");
|
||||
Assert.equal(page.title, origin.title, "onResult has the right title");
|
||||
});
|
||||
Assert.ok(removed, "Something was removed");
|
||||
|
||||
PlacesUtils.history.removeObserver(observer);
|
||||
|
||||
do_print("Checking out results");
|
||||
// By now the observers should have been called.
|
||||
for (let i = 0; i < pages.length; ++i) {
|
||||
let page = pages[i];
|
||||
do_print("Page: " + i);
|
||||
Assert.ok(page.onResultCalled, "We have reached the page from the callback");
|
||||
Assert.ok(visits_in_database(page.uri) == 0, "History entry has disappeared");
|
||||
Assert.equal(page_in_database(page.uri) != 0, page.hasBookmark, "Page is present only if it also has bookmarks");
|
||||
Assert.equal(page.onFrecencyChangedCalled, page.onDeleteVisitsCalled, "onDeleteVisits was called iff onFrecencyChanged was called");
|
||||
Assert.ok(page.onFrecencyChangedCalled ^ page.onDeleteURICalled, "Either onFrecencyChanged or onDeleteURI was called");
|
||||
}
|
||||
|
||||
Assert.notEqual(visits_in_database(WITNESS_URI), 0, "Witness URI still has visits");
|
||||
Assert.notEqual(page_in_database(WITNESS_URI), 0, "Witness URI is still here");
|
||||
|
||||
do_print("Cleaning up");
|
||||
yield promiseClearHistory();
|
||||
|
||||
});
|
||||
|
||||
// Test the various error cases
|
||||
add_task(function* test_error_cases() {
|
||||
Assert.throws(
|
||||
() => PlacesUtils.history.remove(),
|
||||
/TypeError: Invalid url/,
|
||||
"History.remove with no argument should throw a TypeError"
|
||||
);
|
||||
Assert.throws(
|
||||
() => PlacesUtils.history.remove(null),
|
||||
/TypeError: Invalid url/,
|
||||
"History.remove with `null` should throw a TypeError"
|
||||
);
|
||||
Assert.throws(
|
||||
() => PlacesUtils.history.remove(undefined),
|
||||
/TypeError: Invalid url/,
|
||||
"History.remove with `undefined` should throw a TypeError"
|
||||
);
|
||||
Assert.throws(
|
||||
() => PlacesUtils.history.remove("not a guid, obviously"),
|
||||
/TypeError: .* is not a valid URL/,
|
||||
"History.remove with an ill-formed guid/url argument should throw a TypeError"
|
||||
);
|
||||
Assert.throws(
|
||||
() => PlacesUtils.history.remove({"not the kind of object we know how to handle": true}),
|
||||
/TypeError: Invalid url/,
|
||||
"History.remove with an unexpected object should throw a TypeError"
|
||||
);
|
||||
Assert.throws(
|
||||
() => PlacesUtils.history.remove([]),
|
||||
/TypeError: Expected at least one page/,
|
||||
"History.remove with an empty array should throw a TypeError"
|
||||
);
|
||||
Assert.throws(
|
||||
() => PlacesUtils.history.remove([null]),
|
||||
/TypeError: Invalid url or guid/,
|
||||
"History.remove with an array containing null should throw a TypeError"
|
||||
);
|
||||
Assert.throws(
|
||||
() => PlacesUtils.history.remove(["http://example.org", "not a guid, obviously"]),
|
||||
/TypeError: .* is not a valid URL/,
|
||||
"History.remove with an array containing an ill-formed guid/url argument should throw a TypeError"
|
||||
);
|
||||
Assert.throws(
|
||||
() => PlacesUtils.history.remove(["0123456789ab"/*valid guid*/, null]),
|
||||
/TypeError: Invalid url or guid: null/,
|
||||
"History.remove with an array containing a guid and a second argument that is null should throw a TypeError"
|
||||
);
|
||||
Assert.throws(
|
||||
() => PlacesUtils.history.remove(["http://example.org", {"not the kind of object we know how to handle": true}]),
|
||||
/TypeError: Invalid url/,
|
||||
"History.remove with an array containing an unexpected objecgt should throw a TypeError"
|
||||
);
|
||||
Assert.throws(
|
||||
() => PlacesUtils.history.remove("http://example.org", "not a function, obviously"),
|
||||
/TypeError: Invalid function/,
|
||||
"History.remove with a second argument that is not a function argument should throw a TypeError"
|
||||
);
|
||||
try {
|
||||
PlacesUtils.history.remove("http://example.org/I/have/clearly/not/been/added", null);
|
||||
Assert.ok(true, "History.remove should ignore `null` as a second argument");
|
||||
} catch (ex) {
|
||||
Assert.ok(false, "History.remove should ignore `null` as a second argument");
|
||||
}
|
||||
});
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
[DEFAULT]
|
||||
head = head_history.js
|
||||
tail =
|
||||
|
||||
[test_remove.js]
|
|
@ -18,8 +18,20 @@ interface nsIToolkitProfileService : nsISupports
|
|||
|
||||
readonly attribute nsISimpleEnumerator /*nsIToolkitProfile*/ profiles;
|
||||
|
||||
/**
|
||||
* The currently selected profile (the one used or about to be used by the
|
||||
* browser).
|
||||
*/
|
||||
attribute nsIToolkitProfile selectedProfile;
|
||||
|
||||
/**
|
||||
* The default profile (the one used or about to be used by the
|
||||
* browser if no other profile is specified at runtime). This is the profile
|
||||
* marked with Default=1 in profiles.ini and is usually the same as
|
||||
* selectedProfile, except on Developer Edition.
|
||||
*/
|
||||
attribute nsIToolkitProfile defaultProfile;
|
||||
|
||||
/**
|
||||
* Get a profile by name. This is mainly for use by the -P
|
||||
* commandline flag.
|
||||
|
|
|
@ -139,6 +139,7 @@ private:
|
|||
|
||||
nsRefPtr<nsToolkitProfile> mFirst;
|
||||
nsCOMPtr<nsIToolkitProfile> mChosen;
|
||||
nsCOMPtr<nsIToolkitProfile> mDefault;
|
||||
nsCOMPtr<nsIFile> mAppData;
|
||||
nsCOMPtr<nsIFile> mTempData;
|
||||
nsCOMPtr<nsIFile> mListFile;
|
||||
|
@ -424,6 +425,7 @@ nsToolkitProfileService::Init()
|
|||
nsToolkitProfile* currentProfile = nullptr;
|
||||
|
||||
unsigned int c = 0;
|
||||
bool foundAuroraDefault = false;
|
||||
for (c = 0; true; ++c) {
|
||||
nsAutoCString profileID("Profile");
|
||||
profileID.AppendInt(c);
|
||||
|
@ -441,7 +443,9 @@ nsToolkitProfileService::Init()
|
|||
continue;
|
||||
}
|
||||
|
||||
rv = parser.GetString(profileID.get(), "Name", buffer);
|
||||
nsAutoCString name;
|
||||
|
||||
rv = parser.GetString(profileID.get(), "Name", name);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_ERROR("Malformed profiles.ini: Name= not found");
|
||||
continue;
|
||||
|
@ -470,15 +474,48 @@ nsToolkitProfileService::Init()
|
|||
localDir = rootDir;
|
||||
}
|
||||
|
||||
currentProfile = new nsToolkitProfile(buffer,
|
||||
currentProfile = new nsToolkitProfile(name,
|
||||
rootDir, localDir,
|
||||
currentProfile, false);
|
||||
NS_ENSURE_TRUE(currentProfile, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
rv = parser.GetString(profileID.get(), "Default", buffer);
|
||||
if (NS_SUCCEEDED(rv) && buffer.EqualsLiteral("1"))
|
||||
if (NS_SUCCEEDED(rv) && buffer.EqualsLiteral("1") && !foundAuroraDefault) {
|
||||
mChosen = currentProfile;
|
||||
this->SetDefaultProfile(currentProfile);
|
||||
}
|
||||
#ifdef MOZ_DEV_EDITION
|
||||
// Use the dev-edition-default profile if this is an Aurora build.
|
||||
if (name.EqualsLiteral("dev-edition-default")) {
|
||||
mChosen = currentProfile;
|
||||
foundAuroraDefault = true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef MOZ_DEV_EDITION
|
||||
// Check if we are running Firefox, as we don't want to create a profile
|
||||
// on webapprt.
|
||||
bool isFirefox = strcmp(gAppData->ID,
|
||||
"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}") == 0;
|
||||
if (!foundAuroraDefault && isFirefox) {
|
||||
// If a single profile exists, it may not be already marked as default.
|
||||
// Do it now to avoid problems when we create the dev-edition-default profile.
|
||||
if (!mChosen && mFirst && !mFirst->mNext)
|
||||
this->SetDefaultProfile(mFirst);
|
||||
|
||||
// Create a default profile for aurora, if none was found.
|
||||
nsCOMPtr<nsIToolkitProfile> profile;
|
||||
rv = CreateProfile(nullptr,
|
||||
NS_LITERAL_CSTRING("dev-edition-default"),
|
||||
getter_AddRefs(profile));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
mChosen = profile;
|
||||
rv = Flush();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!mChosen && mFirst && !mFirst->mNext) // only one profile
|
||||
mChosen = mFirst;
|
||||
return NS_OK;
|
||||
|
@ -569,6 +606,25 @@ nsToolkitProfileService::SetSelectedProfile(nsIToolkitProfile* aProfile)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsToolkitProfileService::GetDefaultProfile(nsIToolkitProfile* *aResult)
|
||||
{
|
||||
if (!mDefault) return NS_ERROR_FAILURE;
|
||||
|
||||
NS_ADDREF(*aResult = mDefault);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsToolkitProfileService::SetDefaultProfile(nsIToolkitProfile* aProfile)
|
||||
{
|
||||
if (mDefault != aProfile) {
|
||||
mDefault = aProfile;
|
||||
mDirty = true;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsToolkitProfileService::GetProfileByName(const nsACString& aName,
|
||||
nsIToolkitProfile* *aResult)
|
||||
|
@ -932,7 +988,9 @@ nsToolkitProfileService::Flush()
|
|||
pCount, cur->mName.get(),
|
||||
isRelative ? "1" : "0", path.get());
|
||||
|
||||
if (mChosen == cur) {
|
||||
nsCOMPtr<nsIToolkitProfile> profile;
|
||||
rv = this->GetDefaultProfile(getter_AddRefs(profile));
|
||||
if (NS_SUCCEEDED(rv) && profile == cur) {
|
||||
end += sprintf(end, "Default=1\n");
|
||||
}
|
||||
|
||||
|
|
|
@ -101,13 +101,14 @@ XRE_ParseAppData(nsIFile* aINIFile, nsXREAppData *aAppData)
|
|||
nsCString str;
|
||||
|
||||
ReadString strings[] = {
|
||||
{ "App", "Vendor", &aAppData->vendor },
|
||||
{ "App", "Name", &aAppData->name },
|
||||
{ "App", "Version", &aAppData->version },
|
||||
{ "App", "BuildID", &aAppData->buildID },
|
||||
{ "App", "ID", &aAppData->ID },
|
||||
{ "App", "Copyright", &aAppData->copyright },
|
||||
{ "App", "Profile", &aAppData->profile },
|
||||
{ "App", "Vendor", &aAppData->vendor },
|
||||
{ "App", "Name", &aAppData->name },
|
||||
{ "App", "RemotingName", &aAppData->remotingName },
|
||||
{ "App", "Version", &aAppData->version },
|
||||
{ "App", "BuildID", &aAppData->buildID },
|
||||
{ "App", "ID", &aAppData->ID },
|
||||
{ "App", "Copyright", &aAppData->copyright },
|
||||
{ "App", "Profile", &aAppData->profile },
|
||||
{ nullptr }
|
||||
};
|
||||
ReadStrings(parser, strings);
|
||||
|
|
|
@ -1594,7 +1594,7 @@ RemoteCommandLine(const char* aDesktopStartupID)
|
|||
nsresult rv;
|
||||
ArgResult ar;
|
||||
|
||||
nsAutoCString program(gAppData->name);
|
||||
nsAutoCString program(gAppData->remotingName);
|
||||
ToLowerCase(program);
|
||||
const char *username = getenv("LOGNAME");
|
||||
|
||||
|
@ -4078,7 +4078,7 @@ XREMain::XRE_mainRun()
|
|||
if (!mDisableRemote)
|
||||
mRemoteService = do_GetService("@mozilla.org/toolkit/remote-service;1");
|
||||
if (mRemoteService)
|
||||
mRemoteService->Startup(mAppData->name, mProfileName.get());
|
||||
mRemoteService->Startup(mAppData->remotingName, mProfileName.get());
|
||||
#endif /* MOZ_ENABLE_XREMOTE */
|
||||
|
||||
mNativeApp->Enable();
|
||||
|
@ -4126,6 +4126,9 @@ XREMain::XRE_main(int argc, char* argv[], const nsXREAppData* aAppData)
|
|||
mAppData = new ScopedAppData(aAppData);
|
||||
if (!mAppData)
|
||||
return 1;
|
||||
if (!mAppData->remotingName) {
|
||||
SetAllocatedString(mAppData->remotingName, mAppData->name);
|
||||
}
|
||||
// used throughout this file
|
||||
gAppData = mAppData;
|
||||
|
||||
|
|
|
@ -484,7 +484,7 @@ struct MessageWindow {
|
|||
::_snwprintf(classNameBuffer,
|
||||
128, // size of classNameBuffer in PRUnichars
|
||||
L"%s%s",
|
||||
NS_ConvertUTF8toUTF16(gAppData->name).get(),
|
||||
NS_ConvertUTF8toUTF16(gAppData->remotingName).get(),
|
||||
L"MessageWindow" );
|
||||
mClassName = classNameBuffer;
|
||||
}
|
||||
|
|
|
@ -46,6 +46,13 @@ struct nsXREAppData
|
|||
*/
|
||||
const char* name;
|
||||
|
||||
/**
|
||||
* The internal name of the application for remoting purposes. When left
|
||||
* unspecified, "name" is used instead. This must be ASCII, and is normally
|
||||
* lowercase, e.g. "firefox". Optional (may be null but not an empty string).
|
||||
*/
|
||||
const char* remotingName;
|
||||
|
||||
/**
|
||||
* The major version, e.g. "0.8.0+". Optional (may be null), but
|
||||
* required for advanced application features such as the extension
|
||||
|
|
|
@ -43,6 +43,7 @@ ScopedAppData::ScopedAppData(const nsXREAppData* aAppData)
|
|||
|
||||
SetAllocatedString(this->vendor, aAppData->vendor);
|
||||
SetAllocatedString(this->name, aAppData->name);
|
||||
SetAllocatedString(this->remotingName, aAppData->remotingName);
|
||||
SetAllocatedString(this->version, aAppData->version);
|
||||
SetAllocatedString(this->buildID, aAppData->buildID);
|
||||
SetAllocatedString(this->ID, aAppData->ID);
|
||||
|
@ -70,6 +71,7 @@ ScopedAppData::~ScopedAppData()
|
|||
{
|
||||
SetAllocatedString(this->vendor, nullptr);
|
||||
SetAllocatedString(this->name, nullptr);
|
||||
SetAllocatedString(this->remotingName, nullptr);
|
||||
SetAllocatedString(this->version, nullptr);
|
||||
SetAllocatedString(this->buildID, nullptr);
|
||||
SetAllocatedString(this->ID, nullptr);
|
||||
|
|
Загрузка…
Ссылка в новой задаче