Bug 925521 - Part 1: remove filter on recorded search engine identifiers. r=gps

This commit is contained in:
Richard Newman 2013-10-18 12:27:57 -07:00
parent 06829092ec
commit ab84ef25f9
2 changed files with 106 additions and 168 deletions

View File

@ -1186,71 +1186,20 @@ SearchCountMeasurement1.prototype = Object.freeze({
* We don't use the search engine name directly, because it is shared across
* locales; e.g., eBay-de and eBay both share the name "eBay".
*/
function SearchCountMeasurement2() {
this._fieldSpecs = null;
this._interestingEngines = null; // Name -> ID. ("Amazon.com" -> "amazondotcom")
function SearchCountMeasurementBase() {
this._fieldSpecs = {};
Metrics.Measurement.call(this);
}
SearchCountMeasurement2.prototype = Object.freeze({
SearchCountMeasurementBase.prototype = Object.freeze({
__proto__: Metrics.Measurement.prototype,
name: "counts",
version: 2,
/**
* Default implementation; can be overridden by test helpers.
*/
getDefaultEngines: function () {
return Services.search.getDefaultEngines();
},
_initialize: function () {
// Don't create all of these for every profile.
// There are 61 partner engines, translating to 244 fields.
// Instead, compute only those that are possible -- those for whom the
// provider is one of the default search engines.
// This set can grow over time, and change as users run different localized
// Firefox instances.
this._fieldSpecs = {};
this._interestingEngines = {};
for (let source of this.SOURCES) {
this._fieldSpecs["other." + source] = DAILY_COUNTER_FIELD;
}
let engines = this.getDefaultEngines();
for (let engine of engines) {
let id = engine.identifier;
if (!id || (this.PROVIDERS.indexOf(id) == -1)) {
continue;
}
this._interestingEngines[engine.name] = id;
let fieldPrefix = id + ".";
for (let source of this.SOURCES) {
this._fieldSpecs[fieldPrefix + source] = DAILY_COUNTER_FIELD;
}
}
},
// Our fields are dynamic, so we compute them into _fieldSpecs by looking at
// the current set of interesting engines.
// Our fields are dynamic.
get fields() {
if (!this._fieldSpecs) {
this._initialize();
}
return this._fieldSpecs;
},
get interestingEngines() {
if (!this._fieldSpecs) {
this._initialize();
}
return this._interestingEngines;
},
/**
* Override the default behavior: serializers should include every counter
* field from the DB, even if we don't currently have it registered.
@ -1280,101 +1229,6 @@ SearchCountMeasurement2.prototype = Object.freeze({
return Metrics.Storage.FIELD_DAILY_COUNTER;
},
// You can compute the total list of fields by unifying the entire l10n repo
// set with the list of partners:
//
// sort -u */*/searchplugins/list.txt | tr -d '^M' | uniq | grep -f partners.txt
//
// where partners.txt contains
//
// amazon
// aol
// bing
// eBay
// google
// mailru
// mercadolibre
// seznam
// twitter
// yahoo
// yandex
//
// Please update this list as the set of partners changes.
//
PROVIDERS: [
"amazon-co-uk",
"amazon-de",
"amazon-en-GB",
"amazon-france",
"amazon-it",
"amazon-jp",
"amazondotcn",
"amazondotcom",
"amazondotcom-de",
"aol-en-GB",
"aol-web-search",
"bing",
"eBay",
"eBay-de",
"eBay-en-GB",
"eBay-es",
"eBay-fi",
"eBay-france",
"eBay-hu",
"eBay-in",
"eBay-it",
"google",
"google-jp",
"google-ku",
"google-maps-zh-TW",
"mailru",
"mercadolibre-ar",
"mercadolibre-cl",
"mercadolibre-mx",
"seznam-cz",
"twitter",
"twitter-de",
"twitter-ja",
"yahoo",
"yahoo-NO",
"yahoo-answer-zh-TW",
"yahoo-ar",
"yahoo-bid-zh-TW",
"yahoo-br",
"yahoo-ch",
"yahoo-cl",
"yahoo-de",
"yahoo-en-GB",
"yahoo-es",
"yahoo-fi",
"yahoo-france",
"yahoo-fy-NL",
"yahoo-id",
"yahoo-in",
"yahoo-it",
"yahoo-jp",
"yahoo-jp-auctions",
"yahoo-mx",
"yahoo-sv-SE",
"yahoo-zh-TW",
"yandex",
"yandex-ru",
"yandex-slovari",
"yandex-tr",
"yandex.by",
"yandex.ru-be",
],
SOURCES: [
"abouthome",
"contextmenu",
@ -1383,6 +1237,59 @@ SearchCountMeasurement2.prototype = Object.freeze({
],
});
function SearchCountMeasurement2() {
SearchCountMeasurementBase.call(this);
}
SearchCountMeasurement2.prototype = Object.freeze({
__proto__: SearchCountMeasurementBase.prototype,
name: "counts",
version: 2,
});
function SearchCountMeasurement3() {
this.nameMappings = null;
SearchCountMeasurementBase.call(this);
}
SearchCountMeasurement3.prototype = Object.freeze({
__proto__: SearchCountMeasurementBase.prototype,
name: "counts",
version: 3,
getEngines: function () {
return Services.search.getEngines();
},
_initialize: function () {
this.nameMappings = {};
let engines = this.getEngines();
for (let engine of engines) {
let name = engine.name;
if (!name) {
// This is something we'd like to know, but we can't track it unless we
// rejig how recordSearchInHealthReport is implemented.
continue;
}
let id = engine.identifier;
if (!id) {
continue;
}
// TODO: again, we need to rejig this to avoid name collisions.
this.nameMappings[name] = id;
}
},
getEngineID: function (engineName) {
if (!this.nameMappings) {
this._initialize();
}
return this.nameMappings[engineName] || "other-" + engineName;
},
});
this.SearchesProvider = function () {
Metrics.Provider.call(this);
};
@ -1394,6 +1301,7 @@ this.SearchesProvider.prototype = Object.freeze({
measurementTypes: [
SearchCountMeasurement1,
SearchCountMeasurement2,
SearchCountMeasurement3,
],
/**
@ -1413,7 +1321,8 @@ this.SearchesProvider.prototype = Object.freeze({
*
* @param engine
* (string) The search engine used. If the search engine is unknown,
* the search will be attributed to "other".
* the search will be attributed to "other-$engine"; otherwise, its
* identifier will be used.
* @param source
* (string) Where the search was initiated from. Must be one of the
* SearchCountMeasurement2.SOURCES values.
@ -1422,17 +1331,30 @@ this.SearchesProvider.prototype = Object.freeze({
* The promise is resolved when the storage operation completes.
*/
recordSearch: function (engine, source) {
let m = this.getMeasurement("counts", 2);
let m = this.getMeasurement("counts", 3);
if (m.SOURCES.indexOf(source) == -1) {
throw new Error("Unknown source for search: " + source);
}
let id = m.interestingEngines[engine] || "other";
let field = id + "." + source;
return this.enqueueStorageOperation(function recordSearch() {
return m.incrementDailyCounter(field);
});
let field = m.getEngineID(engine) + "." + source;
if (this.storage.hasFieldFromMeasurement(m.id, field,
this.storage.FIELD_DAILY_COUNTER)) {
let fieldID = this.storage.fieldIDFromMeasurement(m.id, field);
return this.enqueueStorageOperation(function recordSearchKnownField() {
return this.storage.incrementDailyCounterFromFieldID(fieldID);
}.bind(this));
}
// Otherwise, we first need to create the field.
return this.enqueueStorageOperation(function recordFieldAndSearch() {
// This function has to return a promise.
return Task.spawn(function () {
let fieldID = yield this.storage.registerField(m.id, field,
this.storage.FIELD_DAILY_COUNTER);
yield this.storage.incrementDailyCounterFromFieldID(fieldID);
}.bind(this));
}.bind(this));
},
});

View File

@ -17,11 +17,12 @@ const DEFAULT_ENGINES = [
];
function MockSearchCountMeasurement() {
bsp.SearchCountMeasurement2.call(this);
bsp.SearchCountMeasurement3.call(this);
}
MockSearchCountMeasurement.prototype = {
__proto__: bsp.SearchCountMeasurement2.prototype,
getDefaultEngines: function () {
__proto__: bsp.SearchCountMeasurement3.prototype,
getEngines: function () {
return DEFAULT_ENGINES;
},
};
@ -52,7 +53,12 @@ add_task(function test_record() {
let now = new Date();
for (let engine of DEFAULT_ENGINES) {
// Record searches for all but one of our defaults, and one engine that's
// not a default.
for (let engine of DEFAULT_ENGINES.concat([{name: "Not Default", identifier: "notdef"}])) {
if (engine.identifier == "yahoo") {
continue;
}
yield provider.recordSearch(engine.name, "abouthome");
yield provider.recordSearch(engine.name, "contextmenu");
yield provider.recordSearch(engine.name, "searchbar");
@ -69,7 +75,7 @@ add_task(function test_record() {
do_check_true(errored);
}
let m = provider.getMeasurement("counts", 2);
let m = provider.getMeasurement("counts", 3);
let data = yield m.getValues();
do_check_eq(data.days.size, 1);
do_check_true(data.days.hasDay(now));
@ -77,17 +83,27 @@ add_task(function test_record() {
let day = data.days.getDay(now);
for (let engine of DEFAULT_ENGINES) {
let identifier = engine.identifier;
if (identifier == "foobar") {
identifier = "other";
}
let expected = identifier != "yahoo";
for (let source of ["abouthome", "contextmenu", "searchbar", "urlbar"]) {
let field = identifier + "." + source;
do_check_true(day.has(field));
do_check_eq(day.get(field), 1);
if (expected) {
do_check_true(day.has(field));
do_check_eq(day.get(field), 1);
} else {
do_check_false(day.has(field));
}
}
}
// Also, check that our non-default engine contributed, with a computed
// identifier.
let identifier = "other-Not Default";
for (let source of ["abouthome", "contextmenu", "searchbar", "urlbar"]) {
let field = identifier + "." + source;
do_check_true(day.has(field));
}
yield storage.close();
});
@ -96,7 +112,7 @@ add_task(function test_includes_other_fields() {
let provider = new MockSearchesProvider();
yield provider.init(storage);
let m = provider.getMeasurement("counts", 2);
let m = provider.getMeasurement("counts", 3);
// Register a search against a provider that isn't live in this session.
let id = yield m.storage.registerField(m.id, "test.searchbar",