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

Precalculate browser.version and browser.userAgent to prevent the I/O call #1361

Merged
merged 6 commits into from
May 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions browser/browser_mapping.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,14 @@ func mapBrowser(vu moduleVU) mapping { //nolint:funlen,cyclop
if err != nil {
return "", err
}
return b.UserAgent() //nolint:wrapcheck
return b.UserAgent(), nil
},
"version": func() (string, error) {
b, err := vu.browser()
if err != nil {
return "", err
}
return b.Version() //nolint:wrapcheck
return b.Version(), nil
},
"newPage": func(opts goja.Value) (mapping, error) {
b, err := vu.browser()
Expand Down
4 changes: 2 additions & 2 deletions browser/mapping_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -255,8 +255,8 @@ type browserAPI interface {
NewContext(opts goja.Value) (*common.BrowserContext, error)
NewPage(opts goja.Value) (*common.Page, error)
On(string) (bool, error)
UserAgent() (string, error)
Version() (string, error)
UserAgent() string
Version() string
}

// browserContextAPI is the public interface of a CDP browser context.
Expand Down
56 changes: 41 additions & 15 deletions common/browser.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,23 @@ type Browser struct {
// Used to display a warning when the browser is reclosed.
closed bool

// version caches the browser version information.
version browserVersion

vu k6modules.VU

logger *log.Logger
}

// browserVersion is a struct to hold the browser version information.
type browserVersion struct {
protocolVersion string
product string
revision string
userAgent string
jsVersion string
}

// NewBrowser creates a new browser, connects to it, then returns it.
func NewBrowser(
ctx context.Context,
Expand All @@ -85,6 +97,13 @@ func NewBrowser(
if err := b.connect(); err != nil {
return nil, err
}

// cache the browser version information.
var err error
if b.version, err = b.fetchVersion(); err != nil {
return nil, err
}

return b, nil
}

Expand Down Expand Up @@ -628,27 +647,34 @@ func (b *Browser) On(event string) (bool, error) {
}

// UserAgent returns the controlled browser's user agent string.
func (b *Browser) UserAgent() (string, error) {
action := cdpbrowser.GetVersion()
_, _, _, ua, _, err := action.Do(cdp.WithExecutor(b.ctx, b.conn)) //nolint:dogsled
if err != nil {
return "", fmt.Errorf("getting browser user agent: %w", err)
}
return ua, nil
func (b *Browser) UserAgent() string {
return b.version.userAgent
}

// Version returns the controlled browser's version.
func (b *Browser) Version() (string, error) {
action := cdpbrowser.GetVersion()
_, product, _, _, _, err := action.Do(cdp.WithExecutor(b.ctx, b.conn)) //nolint:dogsled
if err != nil {
return "", fmt.Errorf("getting browser version: %w", err)
}
func (b *Browser) Version() string {
product := b.version.product
i := strings.Index(product, "/")
if i == -1 {
return product, nil
return product
}
return product[i+1:], nil
return product[i+1:]
}

// fetchVersion returns the browser version information.
func (b *Browser) fetchVersion() (browserVersion, error) {
var (
bv browserVersion
err error
)
bv.protocolVersion, bv.product, bv.revision, bv.userAgent, bv.jsVersion, err = cdpbrowser.
GetVersion().
Do(cdp.WithExecutor(b.ctx, b.conn))
if err != nil {
return browserVersion{}, fmt.Errorf("getting browser version information: %w", err)
}

return bv, nil
}

// WsURL returns the Websocket URL that the browser is listening on for CDP clients.
Expand Down
6 changes: 2 additions & 4 deletions tests/browser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,8 +197,7 @@ func TestBrowserVersion(t *testing.T) {
const re = `^\d+\.\d+\.\d+\.\d+$`
r, err := regexp.Compile(re) //nolint:gocritic
require.NoError(t, err)
ver, err := newTestBrowser(t).Version()
require.NoError(t, err)
ver := newTestBrowser(t).Version()
assert.Regexp(t, r, ver, "expected browser version to match regex %q, but found %q", re, ver)
}

Expand All @@ -212,8 +211,7 @@ func TestBrowserUserAgent(t *testing.T) {

// testBrowserVersion() tests the version already
// just look for "Headless" in UserAgent
ua, err := b.UserAgent()
require.NoError(t, err)
ua := b.UserAgent()
if prefix := "Mozilla/5.0"; !strings.HasPrefix(ua, prefix) {
t.Errorf("UserAgent should start with %q, but got: %q", prefix, ua)
}
Expand Down
Loading