Bug 1552199 - Include records from dump in Remote Settings sync event created data r=glasserc

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

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Mathieu Leplatre 2019-05-20 14:34:10 +00:00
Родитель 0ac415c764
Коммит 0c8c03610c
2 изменённых файлов: 92 добавлений и 35 удалений

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

@ -282,6 +282,7 @@ class RemoteSettingsClient extends EventEmitter {
async maybeSync(expectedTimestamp, options = {}) {
const { loadDump = true, trigger = "manual" } = options;
let importedFromDump = [];
const startedAt = new Date();
let reportStatus = null;
try {
@ -295,7 +296,11 @@ class RemoteSettingsClient extends EventEmitter {
// cold start.
if (!collectionLastModified && loadDump) {
try {
await RemoteSettingsWorker.importJSONDump(this.bucketName, this.collectionName);
const imported = await RemoteSettingsWorker.importJSONDump(this.bucketName, this.collectionName);
// The worker only returns an integer. List the imported records to build the sync event.
if (imported > 0) {
({ data: importedFromDump } = await kintoCollection.list());
}
collectionLastModified = await kintoCollection.db.getLastModified();
} catch (e) {
// Report but go-on.
@ -337,6 +342,9 @@ class RemoteSettingsClient extends EventEmitter {
// With SERVER_WINS, there cannot be any conflicts, but don't silent it anyway.
throw new Error("Synced failed");
}
// The records imported from the dump should be considered as "created" for the
// listeners.
syncResult.created = importedFromDump.concat(syncResult.created);
} catch (e) {
if (e instanceof RemoteSettingsClient.InvalidSignatureError) {
// Signature verification failed during synchronization.

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

@ -51,39 +51,12 @@ function run_test() {
clientWithDump = RemoteSettings("language-dictionaries");
clientWithDump.verifySignature = false;
// Setup server fake responses.
function handleResponse(request, response) {
try {
const sample = getSampleResponse(request, server.identity.primaryPort);
if (!sample) {
do_throw(`unexpected ${request.method} request for ${request.path}?${request.queryString}`);
}
response.setStatusLine(null, sample.status.status,
sample.status.statusText);
// send the headers
for (let headerLine of sample.sampleHeaders) {
let headerElements = headerLine.split(":");
response.setHeader(headerElements[0], headerElements[1].trimLeft());
}
response.setHeader("Date", (new Date()).toUTCString());
const body = typeof sample.responseBody == "string" ? sample.responseBody
: JSON.stringify(sample.responseBody);
response.write(body);
response.finish();
} catch (e) {
info(e);
}
}
const configPath = "/v1/";
const changesPath = "/v1/buckets/monitor/collections/changes/records";
const metadataPath = "/v1/buckets/main/collections/password-fields";
const recordsPath = "/v1/buckets/main/collections/password-fields/records";
server.registerPathHandler(configPath, handleResponse);
server.registerPathHandler(changesPath, handleResponse);
server.registerPathHandler(metadataPath, handleResponse);
server.registerPathHandler(recordsPath, handleResponse);
server.registerPathHandler("/v1/", handleResponse);
server.registerPathHandler("/v1/buckets/monitor/collections/changes/records", handleResponse);
server.registerPathHandler("/v1/buckets/main/collections/password-fields", handleResponse);
server.registerPathHandler("/v1/buckets/main/collections/password-fields/records", handleResponse);
server.registerPathHandler("/v1/buckets/main/collections/language-dictionaries", handleResponse);
server.registerPathHandler("/v1/buckets/main/collections/language-dictionaries/records", handleResponse);
server.registerPathHandler("/fake-x5u", handleResponse);
run_next_test();
@ -104,6 +77,22 @@ add_task(async function test_records_obtained_from_server_are_stored_in_db() {
});
add_task(clear_state);
add_task(async function test_records_from_dump_are_listed_as_created_in_event() {
let received;
clientWithDump.on("sync", ({ data }) => received = data);
// Use a timestamp superior to latest record in dump.
const timestamp = 5000000000000; // Fri Jun 11 2128
await clientWithDump.maybeSync(timestamp);
const list = await clientWithDump.get();
ok(list.length > 20, "The dump was loaded");
equal(received.created[received.created.length - 1].id, "xx", "Last record comes from the sync.");
equal(received.created.length, list.length, "The list of created records contains the dump");
equal(received.current.length, received.created.length);
});
add_task(clear_state);
add_task(async function test_records_can_have_local_fields() {
const c = RemoteSettings("password-fields", { localFields: ["accepted"] });
await c.maybeSync(2000);
@ -487,7 +476,30 @@ add_task(async function test_inspect_changes_the_list_when_bucket_pref_is_change
});
add_task(clear_state);
// get a response for a given request from sample data
function handleResponse(request, response) {
try {
const sample = getSampleResponse(request, server.identity.primaryPort);
if (!sample) {
do_throw(`unexpected ${request.method} request for ${request.path}?${request.queryString}`);
}
response.setStatusLine(null, sample.status.status, sample.status.statusText);
// send the headers
for (let headerLine of sample.sampleHeaders) {
let headerElements = headerLine.split(":");
response.setHeader(headerElements[0], headerElements[1].trimLeft());
}
response.setHeader("Date", (new Date()).toUTCString());
const body = typeof sample.responseBody == "string" ? sample.responseBody
: JSON.stringify(sample.responseBody);
response.write(body);
response.finish();
} catch (e) {
info(e);
}
}
function getSampleResponse(req, port) {
const responses = {
"OPTIONS": {
@ -741,6 +753,43 @@ wNuvFqc=
}],
},
},
"GET:/v1/buckets/main/collections/language-dictionaries": {
"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: \"1234\"",
],
"status": { status: 200, statusText: "OK" },
"responseBody": JSON.stringify({
"data": {
"id": "language-dictionaries",
"last_modified": 1234,
"signature": {
"signature": "xyz",
"x5u": `http://localhost:${port}/fake-x5u`,
},
},
}),
},
"GET:/v1/buckets/main/collections/language-dictionaries/records": {
"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: \"5000000000000\"",
],
"status": { status: 200, statusText: "OK" },
"responseBody": {
"data": [{
"id": "xx",
"last_modified": 5000000000000,
"dictionaries": ["xx-XX@dictionaries.addons.mozilla.org"],
}],
},
},
"GET:/v1/buckets/monitor/collections/changes/records?collection=no-mocked-responses&bucket=main": {
"sampleHeaders": [
"Access-Control-Allow-Origin: *",