summaryrefslogtreecommitdiffstats
path: root/toolkit/mozapps/extensions/test/xpcshell/test_AbuseReporter.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/mozapps/extensions/test/xpcshell/test_AbuseReporter.js')
-rw-r--r--toolkit/mozapps/extensions/test/xpcshell/test_AbuseReporter.js687
1 files changed, 3 insertions, 684 deletions
diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_AbuseReporter.js b/toolkit/mozapps/extensions/test/xpcshell/test_AbuseReporter.js
index c94ef29e31..4fe0821c70 100644
--- a/toolkit/mozapps/extensions/test/xpcshell/test_AbuseReporter.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_AbuseReporter.js
@@ -2,88 +2,21 @@
* http://creativecommons.org/publicdomain/zero/1.0/
*/
-const { AbuseReporter, AbuseReportError } = ChromeUtils.importESModule(
+const { AbuseReporter } = ChromeUtils.importESModule(
"resource://gre/modules/AbuseReporter.sys.mjs"
);
const { ClientID } = ChromeUtils.importESModule(
"resource://gre/modules/ClientID.sys.mjs"
);
-const { TelemetryController } = ChromeUtils.importESModule(
- "resource://gre/modules/TelemetryController.sys.mjs"
-);
-const { TelemetryTestUtils } = ChromeUtils.importESModule(
- "resource://testing-common/TelemetryTestUtils.sys.mjs"
-);
const APPNAME = "XPCShell";
const APPVERSION = "1";
const ADDON_ID = "test-addon@tests.mozilla.org";
-const ADDON_ID2 = "test-addon2@tests.mozilla.org";
const FAKE_INSTALL_INFO = {
source: "fake-Install:Source",
method: "fake:install method",
};
-const PREF_REQUIRED_LOCALE = "intl.locale.requested";
-const REPORT_OPTIONS = { reportEntryPoint: "menu" };
-const TELEMETRY_EVENTS_FILTERS = {
- category: "addonsManager",
- method: "report",
-};
-
-const FAKE_AMO_DETAILS = {
- name: {
- "en-US": "fake name",
- "it-IT": "fake it-IT name",
- },
- current_version: { version: "1.0" },
- type: "extension",
- is_recommended: true,
-};
-
-createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "49");
-
-const server = createHttpServer({ hosts: ["test.addons.org"] });
-
-// Mock abuse report API endpoint.
-let apiRequestHandler;
-server.registerPathHandler("/api/report/", (request, response) => {
- const stream = request.bodyInputStream;
- const buffer = NetUtil.readInputStream(stream, stream.available());
- const data = new TextDecoder().decode(buffer);
- apiRequestHandler({ data, request, response });
-});
-
-// Mock addon details API endpoint.
-const amoAddonDetailsMap = new Map();
-server.registerPrefixHandler("/api/addons/addon/", (request, response) => {
- const addonId = request.path.split("/").pop();
- if (!amoAddonDetailsMap.has(addonId)) {
- response.setStatusLine(request.httpVersion, 404, "Not Found");
- response.write(JSON.stringify({ detail: "Not found." }));
- } else {
- response.setStatusLine(request.httpVersion, 200, "Success");
- response.write(JSON.stringify(amoAddonDetailsMap.get(addonId)));
- }
-});
-
-function getProperties(obj, propNames) {
- return propNames.reduce((acc, el) => {
- acc[el] = obj[el];
- return acc;
- }, {});
-}
-
-function handleSubmitRequest({ request, response }) {
- response.setStatusLine(request.httpVersion, 200, "OK");
- response.setHeader("Content-Type", "application/json", false);
- response.write("{}");
-}
-
-function clearAbuseReportState() {
- // Clear the timestamp of the last submission.
- AbuseReporter._lastReportTimestamp = null;
-}
async function installTestExtension(overrideOptions = {}) {
const extOptions = {
@@ -104,34 +37,6 @@ async function installTestExtension(overrideOptions = {}) {
return { extension, addon };
}
-async function assertRejectsAbuseReportError(promise, errorType, errorInfo) {
- let error;
-
- await Assert.rejects(
- promise,
- err => {
- // Log the actual error to make investigating test failures easier.
- Cu.reportError(err);
- error = err;
- return err instanceof AbuseReportError;
- },
- `Got an AbuseReportError`
- );
-
- equal(error.errorType, errorType, "Got the expected errorType");
- equal(error.errorInfo, errorInfo, "Got the expected errorInfo");
- ok(
- error.message.includes(errorType),
- "errorType should be included in the error message"
- );
- if (errorInfo) {
- ok(
- error.message.includes(errorInfo),
- "errorInfo should be included in the error message"
- );
- }
-}
-
async function assertBaseReportData({ reportData, addon }) {
// Report properties related to addon metadata.
equal(reportData.addon, ADDON_ID, "Got expected 'addon'");
@@ -191,42 +96,10 @@ async function assertBaseReportData({ reportData, addon }) {
);
}
-add_task(async function test_setup() {
- Services.prefs.setCharPref(
- "extensions.abuseReport.url",
- "http://test.addons.org/api/report/"
- );
-
- Services.prefs.setCharPref(
- "extensions.abuseReport.amoDetailsURL",
- "http://test.addons.org/api/addons/addon"
- );
+createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "49");
+add_setup(async () => {
await promiseStartupManager();
- // Telemetry test setup needed to ensure that the builtin events are defined
- // and they can be collected and verified.
- await TelemetryController.testSetup();
-
- // This is actually only needed on Android, because it does not properly support unified telemetry
- // and so, if not enabled explicitly here, it would make these tests to fail when running on a
- // non-Nightly build.
- const oldCanRecordBase = Services.telemetry.canRecordBase;
- Services.telemetry.canRecordBase = true;
- registerCleanupFunction(() => {
- Services.telemetry.canRecordBase = oldCanRecordBase;
- });
-
- // Register a fake it-IT locale (used to test localized AMO details in some
- // of the test case defined in this test file).
- L10nRegistry.getInstance().registerSources([
- L10nFileSource.createMock(
- "mock",
- "app",
- ["it-IT", "fr-FR"],
- "resource://fake/locales/{locale}",
- []
- ),
- ]);
});
add_task(async function test_addon_report_data() {
@@ -260,37 +133,6 @@ add_task(async function test_addon_report_data() {
await extension3.unload();
});
-add_task(async function test_report_on_not_installed_addon() {
- Services.telemetry.clearEvents();
-
- // Make sure that the AMO addons details API endpoint is going to
- // return a 404 status for the not installed addon.
- amoAddonDetailsMap.delete(ADDON_ID);
-
- await assertRejectsAbuseReportError(
- AbuseReporter.createAbuseReport(ADDON_ID, REPORT_OPTIONS),
- "ERROR_ADDON_NOTFOUND"
- );
-
- TelemetryTestUtils.assertEvents(
- [
- {
- object: REPORT_OPTIONS.reportEntryPoint,
- value: ADDON_ID,
- extra: { error_type: "ERROR_AMODETAILS_NOTFOUND" },
- },
- {
- object: REPORT_OPTIONS.reportEntryPoint,
- value: ADDON_ID,
- extra: { error_type: "ERROR_ADDON_NOTFOUND" },
- },
- ],
- TELEMETRY_EVENTS_FILTERS
- );
-
- Services.telemetry.clearEvents();
-});
-
// This tests verifies how the addon installTelemetryInfo values are being
// normalized into the addon_install_source and addon_install_method
// expected by the API endpoint.
@@ -379,526 +221,3 @@ add_task(async function test_normalized_addon_install_source_and_method() {
await assertAddonInstallMethod(test, expect);
}
});
-
-add_task(async function test_report_create_and_submit() {
- Services.telemetry.clearEvents();
-
- // Override the test api server request handler, to be able to
- // intercept the submittions to the test api server.
- let reportSubmitted;
- apiRequestHandler = ({ data, request, response }) => {
- reportSubmitted = JSON.parse(data);
- handleSubmitRequest({ request, response });
- };
-
- const { addon, extension } = await installTestExtension();
-
- const reportEntryPoint = "menu";
- const report = await AbuseReporter.createAbuseReport(ADDON_ID, {
- reportEntryPoint,
- });
-
- equal(report.addon, addon, "Got the expected addon property");
- equal(
- report.reportEntryPoint,
- reportEntryPoint,
- "Got the expected reportEntryPoint"
- );
-
- const baseReportData = await AbuseReporter.getReportData(addon);
- const reportProperties = {
- message: "test message",
- reason: "test-reason",
- };
-
- info("Submitting report");
- report.setMessage(reportProperties.message);
- report.setReason(reportProperties.reason);
- await report.submit();
-
- const expectedEntries = Object.entries({
- report_entry_point: reportEntryPoint,
- ...baseReportData,
- ...reportProperties,
- });
-
- for (const [expectedKey, expectedValue] of expectedEntries) {
- equal(
- reportSubmitted[expectedKey],
- expectedValue,
- `Got the expected submitted value for "${expectedKey}"`
- );
- }
-
- TelemetryTestUtils.assertEvents(
- [
- {
- object: reportEntryPoint,
- value: ADDON_ID,
- extra: { addon_type: "extension" },
- },
- ],
- TELEMETRY_EVENTS_FILTERS
- );
-
- await extension.unload();
-});
-
-add_task(async function test_error_recent_submit() {
- Services.telemetry.clearEvents();
- clearAbuseReportState();
-
- let reportSubmitted;
- apiRequestHandler = ({ data, request, response }) => {
- reportSubmitted = JSON.parse(data);
- handleSubmitRequest({ request, response });
- };
-
- const { extension } = await installTestExtension();
- const report = await AbuseReporter.createAbuseReport(ADDON_ID, {
- reportEntryPoint: "uninstall",
- });
-
- const { extension: extension2 } = await installTestExtension({
- manifest: {
- browser_specific_settings: { gecko: { id: ADDON_ID2 } },
- name: "Test Extension2",
- },
- });
- const report2 = await AbuseReporter.createAbuseReport(
- ADDON_ID2,
- REPORT_OPTIONS
- );
-
- // Submit the two reports in fast sequence.
- report.setReason("reason1");
- report2.setReason("reason2");
- await report.submit();
- await assertRejectsAbuseReportError(report2.submit(), "ERROR_RECENT_SUBMIT");
- equal(
- reportSubmitted.reason,
- "reason1",
- "Server only received the data from the first submission"
- );
-
- TelemetryTestUtils.assertEvents(
- [
- {
- object: "uninstall",
- value: ADDON_ID,
- extra: { addon_type: "extension" },
- },
- {
- object: REPORT_OPTIONS.reportEntryPoint,
- value: ADDON_ID2,
- extra: {
- addon_type: "extension",
- error_type: "ERROR_RECENT_SUBMIT",
- },
- },
- ],
- TELEMETRY_EVENTS_FILTERS
- );
-
- await extension.unload();
- await extension2.unload();
-});
-
-add_task(async function test_submission_server_error() {
- const { extension } = await installTestExtension();
-
- async function testErrorCode({
- responseStatus,
- responseText = "",
- expectedErrorType,
- expectedErrorInfo,
- expectRequest = true,
- }) {
- info(
- `Test expected AbuseReportError on response status "${responseStatus}"`
- );
- Services.telemetry.clearEvents();
- clearAbuseReportState();
-
- let requestReceived = false;
- apiRequestHandler = ({ request, response }) => {
- requestReceived = true;
- response.setStatusLine(request.httpVersion, responseStatus, "Error");
- response.write(responseText);
- };
-
- const report = await AbuseReporter.createAbuseReport(
- ADDON_ID,
- REPORT_OPTIONS
- );
- report.setReason("a-reason");
- const promiseSubmit = report.submit();
- if (typeof expectedErrorType === "string") {
- // Assert a specific AbuseReportError errorType.
- await assertRejectsAbuseReportError(
- promiseSubmit,
- expectedErrorType,
- expectedErrorInfo
- );
- } else {
- // Assert on a given Error class.
- await Assert.rejects(promiseSubmit, expectedErrorType);
- }
- equal(
- requestReceived,
- expectRequest,
- `${expectRequest ? "" : "Not "}received a request as expected`
- );
-
- TelemetryTestUtils.assertEvents(
- [
- {
- object: REPORT_OPTIONS.reportEntryPoint,
- value: ADDON_ID,
- extra: {
- addon_type: "extension",
- error_type:
- typeof expectedErrorType === "string"
- ? expectedErrorType
- : "ERROR_UNKNOWN",
- },
- },
- ],
- TELEMETRY_EVENTS_FILTERS
- );
- }
-
- await testErrorCode({
- responseStatus: 500,
- responseText: "A server error",
- expectedErrorType: "ERROR_SERVER",
- expectedErrorInfo: JSON.stringify({
- status: 500,
- responseText: "A server error",
- }),
- });
- await testErrorCode({
- responseStatus: 404,
- responseText: "Not found error",
- expectedErrorType: "ERROR_CLIENT",
- expectedErrorInfo: JSON.stringify({
- status: 404,
- responseText: "Not found error",
- }),
- });
- // Test response with unexpected status code.
- await testErrorCode({
- responseStatus: 604,
- responseText: "An unexpected status code",
- expectedErrorType: "ERROR_UNKNOWN",
- expectedErrorInfo: JSON.stringify({
- status: 604,
- responseText: "An unexpected status code",
- }),
- });
- // Test response status 200 with invalid json data.
- await testErrorCode({
- responseStatus: 200,
- expectedErrorType: /SyntaxError: JSON.parse/,
- });
-
- // Test on invalid url.
- Services.prefs.setCharPref(
- "extensions.abuseReport.url",
- "invalid-protocol://abuse-report"
- );
- await testErrorCode({
- expectedErrorType: "ERROR_NETWORK",
- expectRequest: false,
- });
-
- await extension.unload();
-});
-
-add_task(async function set_test_abusereport_url() {
- Services.prefs.setCharPref(
- "extensions.abuseReport.url",
- "http://test.addons.org/api/report/"
- );
-});
-
-add_task(async function test_submission_aborting() {
- Services.telemetry.clearEvents();
- clearAbuseReportState();
-
- const { extension } = await installTestExtension();
-
- // override the api request handler with one that is never going to reply.
- let receivedRequestsCount = 0;
- let resolvePendingResponses;
- const waitToReply = new Promise(
- resolve => (resolvePendingResponses = resolve)
- );
-
- const onRequestReceived = new Promise(resolve => {
- apiRequestHandler = ({ request, response }) => {
- response.processAsync();
- response.setStatusLine(request.httpVersion, 200, "OK");
- receivedRequestsCount++;
- resolve();
-
- // Keep the request pending until resolvePendingResponses have been
- // called.
- waitToReply.then(() => {
- response.finish();
- });
- };
- });
-
- const report = await AbuseReporter.createAbuseReport(
- ADDON_ID,
- REPORT_OPTIONS
- );
- report.setReason("a-reason");
- const promiseResult = report.submit();
-
- await onRequestReceived;
-
- Assert.greater(
- receivedRequestsCount,
- 0,
- "Got the expected number of requests"
- );
- Assert.strictEqual(
- await Promise.race([promiseResult, Promise.resolve("pending")]),
- "pending",
- "Submission fetch request should still be pending"
- );
-
- report.abort();
-
- await assertRejectsAbuseReportError(promiseResult, "ERROR_ABORTED_SUBMIT");
-
- TelemetryTestUtils.assertEvents(
- [
- {
- object: REPORT_OPTIONS.reportEntryPoint,
- value: ADDON_ID,
- extra: { addon_type: "extension", error_type: "ERROR_ABORTED_SUBMIT" },
- },
- ],
- TELEMETRY_EVENTS_FILTERS
- );
-
- await extension.unload();
-
- // Unblock pending requests on the server request handler side, so that the
- // test file can shutdown (otherwise the test run will be stuck after this
- // task completed).
- resolvePendingResponses();
-});
-
-add_task(async function test_truncated_string_properties() {
- const generateString = len => new Array(len).fill("a").join("");
-
- const LONG_STRINGS_ADDON_ID = "addon-with-long-strings-props@mochi.test";
- const { extension } = await installTestExtension({
- manifest: {
- name: generateString(400),
- description: generateString(400),
- browser_specific_settings: { gecko: { id: LONG_STRINGS_ADDON_ID } },
- },
- });
-
- // Override the test api server request handler, to be able to
- // intercept the properties actually submitted.
- let reportSubmitted;
- apiRequestHandler = ({ data, request, response }) => {
- reportSubmitted = JSON.parse(data);
- handleSubmitRequest({ request, response });
- };
-
- const report = await AbuseReporter.createAbuseReport(
- LONG_STRINGS_ADDON_ID,
- REPORT_OPTIONS
- );
-
- report.setMessage("fake-message");
- report.setReason("fake-reason");
- await report.submit();
-
- const expected = {
- addon_name: generateString(255),
- addon_summary: generateString(255),
- };
-
- Assert.deepEqual(
- {
- addon_name: reportSubmitted.addon_name,
- addon_summary: reportSubmitted.addon_summary,
- },
- expected,
- "Got the long strings truncated as expected"
- );
-
- await extension.unload();
-});
-
-add_task(async function test_report_recommended() {
- const NON_RECOMMENDED_ADDON_ID = "non-recommended-addon@mochi.test";
- const RECOMMENDED_ADDON_ID = "recommended-addon@mochi.test";
-
- const now = Date.now();
- const not_before = new Date(now - 3600000).toISOString();
- const not_after = new Date(now + 3600000).toISOString();
-
- const { extension: nonRecommended } = await installTestExtension({
- manifest: {
- name: "Fake non recommended addon",
- browser_specific_settings: { gecko: { id: NON_RECOMMENDED_ADDON_ID } },
- },
- });
-
- const { extension: recommended } = await installTestExtension({
- manifest: {
- name: "Fake recommended addon",
- browser_specific_settings: { gecko: { id: RECOMMENDED_ADDON_ID } },
- },
- files: {
- "mozilla-recommendation.json": {
- addon_id: RECOMMENDED_ADDON_ID,
- states: ["recommended"],
- validity: { not_before, not_after },
- },
- },
- });
-
- // Override the test api server request handler, to be able to
- // intercept the properties actually submitted.
- let reportSubmitted;
- apiRequestHandler = ({ data, request, response }) => {
- reportSubmitted = JSON.parse(data);
- handleSubmitRequest({ request, response });
- };
-
- async function checkReportedSignature(addonId, expectedAddonSignature) {
- clearAbuseReportState();
- const report = await AbuseReporter.createAbuseReport(
- addonId,
- REPORT_OPTIONS
- );
- report.setMessage("fake-message");
- report.setReason("fake-reason");
- await report.submit();
- equal(
- reportSubmitted.addon_signature,
- expectedAddonSignature,
- `Got the expected addon_signature for ${addonId}`
- );
- }
-
- await checkReportedSignature(NON_RECOMMENDED_ADDON_ID, "signed");
- await checkReportedSignature(RECOMMENDED_ADDON_ID, "curated");
-
- await nonRecommended.unload();
- await recommended.unload();
-});
-
-add_task(async function test_query_amo_details() {
- async function assertReportOnAMODetails({ addonId, expectedReport } = {}) {
- // Clear last report timestamp and any telemetry event recorded so far.
- clearAbuseReportState();
- Services.telemetry.clearEvents();
-
- const report = await AbuseReporter.createAbuseReport(addonId, {
- reportEntryPoint: "menu",
- });
-
- let reportSubmitted;
- apiRequestHandler = ({ data, request, response }) => {
- reportSubmitted = JSON.parse(data);
- handleSubmitRequest({ request, response });
- };
-
- report.setMessage("fake message");
- report.setReason("reason1");
- await report.submit();
-
- Assert.deepEqual(
- expectedReport,
- getProperties(reportSubmitted, Object.keys(expectedReport)),
- "Got the expected report properties"
- );
-
- // Telemetry recorded for the successfully submitted report.
- TelemetryTestUtils.assertEvents(
- [
- {
- object: "menu",
- value: addonId,
- extra: { addon_type: FAKE_AMO_DETAILS.type },
- },
- ],
- TELEMETRY_EVENTS_FILTERS
- );
-
- clearAbuseReportState();
- }
-
- // Add the expected AMO addons details.
- const addonId = "not-installed-addon@mochi.test";
- amoAddonDetailsMap.set(addonId, FAKE_AMO_DETAILS);
-
- // Test on the default en-US locale.
- Services.prefs.setCharPref(PREF_REQUIRED_LOCALE, "en-US");
- let locale = Services.locale.appLocaleAsBCP47;
- equal(locale, "en-US", "Got the expected app locale set");
-
- let expectedReport = {
- addon: addonId,
- addon_name: FAKE_AMO_DETAILS.name[locale],
- addon_version: FAKE_AMO_DETAILS.current_version.version,
- addon_install_source: "not_installed",
- addon_install_method: null,
- addon_signature: "curated",
- };
-
- await assertReportOnAMODetails({ addonId, expectedReport });
-
- // Test with a non-default locale also available in the AMO details.
- Services.prefs.setCharPref(PREF_REQUIRED_LOCALE, "it-IT");
- locale = Services.locale.appLocaleAsBCP47;
- equal(locale, "it-IT", "Got the expected app locale set");
-
- expectedReport = {
- ...expectedReport,
- addon_name: FAKE_AMO_DETAILS.name[locale],
- };
- await assertReportOnAMODetails({ addonId, expectedReport });
-
- // Test with a non-default locale not available in the AMO details.
- Services.prefs.setCharPref(PREF_REQUIRED_LOCALE, "fr-FR");
- locale = Services.locale.appLocaleAsBCP47;
- equal(locale, "fr-FR", "Got the expected app locale set");
-
- expectedReport = {
- ...expectedReport,
- // Fallbacks on en-US for non available locales.
- addon_name: FAKE_AMO_DETAILS.name["en-US"],
- };
- await assertReportOnAMODetails({ addonId, expectedReport });
-
- Services.prefs.clearUserPref(PREF_REQUIRED_LOCALE);
-
- amoAddonDetailsMap.clear();
-});
-
-add_task(async function test_statictheme_normalized_into_type_theme() {
- const themeId = "not-installed-statictheme@mochi.test";
- amoAddonDetailsMap.set(themeId, {
- ...FAKE_AMO_DETAILS,
- type: "statictheme",
- });
-
- const report = await AbuseReporter.createAbuseReport(themeId, REPORT_OPTIONS);
-
- equal(report.addon.id, themeId, "Got a report for the expected theme id");
- equal(report.addon.type, "theme", "Got the expected addon type");
-
- amoAddonDetailsMap.clear();
-});