Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

core(driver): use execution context isolation when necessary #3500

Merged
merged 5 commits into from
Oct 13, 2017

Conversation

patrickhulce
Copy link
Collaborator

closes #2511
fixes #2505

@paulirish paulirish changed the title fix(driver): use execution context isolation when necessary fix(driver): use execution context isolation when it's necessary Oct 7, 2017
@paulirish paulirish changed the title fix(driver): use execution context isolation when it's necessary fix(driver): use execution context isolation when necessary Oct 8, 2017
@paulirish paulirish changed the title fix(driver): use execution context isolation when necessary fix(driver): use execution context isolation when necessary. Oct 8, 2017
}).then(result => {
};

if (useIsolation && typeof this._isolatedExecutionContextId === 'number') {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if isolation is requested but there is no contextId... should we throw?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had this originally to check for leaks and it seemed ok, but it's definitely possible and seemed bad to tank the run because it since it won't matter most of the time

perhaps something to add to sentry though when it lands?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like we should be able to figure out definitively if it's possible to reach here without having created a new context? Then future violations of this can complain loudly by throwing (alternatively, see other comment about lazily calling _createIsolatedWorld())

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

going the lazy route 👍

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

for d in "$DIR"/*/ ; do
bash "${d}run-tests.sh"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there are a few other ways to do this, but the benefit of this approach is the failures won't be silent. :)

sgtm

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we just manually list the files in here? If I'm messing with some smoke tests it's a lot easier to comment out lines in one place by name than look up where the individual run-tests file is

also it'd probably be better to just get rid of all the run-tests.sh files since they're all exactly the same except for the expectations and config filename strings :)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will nuke 'em all in a follow up PR and improve this file here 👍

Copy link
Member

@brendankenny brendankenny left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for future calls to evaluateAsync, how does one know if it should be isolated or not? Try the default out and if it fails (returns nothing when expected something?) try turning off isolation? :)

Is there anything we can do for these non-isolated ones (js-libraries, function callsites, and check for quiet) to make them isolated? I guess it's just unclear what's isolated and what's not if the axe checks work but js-library-detector does not

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

for d in "$DIR"/*/ ; do
bash "${d}run-tests.sh"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we just manually list the files in here? If I'm messing with some smoke tests it's a lot easier to comment out lines in one place by name than look up where the individual run-tests file is

also it'd probably be better to just get rid of all the run-tests.sh files since they're all exactly the same except for the expectations and config filename strings :)

* @return {!Promise<*>}
*/
evaluateAsync(expression) {
evaluateAsync(expression, options) {
const {useIsolation = true} = options || {};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the double defaults here is kind of confusing. Maybe move the {} default for options to the params?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

}).then(result => {
};

if (useIsolation && typeof this._isolatedExecutionContextId === 'number') {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like we should be able to figure out definitively if it's possible to reach here without having created a new context? Then future violations of this can complain loudly by throwing (alternatively, see other comment about lazily calling _createIsolatedWorld())

@@ -633,6 +661,7 @@ class Driver {
})
.then(_ => waitForLoad && this._waitForFullyLoaded(pauseAfterLoadMs,
networkQuietThresholdMs, cpuQuietThresholdMs, maxWaitMs))
.then(_ => this._createIsolatedWorld())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would there be downsides to clearing on all navigations (as above) but calling _createIsolatedWorld lazily on next evaluateAsync() when _isolatedExecutionContextId isn't defined?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@patrickhulce
Copy link
Collaborator Author

Is there anything we can do for these non-isolated ones (js-libraries, function callsites, and check for quiet) to make them isolated? I guess it's just unclear what's isolated and what's not if the axe checks work but js-library-detector does not

discussed offline, decided to switch the default to useIsolation=false and just opt-in a11y for now

@patrickhulce patrickhulce changed the title fix(driver): use execution context isolation when necessary. core(driver): use execution context isolation when necessary Oct 11, 2017
@patrickhulce
Copy link
Collaborator Author

PTAL :)

Copy link
Member

@paulirish paulirish left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this lgtm in general. just nits

@@ -197,5 +197,13 @@
<section>
<video id="video-description"></video>
</section>
<script>
// axe fails if `define` is present but misbehaves, create a bogus implementation to exercise our
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't totally get this. I'll ask you in person if i'm interpreting it correctly, but it could probably use a slightly more extended comment. :)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// axe fails if a different UMD loader like almond.js is used on the page, see https://github.com/GoogleChrome/lighthouse/issues/2505
// We can simulate this behavior by defining a similarly misbehaving `define` function.

sounds better?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

YESSS so good

settings: {
onlyCategories: [
'accessibility',
],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since we were talking about it yesterday... is it possible to reuse an existing smoketest?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know we were literally just talking about not adding more yesterday but of all the testers that should probably get their own one, I think a11y is one of them 😆

maybe we can start by reducing DBW's 6 passes instead? :)

@@ -596,6 +619,26 @@ class Driver {
}

/**
* @return {!Promise<number>}
*/
_getOrCreateIsolatedContextId() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_acquireIsolatedContextId() ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

discussed offline, Paul's a huge fan of getOrCreate now 🚗 🎏 🎉

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lol

return this.sendCommand('Page.getResourceTree')
.then(data => {
const frameId = data.frameTree.frame.id;
return this.sendCommand('Page.createIsolatedWorld', {frameId});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's give it a worldName while we're at it.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


return this.sendCommand('Page.getResourceTree')
.then(data => {
const frameId = data.frameTree.frame.id;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

frameId => mainFrameId

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Copy link
Member

@brendankenny brendankenny left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. ⛰ 💻 🔐

* Evaluate an expression in the context of the current page.
* Evaluate an expression in the context of the current page. If useIsolation is true, the expression
* will be evaluated in a content script that has access to the page's DOM but whose JavaScript state
* is completely separate.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 👍

* Evaluate an expression in the given execution context; an undefined contextId implies the main
* page without isolation.
* @param {string} expression
* @param {number|undefined} contextId
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can be {number=} FWIW

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah just seemed more explicit since something is always passed in but doesn't matter to me

@@ -596,6 +619,26 @@ class Driver {
}

/**
* @return {!Promise<number>}
*/
_getOrCreateIsolatedContextId() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe a jsdoc comment here that the contextId won't persist past a page load (so should be cleared and recreated)?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good call, done

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants