Skip to content
This repository was archived by the owner on Jul 12, 2023. It is now read-only.

Conversation

sethvargo
Copy link
Contributor

@sethvargo sethvargo commented Oct 22, 2020

After evaluation, I decided to use chromedp since it's a pure-go solution that should work headlessly on our existing CI infrastructure (fingers crossed).

This also adds a few new internal-only packages to help with testing:

  • internal/project - project-wide helpers. Currently the only function is one that returns the filesystem root of the project, which is needed for telling the server where to find its assets. It will also be used by enx-redirector and any other filesystem-ey things.

  • internal/envstest - globally shared test helpers. I'm going to start centralizing things here across all our test suites. This package also includes all the logic and helpers for spinning up a full in-memory UI server (with database and dependencies) for local testing.

  • internal/browser - wrapper around chromedp. It's small, but I expect to add more helpers and things as we expand our testing.

Release Note

Add test harness for headless browser testing

@googlebot googlebot added the cla: yes Auto: added by CLA bot when all committers have signed a CLA. label Oct 22, 2020
@sethvargo
Copy link
Contributor Author

Hmm... I guess chromedp needs Chrome 😄

@chaodaiG any ideas of how we'd get chrome into our binary? There's a base image we could borrow from: https://github.com/chromedp/docker-headless-shell

@mikehelmick
Copy link
Contributor

For FB config - can we make that injected config from the runtime environment?

Copy link
Contributor

@jeremyfaller jeremyfaller left a comment

Choose a reason for hiding this comment

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

Modulo some nits, this LGTM.

// NewServer creates a new test UI server instance. When this function returns,
// a full UI server will be running locally on a random port. Cleanup is handled
// automatically.
func NewServer(tb testing.TB) *TestServerResponse {
Copy link
Contributor

Choose a reason for hiding this comment

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

Small nomenclature niggle. The function's entitled NewServer yet it doesn't return a Server type, it returns a response. It feels like here (and the below function NewServerConfig) are either misnamed, or the the type returned is.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It returns the server and everything needed to run it. We have to return things like the database because tests might need to insert or assert records.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm open to other names

var _, self, _, _ = runtime.Caller(0)

// Root returns the filepath to the root of this project.
func Root() string {
Copy link
Contributor

Choose a reason for hiding this comment

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

This could be a global constant, like self, and the init generation code in the compiler will sort out the dependency chain.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It'd be a global var, which would be mutable. AFAIK, you can't create a constant that uses filepath.Join since it wouldn't be constant across systems.

Copy link
Contributor

Choose a reason for hiding this comment

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

fair point. Root could still be a LHS.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What's an LHS?

Copy link
Contributor

@jeremyfaller jeremyfaller Oct 29, 2020

Choose a reason for hiding this comment

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

left hand side. common compiler nomenclature for a "result of an expression"

}

// RandomString returns a random hex-encoded string of the given length.
func RandomString(tb testing.TB, length int) string {
Copy link
Contributor

Choose a reason for hiding this comment

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

API is slightly clunky. length is the length of the random string, not the encoded string. Might want to document.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It is the length of the encoded string (that's why I divide by 2).

@chaodaiG
Copy link
Contributor

Hmm... I guess chromedp needs Chrome 😄

@chaodaiG any ideas of how we'd get chrome into our binary? There's a base image we could borrow from: https://github.com/chromedp/docker-headless-shell

How about add docker-headless-shell in prow test base image, and chromedp references it's entrypoint /headless-shell/headless-shell as ExecPath https://godoc.org/github.com/knq/chromedp#ExecPath?

@sethvargo
Copy link
Contributor Author

sethvargo commented Oct 22, 2020

@chaodaiG That could work, but it will make running tests locally harder. It would be better if we could have chrome or chrome-headless in $PATH.

@chaodaiG
Copy link
Contributor

@chaodaiG That could work, but it will make running tests locally harder. It would be better if we could have chrome or chrome-headless in $PATH.

Agreed, we can append /headless-shell to PATH in dockerfile

@sethvargo
Copy link
Contributor Author

@chaodaiG sounds good. Do you have any cycles to work on that today? I imagine we're going to have some trial and error to get it working against this PR.

@chaodaiG
Copy link
Contributor

@chaodaiG sounds good. Do you have any cycles to work on that today? I imagine we're going to have some trial and error to get it working against this PR.

google/exposure-notifications-server#1104
@sethvargo could you take a quick look? If there is no obvious problem I'll push the image for testing current PR

@sethvargo
Copy link
Contributor Author

Just approved

@chaodaiG
Copy link
Contributor

Image pushed

@chaodaiG
Copy link
Contributor

/retest

@sethvargo
Copy link
Contributor Author

Hmm @chaodaiG

could not dial "ws://127.0.0.1:42897/devtools/browser/91b93c42-b53a-44d1-8b9c-7c822949108a": EOF

Different error this time. Do we need to do something to allow for that networking?

@sethvargo sethvargo force-pushed the sethvargo/browser branch 2 times, most recently from 1d683f6 to a56da70 Compare October 28, 2020 00:37
@sethvargo sethvargo force-pushed the sethvargo/browser branch 9 times, most recently from 3f52773 to f68dea8 Compare October 28, 2020 22:45
@sethvargo sethvargo force-pushed the sethvargo/browser branch 3 times, most recently from e154154 to b1fb8e6 Compare October 29, 2020 15:05
Copy link
Contributor Author

@sethvargo sethvargo left a comment

Choose a reason for hiding this comment

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

@chaodaiG @jeremyfaller @whaught this is ready for review now

var _, self, _, _ = runtime.Caller(0)

// Root returns the filepath to the root of this project.
func Root() string {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

What's an LHS?

Copy link
Contributor

@chaodaiG chaodaiG left a comment

Choose a reason for hiding this comment

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

LGTM generally, left a comment

After evaluation, I decided to use chromedp since it's a pure-go
solution that should work headlessly on our existing CI infrastructure
(fingers crossed).

This also adds a few new internal-only packages to help with testing:

- `internal/project` - project-wide helpers. Currently the only function
is one that returns the filesystem root of the project, which is needed
for telling the server where to find its assets. It will also be used by
enx-redirector and any other filesystem-ey things.

- `internal/envstest` - globally shared test helpers. I'm going to start
centralizing things here across all our test suites. This package also
includes all the logic and helpers for spinning up a full in-memory UI
server (with database and dependencies) for local testing.

- `internal/browser` - wrapper around chromedp. It's small, but I expect
to add more helpers and things as we expand our testing.
@chaodaiG
Copy link
Contributor

/lgtm
/approve

@google-oss-robot
Copy link

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: chaodaiG, sethvargo

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@google-oss-robot google-oss-robot merged commit 73782ae into main Oct 29, 2020
@google-oss-robot google-oss-robot deleted the sethvargo/browser branch October 29, 2020 15:41
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Oct 30, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
cla: yes Auto: added by CLA bot when all committers have signed a CLA.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants