servo/python/servo/testing_commands.py
bors-servo f06e0a818d auto merge of #4048 : mttr/servo/mach_unit_test_fix, r=larsbergstrom
This is a quick and dirty workaround for issue #3928. Basically, `cargo test` is deleting `./target/servo`, which is clearly not ideal if we want to do anything with servo after running the unit tests. This PR makes sure to rebuild after running `./mach test-unit`.

I'm not familiar enough with cargo yet to know why it's doing this or what better alternatives there are to fixing this. Having to rebuild afterwards feels pretty ugly to me, but my rationalization right now is that the time it takes to build is negligible in comparison to the time it takes to run the tests. Ideally, this should be something we could take care of in Cargo.toml, but again, I'm new to this (and the documentation seems less than helpful from what I can tell so far).

I won't be available for the rest of the day, so if anyone has suggestions, or wants to wait for a better solution, I'll get back to it tomorrow probably. Otherwise, this PR at least makes `./mach test` work properly, so there's that.
2014-12-22 14:05:34 -07:00

224 lines
7.9 KiB
Python

from __future__ import print_function, unicode_literals
import argparse
import os
import os.path as path
import subprocess
from time import time
from mach.registrar import Registrar
from mach.decorators import (
CommandArgument,
CommandProvider,
Command,
)
from servo.command_base import CommandBase
import tidy
@CommandProvider
class MachCommands(CommandBase):
def __init__(self, context):
CommandBase.__init__(self, context)
if not hasattr(self.context, "built_tests"):
self.context.built_tests = False
def ensure_built_tests(self):
if self.context.built_tests:
return
Registrar.dispatch('build-tests', context=self.context)
self.context.built_tests = True
def find_test(self, prefix):
target_contents = os.listdir(path.join(
self.context.topdir, "components", "servo", "target"))
for filename in target_contents:
if filename.startswith(prefix + "-"):
filepath = path.join(
self.context.topdir, "components", "servo",
"target", filename)
if path.isfile(filepath) and os.access(filepath, os.X_OK):
return filepath
def run_test(self, prefix, args=[]):
t = self.find_test(prefix)
if t:
return subprocess.call([t] + args, env=self.build_env())
def infer_test_by_dir(self, params):
maybe_path = path.normpath(params[0])
mach_command = path.join(self.context.topdir, "mach")
args = None
if not path.exists(maybe_path):
print("%s is not a valid file or directory" % maybe_path)
return 1
test_dirs = [
# path, mach test command, optional flag for path argument
(path.join("tests", "content"), "test-content", None),
(path.join("tests", "wpt"), "test-wpt", None),
(path.join("tests", "ref"), "test-ref", ["--name"]),
]
for test_dir, test_name, path_flag in test_dirs:
if not path_flag:
path_flag = []
if test_dir in maybe_path:
args = ([mach_command, test_name] + path_flag +
[maybe_path] + params[1:])
break
else:
print("%s is not a valid test file or directory" % maybe_path)
return 1
return subprocess.call(args, env=self.build_env())
@Command('test',
description='Run all Servo tests',
category='testing')
@CommandArgument('params', default=None, nargs="...",
help="Optionally select test based on "
"test file directory")
def test(self, params):
if params:
return self.infer_test_by_dir(params)
test_start = time()
for t in ["tidy", "ref", "content", "wpt", "unit"]:
Registrar.dispatch("test-%s" % t, context=self.context)
elapsed = time() - test_start
print("Tests completed in %0.2fs" % elapsed)
@Command('test-unit',
description='Run unit tests',
category='testing')
@CommandArgument('--component', '-c', default=None,
help="Specific component to test")
@CommandArgument('test_name', nargs=argparse.REMAINDER,
help="Only run tests that match this pattern")
def test_unit(self, test_name=None, component=None):
if test_name is None:
test_name = []
self.ensure_bootstrapped()
self.ensure_built_tests()
ret = self.run_test("servo", test_name) != 0
def cargo_test(component):
return 0 != subprocess.call(
["cargo", "test", "-p", component]
+ test_name, env=self.build_env(), cwd=self.servo_crate())
if component is not None:
ret = ret or cargo_test(component)
else:
for c in os.listdir("components"):
if c != "servo":
ret = ret or cargo_test(c)
print("WARNING: test-unit has probably destroyed your servo binary "
" (see https://github.com/rust-lang/cargo/issues/961 ). You "
" may want to rebuild now.")
return ret
@Command('test-ref',
description='Run the reference tests',
category='testing')
@CommandArgument('--kind', '-k', default=None,
help="'cpu' or 'gpu' (default both)")
@CommandArgument('--name', default=None,
help="Only run tests that match this pattern. If the "
"path to the ref test directory is included, it "
"will automatically be trimmed out.")
@CommandArgument(
'servo_params', default=None, nargs=argparse.REMAINDER,
help="Command-line arguments to be passed through to Servo")
def test_ref(self, kind=None, name=None, servo_params=None):
self.ensure_bootstrapped()
self.ensure_built_tests()
kinds = ["cpu", "gpu"] if kind is None else [kind]
test_path = path.join(self.context.topdir, "tests", "ref")
error = False
test_start = time()
for k in kinds:
print("Running %s reftests..." % k)
test_args = [k, test_path]
if name is not None:
maybe_path = path.normpath(name)
ref_path = path.join("tests", "ref")
# Check to see if we were passed something leading with the
# path to the ref test directory, and trim it so that reftest
# knows how to filter it.
if ref_path in maybe_path:
test_args.append(path.relpath(maybe_path, ref_path))
else:
test_args.append(name)
if servo_params is not None:
test_args += ["--"] + servo_params
ret = self.run_test("reftest", test_args)
error = error or ret != 0
elapsed = time() - test_start
print("Reference tests completed in %0.2fs" % elapsed)
if error:
return 1
@Command('test-content',
description='Run the content tests',
category='testing')
@CommandArgument('test_name', default=None, nargs="?",
help="Only run tests that match this pattern")
def test_content(self, test_name=None):
self.ensure_bootstrapped()
self.ensure_built_tests()
test_path = path.join(self.context.topdir, "tests", "content")
test_args = ["--source-dir=%s" % test_path]
if test_name is not None:
test_args.append(test_name)
test_start = time()
ret = self.run_test("contenttest", test_args)
elapsed = time() - test_start
print("Content tests completed in %0.2fs" % elapsed)
return ret
@Command('test-tidy',
description='Run the source code tidiness check',
category='testing')
def test_tidy(self):
return tidy.scan()
@Command('test-wpt',
description='Run the web platform tests',
category='testing')
@CommandArgument(
'params', default=None, nargs='...',
help="Command-line arguments to be passed through to wpt/run.sh")
def test_wpt(self, params=None):
if params is None:
params = []
else:
# Allow the first argument to be a relative path from Servo's root
# directory, converting it to `--include some/wpt/test.html`
maybe_path = path.normpath(params[0])
wpt_path = path.join('tests', 'wpt', 'web-platform-tests')
if path.exists(maybe_path) and wpt_path in maybe_path:
params = ["--include",
path.relpath(maybe_path, wpt_path)] + params[1:]
return subprocess.call(
["bash", path.join("tests", "wpt", "run.sh")] + params,
env=self.build_env())