mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 03:15:11 +00:00
Bug 1616052 - Add low-level helpers to debug and test Remote Settings r=tarek,glasserc
Differential Revision: https://phabricator.services.mozilla.com/D63207 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
234f641a3d
commit
38a37caab2
@ -142,7 +142,6 @@ The provided helper will:
|
||||
|
||||
The following aspects are not taken care of (yet! help welcome):
|
||||
|
||||
- report Telemetry when download fails
|
||||
- check available disk space
|
||||
- preserve bandwidth
|
||||
- resume downloads of large files
|
||||
@ -295,6 +294,12 @@ The synchronization of every known remote settings clients can be triggered manu
|
||||
|
||||
await RemoteSettings.pollChanges()
|
||||
|
||||
In order to ignore last synchronization status during polling for changes, set the ``full`` option:
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
await RemoteSettings.pollChanges({ full: true })
|
||||
|
||||
The synchronization of a single client can be forced with the ``.sync()`` method:
|
||||
|
||||
.. code-block:: js
|
||||
@ -314,6 +319,16 @@ The internal IndexedDB of Remote Settings can be accessed via the Storage Inspec
|
||||
For example, the local data of the ``"key"`` collection can be accessed in the ``remote-settings`` database at *Browser Toolbox* > *Storage* > *IndexedDB* > *chrome*, in the ``records`` store.
|
||||
|
||||
|
||||
Delete all local data
|
||||
---------------------
|
||||
|
||||
All local data, of **every collection**, including downloaded attachments, can be deleted with:
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
await RemoteSettings.clearAll();
|
||||
|
||||
|
||||
Unit Tests
|
||||
==========
|
||||
|
||||
|
@ -171,6 +171,21 @@ class AttachmentDownloader extends Downloader {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all downloaded records attachments.
|
||||
*
|
||||
* Note: the list of attachments to be deleted is based on the
|
||||
* current list of records.
|
||||
*/
|
||||
async deleteAll() {
|
||||
const kintoCol = await this._client.openCollection();
|
||||
const { data: allRecords } = await kintoCol.list();
|
||||
await kintoCol.db.close();
|
||||
return Promise.all(
|
||||
allRecords.filter(r => !!r.attachment).map(r => this.delete(r))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class RemoteSettingsClient extends EventEmitter {
|
||||
@ -263,7 +278,6 @@ class RemoteSettingsClient extends EventEmitter {
|
||||
*/
|
||||
async getLastModified() {
|
||||
let timestamp = -1;
|
||||
|
||||
try {
|
||||
const collection = await this.openCollection();
|
||||
timestamp = await collection.db.getLastModified();
|
||||
|
@ -17,31 +17,15 @@ const { XPCOMUtils } = ChromeUtils.import(
|
||||
"resource://gre/modules/XPCOMUtils.jsm"
|
||||
);
|
||||
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"UptakeTelemetry",
|
||||
"resource://services-common/uptake-telemetry.js"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"pushBroadcastService",
|
||||
"resource://gre/modules/PushBroadcastService.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"RemoteSettingsClient",
|
||||
"resource://services-settings/RemoteSettingsClient.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"Utils",
|
||||
"resource://services-settings/Utils.jsm"
|
||||
);
|
||||
ChromeUtils.defineModuleGetter(
|
||||
this,
|
||||
"FilterExpressions",
|
||||
"resource://gre/modules/components-utils/FilterExpressions.jsm"
|
||||
);
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
UptakeTelemetry: "resource://services-common/uptake-telemetry.js",
|
||||
pushBroadcastService: "resource://gre/modules/PushBroadcastService.jsm",
|
||||
RemoteSettingsClient: "resource://services-settings/RemoteSettingsClient.jsm",
|
||||
Utils: "resource://services-settings/Utils.jsm",
|
||||
FilterExpressions:
|
||||
"resource://gre/modules/components-utils/FilterExpressions.jsm",
|
||||
RemoteSettingsWorker: "resource://services-settings/RemoteSettingsWorker.jsm",
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["fetch"]);
|
||||
|
||||
@ -171,12 +155,21 @@ function remoteSettingsFunction() {
|
||||
* @param {Object} options
|
||||
. * @param {Object} options.expectedTimestamp (optional) The expected timestamp to be received — used by servers for cache busting.
|
||||
* @param {string} options.trigger (optional) label to identify what triggered this sync (eg. ``"timer"``, default: `"manual"`)
|
||||
* @param {bool} options.full (optional) Ignore last polling status and fetch all changes (default: `false`)
|
||||
* @returns {Promise} or throws error if something goes wrong.
|
||||
*/
|
||||
remoteSettings.pollChanges = async ({
|
||||
expectedTimestamp,
|
||||
trigger = "manual",
|
||||
full = false,
|
||||
} = {}) => {
|
||||
// When running in full mode, we ignore last polling status.
|
||||
if (full) {
|
||||
gPrefs.clearUserPref(PREF_SETTINGS_SERVER_BACKOFF);
|
||||
gPrefs.clearUserPref(PREF_SETTINGS_LAST_UPDATE);
|
||||
gPrefs.clearUserPref(PREF_SETTINGS_LAST_ETAG);
|
||||
}
|
||||
|
||||
let pollTelemetryArgs = {
|
||||
source: TELEMETRY_SOURCE_POLL,
|
||||
trigger,
|
||||
@ -419,6 +412,26 @@ function remoteSettingsFunction() {
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Delete all local data, of every collection.
|
||||
*/
|
||||
remoteSettings.clearAll = async () => {
|
||||
const { collections } = await remoteSettings.inspect();
|
||||
await Promise.all(
|
||||
collections.map(async ({ collection }) => {
|
||||
const client = RemoteSettings(collection);
|
||||
// Delete all potential attachments.
|
||||
await client.attachments.deleteAll();
|
||||
// Delete local data.
|
||||
const kintoCollection = await client.openCollection();
|
||||
await kintoCollection.clear();
|
||||
await kintoCollection.db.close();
|
||||
// Remove status pref.
|
||||
Services.prefs.clearUserPref(client.lastCheckTimePref);
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Startup function called from nsBrowserGlue.
|
||||
*/
|
||||
|
@ -196,6 +196,20 @@ add_task(async function test_delete_removes_local_file() {
|
||||
});
|
||||
add_task(clear_state);
|
||||
|
||||
add_task(async function test_delete_all() {
|
||||
const client = RemoteSettings("some-collection");
|
||||
const kintoCol = await client.openCollection();
|
||||
await kintoCol.create(RECORD);
|
||||
const fileURL = await downloader.download(RECORD);
|
||||
const localFilePath = pathFromURL(fileURL);
|
||||
Assert.ok(await OS.File.exists(localFilePath));
|
||||
|
||||
await client.attachments.deleteAll();
|
||||
|
||||
Assert.ok(!(await OS.File.exists(localFilePath)));
|
||||
});
|
||||
add_task(clear_state);
|
||||
|
||||
add_task(async function test_downloader_is_accessible_via_client() {
|
||||
const client = RemoteSettings("some-collection");
|
||||
|
||||
|
@ -269,6 +269,7 @@ add_task(async function test_get_does_not_sync_if_empty_dump_is_provided() {
|
||||
equal(data.length, 0);
|
||||
Assert.ok(await Utils.hasLocalData(clientWithEmptyDump));
|
||||
});
|
||||
add_task(clear_state);
|
||||
|
||||
add_task(async function test_get_synchronization_can_be_disabled() {
|
||||
const data = await client.get({ syncIfEmpty: false });
|
||||
@ -501,6 +502,28 @@ add_task(async function test_inspect_method() {
|
||||
});
|
||||
add_task(clear_state);
|
||||
|
||||
add_task(async function test_clearAll_method() {
|
||||
// Make sure we have some local data.
|
||||
await client.maybeSync(2000);
|
||||
await clientWithDump.maybeSync(2000);
|
||||
|
||||
await RemoteSettings.clearAll();
|
||||
|
||||
ok(!(await Utils.hasLocalData(client)), "Local data was deleted");
|
||||
ok(!(await Utils.hasLocalData(clientWithDump)), "Local data was deleted");
|
||||
ok(
|
||||
!Services.prefs.prefHasUserValue(client.lastCheckTimePref),
|
||||
"Pref was cleaned"
|
||||
);
|
||||
|
||||
// Synchronization is not broken after resuming.
|
||||
await client.maybeSync(2000);
|
||||
await clientWithDump.maybeSync(2000);
|
||||
ok(await Utils.hasLocalData(client), "Local data was populated");
|
||||
ok(await Utils.hasLocalData(clientWithDump), "Local data was populated");
|
||||
});
|
||||
add_task(clear_state);
|
||||
|
||||
add_task(async function test_listeners_are_not_deduplicated() {
|
||||
let count = 0;
|
||||
const plus1 = () => {
|
||||
|
@ -538,6 +538,34 @@ add_task(async function test_success_with_partial_list() {
|
||||
});
|
||||
add_task(clear_state);
|
||||
|
||||
add_task(async function test_full_polling() {
|
||||
server.registerPathHandler(
|
||||
CHANGES_PATH,
|
||||
serveChangesEntries(10000, [
|
||||
{
|
||||
id: "b6ba7fab-a40a-4d03-a4af-6b627f3c5b36",
|
||||
last_modified: 42,
|
||||
host: "localhost",
|
||||
bucket: "main",
|
||||
collection: "poll-test-collection",
|
||||
},
|
||||
])
|
||||
);
|
||||
|
||||
const c = RemoteSettings("poll-test-collection");
|
||||
let maybeSyncCount = 0;
|
||||
c.maybeSync = () => {
|
||||
maybeSyncCount++;
|
||||
};
|
||||
|
||||
await RemoteSettings.pollChanges();
|
||||
await RemoteSettings.pollChanges({ full: true });
|
||||
|
||||
// Since the second call is full, clients are called
|
||||
Assert.equal(maybeSyncCount, 2, "maybeSync should be called twice");
|
||||
});
|
||||
add_task(clear_state);
|
||||
|
||||
add_task(async function test_server_bad_json() {
|
||||
const startHistogram = getUptakeTelemetrySnapshot(
|
||||
TELEMETRY_HISTOGRAM_POLL_KEY
|
||||
|
Loading…
Reference in New Issue
Block a user