Bug 1361965 - Provide access to a formautofill storage singleton. r=lchang

MozReview-Commit-ID: 6IbeuOmONxb

--HG--
extra : rebase_source : 44c5c1536b41457e945ab3e00466489929e163ff
This commit is contained in:
Mark Hammond 2017-05-04 18:25:46 +10:00
parent 543c8341d6
commit 9761a9f6b7
8 changed files with 50 additions and 59 deletions

View File

@ -39,9 +39,7 @@ Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://formautofill/FormAutofillUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "OS",
"resource://gre/modules/osfile.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "ProfileStorage",
XPCOMUtils.defineLazyModuleGetter(this, "profileStorage",
"resource://formautofill/ProfileStorage.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "FormAutofillPreferences",
"resource://formautofill/FormAutofillPreferences.jsm");
@ -49,7 +47,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "FormAutofillPreferences",
this.log = null;
FormAutofillUtils.defineLazyLogGetter(this, this.EXPORTED_SYMBOLS[0]);
const PROFILE_JSON_FILE_NAME = "autofill-profiles.json";
const ENABLED_PREF = "browser.formautofill.enabled";
function FormAutofillParent() {
@ -58,8 +55,6 @@ function FormAutofillParent() {
FormAutofillParent.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports, Ci.nsIObserver]),
_profileStore: null,
/**
* Whether Form Autofill is enabled in preferences.
* Caches the latest value of this._getStatus().
@ -69,11 +64,9 @@ FormAutofillParent.prototype = {
/**
* Initializes ProfileStorage and registers the message handler.
*/
init() {
async init() {
log.debug("init");
let storePath = OS.Path.join(OS.Constants.Path.profileDir, PROFILE_JSON_FILE_NAME);
this._profileStore = new ProfileStorage(storePath);
this._profileStore.initialize();
await profileStorage.initialize();
Services.obs.addObserver(this, "advanced-pane-loaded");
Services.ppmm.addMessageListener("FormAutofill:GetAddresses", this);
@ -160,7 +153,7 @@ FormAutofillParent.prototype = {
return false;
}
return this._profileStore.getAll().length > 0;
return profileStorage.getAll().length > 0;
},
/**
@ -188,40 +181,26 @@ FormAutofillParent.prototype = {
}
case "FormAutofill:SaveAddress": {
if (data.guid) {
this.getProfileStore().update(data.guid, data.address);
profileStorage.update(data.guid, data.address);
} else {
this.getProfileStore().add(data.address);
profileStorage.add(data.address);
}
break;
}
case "FormAutofill:RemoveAddresses": {
data.guids.forEach(guid => this.getProfileStore().remove(guid));
data.guids.forEach(guid => profileStorage.remove(guid));
break;
}
}
},
/**
* Returns the instance of ProfileStorage. To avoid syncing issues, anyone
* who needs to access the profile should request the instance by this instead
* of creating a new one.
*
* @returns {ProfileStorage}
*/
getProfileStore() {
return this._profileStore;
},
/**
* Uninitializes FormAutofillParent. This is for testing only.
*
* @private
*/
_uninit() {
if (this._profileStore) {
this._profileStore._saveImmediately();
this._profileStore = null;
}
profileStorage._saveImmediately();
Services.ppmm.removeMessageListener("FormAutofill:GetAddresses", this);
Services.ppmm.removeMessageListener("FormAutofill:SaveAddress", this);
@ -246,9 +225,9 @@ FormAutofillParent.prototype = {
let addresses = [];
if (info && info.fieldName) {
addresses = this._profileStore.getByFilter({searchString, info});
addresses = profileStorage.getByFilter({searchString, info});
} else {
addresses = this._profileStore.getAll();
addresses = profileStorage.getAll();
}
target.sendAsyncMessage("FormAutofill:Addresses", addresses);
@ -261,7 +240,7 @@ FormAutofillParent.prototype = {
Services.ppmm.initialProcessData.autofillSavedFieldNames.clear();
}
this._profileStore.getAll().forEach((address) => {
profileStorage.getAll().forEach((address) => {
Object.keys(address).forEach((fieldName) => {
if (!address[fieldName]) {
return;
@ -271,7 +250,7 @@ FormAutofillParent.prototype = {
});
// Remove the internal guid and metadata fields.
this._profileStore.INTERNAL_FIELDS.forEach((fieldName) => {
profileStorage.INTERNAL_FIELDS.forEach((fieldName) => {
Services.ppmm.initialProcessData.autofillSavedFieldNames.delete(fieldName);
});

View File

@ -50,13 +50,15 @@
"use strict";
this.EXPORTED_SYMBOLS = ["ProfileStorage"];
// We expose a singleton from this module. Some tests may import the
// constructor via a backstage pass.
this.EXPORTED_SYMBOLS = ["profileStorage"];
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource://gre/modules/osfile.jsm");
Cu.import("resource://formautofill/FormAutofillUtils.jsm");
@ -72,6 +74,8 @@ XPCOMUtils.defineLazyServiceGetter(this, "gUUIDGenerator",
this.log = null;
FormAutofillUtils.defineLazyLogGetter(this, this.EXPORTED_SYMBOLS[0]);
const PROFILE_JSON_FILE_NAME = "autofill-profiles.json";
const SCHEMA_VERSION = 1;
const VALID_FIELDS = [
@ -90,6 +94,7 @@ const VALID_FIELDS = [
function ProfileStorage(path) {
this._path = path;
this._initializePromise = null;
}
ProfileStorage.prototype = {
@ -104,11 +109,14 @@ ProfileStorage.prototype = {
* @rejects JavaScript exception.
*/
initialize() {
this._store = new JSONFile({
path: this._path,
dataPostProcessor: this._dataPostProcessor.bind(this),
});
return this._store.load();
if (!this._initializePromise) {
this._store = new JSONFile({
path: this._path,
dataPostProcessor: this._dataPostProcessor.bind(this),
});
this._initializePromise = this._store.load();
}
return this._initializePromise;
},
/**
@ -378,3 +386,7 @@ ProfileStorage.prototype = {
return this._store._save();
},
};
// The singleton exposed by this module.
this.profileStorage = new ProfileStorage(
OS.Path.join(OS.Constants.Path.profileDir, PROFILE_JSON_FILE_NAME));

View File

@ -59,7 +59,7 @@ function startup() {
Services.wm.addListener(windowListener);
parent.init();
parent.init().catch(Cu.reportError);
Services.ppmm.loadProcessScript("data:,new " + function() {
Components.utils.import("resource://formautofill/FormAutofillContent.jsm");
}, true);

View File

@ -5,8 +5,9 @@
"use strict";
Cu.import("resource://formautofill/FormAutofillParent.jsm");
Cu.import("resource://formautofill/ProfileStorage.jsm");
add_task(function* test_enabledStatus_init() {
add_task(async function test_enabledStatus_init() {
let formAutofillParent = new FormAutofillParent();
sinon.spy(formAutofillParent, "_setStatus");
@ -14,7 +15,7 @@ add_task(function* test_enabledStatus_init() {
do_check_eq(formAutofillParent._enabled, false);
do_check_eq(Services.ppmm.initialProcessData.autofillEnabled, undefined);
formAutofillParent.init();
await formAutofillParent.init();
do_check_eq(formAutofillParent._setStatus.called, true);
do_check_eq(Services.ppmm.initialProcessData.autofillEnabled, false);
@ -63,10 +64,8 @@ add_task(function* test_enabledStatus_getStatus() {
Services.prefs.clearUserPref("browser.formautofill.enabled");
});
let fakeStorage = [];
formAutofillParent._profileStore = {
getAll: () => fakeStorage,
};
sinon.stub(profileStorage, "getAll");
profileStorage.getAll.returns([]);
// pref is enabled and profile is empty.
Services.prefs.setBoolPref("browser.formautofill.enabled", true);
@ -76,7 +75,7 @@ add_task(function* test_enabledStatus_getStatus() {
Services.prefs.setBoolPref("browser.formautofill.enabled", false);
do_check_eq(formAutofillParent._getStatus(), false);
fakeStorage = ["test-profile"];
profileStorage.getAll.returns(["test-profile"]);
// pref is enabled and profile is not empty.
Services.prefs.setBoolPref("browser.formautofill.enabled", true);
do_check_eq(formAutofillParent._getStatus(), true);

View File

@ -5,7 +5,7 @@
"use strict";
Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource://formautofill/ProfileStorage.jsm");
const {ProfileStorage} = Cu.import("resource://formautofill/ProfileStorage.jsm", {});
const TEST_STORE_FILE_NAME = "test-profile.json";

View File

@ -7,21 +7,21 @@
Cu.import("resource://formautofill/FormAutofillParent.jsm");
Cu.import("resource://formautofill/ProfileStorage.jsm");
add_task(function* test_profileSavedFieldNames_init() {
add_task(async function test_profileSavedFieldNames_init() {
let formAutofillParent = new FormAutofillParent();
sinon.stub(formAutofillParent, "_updateSavedFieldNames");
formAutofillParent.init();
await formAutofillParent.init();
do_check_eq(formAutofillParent._updateSavedFieldNames.called, true);
formAutofillParent._uninit();
});
add_task(function* test_profileSavedFieldNames_observe() {
add_task(async function test_profileSavedFieldNames_observe() {
let formAutofillParent = new FormAutofillParent();
sinon.stub(formAutofillParent, "_updateSavedFieldNames");
formAutofillParent.init();
await formAutofillParent.init();
// profile added => Need to trigger updateValidFields
formAutofillParent.observe(null, "formautofill-storage-changed", "add");
@ -38,15 +38,15 @@ add_task(function* test_profileSavedFieldNames_observe() {
do_check_eq(formAutofillParent._updateSavedFieldNames.called, false);
});
add_task(function* test_profileSavedFieldNames_update() {
add_task(async function test_profileSavedFieldNames_update() {
let formAutofillParent = new FormAutofillParent();
formAutofillParent.init();
await formAutofillParent.init();
do_register_cleanup(function cleanup() {
Services.prefs.clearUserPref("browser.formautofill.enabled");
});
sinon.stub(formAutofillParent._profileStore, "getAll");
formAutofillParent._profileStore.getAll.returns([]);
sinon.stub(profileStorage, "getAll");
profileStorage.getAll.returns([]);
// The set is empty if there's no profile in the store.
formAutofillParent._updateSavedFieldNames();
@ -74,7 +74,7 @@ add_task(function* test_profileSavedFieldNames_update() {
timeLastModified: 0,
timesUsed: 0,
}];
formAutofillParent._profileStore.getAll.returns(fakeStorage);
profileStorage.getAll.returns(fakeStorage);
formAutofillParent._updateSavedFieldNames();
let autofillSavedFieldNames = Services.ppmm.initialProcessData.autofillSavedFieldNames;

View File

@ -5,7 +5,7 @@
"use strict";
Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource://formautofill/ProfileStorage.jsm");
const {ProfileStorage} = Cu.import("resource://formautofill/ProfileStorage.jsm", {});
const TEST_STORE_FILE_NAME = "test-profile.json";

View File

@ -166,6 +166,7 @@
"prefs.js": ["PrefsEngine", "PrefRec"],
"prefs.jsm": ["Preference"],
"PresentationDeviceInfoManager.jsm": ["PresentationDeviceInfoService"],
"ProfileStorage.jsm": ["profileStorage"],
"PromiseWorker.jsm": ["BasePromiseWorker"],
"PushCrypto.jsm": ["PushCrypto", "concatArray"],
"quit.js": ["goQuitApplication"],