Bug 1530346 - Upgrade kinto-offline-client and report IndexedDB errors properly r=glasserc

- Upgrade kinto-offline-client to v12.3.0
- Make sure IndexedDB errors are not reported as unknown errors

Differential Revision: https://phabricator.services.mozilla.com/D21208

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Mathieu Leplatre 2019-02-26 16:15:05 +00:00
parent 73b09a782e
commit 742e5c134a
6 changed files with 92 additions and 13 deletions

View File

@ -33,7 +33,7 @@ const global = this;
var EXPORTED_SYMBOLS = ["Kinto"];
/*
* Version 12.2.4 - 8fb687a
* Version 12.3.0 - f7a9e81
*/
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Kinto = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
@ -565,7 +565,7 @@ class IDB extends _base.default {
}
_handleError(method, err) {
const error = new Error(method + "() " + err.message);
const error = new Error(`IndexedDB ${method}() ${err.message}`);
error.stack = err.stack;
throw error;
}
@ -614,7 +614,7 @@ class IDB extends _base.default {
records,
timestamp
} = dataToMigrate;
await this.loadDump(records);
await this.importBulk(records);
await this.saveLastModified(timestamp);
console.log(`${this.cid}: data was migrated successfully.`); // Delete the old database.
@ -886,6 +886,7 @@ class IDB extends _base.default {
/**
* Load a dump of records exported from a server.
*
* @deprecated Use {@link importBulk} instead.
* @abstract
* @param {Array} records The records to load.
* @return {Promise}
@ -893,6 +894,18 @@ class IDB extends _base.default {
async loadDump(records) {
return this.importBulk(records);
}
/**
* Load records in bulk that were exported from a server.
*
* @abstract
* @param {Array} records The records to load.
* @return {Promise}
*/
async importBulk(records) {
try {
await this.execute(transaction => {
// Since the put operations are asynchronous, we chain
@ -920,7 +933,7 @@ class IDB extends _base.default {
return records;
} catch (e) {
this._handleError("loadDump", e);
this._handleError("importBulk", e);
}
}
@ -1116,9 +1129,22 @@ class BaseAdapter {
getLastModified() {
throw new Error("Not Implemented.");
}
/**
* Load records in bulk that were exported from a server.
*
* @abstract
* @param {Array} records The records to load.
* @return {Promise}
*/
importBulk(records) {
throw new Error("Not Implemented.");
}
/**
* Load a dump of records exported from a server.
*
* @deprecated Use {@link importBulk} instead.
* @abstract
* @param {Array} records The records to load.
* @return {Promise}
@ -1140,7 +1166,7 @@ Object.defineProperty(exports, "__esModule", {
value: true
});
exports.recordsEqual = recordsEqual;
exports.CollectionTransaction = exports.default = exports.SyncResultObject = void 0;
exports.CollectionTransaction = exports.default = exports.ServerWasFlushedError = exports.SyncResultObject = void 0;
var _base = _interopRequireDefault(require("./adapters/base"));
@ -1263,6 +1289,22 @@ class SyncResultObject {
exports.SyncResultObject = SyncResultObject;
class ServerWasFlushedError extends Error {
constructor(clientTimestamp, serverTimestamp, message) {
super(message);
if (Error.captureStackTrace) {
Error.captureStackTrace(this, ServerWasFlushedError);
}
this.clientTimestamp = clientTimestamp;
this.serverTimestamp = serverTimestamp;
}
}
exports.ServerWasFlushedError = ServerWasFlushedError;
function createUUIDSchema() {
return {
generate() {
@ -2262,7 +2304,8 @@ class Collection {
const emptyCollection = data.length === 0;
if (!options.exclude && localSynced && serverChanged && emptyCollection) {
throw Error("Server has been flushed.");
const e = new ServerWasFlushedError(localSynced, unquoted, "Server has been flushed. Client Side Timestamp: " + localSynced + " Server Side Timestamp: " + unquoted);
throw e;
}
syncResultObject.lastModified = unquoted; // Decode incoming changes.
@ -2578,12 +2621,27 @@ class Collection {
* The local records which are unsynced or whose timestamp is either missing
* or superior to those being loaded will be ignored.
*
* @deprecated Use {@link importBulk} instead.
* @param {Array} records The previously exported list of records to load.
* @return {Promise} with the effectively imported records.
*/
async loadDump(records) {
return this.importBulk(records);
}
/**
* Load a list of records already synced with the remote server.
*
* The local records which are unsynced or whose timestamp is either missing
* or superior to those being loaded will be ignored.
*
* @param {Array} records The previously exported list of records to load.
* @return {Promise} with the effectively imported records.
*/
async importBulk(records) {
if (!Array.isArray(records)) {
throw new Error("Records is not an array.");
}
@ -2619,7 +2677,7 @@ class Collection {
record.last_modified > localRecord.last_modified;
return shouldKeep;
});
return await this.db.loadDump(newRecords.map(markSynced));
return await this.db.importBulk(newRecords.map(markSynced));
}
}

View File

@ -331,6 +331,10 @@ class FirefoxAdapter extends Kinto.adapters.BaseAdapter {
});
}
async loadDump(records) {
return this.importBulk(records);
}
/**
* Load a list of records into the local database.
*
@ -341,7 +345,7 @@ class FirefoxAdapter extends Kinto.adapters.BaseAdapter {
* @param {Array} records.
* @return {Array} imported records.
*/
async loadDump(records) {
async importBulk(records) {
const connection = this._connection;
const collection_name = this.collection;
await connection.executeTransaction(async function doImport() {

View File

@ -213,14 +213,14 @@ add_task(async function test_kinto_list() {
add_task(clear_collection);
add_task(async function test_loadDump_ignores_already_imported_records() {
add_task(async function test_importBulk_ignores_already_imported_records() {
let sqliteHandle;
try {
sqliteHandle = await do_get_kinto_sqliteHandle();
const collection = do_get_kinto_collection(sqliteHandle);
const record = {id: "41b71c13-17e9-4ee3-9268-6a41abf9730f", title: "foo", last_modified: 1457896541};
await collection.loadDump([record]);
let impactedRecords = await collection.loadDump([record]);
await collection.importBulk([record]);
let impactedRecords = await collection.importBulk([record]);
Assert.equal(impactedRecords.length, 0);
} finally {
await sqliteHandle.close();

View File

@ -385,7 +385,7 @@ class RemoteSettingsClient extends EventEmitter {
}
} catch (e) {
// IndexedDB errors. See https://developer.mozilla.org/en-US/docs/Web/API/IDBRequest/error
if (/(AbortError|ConstraintError|QuotaExceededError|VersionError)/.test(e.message)) {
if (/(IndexedDB|AbortError|ConstraintError|QuotaExceededError|VersionError)/.test(e.message)) {
reportStatus = UptakeTelemetry.STATUS.CUSTOM_1_ERROR;
}
// No specific error was tracked, mark it as unknown.

View File

@ -385,6 +385,23 @@ add_task(async function test_telemetry_reports_unknown_errors() {
});
add_task(clear_state);
add_task(async function test_telemetry_reports_indexeddb_as_custom_1() {
const backup = client.openCollection;
const msg = "IndexedDB getLastModified() The operation failed for reasons unrelated to the database itself";
client.openCollection = () => { throw new Error(msg); };
const startHistogram = getUptakeTelemetrySnapshot(client.identifier);
try {
await client.maybeSync(2000);
} catch (e) { }
client.openCollection = backup;
const endHistogram = getUptakeTelemetrySnapshot(client.identifier);
const expectedIncrements = {[UptakeTelemetry.STATUS.CUSTOM_1_ERROR]: 1};
checkUptakeTelemetry(startHistogram, endHistogram, expectedIncrements);
});
add_task(clear_state);
add_task(async function test_bucketname_changes_when_bucket_pref_changes() {
equal(client.bucketName, "main");

View File

@ -1057,7 +1057,7 @@ class ExtensionStorageSync {
e instanceof ServerKeyringDeleted ||
// This is another way that ServerKeyringDeleted can
// manifest; see bug 1350088 for more details.
e.message == "Server has been flushed.") {
e.message.includes("Server has been flushed.")) {
// Check if our token is still valid, or if we got locked out
// between starting the sync and talking to Kinto.
const isSessionValid = await this._fxaService.sessionStatus();