--- a/browser/components/search/SearchSERPTelemetry.jsm
+++ b/browser/components/search/SearchSERPTelemetry.jsm
@@ -22,17 +22,17 @@ const SEARCH_COUNTS_HISTOGRAM_KEY = "SEA
const SEARCH_CONTENT_SCALAR_BASE = "browser.search.content.";
const SEARCH_WITH_ADS_SCALAR_OLD = "browser.search.with_ads";
const SEARCH_WITH_ADS_SCALAR_BASE = "browser.search.withads.";
const SEARCH_AD_CLICKS_SCALAR_OLD = "browser.search.ad_clicks";
const SEARCH_AD_CLICKS_SCALAR_BASE = "browser.search.adclicks.";
const SEARCH_DATA_TRANSFERRED_SCALAR = "browser.search.data_transferred";
const SEARCH_TELEMETRY_PRIVATE_BROWSING_KEY_SUFFIX = "pb";
-const TELEMETRY_SETTINGS_KEY = "search-telemetry";
+const TELEMETRY_SETTINGS_KEY = "search-telemetry-v2";
XPCOMUtils.defineLazyGetter(this, "logConsole", () => {
return console.createInstance({
prefix: "SearchTelemetry",
maxLogLevel: SearchUtils.loggingEnabled ? "Debug" : "Warn",
});
});
@@ -471,29 +471,33 @@ class TelemetryHandler {
// We have an oldType and type split, because the older telemetry uses "sap"
// and "sap-follow-on" versus "tagged-sap" and "tagged-follow-on".
// The latter is a more accurate description of what we're reporting.
let oldType = "organic";
let type = "organic";
let code;
if (searchProviderInfo.codeParamName) {
code = queries.get(searchProviderInfo.codeParamName);
- if (
- code &&
- searchProviderInfo.codePrefixes.some(p => code.startsWith(p))
- ) {
- if (
- searchProviderInfo.followOnParamNames &&
- searchProviderInfo.followOnParamNames.some(p => queries.has(p))
- ) {
- oldType = "sap-follow-on";
- type = "tagged-follow-on";
- } else {
+ if (code) {
+ // The code is only included if it matches one of the specific ones.
+ if (searchProviderInfo.taggedCodes.includes(code)) {
oldType = "sap";
type = "tagged";
+ if (
+ searchProviderInfo.followOnParamNames &&
+ searchProviderInfo.followOnParamNames.some(p => queries.has(p))
+ ) {
+ oldType += "-follow-on";
+ type += "-follow-on";
+ }
+ } else if (searchProviderInfo.organicCodes.includes(code)) {
+ oldType = "organic";
+ type = "organic";
+ } else {
+ code = "other";
}
} else if (searchProviderInfo.followOnCookies) {
// Especially Bing requires lots of extra work related to cookies.
for (let followOnCookie of searchProviderInfo.followOnCookies) {
if (followOnCookie.extraCodeParamName) {
let eCode = queries.get(followOnCookie.extraCodeParamName);
if (
!eCode ||
@@ -514,17 +518,17 @@ class TelemetryHandler {
continue;
}
let [cookieParam, cookieValue] = cookie.value
.split("=")
.map(p => p.trim());
if (
cookieParam == followOnCookie.codeParamName &&
- followOnCookie.codePrefixes.some(p => cookieValue.startsWith(p))
+ searchProviderInfo.taggedCodes.includes(cookieValue)
) {
oldType = "sap-follow-on";
type = "tagged-follow-on";
code = cookieValue;
break;
}
}
}
--- a/browser/components/search/docs/telemetry.rst
+++ b/browser/components/search/docs/telemetry.rst
@@ -104,23 +104,23 @@ navigation.search (OBSOLETE)
SearchSERPTelemetry.jsm
~~~~~~~~~~~~~~~~~~~~~~~
This telemetry is handled by `SearchSERPTelemetry.jsm and the associated parent/child actors`_.
SEARCH_COUNTS - SERP results
This histogram records search counts for visits to SERP in-content pages.
For in-content searches, the format is
- ``<provider>.in-content:[sap|sap-follow-on|organic]:[code|none]``.
+ ``<provider>.in-content:[sap|sap-follow-on|organic]:[<code>|other|none]``.
This is obsolete, browser.search.content.* should be preferred.
browser.search.content.*
These keyed scalar track counts of SERP page loads. The key format is
- ``<provider>:[tagged|tagged-follow-on|organic]:[<code>|none]``.
+ ``<provider>:[tagged|tagged-follow-on|organic]:[<code>|other|none]``.
These will eventually replace the SEARCH_COUNTS - SERP results.
They are broken down by the originating SAP where known:
- ``urlbar`` Except search mode.
- ``urlbar_handoff`` Used when searching from about:newtab.
- ``urlbar_searchmode`` Used when the Urlbar is in search mode.
--- a/browser/components/search/schema/search-telemetry-schema.json
+++ b/browser/components/search/schema/search-telemetry-schema.json
@@ -22,20 +22,29 @@
"title": "Search Query Parameter Name",
"description": "The name of the query parameter for the user's search string."
},
"codeParamName": {
"type": "string",
"title": "Partner Code Parameter Name",
"description": "The name of the query parameter for the partner code."
},
- "codePrefixes": {
+ "taggedCodes": {
"type": "array",
- "title": "Partner Code Prefixes",
- "description": "An array of prefixes (or complete values) to match against the partner code paramters in the url.",
+ "title": "Partner Codes",
+ "description": "An array of partner codes to match against the parameters in the url. Matching these codes will report the SERP as tagged.",
+ "items": {
+ "type": "string",
+ "pattern": "^[a-zA-Z0-9-._]*$"
+ }
+ },
+ "organicCodes": {
+ "type": "array",
+ "title": "Organic Codes",
+ "description": "An array of partner codes to match against the parameters in the url. Matching these codes will report the SERP as organic.",
"items": {
"type": "string",
"pattern": "^[a-zA-Z0-9-._]*$"
}
},
"followOnParamNames": {
"type": "array",
"title": "Follow-on Search Parameter Names",
@@ -54,17 +63,17 @@
"properties": {
"extraCodeParamName": {
"type": "string",
"description": "The query parameter name in the URL that indicates this might be a follow-on search.",
"pattern": "^[a-z0-9-._]*$"
},
"extraCodePrefixes": {
"type": "array",
- "description": "Possbile values for the query parameter in the URL that indicates this might be a follow-on search.",
+ "description": "Possible values for the query parameter in the URL that indicates this might be a follow-on search.",
"items": {
"type": "string",
"pattern": "^[a-zA-Z0-9-._]*$"
}
},
"host": {
"type": "string",
"description": "The hostname on which the cookie is stored.",
@@ -74,24 +83,16 @@
"type": "string",
"description": "The name of the cookie to check.",
"pattern": "^[a-zA-Z0-9-._]*$"
},
"codeParamName": {
"type": "string",
"description": "The name of parameter within the cookie.",
"pattern": "^[a-zA-Z0-9-._]*$"
- },
- "codePrefixes": {
- "type": "array",
- "description": "Possbile values for the parameter within the cookie.",
- "items": {
- "type": "string",
- "pattern": "^[a-zA-Z0-9-._]*$"
- }
}
}
}
},
"extraAdServersRegexps": {
"type": "array",
"title": "Extra Ad Server Regular Expressions",
"description": "An array of regular expressions that match URLs of potential ad servers.",
--- a/browser/components/search/schema/search-telemetry-ui-schema.json
+++ b/browser/components/search/schema/search-telemetry-ui-schema.json
@@ -1,12 +1,13 @@
{
"ui:order": [
"telemetryId",
"searchPageRegexp",
"queryParamName",
"codeParamName",
- "codePrefixes",
+ "taggedCodes",
+ "organicCodes",
"followOnParamNames",
"followOnCookies",
"extraAdServersRegexps"
]
}
--- a/browser/components/search/test/browser/browser_search_telemetry_sources.js
+++ b/browser/components/search/test/browser/browser_search_telemetry_sources.js
@@ -21,17 +21,17 @@ const { SearchTestUtils } = ChromeUtils.
);
const TEST_PROVIDER_INFO = [
{
telemetryId: "example",
searchPageRegexp: /^https:\/\/example.com\/browser\/browser\/components\/search\/test\/browser\/searchTelemetry(?:Ad)?.html/,
queryParamName: "s",
codeParamName: "abc",
- codePrefixes: ["ff"],
+ taggedCodes: ["ff"],
followOnParamNames: ["a"],
extraAdServersRegexps: [/^https:\/\/example\.com\/ad2?/],
},
];
function getPageUrl(useAdPage = false) {
let page = useAdPage ? "searchTelemetryAd.html" : "searchTelemetry.html";
return `https://example.com/browser/browser/components/search/test/browser/${page}`;
--- a/browser/components/search/test/browser/browser_search_telemetry_sources_ads.js
+++ b/browser/components/search/test/browser/browser_search_telemetry_sources_ads.js
@@ -15,17 +15,17 @@ const { SearchSERPTelemetry } = ChromeUt
);
const TEST_PROVIDER_INFO = [
{
telemetryId: "example",
searchPageRegexp: /^http:\/\/mochi.test:.+\/browser\/browser\/components\/search\/test\/browser\/searchTelemetry(?:Ad)?.html/,
queryParamName: "s",
codeParamName: "abc",
- codePrefixes: ["ff"],
+ taggedCodes: ["ff"],
followOnParamNames: ["a"],
extraAdServersRegexps: [/^https:\/\/example\.com\/ad2?/],
},
];
function getPageUrl(useExample = false, useAdPage = false) {
let server = useExample ? "example.com" : "mochi.test:8888";
let page = useAdPage ? "searchTelemetryAd.html" : "searchTelemetry.html";
--- a/browser/components/search/test/browser/browser_search_telemetry_sources_navigation.js
+++ b/browser/components/search/test/browser/browser_search_telemetry_sources_navigation.js
@@ -21,17 +21,17 @@ const { SearchTestUtils } = ChromeUtils.
);
const TEST_PROVIDER_INFO = [
{
telemetryId: "example",
searchPageRegexp: /^https:\/\/example.com\/browser\/browser\/components\/search\/test\/browser\/searchTelemetry(?:Ad)?.html/,
queryParamName: "s",
codeParamName: "abc",
- codePrefixes: ["ff"],
+ taggedCodes: ["ff"],
followOnParamNames: ["a"],
extraAdServersRegexps: [/^https:\/\/example\.com\/ad2?/],
},
];
function getPageUrl(useAdPage = false) {
let page = useAdPage ? "searchTelemetryAd.html" : "searchTelemetry.html";
return `https://example.com/browser/browser/components/search/test/browser/${page}`;
--- a/browser/components/search/test/unit/test_urlTelemetry.js
+++ b/browser/components/search/test/unit/test_urlTelemetry.js
@@ -38,16 +38,25 @@ const TESTS = [
title: "Google search access point follow-on",
trackingUrl:
"https://www.google.com/search?client=firefox-b-1-ab&ei=EI_VALUE&q=test2&oq=test2&gs_l=GS_L_VALUE",
expectedSearchCountEntry: "google.in-content:sap-follow-on:firefox-b-1-ab",
},
{
title: "Google organic",
trackingUrl:
+ "https://www.google.com/search?client=firefox-b-d-invalid&source=hp&ei=EI_VALUE&q=test&oq=test&gs_l=GS_L_VALUE",
+ expectedSearchCountEntry: "google.in-content:organic:other",
+ expectedAdKey: "google:organic",
+ adUrls: ["https://www.googleadservices.com/aclk=foobar"],
+ nonAdUrls: ["https://www.googleadservices.com/?aclk=foobar"],
+ },
+ {
+ title: "Google organic no code",
+ trackingUrl:
"https://www.google.com/search?source=hp&ei=EI_VALUE&q=test&oq=test&gs_l=GS_L_VALUE",
expectedSearchCountEntry: "google.in-content:organic:none",
expectedAdKey: "google:organic",
adUrls: ["https://www.googleadservices.com/aclk=foobar"],
nonAdUrls: ["https://www.googleadservices.com/?aclk=foobar"],
},
{
title: "Google organic UK",
@@ -87,36 +96,44 @@ const TESTS = [
},
{
setUp() {
Services.cookies.removeAll();
Services.cookies.add(
"www.bing.com",
"/",
"SRCHS",
- "PC=MOZ",
+ "PC=MOZI",
false,
false,
false,
Date.now() + 1000 * 60 * 60,
{},
Ci.nsICookie.SAMESITE_NONE,
Ci.nsICookie.SCHEME_HTTPS
);
},
tearDown() {
Services.cookies.removeAll();
},
title: "Bing search access point follow-on",
trackingUrl:
"https://www.bing.com/search?q=test&qs=n&form=QBRE&sp=-1&pq=&sc=0-0&sk=&cvid=CVID_VALUE",
- expectedSearchCountEntry: "bing.in-content:sap-follow-on:MOZ",
+ expectedSearchCountEntry: "bing.in-content:sap-follow-on:MOZI",
},
{
title: "Bing organic",
+ trackingUrl: "https://www.bing.com/search?q=test&pc=MOZIfoo&form=MOZLBR",
+ expectedSearchCountEntry: "bing.in-content:organic:other",
+ expectedAdKey: "bing:organic",
+ adUrls: ["https://www.bing.com/aclick?ld=foo"],
+ nonAdUrls: ["https://www.bing.com/fd/ls/ls.gif?IG=foo"],
+ },
+ {
+ title: "Bing organic no code",
trackingUrl:
"https://www.bing.com/search?q=test&qs=n&form=QBLH&sp=-1&pq=&sc=0-0&sk=&cvid=CVID_VALUE",
expectedSearchCountEntry: "bing.in-content:organic:none",
expectedAdKey: "bing:organic",
adUrls: ["https://www.bing.com/aclick?ld=foo"],
nonAdUrls: ["https://www.bing.com/fd/ls/ls.gif?IG=foo"],
},
{
@@ -133,17 +150,25 @@ const TESTS = [
"https://duckduckgo.com/?q=foo&t=ffab&ia=images&iax=images",
"https://duckduckgo.com/y.js?ifu=foo",
"https://improving.duckduckgo.com/t/bar",
],
},
{
title: "DuckDuckGo organic",
trackingUrl: "https://duckduckgo.com/?q=test&t=hi&ia=news",
- expectedSearchCountEntry: "duckduckgo.in-content:organic:hi",
+ expectedSearchCountEntry: "duckduckgo.in-content:organic:other",
+ expectedAdKey: "duckduckgo:organic",
+ adUrls: ["https://duckduckgo.com/y.js?ad_provider=foo"],
+ nonAdUrls: ["https://duckduckgo.com/?q=foo&t=ffab&ia=images&iax=images"],
+ },
+ {
+ title: "DuckDuckGo organic no code",
+ trackingUrl: "https://duckduckgo.com/?q=test&ia=news",
+ expectedSearchCountEntry: "duckduckgo.in-content:organic:none",
expectedAdKey: "duckduckgo:organic",
adUrls: ["https://duckduckgo.com/y.js?ad_provider=foo"],
nonAdUrls: ["https://duckduckgo.com/?q=foo&t=ffab&ia=images&iax=images"],
},
{
title: "Baidu search access point",
trackingUrl: "https://www.baidu.com/baidu?wd=test&tn=monline_7_dg&ie=utf-8",
expectedSearchCountEntry: "baidu.in-content:sap:monline_7_dg",
@@ -155,18 +180,24 @@ const TESTS = [
title: "Baidu search access point follow-on",
trackingUrl:
"https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&tn=monline_7_dg&wd=test2&oq=test&rsv_pq=RSV_PQ_VALUE&rsv_t=RSV_T_VALUE&rqlang=cn&rsv_enter=1&rsv_sug3=2&rsv_sug2=0&inputT=227&rsv_sug4=397",
expectedSearchCountEntry: "baidu.in-content:sap-follow-on:monline_7_dg",
},
{
title: "Baidu organic",
trackingUrl:
- "https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&ch=&tn=baidu&bar=&wd=test&rn=&oq=&rsv_pq=RSV_PQ_VALUE&rsv_t=RSV_T_VALUE&rqlang=cn",
- expectedSearchCountEntry: "baidu.in-content:organic:baidu",
+ "https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&ch=&tn=baidu&bar=&wd=test&rn=&oq&rsv_pq=RSV_PQ_VALUE&rsv_t=RSV_T_VALUE&rqlang=cn",
+ expectedSearchCountEntry: "baidu.in-content:organic:other",
+ },
+ {
+ title: "Baidu organic no code",
+ trackingUrl:
+ "https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&ch=&bar=&wd=test&rn=&oq&rsv_pq=RSV_PQ_VALUE&rsv_t=RSV_T_VALUE&rqlang=cn",
+ expectedSearchCountEntry: "baidu.in-content:organic:none",
},
];
/**
* This function is primarily for testing the Ad URL regexps that are triggered
* when a URL is clicked on. These regexps are also used for the `with_ads`
* probe. However, we test the ad_clicks route as that is easier to hit.
*
@@ -228,31 +259,31 @@ add_task(async function test_parsing_sea
test.setUp();
}
SearchSERPTelemetry.updateTrackingStatus(
{
getTabBrowser: () => {},
},
test.trackingUrl
);
- const hs = Services.telemetry
- .getKeyedHistogramById("SEARCH_COUNTS")
- .snapshot();
- Assert.ok(hs);
+ let histogram = Services.telemetry.getKeyedHistogramById("SEARCH_COUNTS");
+ let snapshot = histogram.snapshot();
+ Assert.ok(snapshot);
Assert.ok(
- test.expectedSearchCountEntry in hs,
+ test.expectedSearchCountEntry in snapshot,
"The histogram must contain the correct key"
);
if ("adUrls" in test) {
for (const adUrl of test.adUrls) {
await testAdUrlClicked(test.trackingUrl, adUrl, test.expectedAdKey);
}
for (const nonAdUrls of test.nonAdUrls) {
await testAdUrlClicked(test.trackingUrl, nonAdUrls);
}
}
if (test.tearDown) {
test.tearDown();
}
+ histogram.clear();
}
});
new file mode 100644
--- /dev/null
+++ b/browser/components/search/test/unit/test_urlTelemetry_generic.js
@@ -0,0 +1,173 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const { XPCOMUtils } = ChromeUtils.import(
+ "resource://gre/modules/XPCOMUtils.jsm"
+);
+
+XPCOMUtils.defineLazyModuleGetters(this, {
+ BrowserSearchTelemetry: "resource:///modules/BrowserSearchTelemetry.jsm",
+ NetUtil: "resource://gre/modules/NetUtil.jsm",
+ SearchSERPTelemetry: "resource:///modules/SearchSERPTelemetry.jsm",
+ SearchUtils: "resource://gre/modules/SearchUtils.jsm",
+ Services: "resource://gre/modules/Services.jsm",
+ sinon: "resource://testing-common/Sinon.jsm",
+ TelemetryTestUtils: "resource://testing-common/TelemetryTestUtils.jsm",
+});
+
+const TEST_PROVIDER_INFO = [
+ {
+ telemetryId: "example",
+ searchPageRegexp: /^https:\/\/www\.example\.com\/search/,
+ queryParamName: "q",
+ codeParamName: "abc",
+ taggedCodes: ["ff", "tb"],
+ organicCodes: ["foo"],
+ followOnParamNames: ["a"],
+ extraAdServersRegexps: [/^https:\/\/www\.example\.com\/ad2/],
+ },
+];
+
+const TESTS = [
+ {
+ title: "Tagged search",
+ trackingUrl: "https://www.example.com/search?q=test&abc=ff",
+ expectedSearchCountEntry: "example.in-content:sap:ff",
+ expectedAdKey: "example:sap",
+ adUrls: ["https://www.example.com/ad2"],
+ nonAdUrls: ["https://www.example.com/ad3"],
+ },
+ {
+ title: "Tagged follow-on",
+ trackingUrl: "https://www.example.com/search?q=test&abc=tb&a=next",
+ expectedSearchCountEntry: "example.in-content:sap-follow-on:tb",
+ expectedAdKey: "example:sap-follow-on",
+ adUrls: ["https://www.example.com/ad2"],
+ nonAdUrls: ["https://www.example.com/ad3"],
+ },
+ {
+ title: "Organic search matched code",
+ trackingUrl: "https://www.example.com/search?q=test&abc=foo",
+ expectedSearchCountEntry: "example.in-content:organic:foo",
+ expectedAdKey: "example:organic",
+ adUrls: ["https://www.example.com/ad2"],
+ nonAdUrls: ["https://www.example.com/ad3"],
+ },
+ {
+ title: "Organic search non-matched code",
+ trackingUrl: "https://www.example.com/search?q=test&abc=ff123",
+ expectedSearchCountEntry: "example.in-content:organic:other",
+ expectedAdKey: "example:organic",
+ adUrls: ["https://www.example.com/ad2"],
+ nonAdUrls: ["https://www.example.com/ad3"],
+ },
+ {
+ title: "Organic search non-matched code 2",
+ trackingUrl: "https://www.example.com/search?q=test&abc=foo123",
+ expectedSearchCountEntry: "example.in-content:organic:other",
+ expectedAdKey: "example:organic",
+ adUrls: ["https://www.example.com/ad2"],
+ nonAdUrls: ["https://www.example.com/ad3"],
+ },
+ {
+ title: "Organic search no codes",
+ trackingUrl: "https://www.example.com/search?q=test",
+ expectedSearchCountEntry: "example.in-content:organic:none",
+ expectedAdKey: "example:organic",
+ adUrls: ["https://www.example.com/ad2"],
+ nonAdUrls: ["https://www.example.com/ad3"],
+ },
+];
+
+/**
+ * This function is primarily for testing the Ad URL regexps that are triggered
+ * when a URL is clicked on. These regexps are also used for the `with_ads`
+ * probe. However, we test the ad_clicks route as that is easier to hit.
+ *
+ * @param {string} serpUrl
+ * The url to simulate where the page the click came from.
+ * @param {string} adUrl
+ * The ad url to simulate being clicked.
+ * @param {string} [expectedAdKey]
+ * The expected key to be logged for the scalar. Omit if no scalar should be
+ * logged.
+ */
+async function testAdUrlClicked(serpUrl, adUrl, expectedAdKey) {
+ info(`Testing Ad URL: ${adUrl}`);
+ let channel = NetUtil.newChannel({
+ uri: NetUtil.newURI(adUrl),
+ triggeringPrincipal: Services.scriptSecurityManager.createContentPrincipal(
+ NetUtil.newURI(serpUrl),
+ {}
+ ),
+ loadUsingSystemPrincipal: true,
+ });
+ SearchSERPTelemetry._contentHandler.observeActivity(
+ channel,
+ Ci.nsIHttpActivityObserver.ACTIVITY_TYPE_HTTP_TRANSACTION,
+ Ci.nsIHttpActivityObserver.ACTIVITY_SUBTYPE_TRANSACTION_CLOSE
+ );
+ // Since the content handler takes a moment to allow the channel information
+ // to settle down, wait the same amount of time here.
+ await new Promise(resolve => Services.tm.dispatchToMainThread(resolve));
+
+ const scalars = TelemetryTestUtils.getProcessScalars("parent", true, true);
+ if (!expectedAdKey) {
+ Assert.ok(
+ !("browser.search.ad_clicks" in scalars),
+ "Should not have recorded an ad click"
+ );
+ } else {
+ TelemetryTestUtils.assertKeyedScalar(
+ scalars,
+ "browser.search.ad_clicks",
+ expectedAdKey,
+ 1
+ );
+ }
+}
+
+do_get_profile();
+
+add_task(async function setup() {
+ Services.prefs.setBoolPref(SearchUtils.BROWSER_SEARCH_PREF + "log", true);
+ await SearchSERPTelemetry.init();
+ SearchSERPTelemetry.overrideSearchTelemetryForTests(TEST_PROVIDER_INFO);
+ sinon.stub(BrowserSearchTelemetry, "shouldRecordSearchCount").returns(true);
+});
+
+add_task(async function test_parsing_search_urls() {
+ for (const test of TESTS) {
+ info(`Running ${test.title}`);
+ if (test.setUp) {
+ test.setUp();
+ }
+ SearchSERPTelemetry.updateTrackingStatus(
+ {
+ getTabBrowser: () => {},
+ },
+ test.trackingUrl
+ );
+ let histogram = Services.telemetry.getKeyedHistogramById("SEARCH_COUNTS");
+ let snapshot = histogram.snapshot();
+ Assert.ok(snapshot);
+ Assert.ok(
+ test.expectedSearchCountEntry in snapshot,
+ "The histogram must contain the correct key"
+ );
+
+ if ("adUrls" in test) {
+ for (const adUrl of test.adUrls) {
+ await testAdUrlClicked(test.trackingUrl, adUrl, test.expectedAdKey);
+ }
+ for (const nonAdUrls of test.nonAdUrls) {
+ await testAdUrlClicked(test.trackingUrl, nonAdUrls);
+ }
+ }
+
+ if (test.tearDown) {
+ test.tearDown();
+ }
+ histogram.clear();
+ }
+});
--- a/browser/components/search/test/unit/xpcshell.ini
+++ b/browser/components/search/test/unit/xpcshell.ini
@@ -1,5 +1,6 @@
[DEFAULT]
skip-if = toolkit == 'android' # bug 1730213
firefox-appdir = browser
[test_urlTelemetry.js]
+[test_urlTelemetry_generic.js]
--- a/browser/components/urlbar/tests/browser/browser_urlbar_telemetry_handoff.js
+++ b/browser/components/urlbar/tests/browser/browser_urlbar_telemetry_handoff.js
@@ -8,17 +8,17 @@ const { SearchSERPTelemetry } = ChromeUt
);
const TEST_PROVIDER_INFO = [
{
telemetryId: "example",
searchPageRegexp: /^https:\/\/example.com\/browser\/browser\/components\/search\/test\/browser\/searchTelemetry(?:Ad)?.html/,
queryParamName: "s",
codeParamName: "abc",
- codePrefixes: ["ff"],
+ taggedCodes: ["ff"],
followOnParamNames: ["a"],
extraAdServersRegexps: [/^https:\/\/example\.com\/ad2?/],
},
];
function getPageUrl(useAdPage = false) {
let page = useAdPage ? "searchTelemetryAd.html" : "searchTelemetry.html";
return `https://example.com/browser/browser/components/search/test/browser/${page}`;
--- a/services/settings/dumps/main/moz.build
+++ b/services/settings/dumps/main/moz.build
@@ -6,17 +6,17 @@ FINAL_TARGET_FILES.defaults.settings.mai
"anti-tracking-url-decoration.json",
"example.json",
"hijack-blocklists.json",
"language-dictionaries.json",
"password-recipes.json",
"password-rules.json",
"search-config.json",
"search-default-override-allowlist.json",
- "search-telemetry.json",
+ "search-telemetry-v2.json",
"sites-classification.json",
"top-sites.json",
"url-classifier-skip-urls.json",
"websites-with-shared-credential-backends.json",
]
if CONFIG["MOZ_BUILD_APP"] == "browser":
DIST_SUBDIR = "browser"
new file mode 100644
--- /dev/null
+++ b/services/settings/dumps/main/search-telemetry-v2.json
@@ -0,0 +1,149 @@
+{
+ "data": [
+ {
+ "schema": 1643096116299,
+ "taggedCodes": [
+ "MOZ2",
+ "MOZ4",
+ "MOZ5",
+ "MOZA",
+ "MOZB",
+ "MOZD",
+ "MOZE",
+ "MOZI",
+ "MOZM",
+ "MOZO",
+ "MOZT",
+ "MOZW",
+ "MOZSL01",
+ "MOZSL02",
+ "MOZSL03"
+ ],
+ "telemetryId": "bing",
+ "organicCodes": [],
+ "codeParamName": "pc",
+ "queryParamName": "q",
+ "followOnCookies": [
+ {
+ "host": "www.bing.com",
+ "name": "SRCHS",
+ "codeParamName": "PC",
+ "extraCodePrefixes": [
+ "QBRE"
+ ],
+ "extraCodeParamName": "form"
+ }
+ ],
+ "searchPageRegexp": "^https://www\\.bing\\.com/search",
+ "extraAdServersRegexps": [
+ "^https://www\\.bing\\.com/acli?c?k"
+ ],
+ "id": "e1eec461-f1f3-40de-b94b-3b670b78108c",
+ "last_modified": 1643136934001
+ },
+ {
+ "schema": 1643100256547,
+ "taggedCodes": [
+ "firefox-a",
+ "firefox-b",
+ "firefox-b-1",
+ "firefox-b-ab",
+ "firefox-b-1-ab",
+ "firefox-b-d",
+ "firefox-b-1-d",
+ "firefox-b-e",
+ "firefox-b-1-e",
+ "firefox-b-m",
+ "firefox-b-1-m",
+ "firefox-b-o",
+ "firefox-b-1-o",
+ "firefox-b-lm",
+ "firefox-b-1-lm",
+ "firefox-b-lg",
+ "firefox-b-huawei-h1611",
+ "firefox-b-is-oem1",
+ "firefox-b-oem1",
+ "firefox-b-oem2",
+ "firefox-b-tinno",
+ "firefox-b-pn-wt",
+ "firefox-b-pn-wt-us",
+ "ubuntu"
+ ],
+ "telemetryId": "google",
+ "organicCodes": [],
+ "codeParamName": "client",
+ "queryParamName": "q",
+ "searchPageRegexp": "^https://www\\.google\\.(?:.+)/search",
+ "followOnParamNames": [
+ "oq",
+ "ved",
+ "ei"
+ ],
+ "extraAdServersRegexps": [
+ "^https://www\\.google(?:adservices)?\\.com/(?:pagead/)?aclk"
+ ],
+ "id": "635a3325-1995-42d6-be09-dbe4b2a95453",
+ "last_modified": 1643136933998
+ },
+ {
+ "schema": 1643100257574,
+ "taggedCodes": [
+ "ffab",
+ "ffcm",
+ "ffhp",
+ "ffip",
+ "ffit",
+ "ffnt",
+ "ffocus",
+ "ffos",
+ "ffsb",
+ "fpas",
+ "fpsa",
+ "ftas",
+ "ftsa",
+ "newext"
+ ],
+ "telemetryId": "duckduckgo",
+ "organicCodes": [],
+ "codeParamName": "t",
+ "queryParamName": "q",
+ "searchPageRegexp": "^https://duckduckgo\\.com/",
+ "extraAdServersRegexps": [
+ "^https://duckduckgo.com/y\\.js?.*ad_provider\\=",
+ "^https://www\\.amazon\\.(?:[a-z.]{2,24}).*(?:tag=duckduckgo-)"
+ ],
+ "id": "9dfd626b-26f2-4913-9d0a-27db6cb7d8ca",
+ "last_modified": 1643136933995
+ },
+ {
+ "schema": 1643100258578,
+ "telemetryId": "yahoo",
+ "queryParamName": "p",
+ "searchPageRegexp": "^https://(?:.*)search\\.yahoo\\.com/search",
+ "id": "0433b88a-1ddc-47b1-ab1f-9a77daeae1b7",
+ "last_modified": 1643136933992
+ },
+ {
+ "schema": 1643107838909,
+ "taggedCodes": [
+ "monline_dg",
+ "monline_3_dg",
+ "monline_4_dg",
+ "monline_7_dg"
+ ],
+ "telemetryId": "baidu",
+ "organicCodes": [],
+ "codeParamName": "tn",
+ "queryParamName": "wd",
+ "searchPageRegexp": "^https://www\\.baidu\\.com/(?:s|baidu)",
+ "followOnParamNames": [
+ "oq"
+ ],
+ "extraAdServersRegexps": [
+ "^https?://www\\.baidu\\.com/baidu\\.php?"
+ ],
+ "id": "19c434a3-d173-4871-9743-290ac92a3f6a",
+ "last_modified": 1643136933989
+ }
+ ]
+}
deleted file mode 100644
--- a/services/settings/dumps/main/search-telemetry.json
+++ /dev/null
@@ -1,99 +0,0 @@
-{
- "data": [
- {
- "schema": 1623194745447,
- "telemetryId": "bing",
- "codePrefixes": [
- "MOZ",
- "MZ"
- ],
- "codeParamName": "pc",
- "queryParamName": "q",
- "followOnCookies": [
- {
- "host": "www.bing.com",
- "name": "SRCHS",
- "codePrefixes": [
- "MOZ",
- "MZ"
- ],
- "codeParamName": "PC",
- "extraCodePrefixes": [
- "QBRE"
- ],
- "extraCodeParamName": "form"
- }
- ],
- "searchPageRegexp": "^https://www\\.bing\\.com/search",
- "extraAdServersRegexps": [
- "^https://www\\.bing\\.com/acli?c?k"
- ],
- "id": "00cf8706-3253-40b8-8fbc-066974d0ce45",
- "last_modified": 1623330491976
- },
- {
- "schema": 1613245319518,
- "telemetryId": "baidu",
- "codePrefixes": [
- "34046034_",
- "monline_"
- ],
- "codeParamName": "tn",
- "queryParamName": "wd",
- "searchPageRegexp": "^https://www\\.baidu\\.com/(?:s|baidu)",
- "followOnParamNames": [
- "oq"
- ],
- "extraAdServersRegexps": [
- "^https?://www\\.baidu\\.com/baidu\\.php?"
- ],
- "id": "9eb134ac-5790-4412-9e08-915f66c9d919",
- "last_modified": 1613587794383
- },
- {
- "schema": 1601840497837,
- "telemetryId": "google",
- "codePrefixes": [
- "firefox"
- ],
- "codeParamName": "client",
- "queryParamName": "q",
- "searchPageRegexp": "^https://www\\.google\\.(?:.+)/search",
- "followOnParamNames": [
- "oq",
- "ved",
- "ei"
- ],
- "extraAdServersRegexps": [
- "^https://www\\.google(?:adservices)?\\.com/(?:pagead/)?aclk"
- ],
- "id": "40c29a38-c660-4b99-bbac-55c3e2c5c23f",
- "last_modified": 1602016373960
- },
- {
- "schema": 1601909707246,
- "telemetryId": "duckduckgo",
- "codePrefixes": [
- "ff",
- "newext"
- ],
- "codeParamName": "t",
- "queryParamName": "q",
- "searchPageRegexp": "^https://duckduckgo\\.com/",
- "extraAdServersRegexps": [
- "^https://duckduckgo.com/y\\.js?.*ad_provider\\=",
- "^https://www\\.amazon\\.(?:[a-z.]{2,24}).*(?:tag=duckduckgo-)"
- ],
- "id": "6addffe8-609a-4ea8-9261-69c14c729d83",
- "last_modified": 1602016373957
- },
- {
- "schema": 1601909708566,
- "telemetryId": "yahoo",
- "queryParamName": "p",
- "searchPageRegexp": "^https://(?:.*)search\\.yahoo\\.com/search",
- "id": "554774d7-d5f1-443d-bb9a-9447d16e54cd",
- "last_modified": 1602016373954
- }
- ]
-}