Skip to content

Commit

Permalink
Bug 1543247 - Part 1: Add mach browsertime command that installs an…
Browse files Browse the repository at this point in the history
…d invokes browsertime. r=Standard8,ahal

[browsertime](https://github.com/sitespeedio/browsertime) is a harness
for running performance tests, similar to Mozilla's Raptor testing
framework.  The Performance Team is using it locally with some
success, but we're running a heavily modified toolchain that is
challenging to install.  This mach command is intended to be leverage
for getting more folks able to use browsertime easily.

In particular, the version of browsertime that this installs has
nalexander's changes to support testing GeckoView-based vehicles.  If
this approach meets with approval, I'll continue to follow-up with
additional configuration and tooling layers to make it even easier to
drive GeckoView-based vehicles.

I elected to piggy-back install on the eslint installation process,
since this is very similar.  To that end, I generalized what was there
very slightly.  I elected not to try to move the existing code into a
more obvious shared location, although it might be possible, because
it wasn't clear what contexts the existing code would be invoked
from.  In particular I wasn't certain the code could rely on a
complete mozbuild checkout.

I did need to ensure the local Node.js binary is early on the PATH;
this was an issue I ran into with my initial Node/Yarn prototyping
many months ago.  At heart the issue is that package scripts in the
wild invoke a bare `node` or `npm` command; if there was a culture of
invoking $NODE or $NPM, this wouldn't be necessary.  There's no harm
doing it for ESlint, and it will help the next person who wants to
install an NPM package for tooling in this manner.

Differential Revision: https://phabricator.services.mozilla.com/D26820

--HG--
extra : moz-landing-system : lando
  • Loading branch information
ncalexan committed May 6, 2019
1 parent c9f5e41 commit a7e3d82
Show file tree
Hide file tree
Showing 6 changed files with 4,246 additions and 51 deletions.
3 changes: 2 additions & 1 deletion .hgignore
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,9 @@ _OPT\.OBJ/
# Ignore tox generated dir
.tox/

# Ignore ESLint node_modules
# Ignore ESLint and other tool's node_modules.
^node_modules/
^tools/browsertime/node_modules/
^tools/lint/eslint/eslint-plugin-mozilla/node_modules/

# Ignore talos virtualenv and tp5n files.
Expand Down
1 change: 1 addition & 0 deletions build/mach_bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
'testing/web-platform/mach_commands.py',
'testing/xpcshell/mach_commands.py',
'toolkit/components/telemetry/tests/marionette/mach_commands.py',
'tools/browsertime/mach_commands.py',
'tools/compare-locales/mach_commands.py',
'tools/docs/mach_commands.py',
'tools/lint/mach_commands.py',
Expand Down
105 changes: 105 additions & 0 deletions tools/browsertime/mach_commands.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

r'''Make it easy to install and run [browsertime](https://github.com/sitespeedio/browsertime).
Browsertime is a harness for running performance tests, similar to
Mozilla's Raptor testing framework. Browsertime is written in Node.js
and uses Selenium WebDriver to drive multiple browsers including
Chrome, Chrome for Android, Firefox, and (pending the resolution of
[Bug 1525126](https://bugzilla.mozilla.org/show_bug.cgi?id=1525126)
and similar tickets) Firefox for Android and GeckoView-based vehicles.
Right now a custom version of browsertime and the underlying
geckodriver binary are needed to support GeckoView-based vehicles;
this module accommodates those in-progress custom versions.
To get started, run
```
./mach browsertime --setup [--clobber]
```
This will populate `tools/browsertime/node_modules`.
To invoke browsertime, run
```
./mach browsertime [ARGS]
```
All arguments are passed through to browsertime.
'''

from __future__ import absolute_import, print_function, unicode_literals

import argparse
import logging
import os
import sys

import mozpack.path as mozpath
from mach.decorators import CommandArgument, CommandProvider, Command
from mozbuild.base import MachCommandBase
from mozbuild.nodeutil import find_node_executable

sys.path.append(mozpath.join(os.path.dirname(__file__), '..', '..', 'tools', 'lint', 'eslint'))
import setup_helper


@CommandProvider
class MachBrowsertime(MachCommandBase):
def setup(self, should_clobber=False):
if not setup_helper.check_node_executables_valid():
return 1

return setup_helper.package_setup(
os.path.dirname(__file__),
'browsertime',
should_clobber=should_clobber)

def node(self, args):
node, _ = find_node_executable()

# Ensure that bare `node` and `npm` in scripts, including post-install
# scripts, finds the binary we're invoking with. Without this, it's
# easy for compiled extensions to get mismatched versions of the Node.js
# extension API.
path = os.environ.get('PATH', '').split(os.pathsep)
node_path = os.path.dirname(node)
if node_path not in path:
path = [node_path] + path

return self.run_process(
[node] + args,
append_env={'PATH': os.pathsep.join(path)},
pass_thru=True, # Allow user to run Node interactively.
ensure_exit_code=False, # Don't throw on non-zero exit code.
cwd=mozpath.join(self.topsrcdir))

def bin_path(self):
# On Windows, invoking `node_modules/.bin/browsertime{.cmd}`
# doesn't work when invoked as an argument to our specific
# binary. Since we want our version of node, invoke the
# actual script directly.
return mozpath.join(
os.path.dirname(__file__),
'node_modules',
'browsertime',
'bin',
'browsertime.js')

@Command('browsertime', category='testing',
description='Run [browsertime](https://github.com/sitespeedio/browsertime) '
'performance tests.')
@CommandArgument('--verbose', action='store_true',
help='Verbose output for what commands the build is running.')
@CommandArgument('--setup', default=False, action='store_true')
@CommandArgument('--clobber', default=False, action='store_true')
@CommandArgument('args', nargs=argparse.REMAINDER)
def browsertime(self, args, verbose=False, setup=False, clobber=False):
if setup:
return self.setup(should_clobber=clobber)

if not verbose:
# Avoid logging the command
self.log_manager.terminal_handler.setLevel(logging.CRITICAL)

return self.node([self.bin_path()] + args)
Loading

0 comments on commit a7e3d82

Please sign in to comment.