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

test(smokehouse): use static requires for test definitions #9501

Merged
merged 11 commits into from
Oct 2, 2019

Conversation

connorjclark
Copy link
Collaborator

@connorjclark connorjclark commented Aug 2, 2019

I'm exploring creating a new bundle whose entry point is an interface for a Smoke test runner. This would eventually be used in a layout test in Chromium. It'd also bundle the test definitions, but to do that bundle.require is necessary to shim the expectations / configs loaded dynamically in smoke-test-dfns.js. See here for how the build script looks.

This is fine enough, but it made me think about how the smoke tests are defined. Doesn't seem to be much value in defining the paths and resolving them specially the way we do. I think doing it explicitly makes way more sense. Then no special require logic is necessary for bundling this code.

With this, some TypeScript gremlins were awakened. The types for most of the values in the expectations are wishy-washy, in that we accept RegExps anywhere and do strange stuff with arrays ({length: 1}). So I figured the values should be loose (any), and we should just verify that the keys make sense.

@@ -19,17 +19,28 @@
diff?: Difference | null;
}

export type ExpectedLHR = Pick<LH.Result, 'audits' | 'finalUrl' | 'requestedUrl' | 'runtimeError'>
interface ExpectedLHR {
audits: Record<string, any>;
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Is there a way to get all the audit ids? I tried something with import('../lighthouse-core/config/default-config') but couldn't get it to work.

Copy link
Collaborator

Choose a reason for hiding this comment

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

why is it divorced from LH.Result at all?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Because we allow RegExps for any place a string is found, and {length:1} for arrays. Since the expectation files were changed to directly use this type now, it breaks if just LH.Result is used.

* @param {string} payloadPath
* @return {string}
*/
function resolveLocalOrProjectRoot(payloadPath) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This actually still sticks arounds because the smoke runner needs a path to use with the LH CLI.

Instead, maybe the smoke runner could save a temporary file to disk, and pass that path? Does that sound better - temporary file creation vs this weird paths shenanigans?

Copy link
Collaborator

Choose a reason for hiding this comment

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

could we leave it where it was then to avoid the unnecessary diff/blame churn?

Instead, maybe the smoke runner could save a temporary file to disk, and pass that path? Does that sound better - temporary file creation vs this weird paths shenanigans?

you know I support this :) this was one of my fav features of #8962

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 didn't notice the file shenanigans you did there until now (I was just focused on the jest stuff), but yeah good to see this is supported by you too!

could we leave it where it was then to avoid the unnecessary diff/blame churn?

I am bad about deleting code when I think it's no longer needed, then adding it back when I realize I need it but putting it in a different place :(

@connorjclark
Copy link
Collaborator Author

Oh, you can test with this: npx browserify --s LH.SmokeTests lighthouse-cli/test/smokehouse/smoke-test-dfns.js -> paste in browser -> LH.SmokeTests

Copy link
Collaborator

@patrickhulce patrickhulce left a comment

Choose a reason for hiding this comment

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

Love the goal of smoketests for Chromium layout tests :)

This seems like a decent step in that direction though I'd be a bit bummed to see the structural change to smoketestdefns in a way that entrenches us further from #8962 (not saying we've hit that point yet, just throwing it out there as an internal measuring stick I'm using)

lighthouse-cli/test/smokehouse/seo/expectations.js Outdated Show resolved Hide resolved
* @param {string} payloadPath
* @return {string}
*/
function resolveLocalOrProjectRoot(payloadPath) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

could we leave it where it was then to avoid the unnecessary diff/blame churn?

Instead, maybe the smoke runner could save a temporary file to disk, and pass that path? Does that sound better - temporary file creation vs this weird paths shenanigans?

you know I support this :) this was one of my fav features of #8962

