-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[workspace] Add drake_models regression test
- Loading branch information
1 parent
bedd6b8
commit cb0babc
Showing
2 changed files
with
129 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,22 @@ | ||
load("//doc:defs.bzl", "enumerate_filegroup") | ||
load("//tools/skylark:drake_py.bzl", "drake_py_unittest") | ||
load("//tools/lint:lint.bzl", "add_lint_tests") | ||
|
||
enumerate_filegroup( | ||
name = "inventory.txt", | ||
data = ["@drake_models"], | ||
) | ||
|
||
drake_py_unittest( | ||
name = "parse_test", | ||
data = [ | ||
":inventory.txt", | ||
"@drake_models", | ||
], | ||
deps = [ | ||
"//bindings/pydrake", | ||
"@bazel_tools//tools/python/runfiles", | ||
], | ||
) | ||
|
||
add_lint_tests() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
from pathlib import Path | ||
from typing import Iterator | ||
import unittest | ||
|
||
from bazel_tools.tools.python.runfiles import runfiles | ||
|
||
from pydrake.planning import RobotDiagramBuilder | ||
|
||
|
||
class TestDrakeModels(unittest.TestCase): | ||
|
||
@staticmethod | ||
def package_xml() -> Path: | ||
"""Returns the path to drake_models/package.xml in runfiles. | ||
""" | ||
manifest = runfiles.Create() | ||
result = Path(manifest.Rlocation("drake_models/package.xml")) | ||
assert result.exists(), result | ||
return result | ||
|
||
@staticmethod | ||
def inventory() -> Iterator[str]: | ||
"""Generates the list of all the runfiles of @drake_models. The result | ||
is strings like "drake_models/veggies/pepper.png". | ||
""" | ||
manifest = runfiles.Create() | ||
inventory = Path(manifest.Rlocation( | ||
"drake/tools/workspace/drake_models/inventory.txt")) | ||
with open(inventory, encoding="utf-8") as f: | ||
for line in f.readlines(): | ||
assert line.startswith("drake_models/") | ||
yield line.strip() | ||
|
||
@staticmethod | ||
def get_all_models() -> Iterator[str]: | ||
"""Generates the Paths of all top-level model files in @drake_models. | ||
The result is URLs like "package://drake_models/veggies/pepper.sdf". | ||
""" | ||
for path in TestDrakeModels.inventory(): | ||
url = f"package://{path}" | ||
if any([path.endswith(".dmd.yaml"), | ||
path.endswith(".sdf"), | ||
path.endswith(".urdf")]): | ||
yield url | ||
elif path.endswith(".xml"): | ||
# We can't tell a MuJoCo file just by its suffix. | ||
runfiles = TestDrakeModels.package_xml().parent.parent | ||
if "<mujoco" in (runfiles / path).open().read(): | ||
yield url | ||
return | ||
|
||
def test_all_models(self): | ||
"""Checks that all model files in @drake_models parse without any | ||
errors nor warnings. | ||
""" | ||
all_models = list(TestDrakeModels.get_all_models()) | ||
|
||
# Allow warnings on these models until they are repaired. | ||
models_with_warnings = [ | ||
# TODO(#19992) for tracking these warnings. | ||
"package://drake_models/atlas/atlas_convex_hull.urdf", | ||
"package://drake_models/atlas/atlas_minimal_contact.urdf", | ||
"package://drake_models/atlas/robotiq_simple.urdf", | ||
] | ||
self.assertFalse(set(models_with_warnings) - set(all_models)) | ||
|
||
# Allow errors on these models until they are repaired. | ||
models_with_errors = [ | ||
# TODO(#19992) for tracking these errors. | ||
"package://drake_models/atlas/robotiq.urdf", | ||
"package://drake_models/atlas/robotiq_tendons.urdf", | ||
] | ||
self.assertFalse(set(models_with_errors) - set(all_models)) | ||
self.assertFalse(set(models_with_warnings) & set(models_with_errors)) | ||
|
||
# Run all tests. | ||
for url in all_models: | ||
with self.subTest(url=url): | ||
expect_warnings = url in models_with_warnings | ||
expect_errors = url in models_with_errors | ||
self._check_model( | ||
url=url, | ||
expect_warnings=expect_warnings, | ||
expect_errors=expect_errors) | ||
|
||
def _check_model(self, *, | ||
url: str, | ||
expect_warnings: bool, | ||
expect_errors: bool): | ||
"""Checks that when parsed, the given url contains warnings and/or | ||
errors consistent with the expected conditions. | ||
""" | ||
if expect_errors: | ||
with self.assertRaises(Exception): | ||
self._parse(url=url, strict=False) | ||
return | ||
if expect_warnings: | ||
self._parse(url=url, strict=False) | ||
with self.assertRaises(Exception): | ||
self._parse(url=url, strict=True) | ||
return | ||
self._parse(url=url, strict=True) | ||
|
||
def _parse(self, *, url: str, strict: bool): | ||
builder = RobotDiagramBuilder() | ||
parser = builder.parser() | ||
parser.package_map().AddPackageXml(str(self.package_xml())) | ||
if strict: | ||
parser.SetStrictParsing() | ||
parser.AddModels(url=url) |