Bug 1822865 - Support persistent events for android downloads API r=geckoview-reviewers,extension-reviewers,robwu,zmckenney

Differential Revision: https://phabricator.services.mozilla.com/D174960
This commit is contained in:
Cathy Lu 2023-04-27 20:14:48 +00:00
Родитель 873d09c98e
Коммит 26bdd74175
5 изменённых файлов: 148 добавлений и 27 удалений

Просмотреть файл

@ -144,7 +144,30 @@ class DownloadItem {
}
}
this.downloads = class extends ExtensionAPI {
this.downloads = class extends ExtensionAPIPersistent {
PERSISTENT_EVENTS = {
onChanged({ fire, context }, params) {
const listener = (eventName, event) => {
const { delta, downloadItem } = event;
const { extension } = this;
if (extension.privateBrowsingAllowed || !downloadItem.incognito) {
fire.async(delta);
}
};
DownloadTracker.on("download-changed", listener);
return {
unregister() {
DownloadTracker.off("download-changed", listener);
},
convert(_fire, _context) {
fire = _fire;
context = _context;
},
};
},
};
getAPI(context) {
const { extension } = context;
return {
@ -268,20 +291,9 @@ this.downloads = class extends ExtensionAPI {
onChanged: new EventManager({
context,
name: "downloads.onChanged",
register: fire => {
const listener = (eventName, event) => {
const { delta, downloadItem } = event;
if (context.privateBrowsingAllowed || !downloadItem.incognito) {
fire.async(delta);
}
};
DownloadTracker.on("download-changed", listener);
return () => {
DownloadTracker.off("download-changed", listener);
};
},
module: "downloads",
event: "onChanged",
extensionApi: this,
}).api(),
onCreated: ignoreEvent(context, "downloads.onCreated"),

Просмотреть файл

@ -13,25 +13,29 @@ var TEST_ICON_ARRAYBUFFER = Uint8Array.from(atob(TEST_ICON_DATA), byte =>
byte.charCodeAt(0)
).buffer;
async function assertPersistentListeners(extension, expected) {
const EVENTS = ["onActivated", "onCreated", "onRemoved", "onUpdated"];
async function assertPersistentListeners(
extWrapper,
apiNs,
apiEvents,
expected
) {
const stringErr = await SpecialPowers.spawnChrome(
[extension.id, EVENTS, expected],
async (id, EVENTS, expectedParam) => {
[extWrapper.id, apiNs, apiEvents, expected],
async (id, apiNs, apiEvents, expected) => {
try {
const { ExtensionTestCommon } = ChromeUtils.import(
"resource://testing-common/ExtensionTestCommon.jsm"
);
const ext = { id };
for (const event of EVENTS) {
for (const event of apiEvents) {
ExtensionTestCommon.testAssertions.assertPersistentListeners(
ext,
"tabs",
apiNs,
event,
{
primed: expectedParam.primed,
persisted: expectedParam.persisted,
primedListenersCount: expectedParam.primedListenersCount,
primed: expected.primed,
persisted: expected.persisted,
primedListenersCount: expected.primedListenersCount,
}
);
}

Просмотреть файл

@ -16,6 +16,7 @@ prefs =
javascript.options.asyncstack_capture_debuggee_only=false
[test_ext_all_apis.html]
[test_ext_downloads_event_page.html]
[test_ext_tab_runtimeConnect.html]
[test_ext_tabs_create.html]
[test_ext_tabs_events.html]

Просмотреть файл

@ -0,0 +1,102 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Downloads Events Test</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
<script type="text/javascript" src="head.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<script type="text/javascript">
"use strict";
add_task(async function test_downloads_event_page() {
const apiEvents = ["onChanged"];
const apiNs = "downloads";
const extension = ExtensionTestUtils.loadExtension({
useAddonManager: "permanent",
manifest: {
browser_specific_settings: { gecko: { id: "eventpage@downloads" } },
permissions: ["downloads"],
background: { persistent: false },
},
background() {
browser.downloads.onChanged.addListener(() => {
browser.test.sendMessage("onChanged");
browser.test.notifyPass("downloads-events");
});
browser.test.sendMessage("ready");
},
});
// on startup, onChanged event listener should not be primed
await extension.startup();
info("Wait for event page to be started");
await extension.awaitMessage("ready");
await assertPersistentListeners(extension, apiNs, apiEvents, { primed: false });
// when the extension is killed, onChanged event listener should be primed
info("Terminate event page");
await extension.terminateBackground();
await assertPersistentListeners(extension, apiNs, apiEvents, { primed: true });
// fire download-changed event and onChanged event listener should not be primed
info("Wait for download-changed to be emitted");
await SpecialPowers.spawnChrome([], async () => {
const { DownloadTracker } = ChromeUtils.importESModule(
"resource://gre/modules/GeckoViewWebExtension.sys.mjs"
);
const delta = {
filename: "test.gif",
id: 4,
mime: "image/gif",
totalBytes: 5,
};
// Mocks DownloadItem from mobile/android/components/extensions/ext-downloads.js
const downloadItem = {
byExtensionId: "download-onChanged@tests.mozilla.org",
byExtensionName: "Download",
bytesReceived: 0,
canResume: false,
danger: "safe",
exists: false,
fileSize: -1,
filename: "test.gif",
id: 4,
incognito: false,
mime: "image/gif",
paused: false,
referrer: "",
startTime: 1680818149350,
state: "in_progress",
totalBytes: 5,
url: "http://localhost:4245/assets/www/images/test.gif",
};
// WebExtension.DownloadDelegate has not been overridden in
// TestRunnerActivity (used by mochitests), so the downloads API
// does not actually work. In this test, we are only interested in
// whether or not dispatching an event would wake up the event page,
// so we artificially trigger a fake onChanged event to test that.
DownloadTracker.emit("download-changed", { delta, downloadItem });
});
info("Triggered download change, expecting downloads.onChanged event");
await extension.awaitMessage("ready");
await extension.awaitMessage("onChanged");
await extension.awaitFinish("downloads-events");
await assertPersistentListeners(extension, apiNs, apiEvents, { primed: false });
await extension.unload();
});
</script>
</body>
</html>

Просмотреть файл

@ -256,6 +256,8 @@ add_task(async function test_tabs_event_page() {
browser.test.sendMessage("ready");
}
const apiEvents = ["onActivated", "onCreated", "onRemoved", "onUpdated"];
const apiNs = "tabs";
const extension = ExtensionTestUtils.loadExtension({
manifest: {
browser_specific_settings: { gecko: { id: "eventpage@tabs" } },
@ -274,12 +276,12 @@ add_task(async function test_tabs_event_page() {
await extension.awaitMessage("onCreated");
// on startup, all event listeners should not be primed
await assertPersistentListeners(extension, { primed: false });
await assertPersistentListeners(extension, apiNs, apiEvents, { primed: false });
// when the extension is killed, all event listeners should be primed
info("Terminate event page");
await extension.terminateBackground({ disableResetIdleForTest: true });
await assertPersistentListeners(extension, { primed: true });
await assertPersistentListeners(extension, apiNs, apiEvents, { primed: true });
// on start up again, all event listeners should not be primed
info("Wake up event page on a new tabs.onCreated event");
@ -288,7 +290,7 @@ add_task(async function test_tabs_event_page() {
await extension.awaitMessage("ready");
info("Wait for the primed tabs.onCreated to be received by the event page");
await extension.awaitMessage("onCreated");
await assertPersistentListeners(extension, { primed: false });
await assertPersistentListeners(extension, apiNs, apiEvents, { primed: false });
await extension.unload();
newWin.close();