Bug 1259510 - record usage of the search service's update feature, r=adw,bsmedberg.
authorFlorian Quèze <florian@queze.net>
Tue, 05 Apr 2016 12:13:55 +0200
changeset 347684 0cfa4f8c142913e697706ec92bd48fb90ff3cf53
parent 347683 3466c5a966966230a9347bb31ced93b1985f529c
child 347685 d3223eecac1f7dcc0f618c203aff39d177f80493
push id14647
push userbmo:ahunt@mozilla.com
push dateTue, 05 Apr 2016 18:15:38 +0000
reviewersadw, bsmedberg
bugs1259510
milestone48.0a1
Bug 1259510 - record usage of the search service's update feature, r=adw,bsmedberg.
toolkit/components/search/nsSearchService.js
toolkit/components/search/tests/xpcshell/data/engine-update.xml
toolkit/components/search/tests/xpcshell/test_update_telemetry.js
toolkit/components/search/tests/xpcshell/xpcshell.ini
toolkit/components/telemetry/Histograms.json
--- a/toolkit/components/search/nsSearchService.js
+++ b/toolkit/components/search/nsSearchService.js
@@ -2734,16 +2734,17 @@ SearchService.prototype = {
 
     gInitialized = true;
     this._cacheFileJSON = null;
 
     this._initObservers.resolve(this._initRV);
 
     Services.obs.notifyObservers(null, SEARCH_SERVICE_TOPIC, "init-complete");
     Services.telemetry.getHistogramById("SEARCH_SERVICE_INIT_SYNC").add(true);
+    this._recordEnginesWithUpdate();
 
     LOG("_syncInit end");
   },
 
   /**
    * Asynchronous implementation of the initializer.
    *
    * @returns {Promise} A promise, resolved successfully if the initialization
@@ -2776,16 +2777,17 @@ SearchService.prototype = {
         LOG("_asyncInit: failure loading engines: " + ex);
       }
       this._addObservers();
       gInitialized = true;
       this._cacheFileJSON = null;
       this._initObservers.resolve(this._initRV);
       Services.obs.notifyObservers(null, SEARCH_SERVICE_TOPIC, "init-complete");
       Services.telemetry.getHistogramById("SEARCH_SERVICE_INIT_SYNC").add(false);
+      this._recordEnginesWithUpdate();
 
       LOG("_asyncInit: Completed _asyncInit");
     }.bind(this));
   },
 
   _metaData: { },
   setGlobalAttr(name, val) {
     this._metaData[name] = val;
@@ -3144,16 +3146,17 @@ SearchService.prototype = {
         // Due to the HTTP requests done by ensureKnownCountryCode, it's possible that
         // at this point a synchronous init has been forced by other code.
         if (!gInitialized)
           yield this._asyncLoadEngines(cache);
 
         // Typically we'll re-init as a result of a pref observer,
         // so signal to 'callers' that we're done.
         Services.obs.notifyObservers(null, SEARCH_SERVICE_TOPIC, "init-complete");
+        this._recordEnginesWithUpdate();
         gInitialized = true;
       } catch (err) {
         LOG("Reinit failed: " + err);
         Services.obs.notifyObservers(null, SEARCH_SERVICE_TOPIC, "reinit-failed");
       } finally {
         Services.obs.notifyObservers(null, SEARCH_SERVICE_TOPIC, "reinit-complete");
       }
     }.bind(this));
@@ -4228,16 +4231,33 @@ SearchService.prototype = {
         uri.userPass = ""; // Avoid reporting a username or password.
         result.submissionURL = uri.spec;
       }
     }
 
     return result;
   },
 
+  _recordEnginesWithUpdate: function() {
+    let hasUpdates = false;
+    let hasIconUpdates = false;
+    for (let name in this._engines) {
+      let engine = this._engines[name];
+      if (engine._hasUpdates) {
+        hasUpdates = true;
+        if (engine._iconUpdateURL) {
+          hasIconUpdates = true;
+          break;
+        }
+      }
+    }
+    Services.telemetry.getHistogramById("SEARCH_SERVICE_HAS_UPDATES").add(hasUpdates);
+    Services.telemetry.getHistogramById("SEARCH_SERVICE_HAS_ICON_UPDATES").add(hasIconUpdates);
+  },
+
   /**
    * This map is built lazily after the available search engines change.  It
    * allows quick parsing of an URL representing a search submission into the
    * search engine name and original terms.
    *
    * The keys are strings containing the domain name and lowercase path of the
    * engine submission, for example "www.google.com/search".
    *
new file mode 100644
--- /dev/null
+++ b/toolkit/components/search/tests/xpcshell/data/engine-update.xml
@@ -0,0 +1,10 @@
+<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
+<ShortName>update</ShortName>
+<Description>update</Description>
+<InputEncoding>UTF-8</InputEncoding>
+<Url type="text/html" method="GET" template="http://searchtest.local">
+  <Param name="search" value="{searchTerms}"/>
+</Url>
+<UpdateUrl>http://searchtest.local/opensearch.xml</UpdateUrl>
+<IconUpdateUrl>http://searchtest.local/favicon.ico</IconUpdateUrl>
+</SearchPlugin>
new file mode 100644
--- /dev/null
+++ b/toolkit/components/search/tests/xpcshell/test_update_telemetry.js
@@ -0,0 +1,36 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function run_test() {
+  do_check_false(Services.search.isInitialized);
+
+  useHttpServer();
+  run_next_test();
+}
+
+function checkTelemetry(histogramName, expected) {
+  let histogram = Services.telemetry.getHistogramById(histogramName);
+  let snapshot = histogram.snapshot();
+  let expectedCounts = [0, 0, 0];
+  expectedCounts[expected ? 1 : 0] = 1;
+  Assert.deepEqual(snapshot.counts, expectedCounts,
+                   "histogram has expected content");
+  histogram.clear();
+}
+
+add_task(function* ignore_cache_files_without_engines() {
+  yield asyncInit();
+
+  checkTelemetry("SEARCH_SERVICE_HAS_UPDATES", false);
+  checkTelemetry("SEARCH_SERVICE_HAS_ICON_UPDATES", false);
+
+  // Add an engine with update urls and re-init, as we record the presence of
+  // engine update urls only while initializing the search service.
+  yield addTestEngines([
+    { name: "update", xmlFileName: "engine-update.xml" },
+  ]);
+  yield asyncReInit();
+
+  checkTelemetry("SEARCH_SERVICE_HAS_UPDATES", true);
+  checkTelemetry("SEARCH_SERVICE_HAS_ICON_UPDATES", true);
+});
--- a/toolkit/components/search/tests/xpcshell/xpcshell.ini
+++ b/toolkit/components/search/tests/xpcshell/xpcshell.ini
@@ -12,16 +12,17 @@ support-files =
   data/engine-app.xml
   data/engine-fr.xml
   data/engineMaker.sjs
   data/engine-pref.xml
   data/engine-rel-searchform.xml
   data/engine-rel-searchform-post.xml
   data/engine-rel-searchform-purpose.xml
   data/engine-system-purpose.xml
+  data/engine-update.xml
   data/engineImages.xml
   data/ico-size-16x16-png.ico
   data/invalid-engine.xml
   data/install.rdf
   data/list.txt
   data/langpack-metadata.json
   data/metadata.json
   data/search-metadata.json
@@ -84,9 +85,10 @@ tags = addons
 [test_sync_profile_engine.js]
 [test_rel_searchform.js]
 [test_remove_profile_engine.js]
 [test_selectedEngine.js]
 [test_geodefaults.js]
 [test_hidden.js]
 [test_currentEngine_fallback.js]
 [test_require_engines_in_cache.js]
+[test_update_telemetry.js]
 [test_svg_icon.js]
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -5370,16 +5370,32 @@
     "description": "Time (ms) it takes to initialize the search service"
   },
   "SEARCH_SERVICE_INIT_SYNC": {
     "alert_emails": ["rvitillo@mozilla.com", "gavin@mozilla.com"],
     "expires_in_version": "never",
     "kind": "boolean",
     "description": "search service has been initialized synchronously"
   },
+  "SEARCH_SERVICE_HAS_UPDATES": {
+    "alert_emails": ["florian@mozilla.com"],
+    "expires_in_version": "50",
+    "kind": "boolean",
+    "bug_numbers": [1259510],
+    "description": "Recorded once per session near startup: records true/false whether the search service has engines with update URLs.",
+    "releaseChannelCollection": "opt-out"
+  },
+  "SEARCH_SERVICE_HAS_ICON_UPDATES": {
+    "alert_emails": ["florian@mozilla.com"],
+    "expires_in_version": "50",
+    "kind": "boolean",
+    "bug_numbers": [1259510],
+    "description": "Recorded once per session near startup: records true/false whether the search service has engines with icon update URLs.",
+    "releaseChannelCollection": "opt-out"
+  },
   "SEARCH_SERVICE_BUILD_CACHE_MS": {
     "expires_in_version": "40",
     "kind": "exponential",
     "high": 1000,
     "n_buckets": 15,
     "description": "Time (ms) it takes to build the cache of the search service"
   },
   "SEARCH_SERVICE_COUNTRY_FETCH_TIME_MS": {