Bug 1673316 - Ensure docShellIsActive is preserved when switching process. r=snorp

I'm not a fan of accessing private bits like `docShellIsActive` in tests like
that but it's both:

1) very important, if we don't correctly activate docShell performance will be
   very poor

2) stable, this API is not likely to change, and if it changes it
   should be easy to get whatever the replacement is

Differential Revision: https://phabricator.services.mozilla.com/D94874
This commit is contained in:
Agi Sferro 2020-10-27 18:41:58 +00:00
Родитель c8201ae614
Коммит 73923d06c0
8 изменённых файлов: 57 добавлений и 0 удалений

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

@ -186,9 +186,18 @@ var ModuleManager = {
this.forEach(module => {
module.onDestroyBrowser();
});
// TODO: Bug 1673683: `docShellIsActive` is sometimes not preserved when
// switching process.
this.docShellIsActiveWhileSwitchingProcess = this.browser.docShellIsActive;
},
didChangeBrowserRemoteness() {
debug`DidChangeBrowserRemoteness`;
this.browser.docShellIsActive = this.docShellIsActiveWhileSwitchingProcess;
this.docShellIsActiveWhileSwitchingProcess = undefined;
this.forEach(module => {
if (module.impl) {
module.impl.onInitBrowser();

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

@ -23,6 +23,9 @@ const APIS = {
GetPrefs({ prefs }) {
return browser.test.getPrefs(prefs);
},
GetActive({ tab }) {
return browser.test.getActive(tab.id);
},
RemoveCertOverride({ host, port }) {
browser.test.removeCertOverride(host, port);
},

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

@ -180,6 +180,11 @@ this.test = class extends ExtensionAPI {
});
},
async getActive(tabId) {
const tab = context.extension.tabManager.get(tabId);
return tab.browser.docShellIsActive;
},
async flushApzRepaints(tabId) {
const tab = context.extension.tabManager.get(tabId);
const { browsingContext } = tab.browser;

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

@ -133,6 +133,18 @@
}
]
},
{
"name": "getActive",
"type": "function",
"async": true,
"description": "Returns true if the docShell is active for given tab.",
"parameters": [
{
"type": "number",
"name": "tabId"
}
]
},
{
"name": "getPidForTab",
"type": "function",

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

@ -191,6 +191,10 @@ open class BaseSessionTest(noErrorCollector: Boolean = false) {
fun GeckoSession.flushApzRepaints() = sessionRule.flushApzRepaints(this)
var GeckoSession.active: Boolean
get() = sessionRule.getActive(this)
set(value) = setActive(value)
@Suppress("UNCHECKED_CAST")
fun Any?.asJsonArray(): JSONArray = this as JSONArray

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

@ -1695,6 +1695,9 @@ class NavigationDelegateTest : BaseSessionTest() {
mainSession.loadTestPath(HELLO2_HTML_PATH)
sessionRule.waitForPageStop()
assertThat("docShell should start out active", mainSession.active,
equalTo(true))
// This loads in the parent process
mainSession.loadUri(url)
sessionRule.waitForPageStop()
@ -1706,6 +1709,9 @@ class NavigationDelegateTest : BaseSessionTest() {
sessionRule.waitForPageStop()
assertThat("URL should match", currentUrl!!, endsWith(HELLO_HTML_PATH))
assertThat("docShell should be active after switching process",
mainSession.active,
equalTo(true))
mainSession.loadUri(url)
sessionRule.waitForPageStop()
@ -1716,6 +1722,9 @@ class NavigationDelegateTest : BaseSessionTest() {
sessionRule.waitForPageStop()
assertThat("URL should match", currentUrl!!, endsWith(HELLO_HTML_PATH))
assertThat("docShell should be active after switching process",
mainSession.active,
equalTo(true))
sessionRule.session.goBack()
sessionRule.waitForPageStop()
@ -1726,6 +1735,9 @@ class NavigationDelegateTest : BaseSessionTest() {
sessionRule.waitForPageStop()
assertThat("URL should match", currentUrl!!, endsWith(HELLO2_HTML_PATH))
assertThat("docShell should be active after switching process",
mainSession.active,
equalTo(true))
settings.aboutConfigEnabled = aboutConfigEnabled
}

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

@ -127,6 +127,8 @@ class SessionLifecycleTest : BaseSessionTest() {
mainSession.loadTestPath(HELLO_HTML_PATH)
mainSession.waitForPageStop()
assertThat("docShell should start active", mainSession.active, equalTo(true))
// Deactivate the GeckoSession and confirm that rAF/setTimeout/etc callbacks do not run
mainSession.setActive(false)
mainSession.evaluateJS(
@ -139,9 +141,13 @@ class SessionLifecycleTest : BaseSessionTest() {
mainSession.waitForJS("new Promise(resolve => { resolve() })")
val isNotGreen = mainSession.evaluateJS("document.documentElement.style.backgroundColor !== 'green'") as Boolean
assertThat("requestAnimationFrame has not run yet", isNotGreen, equalTo(true))
assertThat("docShell shouldn't be active after calling setActive",
mainSession.active, equalTo(false))
// Reactivate the GeckoSession and confirm that rAF/setTimeout/etc callbacks now run
mainSession.setActive(true)
assertThat("docShell should be active after calling setActive(true)",
mainSession.active, equalTo(true))
mainSession.waitForJS("new Promise(resolve => requestAnimationFrame(() => { resolve(); }))");
var isGreen = mainSession.evaluateJS("document.documentElement.style.backgroundColor === 'green'") as Boolean
assertThat("requestAnimationFrame has run", isGreen, equalTo(true))

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

@ -1911,6 +1911,12 @@ public class GeckoSessionTestRule implements TestRule {
return dblPid.intValue();
}
public boolean getActive(final @NonNull GeckoSession session) {
final Boolean isActive = (Boolean)
webExtensionApiCall(session, "GetActive", null);
return isActive;
}
private Object waitForMessage(String id) {
UiThreadUtils.waitForCondition(() -> mPendingMessages.containsKey(id),
mTimeoutMillis);