Bug 1464346 - Skip RemoteSettings changes that were already processed r?mgoodwin draft
authorMathieu Leplatre <mathieu@mozilla.com>
Mon, 28 May 2018 16:21:09 +0200
changeset 804658 e7b01435b33f62aec90a9e8da87f19b647b3d7d5
parent 804582 715e3f81f67c5fb9f9810fd80690b429888ae86e
push id112424
push usermleplatre@mozilla.com
push dateWed, 06 Jun 2018 10:47:33 +0000
reviewersmgoodwin
bugs1464346
milestone62.0a1
Bug 1464346 - Skip RemoteSettings changes that were already processed r?mgoodwin MozReview-Commit-ID: FBe7JLwA0ld
services/settings/remote-settings.js
services/settings/test/unit/test_remote_settings_poll.js
--- a/services/settings/remote-settings.js
+++ b/services/settings/remote-settings.js
@@ -135,20 +135,22 @@ async function fetchLatestChanges(url, l
   // {"data":[
   //   {
   //     "host":"kinto-ota.dev.mozaws.net",
   //     "last_modified":1450717104423,
   //     "bucket":"blocklists",
   //     "collection":"certificates"
   //    }]}
 
-  // Use ETag to obtain a `304 Not modified` when no change occurred.
+  // Use ETag to obtain a `304 Not modified` when no change occurred,
+  // and `?_since` parameter to only keep entries that weren't processed yet.
   const headers = {};
   if (lastEtag) {
     headers["If-None-Match"] = lastEtag;
+    url += `?_since=${lastEtag}`;
   }
   const response = await fetch(url, {headers});
 
   let changes = [];
   // If no changes since last time, go on with empty list of changes.
   if (response.status != 304) {
     let payload;
     try {
--- a/services/settings/test/unit/test_remote_settings_poll.js
+++ b/services/settings/test/unit/test_remote_settings_poll.js
@@ -160,16 +160,60 @@ add_task(async function test_check_up_to
   const expectedIncrements = {
     [UptakeTelemetry.STATUS.UP_TO_DATE]: 1,
   };
   checkUptakeTelemetry(startHistogram, endHistogram, expectedIncrements);
 });
 add_task(clear_state);
 
 
+add_task(async function test_success_with_partial_list() {
+  function partialList(request, response) {
+    const entries = [{
+      id: "028261ad-16d4-40c2-a96a-66f72914d125",
+      last_modified: 43,
+      host: "localhost",
+      bucket: "main",
+      collection: "cid-1"
+    }, {
+      id: "98a34576-bcd6-423f-abc2-1d290b776ed8",
+      last_modified: 42,
+      host: "localhost",
+      bucket: "main",
+      collection: "test-collection"
+    }];
+    if (request.queryString == `_since=${encodeURIComponent('"42"')}`) {
+      response.write(JSON.stringify({
+        data: entries.slice(0, 1)
+      }));
+      response.setHeader("ETag", '"43"');
+    } else {
+      response.write(JSON.stringify({
+        data: entries
+      }));
+      response.setHeader("ETag", '"42"');
+    }
+    response.setHeader("Date", (new Date()).toUTCString());
+    response.setStatusLine(null, 200, "OK");
+  }
+  server.registerPathHandler(CHANGES_PATH, partialList);
+
+  const c = RemoteSettings("test-collection");
+  let maybeSyncCount = 0;
+  c.maybeSync = () => { maybeSyncCount++; };
+
+  await RemoteSettings.pollChanges();
+  await RemoteSettings.pollChanges();
+
+  // On the second call, the server does not mention the test-collection
+  // and maybeSync() is not called.
+  Assert.equal(maybeSyncCount, 1, "maybeSync should not be called twice");
+});
+add_task(clear_state);
+
 add_task(async function test_server_error() {
   const startHistogram = getUptakeTelemetrySnapshot(TELEMETRY_HISTOGRAM_KEY);
 
   // Simulate a server error.
   function simulateErrorResponse(request, response) {
     response.setHeader("Date", (new Date(3000)).toUTCString());
     response.setHeader("Content-Type", "application/json; charset=UTF-8");
     response.write(JSON.stringify({