@@ -129,25 +110,27 @@ function runLighthouse(url, configPath, isDebug) {
const cli = yargs
.help('help')
.describe({
'config-path': 'The path to the config JSON file',
'expectations-path': 'The path to the expected audit results file',
'smoke-id': 'The id of the smoke test to run',
Copy link
Collaborator

Choose a reason for hiding this comment

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

honestly at this point I don't see a reason we couldn't send the entire config/expectations as a stringified argument, this halfway point where you have to resolve everything ahead of time and then it still has to know how to lookup the definitions feels weird

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

agreed ... So it's:

  1. revert back to config/expectation paths and use tmp files as mentioned before
  2. pass objects via CLI args

Is this smokehouse.js script only meant to be used programmatically via run-smoke.js? I'm not sure if others use it directly. If not, then we can change it without breaking anyone's workflow and do option 2.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Oh, smokehouse.js still needs a file path for the config, since it calls lighthouse-cli/index.js --config-path=.... Seems like we should just stick to paths since we can't change that.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

But to further complicate things, writing the expectations to a temporary file means replacing/reviving RegExps.

Copy link
Collaborator Author

@connorjclark connorjclark Aug 5, 2019

Choose a reason for hiding this comment

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

OK, b/c of all the above I think this should just remain "smoke-id". Can still get rid of the config path/value thing though.

@@ -19,17 +19,28 @@
diff?: Difference | null;
}

export type ExpectedLHR = Pick<LH.Result, 'audits' | 'finalUrl' | 'requestedUrl' | 'runtimeError'>
interface ExpectedLHR {
audits: Record<string, any>;
Copy link
Collaborator

Choose a reason for hiding this comment

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

why is it divorced from LH.Result at all?

id: 'a11y',
config: smokehouseDir + 'a11y/a11y-config.js',
expectations: 'a11y/expectations.js',
expectations: require('./a11y/expectations.js'),
Copy link
Collaborator

Choose a reason for hiding this comment

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

static require paths for the smoke tests I'm all for, but the new {path, value} structure of config seems unnecessarily confusing. would it be possible to move to the model in #8962 of colocating the config/expectations and staticly require'ing in that file? IIUC that should alleviate the need for path here since we move to the transient config files :)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Let's drop the path/value thing in favor of writing temporary files for the config when passing to the smokehouse runner. That interface was the only reason path is needed.

Colocating the expectation/config seems like a bigger change to me and not one that's needed for static resolving to work.

@connorjclark
Copy link
Collaborator Author

FYI after a few nights of letting this settle in my mind, I'll say that the shimming workaround mentioned actually doesn't seem too bad to me anymore. So I wouldn't be against reverting most of these changes (and just keeping the type changes, which I believe is an improvement).

Will address @patrickhulce's comments now.

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.

can you give a sketch of the architecture here now and how it'll be used by these two different clients? Smokehouse keeps sprouting new layers while it seems like we could be doing some simplification here and move incrementally closer to #8962

lighthouse-cli/test/smokehouse/seo/expectations.js Outdated Show resolved Hide resolved
types/smokehouse.d.ts Outdated Show resolved Hide resolved
@connorjclark
Copy link
Collaborator Author

Smokehouse keeps sprouting new layers while it seems like we could be doing some simplification here and move incrementally closer to #8962

I think this does some slight simplification (the resolving thing, although rather self-contained, was weird to reason about), but I hope there's more we can do.

can you give a sketch of the architecture here now and how it'll be used by these two different clients?

I'll list out how I see all three of these clients being used (including LR).

First, there's this smoke test runner interface that I linked to in the OP:

await Lighthouse.Firehouse.runSmokes({
  runLighthouse: async (url, config) => {
    const {lhr, artifacts} = await doSomething(url, config);
    return {lhr, artifacts};
  },
  skip: (test, expectation) => {
    // return string (an explanation) or `false`
  },
  modify(test, expectation) {
    // ...
  },
}

This iterates over every smoke test definition (in series), using the given function to run lighthouse in an environment-specific way, and using the other parameters to skip or modify smoke tests to match the environment. It also logs the results. This is what the current LR smoke tests do, and I found myself needing the same thing when running the smoke tests in DevTools.

  1. Lightrider - currently does the above itself, requiring smoke-test-dfns.js and smokehouse-report.js. With the above interface, most of that goes away, it just requires firehouse.js (or whatever its named) and configures the options. These tests run in Node, so no concern re: browserifying. The fixture server is not needed locally, but is instead hosted in GAE.
  2. DevTools - Run as a layout test, which means in a browser, so firehouse.js and its dependencies should be browser-friendly. Requires the fixture server to run locally. You can see the WIP layout test here.
  3. lighthouse-cli - the normal way. This would not use the above smoke test runner, as it does some stuff that can't be generalized to fit that interface (the batching). It would continue to use smoke-test-dfns.js and smokehouse-report.js directly.

The Lightrider smoke tests are not fully-automated. They are meant to be run during every new roll while in staging, to notice any feature regressions due to the version of WRS that LR uses, or some other unexpected environment difference. Making it an automated test is possible with some additional work.

The DevTools smoke tests will also not be fully-automated at first. That will require running the fixture server during the layout tests, which either means figuring out how to run a node server in that test environment, or reimplementing it with the existing layout test runner features (or a python server, I guess). I see that as something that can be added later - I think using it as a manually-run test (just like Lightrider) is enough for a first pass. So the layout test won't actually run in the Chromium CI at first, but it will still leverage the test runner scripts that can be used locally.

@vercel vercel bot temporarily deployed to staging October 1, 2019 06:05 Inactive
Copy link
Collaborator

@patrickhulce patrickhulce left a comment

Choose a reason for hiding this comment

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

With #8962 basically dead, I think this is a good step in the new, right direction of smoketests everywhere 👍

LGTM

lighthouse-cli/test/smokehouse/seo/expectations.js Outdated Show resolved Hide resolved
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants