diff options
Diffstat (limited to 'services/sync/tps/extensions')
23 files changed, 310 insertions, 650 deletions
diff --git a/services/sync/tps/extensions/mozmill/resource/driver/controller.js b/services/sync/tps/extensions/mozmill/resource/driver/controller.js index 8d66a41ae..d5948598e 100644 --- a/services/sync/tps/extensions/mozmill/resource/driver/controller.js +++ b/services/sync/tps/extensions/mozmill/resource/driver/controller.js @@ -5,9 +5,9 @@ var EXPORTED_SYMBOLS = ["MozMillController", "globalEventRegistry", "sleep", "windowMap"]; -var Cc = Components.classes; -var Ci = Components.interfaces; -var Cu = Components.utils; +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; var EventUtils = {}; Cu.import('resource://mozmill/stdlib/EventUtils.js', EventUtils); @@ -44,11 +44,7 @@ waitForEvents.prototype = { node.firedEvents = {}; this.registry = {}; - if (!events) { - return; - } - for (var key in events) { - var e = events[key]; + for each (var e in events) { var listener = function (event) { this.firedEvents[event.type] = true; } @@ -870,7 +866,7 @@ MozMillController.prototype.mouseMove = function (doc, start, dest) { /** * Drag an element to the specified offset on another element, firing mouse and - * drag events. Adapted from EventUtils.js synthesizeDrop() + * drag events. Adapted from ChromeUtils.js synthesizeDrop() * * @deprecated Use the MozMillElement object * @@ -977,10 +973,7 @@ function browserAdditions (controller) { return windows.map.hasPageLoaded(utils.getWindowId(win)); }, "Timeout", timeout, aInterval); } - catch (ex) { - if (!(ex instanceof errors.TimeoutError)) { - throw ex; - } + catch (ex if ex instanceof errors.TimeoutError) { timed_out = true; } finally { diff --git a/services/sync/tps/extensions/mozmill/resource/driver/elementslib.js b/services/sync/tps/extensions/mozmill/resource/driver/elementslib.js index 4bf35a384..f08cf42f3 100644 --- a/services/sync/tps/extensions/mozmill/resource/driver/elementslib.js +++ b/services/sync/tps/extensions/mozmill/resource/driver/elementslib.js @@ -6,9 +6,9 @@ var EXPORTED_SYMBOLS = ["ID", "Link", "XPath", "Selector", "Name", "Anon", "Anon "Lookup", "_byID", "_byName", "_byAttrib", "_byAnonAttrib", ]; -var Cc = Components.classes; -var Ci = Components.interfaces; -var Cu = Components.utils; +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; Cu.import("resource://gre/modules/Services.jsm"); @@ -304,7 +304,7 @@ var _returnResult = function (results) { var _forChildren = function (element, name, value) { var results = []; - var nodes = Array.from(element.childNodes).filter(e => e); + var nodes = [e for each (e in element.childNodes) if (e)] for (var i in nodes) { var n = nodes[i]; @@ -318,7 +318,7 @@ var _forChildren = function (element, name, value) { var _forAnonChildren = function (_document, element, name, value) { var results = []; - var nodes = Array.from(_document.getAnoymousNodes(element)).filter(e => e); + var nodes = [e for each (e in _document.getAnoymousNodes(element)) if (e)]; for (var i in nodes ) { var n = nodes[i]; @@ -381,7 +381,7 @@ var _byAnonAttrib = function (_document, parent, attributes) { } } - var nodes = Array.from(_document.getAnonymousNodes(parent)).filter(n => n.getAttribute); + var nodes = [n for each (n in _document.getAnonymousNodes(parent)) if (n.getAttribute)]; function resultsForNodes (nodes) { for (var i in nodes) { @@ -404,7 +404,7 @@ var _byAnonAttrib = function (_document, parent, attributes) { resultsForNodes(nodes); if (results.length == 0) { - resultsForNodes(Array.from(parent.childNodes).filter(n => n != undefined && n.getAttribute)); + resultsForNodes([n for each (n in parent.childNodes) if (n != undefined && n.getAttribute)]) } return _returnResult(results) @@ -440,7 +440,7 @@ function Lookup(_document, expression) { throw new Error('Lookup constructor did not recieve enough arguments.'); } - var expSplit = smartSplit(expression).filter(e => e != ''); + var expSplit = [e for each (e in smartSplit(expression) ) if (e != '')]; expSplit.unshift(_document); var nCases = {'id':_byID, 'name':_byName, 'attrib':_byAttrib, 'index':_byIndex}; diff --git a/services/sync/tps/extensions/mozmill/resource/driver/mozelement.js b/services/sync/tps/extensions/mozmill/resource/driver/mozelement.js index 850c86523..0af204794 100644 --- a/services/sync/tps/extensions/mozmill/resource/driver/mozelement.js +++ b/services/sync/tps/extensions/mozmill/resource/driver/mozelement.js @@ -9,9 +9,9 @@ var EXPORTED_SYMBOLS = ["Elem", "Selector", "ID", "Link", "XPath", "Name", "Look const NAMESPACE_XUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; -var Cc = Components.classes; -var Ci = Components.interfaces; -var Cu = Components.utils; +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; var EventUtils = {}; Cu.import('resource://mozmill/stdlib/EventUtils.js', EventUtils); @@ -131,7 +131,7 @@ MozMillElement.prototype.__defineGetter__("element", function () { /** * Drag an element to the specified offset on another element, firing mouse and - * drag events. Adapted from EventUtils.js synthesizeDrop() + * drag events. Adapted from ChromeUtils.js synthesizeDrop() * * By default it will drag the source element over the destination's element * center with a "move" dropEffect. @@ -218,7 +218,7 @@ MozMillElement.prototype.dragToElement = function(aElement, aOffsetX, aOffsetY, EventUtils.synthesizeMouse(destNode, destCoords.x, destCoords.y, { type: "mousemove" }, destWindow); - var event = destWindow.document.createEvent("DragEvent"); + var event = destWindow.document.createEvent("DragEvents"); event.initDragEvent("dragenter", true, true, destWindow, 0, 0, 0, 0, 0, false, false, false, false, 0, null, dataTransfer); event.initDragEvent("dragover", true, true, destWindow, 0, 0, 0, 0, 0, diff --git a/services/sync/tps/extensions/mozmill/resource/driver/mozmill.js b/services/sync/tps/extensions/mozmill/resource/driver/mozmill.js index 1e422591f..283c9bfb4 100644 --- a/services/sync/tps/extensions/mozmill/resource/driver/mozmill.js +++ b/services/sync/tps/extensions/mozmill/resource/driver/mozmill.js @@ -13,9 +13,9 @@ var EXPORTED_SYMBOLS = ["controller", "utils", "elementslib", "os", "firePythonCallback", "getAddons" ]; -var Cc = Components.classes; -var Ci = Components.interfaces; -var Cu = Components.utils; +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; Cu.import("resource://gre/modules/AddonManager.jsm"); diff --git a/services/sync/tps/extensions/mozmill/resource/modules/assertions.js b/services/sync/tps/extensions/mozmill/resource/modules/assertions.js index c76f95747..b49502057 100644 --- a/services/sync/tps/extensions/mozmill/resource/modules/assertions.js +++ b/services/sync/tps/extensions/mozmill/resource/modules/assertions.js @@ -4,7 +4,7 @@ var EXPORTED_SYMBOLS = ['Assert', 'Expect']; -var Cu = Components.utils; +const Cu = Components.utils; Cu.import("resource://gre/modules/Services.jsm"); @@ -658,10 +658,7 @@ Expect.prototype.waitFor = function Expect_waitFor(aCallback, aMessage, aTimeout try { Assert.prototype.waitFor.apply(this, arguments); } - catch (ex) { - if (!(ex instanceof errors.AssertionError)) { - throw ex; - } + catch (ex if ex instanceof errors.AssertionError) { message = ex.message; condition = false; } diff --git a/services/sync/tps/extensions/mozmill/resource/modules/frame.js b/services/sync/tps/extensions/mozmill/resource/modules/frame.js index dae8276b6..799e81d55 100644 --- a/services/sync/tps/extensions/mozmill/resource/modules/frame.js +++ b/services/sync/tps/extensions/mozmill/resource/modules/frame.js @@ -5,9 +5,9 @@ var EXPORTED_SYMBOLS = ['Collector','Runner','events', 'runTestFile', 'log', 'timers', 'persisted', 'shutdownApplication']; -var Cc = Components.classes; -var Ci = Components.interfaces; -var Cu = Components.utils; +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; const TIMEOUT_SHUTDOWN_HTTPD = 15000; @@ -256,7 +256,7 @@ events.pass = function (obj) { events.currentTest.__passes__.push(obj); } - for (var timer of timers) { + for each (var timer in timers) { timer.actions.push( {"currentTest": events.currentModule.__file__ + "::" + events.currentTest.__name__, "obj": obj, @@ -286,7 +286,7 @@ events.fail = function (obj) { events.currentTest.__fails__.push(obj); } - for (var time of timers) { + for each (var time in timers) { timer.actions.push( {"currentTest": events.currentModule.__file__ + "::" + events.currentTest.__name__, "obj": obj, @@ -325,7 +325,7 @@ events.fireEvent = function (name, obj) { } } - for (var listener of this.globalListeners) { + for each(var listener in this.globalListeners) { listener(name, obj); } } diff --git a/services/sync/tps/extensions/mozmill/resource/modules/windows.js b/services/sync/tps/extensions/mozmill/resource/modules/windows.js index 1c75a2d3d..fe9cfaa01 100644 --- a/services/sync/tps/extensions/mozmill/resource/modules/windows.js +++ b/services/sync/tps/extensions/mozmill/resource/modules/windows.js @@ -4,9 +4,9 @@ var EXPORTED_SYMBOLS = ["init", "map"]; -var Cc = Components.classes; -var Ci = Components.interfaces; -var Cu = Components.utils; +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; // imports var utils = {}; Cu.import('resource://mozmill/stdlib/utils.js', utils); diff --git a/services/sync/tps/extensions/mozmill/resource/stdlib/EventUtils.js b/services/sync/tps/extensions/mozmill/resource/stdlib/EventUtils.js index 7f08469f0..a821ab2e0 100644 --- a/services/sync/tps/extensions/mozmill/resource/stdlib/EventUtils.js +++ b/services/sync/tps/extensions/mozmill/resource/stdlib/EventUtils.js @@ -8,8 +8,8 @@ var EXPORTED_SYMBOLS = ["disableNonTestMouseEvents","sendMouseEvent", "sendChar" "synthesizeText", "synthesizeComposition", "synthesizeQuerySelectedText"]; -var Ci = Components.interfaces; -var Cc = Components.classes; +const Ci = Components.interfaces; +const Cc = Components.classes; var window = Cc["@mozilla.org/appshell/appShellService;1"] .getService(Ci.nsIAppShellService).hiddenDOMWindow; diff --git a/services/sync/tps/extensions/mozmill/resource/stdlib/os.js b/services/sync/tps/extensions/mozmill/resource/stdlib/os.js index ce88bea8a..fcda30572 100644 --- a/services/sync/tps/extensions/mozmill/resource/stdlib/os.js +++ b/services/sync/tps/extensions/mozmill/resource/stdlib/os.js @@ -4,9 +4,9 @@ var EXPORTED_SYMBOLS = ['listDirectory', 'getFileForPath', 'abspath', 'getPlatform']; -var Cc = Components.classes; -var Ci = Components.interfaces; -var Cu = Components.utils; +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; Cu.import("resource://gre/modules/Services.jsm"); @@ -37,7 +37,7 @@ function abspath(rel, file) { file = file.parent; } - for (var p of relSplit) { + for each(var p in relSplit) { if (p == '..') { file = file.parent; } else if (p == '.') { diff --git a/services/sync/tps/extensions/mozmill/resource/stdlib/securable-module.js b/services/sync/tps/extensions/mozmill/resource/stdlib/securable-module.js index 2648afd27..794c3e2c2 100644 --- a/services/sync/tps/extensions/mozmill/resource/stdlib/securable-module.js +++ b/services/sync/tps/extensions/mozmill/resource/stdlib/securable-module.js @@ -40,8 +40,6 @@ const Cu = Components.utils; const Cr = Components.results; - Cu.import("resource://gre/modules/NetUtil.jsm"); - var exports = {}; var ios = Cc['@mozilla.org/network/io-service;1'] @@ -170,7 +168,8 @@ if (rootPaths) { if (rootPaths.constructor.name != "Array") rootPaths = [rootPaths]; - var fses = rootPaths.map(path => new exports.LocalFileSystem(path)); + var fses = [new exports.LocalFileSystem(path) + for each (path in rootPaths)]; options.fs = new exports.CompositeFileSystem(fses); } else options.fs = new exports.LocalFileSystem(); @@ -315,26 +314,17 @@ else baseURI = ios.newURI(base, null, null); var newURI = ios.newURI(path, null, baseURI); - var channel = NetUtil.newChannel({ - uri: newURI, - loadUsingSystemPrincipal: true - }); + var channel = ios.newChannelFromURI(newURI); try { - channel.open2().close(); - } catch (e) { - if (e.result != Cr.NS_ERROR_FILE_NOT_FOUND) { - throw e; - } + channel.open().close(); + } catch (e if e.result == Cr.NS_ERROR_FILE_NOT_FOUND) { return null; } return newURI.spec; }, getFile: function getFile(path) { - var channel = NetUtil.newChannel({ - uri: path, - loadUsingSystemPrincipal: true - }); - var iStream = channel.open2(); + var channel = ios.newChannel(path, null, null); + var iStream = channel.open(); var ciStream = Cc["@mozilla.org/intl/converter-input-stream;1"]. createInstance(Ci.nsIConverterInputStream); var bufLen = 0x8000; diff --git a/services/sync/tps/extensions/mozmill/resource/stdlib/utils.js b/services/sync/tps/extensions/mozmill/resource/stdlib/utils.js index 73e13e11f..3dcca76e0 100644 --- a/services/sync/tps/extensions/mozmill/resource/stdlib/utils.js +++ b/services/sync/tps/extensions/mozmill/resource/stdlib/utils.js @@ -10,16 +10,16 @@ var EXPORTED_SYMBOLS = ["applicationName", "assert", "Copy", "getBrowserObject", "unwrapNode", "waitFor" ]; -var Cc = Components.classes; -var Ci = Components.interfaces; -var Cu = Components.utils; +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; Cu.import("resource://gre/modules/NetUtil.jsm"); Cu.import("resource://gre/modules/Services.jsm"); const applicationIdMap = { - '{ec8030f7-c20a-464f-9b0e-13a3a9e97384}': 'Firefox' + '{8de7fcbb-c55c-4fbe-bfc5-fc555c87dbc4}': 'Firefox' } const applicationName = applicationIdMap[Services.appinfo.ID] || Services.appinfo.name; @@ -83,7 +83,7 @@ function getWindows(type) { } function getMethodInWindows(methodName) { - for (var w of getWindows()) { + for each (var w in getWindows()) { if (w[methodName] != undefined) { return w[methodName]; } @@ -93,7 +93,7 @@ function getMethodInWindows(methodName) { } function getWindowByTitle(title) { - for (var w of getWindows()) { + for each (var w in getWindows()) { if (w.document.title && w.document.title == title) { return w; } diff --git a/services/sync/tps/extensions/tps/install.rdf b/services/sync/tps/extensions/tps/install.rdf index 3dcdc5e44..cc9491b07 100644 --- a/services/sync/tps/extensions/tps/install.rdf +++ b/services/sync/tps/extensions/tps/install.rdf @@ -12,7 +12,7 @@ <em:targetApplication> <!-- Firefox --> <Description> - <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> + <em:id>{8de7fcbb-c55c-4fbe-bfc5-fc555c87dbc4}</em:id> <em:minVersion>24.0.*</em:minVersion> <em:maxVersion>31.0.*</em:maxVersion> </Description> diff --git a/services/sync/tps/extensions/tps/resource/auth/fxaccounts.jsm b/services/sync/tps/extensions/tps/resource/auth/fxaccounts.jsm index 86d0ed113..f5daa14be 100644 --- a/services/sync/tps/extensions/tps/resource/auth/fxaccounts.jsm +++ b/services/sync/tps/extensions/tps/resource/auth/fxaccounts.jsm @@ -12,7 +12,6 @@ const {classes: Cc, interfaces: Ci, utils: Cu} = Components; Cu.import("resource://gre/modules/FxAccounts.jsm"); Cu.import("resource://gre/modules/FxAccountsClient.jsm"); -Cu.import("resource://gre/modules/FxAccountsConfig.jsm"); Cu.import("resource://services-common/async.js"); Cu.import("resource://services-sync/main.js"); Cu.import("resource://tps/logger.jsm"); @@ -68,10 +67,7 @@ var Authentication = { Logger.AssertTrue(account["username"], "Username has been found"); Logger.AssertTrue(account["password"], "Password has been found"); - Logger.logInfo("Login user: " + account["username"]); - - // Required here since we don't go through the real login page - Async.promiseSpinningly(FxAccountsConfig.ensureConfigured()); + Logger.logInfo("Login user: " + account["username"] + '\n'); let client = new FxAccountsClient(); client.signIn(account["username"], account["password"], true).then(credentials => { @@ -96,26 +92,5 @@ var Authentication = { } catch (error) { throw new Error("signIn() failed with: " + error.message); } - }, - - /** - * Sign out of Firefox Accounts. It also clears out the device ID, if we find one. - */ - signOut() { - if (Authentication.isLoggedIn) { - let user = Authentication.getSignedInUser(); - if (!user) { - throw new Error("Failed to get signed in user!"); - } - let fxc = new FxAccountsClient(); - let { sessionToken, deviceId } = user; - if (deviceId) { - Logger.logInfo("Destroying device " + deviceId); - Async.promiseSpinningly(fxc.signOutAndDestroyDevice(sessionToken, deviceId, { service: "sync" })); - } else { - Logger.logError("No device found."); - Async.promiseSpinningly(fxc.signOut(sessionToken, { service: "sync" })); - } - } } }; diff --git a/services/sync/tps/extensions/tps/resource/auth/sync.jsm b/services/sync/tps/extensions/tps/resource/auth/sync.jsm index 35ffeb269..676b17a91 100644 --- a/services/sync/tps/extensions/tps/resource/auth/sync.jsm +++ b/services/sync/tps/extensions/tps/resource/auth/sync.jsm @@ -80,9 +80,5 @@ var Authentication = { } return true; - }, - - signOut() { - Weave.Service.logout(); } }; diff --git a/services/sync/tps/extensions/tps/resource/modules/addons.jsm b/services/sync/tps/extensions/tps/resource/modules/addons.jsm index 1570b42b1..5c308b5c2 100644 --- a/services/sync/tps/extensions/tps/resource/modules/addons.jsm +++ b/services/sync/tps/extensions/tps/resource/modules/addons.jsm @@ -3,13 +3,13 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; -var EXPORTED_SYMBOLS = ["Addon", "STATE_ENABLED", "STATE_DISABLED"]; +let EXPORTED_SYMBOLS = ["Addon", "STATE_ENABLED", "STATE_DISABLED"]; const {classes: Cc, interfaces: Ci, utils: Cu} = Components; Cu.import("resource://gre/modules/AddonManager.jsm"); Cu.import("resource://gre/modules/addons/AddonRepository.jsm"); -Cu.import("resource://gre/modules/NetUtil.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://services-common/async.js"); Cu.import("resource://services-sync/addonutils.js"); Cu.import("resource://services-sync/util.js"); @@ -20,11 +20,15 @@ const STATE_ENABLED = 1; const STATE_DISABLED = 2; function GetFileAsText(file) { - let channel = NetUtil.newChannel({ - uri: file, - loadUsingSystemPrincipal: true - }); - let inputStream = channel.open2(); + let channel = Services.io.newChannel2(file, + null, + null, + null, // aLoadingNode + Services.scriptSecurityManager.getSystemPrincipal(), + null, // aTriggeringPrincipal + Ci.nsILoadInfo.SEC_NORMAL, + Ci.nsIContentPolicy.TYPE_OTHER); + let inputStream = channel.open(); if (channel instanceof Ci.nsIHttpChannel && channel.responseStatus != 200) { return ""; diff --git a/services/sync/tps/extensions/tps/resource/modules/bookmarks.jsm b/services/sync/tps/extensions/tps/resource/modules/bookmarks.jsm index 857c0c1e8..6a288bbec 100644 --- a/services/sync/tps/extensions/tps/resource/modules/bookmarks.jsm +++ b/services/sync/tps/extensions/tps/resource/modules/bookmarks.jsm @@ -13,7 +13,6 @@ var EXPORTED_SYMBOLS = ["PlacesItem", "Bookmark", "Separator", "Livemark", const {classes: Cc, interfaces: Ci, utils: Cu} = Components; Cu.import("resource://gre/modules/PlacesBackups.jsm"); -Cu.import("resource://gre/modules/PlacesSyncUtils.jsm"); Cu.import("resource://gre/modules/PlacesUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://services-common/async.js"); @@ -110,11 +109,6 @@ PlacesItem.prototype = { return string; }, - GetSyncId() { - let guid = Async.promiseSpinningly(PlacesUtils.promiseItemGuid(this.props.item_id)); - return PlacesSyncUtils.bookmarks.guidToSyncId(guid); - }, - /** * GetPlacesNodeId * @@ -438,19 +432,8 @@ Bookmark.prototype = { * @return nothing */ SetKeyword: function(keyword) { - if (keyword != null) { - // Mirror logic from PlacesSyncUtils's updateBookmarkMetadata - let entry = Async.promiseSpinningly(PlacesUtils.keywords.fetch({ - url: this.props.uri, - })); - if (entry) { - Async.promiseSpinningly(PlacesUtils.keywords.remove(entry)); - } - Async.promiseSpinningly(PlacesUtils.keywords.insert({ - keyword: keyword, - url: this.props.uri - })); - } + if (keyword != null) + PlacesUtils.bookmarks.setKeywordForBookmark(this.props.item_id, keyword); }, /** @@ -559,11 +542,11 @@ Bookmark.prototype = { Update: function() { Logger.AssertTrue(this.props.item_id != -1 && this.props.item_id != null, "Invalid item_id during Remove"); + this.SetKeyword(this.updateProps.keyword); this.SetDescription(this.updateProps.description); this.SetLoadInSidebar(this.updateProps.loadInSidebar); this.SetTitle(this.updateProps.title); this.SetUri(this.updateProps.uri); - this.SetKeyword(this.updateProps.keyword); this.SetTags(this.updateProps.tags); this.SetLocation(this.updateProps.location); this.SetPosition(this.updateProps.position); @@ -595,8 +578,7 @@ Bookmark.prototype = { if (!this.CheckDescription(this.props.description)) return -1; if (this.props.keyword != null) { - let { keyword } = Async.promiseSpinningly( - PlacesSyncUtils.bookmarks.fetch(this.GetSyncId())); + let keyword = PlacesUtils.bookmarks.getKeywordForBookmark(this.props.item_id); if (keyword != this.props.keyword) { Logger.logPotentialError("Incorrect keyword - expected: " + this.props.keyword + ", actual: " + keyword + diff --git a/services/sync/tps/extensions/tps/resource/modules/forms.jsm b/services/sync/tps/extensions/tps/resource/modules/forms.jsm index deb1a28a5..ece2e14f7 100644 --- a/services/sync/tps/extensions/tps/resource/modules/forms.jsm +++ b/services/sync/tps/extensions/tps/resource/modules/forms.jsm @@ -13,45 +13,74 @@ const {classes: Cc, interfaces: Ci, utils: Cu} = Components; Cu.import("resource://tps/logger.jsm"); -Cu.import("resource://gre/modules/FormHistory.jsm"); -Cu.import("resource://gre/modules/Log.jsm"); +let formService = Cc["@mozilla.org/satchel/form-history;1"] + .getService(Ci.nsIFormHistory2); /** * FormDB * - * Helper object containing methods to interact with the FormHistory module. + * Helper object containing methods to interact with the moz_formhistory + * SQLite table. */ -var FormDB = { - _update(data) { - return new Promise((resolve, reject) => { - let handlers = { - handleError(error) { - Logger.logError("Error occurred updating form history: " + Log.exceptionStr(error)); - reject(error); - }, - handleCompletion(reason) { - resolve(); - } - } - FormHistory.update(data, handlers); - }); +let FormDB = { + /** + * makeGUID + * + * Generates a brand-new globally unique identifier (GUID). Borrowed + * from Weave's utils.js. + * + * @return the new guid + */ + makeGUID: function makeGUID() { + // 70 characters that are not-escaped URL-friendly + const code = + "!()*-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~"; + + let guid = ""; + let num = 0; + let val; + + // Generate ten 70-value characters for a 70^10 (~61.29-bit) GUID + for (let i = 0; i < 10; i++) { + // Refresh the number source after using it a few times + if (i == 0 || i == 5) + num = Math.random(); + + // Figure out which code to use for the next GUID character + num *= 70; + val = Math.floor(num); + guid += code[val]; + num -= val; + } + + return guid; }, /** * insertValue * - * Adds the specified value for the specified fieldname into form history. + * Inserts the specified value for the specified fieldname into the + * moz_formhistory table. * * @param fieldname The form fieldname to insert * @param value The form value to insert * @param us The time, in microseconds, to use for the lastUsed * and firstUsed columns - * @return Promise<undefined> + * @return nothing */ - insertValue(fieldname, value, us) { - let data = { op: "add", fieldname, value, timesUsed: 1, - firstUsed: us, lastUsed: us } - return this._update(data); + insertValue: function (fieldname, value, us) { + let query = this.createStatement( + "INSERT INTO moz_formhistory " + + "(fieldname, value, timesUsed, firstUsed, lastUsed, guid) VALUES " + + "(:fieldname, :value, :timesUsed, :firstUsed, :lastUsed, :guid)"); + query.params.fieldname = fieldname; + query.params.value = value; + query.params.timesUsed = 1; + query.params.firstUsed = us; + query.params.lastUsed = us; + query.params.guid = this.makeGUID(); + query.execute(); + query.reset(); }, /** @@ -61,10 +90,15 @@ var FormDB = { * * @param id The id of the row to update * @param newvalue The new value to set - * @return Promise<undefined> + * @return nothing */ - updateValue(id, newvalue) { - return this._update({ op: "update", guid: id, value: newvalue }); + updateValue: function (id, newvalue) { + let query = this.createStatement( + "UPDATE moz_formhistory SET value = :value WHERE id = :id"); + query.params.id = id; + query.params.value = newvalue; + query.execute(); + query.reset(); }, /** @@ -75,44 +109,52 @@ var FormDB = { * * @param fieldname The fieldname of the row to query * @param value The value of the row to query - * @return Promise<null if no row is found with the specified fieldname and value, - * or an object containing the row's guid, lastUsed, and firstUsed - * values> + * @return null if no row is found with the specified fieldname and value, + * or an object containing the row's id, lastUsed, and firstUsed + * values */ - getDataForValue(fieldname, value) { - return new Promise((resolve, reject) => { - let result = null; - let handlers = { - handleResult(oneResult) { - if (result != null) { - reject("more than 1 result for this query"); - return; - } - result = oneResult; - }, - handleError(error) { - Logger.logError("Error occurred updating form history: " + Log.exceptionStr(error)); - reject(error); - }, - handleCompletion(reason) { - resolve(result); - } - } - FormHistory.search(["guid", "lastUsed", "firstUsed"], { fieldname }, handlers); - }); + getDataForValue: function (fieldname, value) { + let query = this.createStatement( + "SELECT id, lastUsed, firstUsed FROM moz_formhistory WHERE " + + "fieldname = :fieldname AND value = :value"); + query.params.fieldname = fieldname; + query.params.value = value; + if (!query.executeStep()) + return null; + + return { + id: query.row.id, + lastUsed: query.row.lastUsed, + firstUsed: query.row.firstUsed + }; }, /** - * remove + * createStatement * - * Removes the specified GUID from the database. + * Creates a statement from a SQL string. This function is borrowed + * from Weave's forms.js. * - * @param guid The guid of the item to delete - * @return Promise<> + * @param query The SQL query string + * @return the mozIStorageStatement created from the specified SQL */ - remove(guid) { - return this._update({ op: "remove", guid }); - }, + createStatement: function createStatement(query) { + try { + // Just return the statement right away if it's okay + return formService.DBConnection.createStatement(query); + } + catch(ex) { + // Assume guid column must not exist yet, so add it with an index + formService.DBConnection.executeSimpleSQL( + "ALTER TABLE moz_formhistory ADD COLUMN guid TEXT"); + formService.DBConnection.executeSimpleSQL( + "CREATE INDEX IF NOT EXISTS moz_formhistory_guid_index " + + "ON moz_formhistory (guid)"); + } + + // Try creating the query now that the column exists + return formService.DBConnection.createStatement(query); + } }; /** @@ -162,18 +204,18 @@ FormData.prototype = { Logger.AssertTrue(this.fieldname != null && this.value != null, "Must specify both fieldname and value"); - return FormDB.getDataForValue(this.fieldname, this.value).then(formdata => { - if (!formdata) { - // this item doesn't exist yet in the db, so we need to insert it - return FormDB.insertValue(this.fieldname, this.value, - this.hours_to_us(this.date)); - } else { - /* Right now, we ignore this case. If bug 552531 is ever fixed, - we might need to add code here to update the firstUsed or - lastUsed fields, as appropriate. - */ - } - }); + let formdata = FormDB.getDataForValue(this.fieldname, this.value); + if (!formdata) { + // this item doesn't exist yet in the db, so we need to insert it + FormDB.insertValue(this.fieldname, this.value, + this.hours_to_us(this.date)); + } + else { + /* Right now, we ignore this case. If bug 552531 is ever fixed, + we might need to add code here to update the firstUsed or + lastUsed fields, as appropriate. + */ + } }, /** @@ -185,22 +227,21 @@ FormData.prototype = { * @return true if this entry exists in the database, otherwise false */ Find: function() { - return FormDB.getDataForValue(this.fieldname, this.value).then(formdata => { - let status = formdata != null; - if (status) { - /* - //form history dates currently not synced! bug 552531 - let us = this.hours_to_us(this.date); - status = Logger.AssertTrue( - us >= formdata.firstUsed && us <= formdata.lastUsed, - "No match for with that date value"); - - if (status) - */ - this.id = formdata.guid; - } - return status; - }); + let formdata = FormDB.getDataForValue(this.fieldname, this.value); + let status = formdata != null; + if (status) { + /* + //form history dates currently not synced! bug 552531 + let us = this.hours_to_us(this.date); + status = Logger.AssertTrue( + us >= formdata.firstUsed && us <= formdata.lastUsed, + "No match for with that date value"); + + if (status) + */ + this.id = formdata.id; + } + return status; }, /** @@ -214,6 +255,7 @@ FormData.prototype = { Remove: function() { /* Right now Weave doesn't handle this correctly, see bug 568363. */ - return FormDB.remove(this.id); + formService.removeEntry(this.fieldname, this.value); + return true; }, }; diff --git a/services/sync/tps/extensions/tps/resource/modules/history.jsm b/services/sync/tps/extensions/tps/resource/modules/history.jsm index 78deb42ab..ab0514bcc 100644 --- a/services/sync/tps/extensions/tps/resource/modules/history.jsm +++ b/services/sync/tps/extensions/tps/resource/modules/history.jsm @@ -33,7 +33,7 @@ var DumpHistory = function TPS_History__DumpHistory() { let node = root.getChild(i); let uri = node.uri; let curvisits = HistoryEntry._getVisits(uri); - for (var visit of curvisits) { + for each (var visit in curvisits) { Logger.logInfo("URI: " + uri + ", type=" + visit.type + ", date=" + visit.date, true); } } @@ -70,8 +70,8 @@ var HistoryEntry = { "WHERE place_id = (" + "SELECT id " + "FROM moz_places " + - "WHERE url_hash = hash(:url) AND url = :url) " + - "ORDER BY date DESC LIMIT 20"); + "WHERE url = :url) " + + "ORDER BY date DESC LIMIT 10"); this.__defineGetter__("_visitStm", () => stm); return stm; }, @@ -110,7 +110,7 @@ var HistoryEntry = { uri: uri, visits: [] }; - for (let visit of item.visits) { + for each (visit in item.visits) { place.visits.push({ visitDate: usSinceEpoch + (visit.date * 60 * 60 * 1000 * 1000), transitionType: visit.type @@ -150,8 +150,8 @@ var HistoryEntry = { "History entry in test file must have both 'visits' " + "and 'uri' properties"); let curvisits = this._getVisits(item.uri); - for (let visit of curvisits) { - for (let itemvisit of item.visits) { + for each (visit in curvisits) { + for each (itemvisit in item.visits) { let expectedDate = itemvisit.date * 60 * 60 * 1000 * 1000 + usSinceEpoch; if (visit.type == itemvisit.type && visit.date == expectedDate) { @@ -161,7 +161,7 @@ var HistoryEntry = { } let all_items_found = true; - for (let itemvisit of item.visits) { + for each (itemvisit in item.visits) { all_items_found = all_items_found && "found" in itemvisit; Logger.logInfo("History entry for " + item.uri + ", type:" + itemvisit.type + ", date:" + itemvisit.date + @@ -189,16 +189,9 @@ var HistoryEntry = { PlacesUtils.history.removePagesFromHost(item.host, false); } else if ("begin" in item && "end" in item) { - let cb = Async.makeSpinningCallback(); - let msSinceEpoch = parseInt(usSinceEpoch / 1000); - let filter = { - beginDate: new Date(msSinceEpoch + (item.begin * 60 * 60 * 1000)), - endDate: new Date(msSinceEpoch + (item.end * 60 * 60 * 1000)) - }; - PlacesUtils.history.removeVisitsByFilter(filter) - .catch(ex => Logger.AssertTrue(false, "An error occurred while deleting history: " + ex)) - .then(result => {cb(null, result)}, err => {cb(err)}); - Async.waitForSyncCallback(cb); + PlacesUtils.history.removeVisitsByTimeframe( + usSinceEpoch + (item.begin * 60 * 60 * 1000 * 1000), + usSinceEpoch + (item.end * 60 * 60 * 1000 * 1000)); } else { Logger.AssertTrue(false, "invalid entry in delete history"); diff --git a/services/sync/tps/extensions/tps/resource/modules/passwords.jsm b/services/sync/tps/extensions/tps/resource/modules/passwords.jsm index a84800bab..f7221224a 100644 --- a/services/sync/tps/extensions/tps/resource/modules/passwords.jsm +++ b/services/sync/tps/extensions/tps/resource/modules/passwords.jsm @@ -14,7 +14,7 @@ const {classes: Cc, interfaces: Ci, utils: Cu} = Components; Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://tps/logger.jsm"); -var nsLoginInfo = new Components.Constructor( +let nsLoginInfo = new Components.Constructor( "@mozilla.org/login-manager/loginInfo;1", Ci.nsILoginInfo, "init"); diff --git a/services/sync/tps/extensions/tps/resource/modules/prefs.jsm b/services/sync/tps/extensions/tps/resource/modules/prefs.jsm index 286c5a6b5..18a6e32ee 100644 --- a/services/sync/tps/extensions/tps/resource/modules/prefs.jsm +++ b/services/sync/tps/extensions/tps/resource/modules/prefs.jsm @@ -13,7 +13,7 @@ const {classes: Cc, interfaces: Ci, utils: Cu} = Components; const WEAVE_PREF_PREFIX = "services.sync.prefs.sync."; -var prefs = Cc["@mozilla.org/preferences-service;1"] +let prefs = Cc["@mozilla.org/preferences-service;1"] .getService(Ci.nsIPrefBranch); Cu.import("resource://tps/logger.jsm"); diff --git a/services/sync/tps/extensions/tps/resource/modules/tabs.jsm b/services/sync/tps/extensions/tps/resource/modules/tabs.jsm index af983573f..a2ce1afc1 100644 --- a/services/sync/tps/extensions/tps/resource/modules/tabs.jsm +++ b/services/sync/tps/extensions/tps/resource/modules/tabs.jsm @@ -13,7 +13,7 @@ const {classes: Cc, interfaces: Ci, utils: Cu} = Components; Cu.import("resource://services-sync/main.js"); -var BrowserTabs = { +let BrowserTabs = { /** * Add * @@ -49,12 +49,8 @@ var BrowserTabs = { Find: function(uri, title, profile) { // Find the uri in Weave's list of tabs for the given profile. let engine = Weave.Service.engineManager.get("tabs"); - for (let [guid, client] of Object.entries(engine.getAllClients())) { - if (!client.tabs) { - continue; - } - for (let key in client.tabs) { - let tab = client.tabs[key]; + for (let [guid, client] in Iterator(engine.getAllClients())) { + for each (tab in client.tabs) { let weaveTabUrl = tab.urlHistory[0]; if (uri == weaveTabUrl && profile == client.clientName) if (title == undefined || title == tab.title) diff --git a/services/sync/tps/extensions/tps/resource/modules/windows.jsm b/services/sync/tps/extensions/tps/resource/modules/windows.jsm index d892aea56..62cc80d2c 100644 --- a/services/sync/tps/extensions/tps/resource/modules/windows.jsm +++ b/services/sync/tps/extensions/tps/resource/modules/windows.jsm @@ -14,7 +14,7 @@ const {classes: Cc, interfaces: Ci, utils: Cu} = Components; Cu.import("resource://services-sync/main.js"); -var BrowserWindows = { +let BrowserWindows = { /** * Add * diff --git a/services/sync/tps/extensions/tps/resource/tps.jsm b/services/sync/tps/extensions/tps/resource/tps.jsm index f4cc0214a..d3a8b0b7d 100644 --- a/services/sync/tps/extensions/tps/resource/tps.jsm +++ b/services/sync/tps/extensions/tps/resource/tps.jsm @@ -7,28 +7,20 @@ * listed symbols will exposed on import, and only when and where imported. */ -var EXPORTED_SYMBOLS = ["ACTIONS", "TPS"]; +let EXPORTED_SYMBOLS = ["ACTIONS", "TPS"]; const {classes: Cc, interfaces: Ci, utils: Cu} = Components; -var module = this; +let module = this; // Global modules -Cu.import("resource://gre/modules/Log.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/AppConstants.jsm"); -Cu.import("resource://gre/modules/PlacesUtils.jsm"); -Cu.import("resource://gre/modules/FileUtils.jsm"); Cu.import("resource://services-common/async.js"); Cu.import("resource://services-sync/constants.js"); Cu.import("resource://services-sync/main.js"); Cu.import("resource://services-sync/util.js"); -Cu.import("resource://services-sync/telemetry.js"); -Cu.import("resource://services-sync/bookmark_validator.js"); -Cu.import("resource://services-sync/engines/passwords.js"); -Cu.import("resource://services-sync/engines/forms.js"); -Cu.import("resource://services-sync/engines/addons.js"); + // TPS modules Cu.import("resource://tps/logger.jsm"); @@ -50,11 +42,6 @@ var prefs = Cc["@mozilla.org/preferences-service;1"] var mozmillInit = {}; Cu.import('resource://mozmill/driver/mozmill.js', mozmillInit); -XPCOMUtils.defineLazyGetter(this, "fileProtocolHandler", () => { - let fileHandler = Services.io.getProtocolHandler("file"); - return fileHandler.QueryInterface(Ci.nsIFileProtocolHandler); -}); - // Options for wiping data during a sync const SYNC_RESET_CLIENT = "resetClient"; const SYNC_WIPE_CLIENT = "wipeClient"; @@ -90,7 +77,7 @@ const ACTIONS = [ const OBSERVER_TOPICS = ["fxaccounts:onlogin", "fxaccounts:onlogout", "private-browsing", - "profile-before-change", + "quit-application-requested", "sessionstore-windows-restored", "weave:engine:start-tracking", "weave:engine:stop-tracking", @@ -102,19 +89,18 @@ const OBSERVER_TOPICS = ["fxaccounts:onlogin", "weave:service:sync:start" ]; -var TPS = { +let TPS = { _currentAction: -1, _currentPhase: -1, _enabledEngines: null, _errors: 0, + _finalPhase: false, _isTracking: false, _operations_pending: 0, _phaseFinished: false, _phaselist: {}, _setupComplete: false, _syncActive: false, - _syncCount: 0, - _syncsReportedViaTelemetry: 0, _syncErrors: 0, _syncWipeAction: null, _tabsAdded: 0, @@ -122,11 +108,6 @@ var TPS = { _test: null, _triggeredSync: false, _usSinceEpoch: 0, - _requestedQuit: false, - shouldValidateAddons: false, - shouldValidateBookmarks: false, - shouldValidatePasswords: false, - shouldValidateForms: false, _init: function TPS__init() { // Check if Firefox Accounts is enabled @@ -141,8 +122,6 @@ var TPS = { Services.obs.addObserver(this, aTopic, true); }, this); - // Configure some logging prefs for Sync itself. - Weave.Svc.Prefs.set("log.appender.dump", "Debug"); // Import the appropriate authentication module if (this.fxaccounts_enabled) { Cu.import("resource://tps/auth/fxaccounts.jsm", module); @@ -152,16 +131,9 @@ var TPS = { } }, - DumpError(msg, exc = null) { + DumpError: function TPS__DumpError(msg) { this._errors++; - let errInfo; - if (exc) { - errInfo = Log.exceptionStr(exc); // includes details and stack-trace. - } else { - // always write a stack even if no error passed. - errInfo = Log.stackTrace(new Error()); - } - Logger.logError(`[phase ${this._currentPhase}] ${msg} - ${errInfo}`); + Logger.logError("[phase" + this._currentPhase + "] " + msg); this.quit(); }, @@ -177,7 +149,14 @@ var TPS = { Logger.logInfo("private browsing " + data); break; - case "profile-before-change": + case "quit-application-requested": + // Ensure that we eventually wipe the data on the server + if (this._errors || !this._phaseFinished || this._finalPhase) { + try { + this.WipeServer(); + } catch (ex) {} + } + OBSERVER_TOPICS.forEach(function(topic) { Services.obs.removeObserver(this, topic); }, this); @@ -253,7 +232,7 @@ var TPS = { } } catch (e) { - this.DumpError("Observer failed", e); + this.DumpError("Exception caught: " + Utils.exceptionStr(e)); return; } }, @@ -286,7 +265,6 @@ var TPS = { }, quit: function TPS__quit() { - this._requestedQuit = true; this.goQuitApplication(); }, @@ -307,7 +285,7 @@ var TPS = { HandleTabs: function (tabs, action) { this._tabsAdded = tabs.length; this._tabsFinished = 0; - for (let tab of tabs) { + for each (let tab in tabs) { Logger.logInfo("executing action " + action.toUpperCase() + " on tab " + JSON.stringify(tab)); switch(action) { @@ -352,7 +330,7 @@ var TPS = { }, HandlePrefs: function (prefs, action) { - for (let pref of prefs) { + for each (pref in prefs) { Logger.logInfo("executing action " + action.toUpperCase() + " on pref " + JSON.stringify(pref)); let preference = new Preference(pref); @@ -371,25 +349,23 @@ var TPS = { }, HandleForms: function (data, action) { - this.shouldValidateForms = true; - for (let datum of data) { + for each (datum in data) { Logger.logInfo("executing action " + action.toUpperCase() + " on form entry " + JSON.stringify(datum)); let formdata = new FormData(datum, this._usSinceEpoch); switch(action) { case ACTION_ADD: - Async.promiseSpinningly(formdata.Create()); + formdata.Create(); break; case ACTION_DELETE: - Async.promiseSpinningly(formdata.Remove()); + formdata.Remove(); break; case ACTION_VERIFY: - Logger.AssertTrue(Async.promiseSpinningly(formdata.Find()), - "form data not found"); + Logger.AssertTrue(formdata.Find(), "form data not found"); break; case ACTION_VERIFY_NOT: - Logger.AssertTrue(!Async.promiseSpinningly(formdata.Find()), - "form data found, but it shouldn't be present"); + Logger.AssertTrue(!formdata.Find(), + "form data found, but it shouldn't be present"); break; default: Logger.AssertTrue(false, "invalid action: " + action); @@ -401,7 +377,7 @@ var TPS = { HandleHistory: function (entries, action) { try { - for (let entry of entries) { + for each (entry in entries) { Logger.logInfo("executing action " + action.toUpperCase() + " on history entry " + JSON.stringify(entry)); switch(action) { @@ -433,32 +409,31 @@ var TPS = { }, HandlePasswords: function (passwords, action) { - this.shouldValidatePasswords = true; try { - for (let password of passwords) { + for each (password in passwords) { let password_id = -1; Logger.logInfo("executing action " + action.toUpperCase() + " on password " + JSON.stringify(password)); - let passwordOb = new Password(password); + var password = new Password(password); switch (action) { case ACTION_ADD: - Logger.AssertTrue(passwordOb.Create() > -1, "error adding password"); + Logger.AssertTrue(password.Create() > -1, "error adding password"); break; case ACTION_VERIFY: - Logger.AssertTrue(passwordOb.Find() != -1, "password not found"); + Logger.AssertTrue(password.Find() != -1, "password not found"); break; case ACTION_VERIFY_NOT: - Logger.AssertTrue(passwordOb.Find() == -1, + Logger.AssertTrue(password.Find() == -1, "password found, but it shouldn't exist"); break; case ACTION_DELETE: - Logger.AssertTrue(passwordOb.Find() != -1, "password not found"); - passwordOb.Remove(); + Logger.AssertTrue(password.Find() != -1, "password not found"); + password.Remove(); break; case ACTION_MODIFY: - if (passwordOb.updateProps != null) { - Logger.AssertTrue(passwordOb.Find() != -1, "password not found"); - passwordOb.Update(); + if (password.updateProps != null) { + Logger.AssertTrue(password.Find() != -1, "password not found"); + password.Update(); } break; default: @@ -475,8 +450,7 @@ var TPS = { }, HandleAddons: function (addons, action, state) { - this.shouldValidateAddons = true; - for (let entry of addons) { + for each (let entry in addons) { Logger.logInfo("executing action " + action.toUpperCase() + " on addon " + JSON.stringify(entry)); let addon = new Addon(this, entry); @@ -505,12 +479,11 @@ var TPS = { }, HandleBookmarks: function (bookmarks, action) { - this.shouldValidateBookmarks = true; try { let items = []; - for (let folder in bookmarks) { + for (folder in bookmarks) { let last_item_pos = -1; - for (let bookmark of bookmarks[folder]) { + for each (bookmark in bookmarks[folder]) { Logger.clearPotentialError(); let placesItem; bookmark['location'] = folder; @@ -552,7 +525,7 @@ var TPS = { } if (action == ACTION_DELETE || action == ACTION_MODIFY) { - for (let item of items) { + for each (item in items) { Logger.logInfo("executing action " + action.toUpperCase() + " on bookmark " + JSON.stringify(item)); switch(action) { @@ -597,163 +570,10 @@ var TPS = { Logger.logInfo("mozmill setTest: " + obj.name); }, - Cleanup() { - try { - this.WipeServer(); - } catch (ex) { - Logger.logError("Failed to wipe server: " + Log.exceptionStr(ex)); - } - try { - if (Authentication.isLoggedIn) { - // signout and wait for Sync to completely reset itself. - Logger.logInfo("signing out"); - let waiter = this.createEventWaiter("weave:service:start-over:finish"); - Authentication.signOut(); - waiter(); - Logger.logInfo("signout complete"); - } - } catch (e) { - Logger.logError("Failed to sign out: " + Log.exceptionStr(e)); - } - }, - - /** - * Use Sync's bookmark validation code to see if we've corrupted the tree. - */ - ValidateBookmarks() { - - let getServerBookmarkState = () => { - let bookmarkEngine = Weave.Service.engineManager.get('bookmarks'); - let collection = bookmarkEngine.itemSource(); - let collectionKey = bookmarkEngine.service.collectionKeys.keyForCollection(bookmarkEngine.name); - collection.full = true; - let items = []; - collection.recordHandler = function(item) { - item.decrypt(collectionKey); - items.push(item.cleartext); - }; - collection.get(); - return items; - }; - let serverRecordDumpStr; - try { - Logger.logInfo("About to perform bookmark validation"); - let clientTree = Async.promiseSpinningly(PlacesUtils.promiseBookmarksTree("", { - includeItemIds: true - })); - let serverRecords = getServerBookmarkState(); - // We can't wait until catch to stringify this, since at that point it will have cycles. - serverRecordDumpStr = JSON.stringify(serverRecords); - - let validator = new BookmarkValidator(); - let {problemData} = validator.compareServerWithClient(serverRecords, clientTree); - - for (let {name, count} of problemData.getSummary()) { - // Exclude mobile showing up on the server hackily so that we don't - // report it every time, see bug 1273234 and 1274394 for more information. - if (name === "serverUnexpected" && problemData.serverUnexpected.indexOf("mobile") >= 0) { - --count; - } - if (count) { - // Log this out before we assert. This is useful in the context of TPS logs, since we - // can see the IDs in the test files. - Logger.logInfo(`Validation problem: "${name}": ${JSON.stringify(problemData[name])}`); - } - Logger.AssertEqual(count, 0, `Bookmark validation error of type ${name}`); - } - } catch (e) { - // Dump the client records (should always be doable) - DumpBookmarks(); - // Dump the server records if gotten them already. - if (serverRecordDumpStr) { - Logger.logInfo("Server bookmark records:\n" + serverRecordDumpStr + "\n"); - } - this.DumpError("Bookmark validation failed", e); - } - Logger.logInfo("Bookmark validation finished"); - }, - - ValidateCollection(engineName, ValidatorType) { - let serverRecordDumpStr; - let clientRecordDumpStr; - try { - Logger.logInfo(`About to perform validation for "${engineName}"`); - let engine = Weave.Service.engineManager.get(engineName); - let validator = new ValidatorType(engine); - let serverRecords = validator.getServerItems(engine); - let clientRecords = Async.promiseSpinningly(validator.getClientItems()); - try { - // This substantially improves the logs for addons while not making a - // substantial difference for the other two - clientRecordDumpStr = JSON.stringify(clientRecords.map(r => { - let res = validator.normalizeClientItem(r); - delete res.original; // Try and prevent cyclic references - return res; - })); - } catch (e) { - // ignore the error, the dump string is just here to make debugging easier. - clientRecordDumpStr = "<Cyclic value>"; - } - try { - serverRecordDumpStr = JSON.stringify(serverRecords); - } catch (e) { - // as above - serverRecordDumpStr = "<Cyclic value>"; - } - let { problemData } = validator.compareClientWithServer(clientRecords, serverRecords); - for (let { name, count } of problemData.getSummary()) { - if (count) { - Logger.logInfo(`Validation problem: "${name}": ${JSON.stringify(problemData[name])}`); - } - Logger.AssertEqual(count, 0, `Validation error for "${engineName}" of type "${name}"`); - } - } catch (e) { - // Dump the client records if possible - if (clientRecordDumpStr) { - Logger.logInfo(`Client state for ${engineName}:\n${clientRecordDumpStr}\n`); - } - // Dump the server records if gotten them already. - if (serverRecordDumpStr) { - Logger.logInfo(`Server state for ${engineName}:\n${serverRecordDumpStr}\n`); - } - this.DumpError(`Validation failed for ${engineName}`, e); - } - Logger.logInfo(`Validation finished for ${engineName}`); - }, - - ValidatePasswords() { - return this.ValidateCollection("passwords", PasswordValidator); - }, - - ValidateForms() { - return this.ValidateCollection("forms", FormValidator); - }, - - ValidateAddons() { - return this.ValidateCollection("addons", AddonValidator); - }, - RunNextTestAction: function() { try { if (this._currentAction >= - this._phaselist[this._currentPhase].length) { - // Run necessary validations and then finish up - if (this.shouldValidateBookmarks) { - this.ValidateBookmarks(); - } - if (this.shouldValidatePasswords) { - this.ValidatePasswords(); - } - if (this.shouldValidateForms) { - this.ValidateForms(); - } - if (this.shouldValidateAddons) { - this.ValidateAddons(); - } - // Force this early so that we run the validation and detect missing pings - // *before* we start shutting down, since if we do it after, the python - // code won't notice the failure. - SyncTelemetry.shutdown(); + this._phaselist["phase" + this._currentPhase].length) { // we're all done Logger.logInfo("test phase " + this._currentPhase + ": " + (this._errors ? "FAIL" : "PASS")); @@ -761,7 +581,7 @@ var TPS = { this.quit(); return; } - this.seconds_since_epoch = prefs.getIntPref("tps.seconds_since_epoch", 0); + if (this.seconds_since_epoch) this._usSinceEpoch = this.seconds_since_epoch * 1000 * 1000; else { @@ -769,7 +589,7 @@ var TPS = { return; } - let phase = this._phaselist[this._currentPhase]; + let phase = this._phaselist["phase" + this._currentPhase]; let action = phase[this._currentAction]; Logger.logInfo("starting action: " + action[0].name); action[0].apply(this, action.slice(1)); @@ -781,64 +601,12 @@ var TPS = { this._currentAction++; } catch(e) { - if (Async.isShutdownException(e)) { - if (this._requestedQuit) { - Logger.logInfo("Sync aborted due to requested shutdown"); - } else { - this.DumpError("Sync aborted due to shutdown, but we didn't request it"); - } - } else { - this.DumpError("RunNextTestAction failed", e); - } + this.DumpError("Exception caught: " + Utils.exceptionStr(e)); return; } this.RunNextTestAction(); }, - _getFileRelativeToSourceRoot(testFileURL, relativePath) { - let file = fileProtocolHandler.getFileFromURLSpec(testFileURL); - let root = file // <root>/services/sync/tests/tps/test_foo.js - .parent // <root>/services/sync/tests/tps - .parent // <root>/services/sync/tests - .parent // <root>/services/sync - .parent // <root>/services - .parent // <root> - ; - root.appendRelativePath(relativePath); - return root; - }, - - // Attempt to load the sync_ping_schema.json and initialize `this.pingValidator` - // based on the source of the tps file. Assumes that it's at "../unit/sync_ping_schema.json" - // relative to the directory the tps test file (testFile) is contained in. - _tryLoadPingSchema(testFile) { - try { - let schemaFile = this._getFileRelativeToSourceRoot(testFile, - "services/sync/tests/unit/sync_ping_schema.json"); - - let stream = Cc["@mozilla.org/network/file-input-stream;1"] - .createInstance(Ci.nsIFileInputStream); - - let jsonReader = Cc["@mozilla.org/dom/json;1"] - .createInstance(Components.interfaces.nsIJSON); - - stream.init(schemaFile, FileUtils.MODE_RDONLY, FileUtils.PERMS_FILE, 0); - let schema = jsonReader.decodeFromStream(stream, stream.available()); - Logger.logInfo("Successfully loaded schema") - - // Importing resource://testing-common/* isn't possible from within TPS, - // so we load Ajv manually. - let ajvFile = this._getFileRelativeToSourceRoot(testFile, "testing/modules/ajv-4.1.1.js"); - let ajvURL = fileProtocolHandler.getURLSpecFromFile(ajvFile); - let ns = {}; - Cu.import(ajvURL, ns); - let ajv = new ns.Ajv({ async: "co*" }); - this.pingValidator = ajv.compile(schema); - } catch (e) { - this.DumpError(`Failed to load ping schema and AJV relative to "${testFile}".`, e); - } - }, - /** * Runs a single test phase. * @@ -872,8 +640,6 @@ var TPS = { Logger.logInfo("Sync version: " + WEAVE_VERSION); Logger.logInfo("Firefox buildid: " + Services.appinfo.appBuildID); Logger.logInfo("Firefox version: " + Services.appinfo.version); - Logger.logInfo("Firefox source revision: " + (AppConstants.SOURCE_REVISION_URL || "unknown")); - Logger.logInfo("Firefox platform: " + AppConstants.platform); Logger.logInfo('Firefox Accounts enabled: ' + this.fxaccounts_enabled); // do some sync housekeeping @@ -887,15 +653,12 @@ var TPS = { this.waitForEvent("weave:service:ready"); } - // We only want to do this if we modified the bookmarks this phase. - this.shouldValidateBookmarks = false; - // Always give Sync an extra tick to initialize. If we waited for the // service:ready event, this is required to ensure all handlers have // executed. Utils.nextTick(this._executeTestPhase.bind(this, file, phase, settings)); } catch(e) { - this.DumpError("RunTestPhase failed", e); + this.DumpError("Exception caught: " + Utils.exceptionStr(e)); return; } }, @@ -907,28 +670,17 @@ var TPS = { */ _executeTestPhase: function _executeTestPhase(file, phase, settings) { try { - this.config = JSON.parse(prefs.getCharPref('tps.config')); // parse the test file Services.scriptloader.loadSubScript(file, this); this._currentPhase = phase; - if (this._currentPhase.startsWith("cleanup-")) { - let profileToClean = Cc["@mozilla.org/toolkit/profile-service;1"] - .getService(Ci.nsIToolkitProfileService) - .selectedProfile.name; - this.phases[this._currentPhase] = profileToClean; - this.Phase(this._currentPhase, [[this.Cleanup]]); - } else { - // Don't bother doing this for cleanup phases. - this._tryLoadPingSchema(file); - } - let this_phase = this._phaselist[this._currentPhase]; + let this_phase = this._phaselist["phase" + this._currentPhase]; if (this_phase == undefined) { this.DumpError("invalid phase " + this._currentPhase); return; } - if (this.phases[this._currentPhase] == undefined) { + if (this.phases["phase" + this._currentPhase] == undefined) { this.DumpError("no profile defined for phase " + this._currentPhase); return; } @@ -937,7 +689,7 @@ var TPS = { // care about. if (settings.ignoreUnusedEngines && Array.isArray(this._enabledEngines)) { let names = {}; - for (let name of this._enabledEngines) { + for each (let name in this._enabledEngines) { names[name] = true; } @@ -948,63 +700,52 @@ var TPS = { } } } - Logger.logInfo("Starting phase " + this._currentPhase); - Logger.logInfo("setting client.name to " + this.phases[this._currentPhase]); - Weave.Svc.Prefs.set("client.name", this.phases[this._currentPhase]); + Logger.logInfo("Starting phase " + parseInt(phase, 10) + "/" + + Object.keys(this._phaselist).length); - this._interceptSyncTelemetry(); + Logger.logInfo("setting client.name to " + this.phases["phase" + this._currentPhase]); + Weave.Svc.Prefs.set("client.name", this.phases["phase" + this._currentPhase]); - // start processing the test actions - this._currentAction = 0; - } - catch(e) { - this.DumpError("_executeTestPhase failed", e); - return; - } - }, + // TODO Phases should be defined in a data type that has strong + // ordering, not by lexical sorting. + let currentPhase = parseInt(this._currentPhase, 10); - /** - * Override sync telemetry functions so that we can detect errors generating - * the sync ping, and count how many pings we report. - */ - _interceptSyncTelemetry() { - let originalObserve = SyncTelemetry.observe; - let self = this; - SyncTelemetry.observe = function() { - try { - originalObserve.apply(this, arguments); - } catch (e) { - self.DumpError("Error when generating sync telemetry", e); + // Login at the beginning of the test. + if (currentPhase <= 1) { + this_phase.unshift([this.Login]); } - }; - SyncTelemetry.submit = record => { - Logger.logInfo("Intercepted sync telemetry submission: " + JSON.stringify(record)); - this._syncsReportedViaTelemetry += record.syncs.length + (record.discarded || 0); - if (record.discarded) { - if (record.syncs.length != SyncTelemetry.maxPayloadCount) { - this.DumpError("Syncs discarded from ping before maximum payload count reached"); - } + + // Wipe the server at the end of the final test phase. + if (currentPhase >= Object.keys(this.phases).length) { + this._finalPhase = true; } - // If this is the shutdown ping, check and see that the telemetry saw all the syncs. - if (record.why === "shutdown") { - // If we happen to sync outside of tps manually causing it, its not an - // error in the telemetry, so we only complain if we didn't see all of them. - if (this._syncsReportedViaTelemetry < this._syncCount) { - this.DumpError(`Telemetry missed syncs: Saw ${this._syncsReportedViaTelemetry}, should have >= ${this._syncCount}.`); - } + + // If a custom server was specified, set it now + if (this.config["serverURL"]) { + Weave.Service.serverURL = this.config.serverURL; + prefs.setCharPref('tps.serverURL', this.config.serverURL); } - if (!record.syncs.length) { - // Note: we're overwriting submit, so this is called even for pings that - // may have no data (which wouldn't be submitted to telemetry and would - // fail validation). - return; + + // Store account details as prefs so they're accessible to the Mozmill + // framework. + if (this.fxaccounts_enabled) { + prefs.setCharPref('tps.account.username', this.config.fx_account.username); + prefs.setCharPref('tps.account.password', this.config.fx_account.password); } - if (!this.pingValidator(record)) { - // Note that we already logged the record. - this.DumpError("Sync ping validation failed with errors: " + JSON.stringify(this.pingValidator.errors)); + else { + prefs.setCharPref('tps.account.username', this.config.sync_account.username); + prefs.setCharPref('tps.account.password', this.config.sync_account.password); + prefs.setCharPref('tps.account.passphrase', this.config.sync_account.passphrase); } - }; + + // start processing the test actions + this._currentAction = 0; + } + catch(e) { + this.DumpError("Exception caught: " + Utils.exceptionStr(e)); + return; + } }, /** @@ -1018,10 +759,6 @@ var TPS = { * Array of functions/actions to perform. */ Phase: function Test__Phase(phasename, fnlist) { - if (Object.keys(this._phaselist).length === 0) { - // This is the first phase, add that we need to login. - fnlist.unshift([this.Login]); - } this._phaselist[phasename] = fnlist; }, @@ -1067,56 +804,28 @@ var TPS = { }, /** - * Return an object that when called, will block until the named event - * is observed. This is similar to waitForEvent, although is typically safer - * if you need to do some other work that may make the event fire. - * - * eg: - * doSomething(); // causes the event to be fired. - * waitForEvent("something"); - * is risky as the call to doSomething may trigger the event before the - * waitForEvent call is made. Contrast with: - * - * let waiter = createEventWaiter("something"); // does *not* block. - * doSomething(); // causes the event to be fired. - * waiter(); // will return as soon as the event fires, even if it fires - * // before this function is called. - * - * @param aEventName - * String event to wait for. - */ - createEventWaiter(aEventName) { - Logger.logInfo("Setting up wait for " + aEventName + "..."); - let cb = Async.makeSpinningCallback(); - Svc.Obs.add(aEventName, cb); - return function() { - try { - cb.wait(); - } finally { - Svc.Obs.remove(aEventName, cb); - Logger.logInfo(aEventName + " observed!"); - } - } - }, - - - /** * Synchronously wait for the named event to be observed. * * When the event is observed, the function will wait an extra tick before * returning. * - * Note that in general, you should probably use createEventWaiter unless you - * are 100% sure that the event being waited on can only be sent after this - * call adds the listener. - * * @param aEventName * String event to wait for. */ waitForEvent: function waitForEvent(aEventName) { - this.createEventWaiter(aEventName)(); + Logger.logInfo("Waiting for " + aEventName + "..."); + let cb = Async.makeSpinningCallback(); + Svc.Obs.add(aEventName, cb); + cb.wait(); + Svc.Obs.remove(aEventName, cb); + Logger.logInfo(aEventName + " observed!"); + + cb = Async.makeSpinningCallback(); + Utils.nextTick(cb); + cb.wait(); }, + /** * Waits for Sync to logged in before returning */ @@ -1159,12 +868,6 @@ var TPS = { this.waitForSetupComplete(); Logger.AssertEqual(Weave.Status.service, Weave.STATUS_OK, "Weave status OK"); this.waitForTracking(); - // If fxaccounts is enabled we get an initial sync at login time - let - // that complete. - if (this.fxaccounts_enabled) { - this._triggeredSync = true; - this.waitForSyncFinished(); - } }, /** @@ -1189,12 +892,10 @@ var TPS = { } this.Login(false); - ++this._syncCount; this._triggeredSync = true; this.StartAsyncOperation(); Weave.Service.sync(); - Logger.logInfo("Sync is complete"); }, WipeServer: function TPS__WipeServer() { @@ -1230,9 +931,6 @@ var Addons = { verifyNot: function Addons__verifyNot(addons) { TPS.HandleAddons(addons, ACTION_VERIFY_NOT); }, - skipValidation() { - TPS.shouldValidateAddons = false; - } }; var Bookmarks = { @@ -1250,9 +948,6 @@ var Bookmarks = { }, verifyNot: function Bookmarks__verifyNot(bookmarks) { TPS.HandleBookmarks(bookmarks, ACTION_VERIFY_NOT); - }, - skipValidation() { - TPS.shouldValidateBookmarks = false; } }; @@ -1301,9 +996,6 @@ var Passwords = { }, verifyNot: function Passwords__verifyNot(passwords) { this.HandlePasswords(passwords, ACTION_VERIFY_NOT); - }, - skipValidation() { - TPS.shouldValidatePasswords = false; } }; @@ -1337,4 +1029,4 @@ var Windows = { }; // Initialize TPS -TPS._init(); +TPS._init();
\ No newline at end of file |