diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-12 05:35:29 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-12 05:35:29 +0000 |
commit | 59203c63bb777a3bacec32fb8830fba33540e809 (patch) | |
tree | 58298e711c0ff0575818c30485b44a2f21bf28a0 /toolkit/mozapps/extensions/test/xpcshell/test_AbuseReporter.js | |
parent | Adding upstream version 126.0.1. (diff) | |
download | firefox-59203c63bb777a3bacec32fb8830fba33540e809.tar.xz firefox-59203c63bb777a3bacec32fb8830fba33540e809.zip |
Adding upstream version 127.0.upstream/127.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'toolkit/mozapps/extensions/test/xpcshell/test_AbuseReporter.js')
-rw-r--r-- | toolkit/mozapps/extensions/test/xpcshell/test_AbuseReporter.js | 687 |
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(); -}); |