Bug 1529584 - Distinguish Remote Settings errors when reporting uptake r=glasserc

Distinguish Remote Settings errors when reporting uptake

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

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Mathieu Leplatre 2019-02-25 20:22:16 +00:00
Родитель ab16f9127e
Коммит d19b2d9d78
6 изменённых файлов: 142 добавлений и 6 удалений

Просмотреть файл

@ -138,6 +138,7 @@ const certBlocklistJSON = `{
function serveResponse(body) {
return (req, response) => {
response.setHeader("Content-Type", "application/json; charset=UTF-8");
response.setStatusLine(null, 200, "OK");
response.write(body);
};

Просмотреть файл

@ -332,9 +332,8 @@ class RemoteSettingsClient extends EventEmitter {
syncResult = await collection.sync({ remote: gServerURL, strategy, expectedTimestamp });
const { ok } = syncResult;
if (!ok) {
// Some synchronization conflicts occured.
reportStatus = UptakeTelemetry.STATUS.CONFLICT_ERROR;
throw new Error("Sync failed");
// With SERVER_WINS, there cannot be any conflicts, but don't silent it anyway.
throw new Error("Synced failed");
}
} catch (e) {
if (e.message.includes(INVALID_SIGNATURE)) {
@ -357,8 +356,14 @@ class RemoteSettingsClient extends EventEmitter {
if (e.message == MISSING_SIGNATURE) {
// Collection metadata has no signature info, no need to retry.
reportStatus = UptakeTelemetry.STATUS.SIGNATURE_ERROR;
} else if (/unparseable/.test(e.message)) {
reportStatus = UptakeTelemetry.STATUS.PARSE_ERROR;
} else if (/NetworkError/.test(e.message)) {
reportStatus = UptakeTelemetry.STATUS.NETWORK_ERROR;
} else if (/Timeout/.test(e.message)) {
reportStatus = UptakeTelemetry.STATUS.TIMEOUT_ERROR;
} else if (/HTTP 5??/.test(e.message)) {
reportStatus = UptakeTelemetry.STATUS.SERVER_ERROR;
} else if (/Backoff/.test(e.message)) {
reportStatus = UptakeTelemetry.STATUS.BACKOFF;
} else {
@ -379,6 +384,10 @@ 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)) {
reportStatus = UptakeTelemetry.STATUS.CUSTOM_1_ERROR;
}
// No specific error was tracked, mark it as unknown.
if (reportStatus === null) {
reportStatus = UptakeTelemetry.STATUS.UNKNOWN_ERROR;

Просмотреть файл

@ -82,6 +82,10 @@ var Utils = {
let changes = [];
// If no changes since last time, go on with empty list of changes.
if (response.status != 304) {
const ct = response.headers.get("Content-Type");
if (!ct || !ct.includes("application/json")) {
throw new Error(`Unexpected content-type "${ct}"`);
}
let payload;
try {
payload = await response.json();

Просмотреть файл

@ -181,8 +181,14 @@ function remoteSettingsFunction() {
} catch (e) {
// Report polling error to Uptake Telemetry.
let reportStatus;
if (/Server/.test(e.message)) {
if (/JSON\.parse/.test(e.message)) {
reportStatus = UptakeTelemetry.STATUS.PARSE_ERROR;
} else if (/content-type/.test(e.message)) {
reportStatus = UptakeTelemetry.STATUS.CONTENT_ERROR;
} else if (/Server/.test(e.message)) {
reportStatus = UptakeTelemetry.STATUS.SERVER_ERROR;
} else if (/Timeout/.test(e.message)) {
reportStatus = UptakeTelemetry.STATUS.TIMEOUT_ERROR;
} else if (/NetworkError/.test(e.message)) {
reportStatus = UptakeTelemetry.STATUS.NETWORK_ERROR;
} else {

Просмотреть файл

@ -64,7 +64,9 @@ function run_test() {
}
response.setHeader("Date", (new Date()).toUTCString());
response.write(JSON.stringify(sample.responseBody));
const body = typeof sample.responseBody == "string" ? sample.responseBody
: JSON.stringify(sample.responseBody);
response.write(body);
response.finish();
} catch (e) {
info(e);
@ -330,7 +332,39 @@ add_task(async function test_telemetry_reports_if_sync_fails() {
} catch (e) {}
const endHistogram = getUptakeTelemetrySnapshot(client.identifier);
const expectedIncrements = {[UptakeTelemetry.STATUS.SYNC_ERROR]: 1};
const expectedIncrements = {[UptakeTelemetry.STATUS.SERVER_ERROR]: 1};
checkUptakeTelemetry(startHistogram, endHistogram, expectedIncrements);
});
add_task(clear_state);
add_task(async function test_telemetry_reports_if_parsing_fails() {
const collection = await client.openCollection();
await collection.db.saveLastModified(10000);
const startHistogram = getUptakeTelemetrySnapshot(client.identifier);
try {
await client.maybeSync(10001);
} catch (e) { }
const endHistogram = getUptakeTelemetrySnapshot(client.identifier);
const expectedIncrements = { [UptakeTelemetry.STATUS.PARSE_ERROR]: 1 };
checkUptakeTelemetry(startHistogram, endHistogram, expectedIncrements);
});
add_task(clear_state);
add_task(async function test_telemetry_reports_if_fetching_signature_fails() {
const collection = await client.openCollection();
await collection.db.saveLastModified(11000);
const startHistogram = getUptakeTelemetrySnapshot(client.identifier);
try {
await client.maybeSync(11001);
} catch (e) { }
const endHistogram = getUptakeTelemetrySnapshot(client.identifier);
const expectedIncrements = { [UptakeTelemetry.STATUS.SERVER_ERROR]: 1 };
checkUptakeTelemetry(startHistogram, endHistogram, expectedIncrements);
});
add_task(clear_state);
@ -526,6 +560,48 @@ function getSampleResponse(req, port) {
error: "Service Unavailable",
},
},
"GET:/v1/buckets/main/collections/password-fields/records?_expected=10001&_sort=-last_modified&_since=10000": {
"sampleHeaders": [
"Access-Control-Allow-Origin: *",
"Access-Control-Expose-Headers: Retry-After, Content-Length, Alert, Backoff",
"Content-Type: application/json; charset=UTF-8",
"Server: waitress",
"Etag: \"10001\"",
],
"status": { status: 200, statusText: "OK" },
"responseBody": "<invalid json",
},
"GET:/v1/buckets/main/collections/password-fields/records?_expected=11001&_sort=-last_modified&_since=11000": {
"sampleHeaders": [
"Access-Control-Allow-Origin: *",
"Access-Control-Expose-Headers: Retry-After, Content-Length, Alert, Backoff",
"Content-Type: application/json; charset=UTF-8",
"Server: waitress",
],
"status": { status: 503, statusText: "Service Unavailable" },
"responseBody": {
"data": [{
"id": "c4f021e3-f68c-4269-ad2a-d4ba87762b35",
"last_modified": 4000,
"website": "https://www.eff.org",
"selector": "#pwd",
}],
},
},
"GET:/v1/buckets/main/collections/password-fields?_expected=11001": {
"sampleHeaders": [
"Access-Control-Allow-Origin: *",
"Access-Control-Expose-Headers: Retry-After, Content-Length, Alert, Backoff",
"Content-Type: application/json; charset=UTF-8",
"Server: waitress",
],
"status": { status: 503, statusText: "Service Unavailable" },
"responseBody": {
code: 503,
errno: 999,
error: "Service Unavailable",
},
},
"GET:/v1/buckets/monitor/collections/changes/records?collection=password-fields&bucket=main": {
"sampleHeaders": [
"Access-Control-Allow-Origin: *",

Просмотреть файл

@ -63,6 +63,7 @@ add_task(clear_state);
add_task(async function test_an_event_is_sent_on_start() {
server.registerPathHandler(CHANGES_PATH, (request, response) => {
response.write(JSON.stringify({ data: [] }));
response.setHeader("Content-Type", "application/json; charset=UTF-8");
response.setHeader("ETag", '"42"');
response.setHeader("Date", (new Date()).toUTCString());
response.setStatusLine(null, 200, "OK");
@ -235,6 +236,7 @@ add_task(async function test_expected_timestamp() {
data: entries,
}));
}
response.setHeader("Content-Type", "application/json; charset=UTF-8");
response.setHeader("ETag", '"1100"');
response.setHeader("Date", (new Date()).toUTCString());
response.setStatusLine(null, 200, "OK");
@ -263,6 +265,7 @@ add_task(async function test_client_last_check_is_saved() {
collection: "models-recipes",
}],
}));
response.setHeader("Content-Type", "application/json; charset=UTF-8");
response.setHeader("ETag", '"42"');
response.setHeader("Date", (new Date()).toUTCString());
response.setStatusLine(null, 200, "OK");
@ -307,6 +310,7 @@ add_task(async function test_success_with_partial_list() {
}));
response.setHeader("ETag", '"42"');
}
response.setHeader("Content-Type", "application/json; charset=UTF-8");
response.setHeader("Date", (new Date()).toUTCString());
response.setStatusLine(null, 200, "OK");
}
@ -327,6 +331,8 @@ add_task(clear_state);
add_task(async function test_server_bad_json() {
const startHistogram = getUptakeTelemetrySnapshot(TELEMETRY_HISTOGRAM_KEY);
function simulateBadJSON(request, response) {
response.setHeader("Content-Type", "application/json; charset=UTF-8");
response.write("<html></html>");
@ -341,6 +347,39 @@ add_task(async function test_server_bad_json() {
error = e;
}
Assert.ok(/JSON.parse: unexpected character/.test(error.message));
const endHistogram = getUptakeTelemetrySnapshot(TELEMETRY_HISTOGRAM_KEY);
const expectedIncrements = {
[UptakeTelemetry.STATUS.PARSE_ERROR]: 1,
};
checkUptakeTelemetry(startHistogram, endHistogram, expectedIncrements);
});
add_task(clear_state);
add_task(async function test_server_bad_content_type() {
const startHistogram = getUptakeTelemetrySnapshot(TELEMETRY_HISTOGRAM_KEY);
function simulateBadContentType(request, response) {
response.setHeader("Content-Type", "text/html");
response.write("<html></html>");
response.setStatusLine(null, 200, "OK");
}
server.registerPathHandler(CHANGES_PATH, simulateBadContentType);
let error;
try {
await RemoteSettings.pollChanges();
} catch (e) {
error = e;
}
Assert.ok(/Unexpected content-type/.test(error.message));
const endHistogram = getUptakeTelemetrySnapshot(TELEMETRY_HISTOGRAM_KEY);
const expectedIncrements = {
[UptakeTelemetry.STATUS.CONTENT_ERROR]: 1,
};
checkUptakeTelemetry(startHistogram, endHistogram, expectedIncrements);
});
add_task(clear_state);
@ -640,6 +679,7 @@ add_task(async function test_adding_client_resets_last_etag() {
response.setHeader("ETag", '"42"');
response.setStatusLine(null, 200, "OK");
}
response.setHeader("Content-Type", "application/json; charset=UTF-8");
response.setHeader("Date", (new Date()).toUTCString());
}
server.registerPathHandler(CHANGES_PATH, serve200or304);