Skip to content

Commit

Permalink
[workspace] Add drake_models regression test
Browse files Browse the repository at this point in the history
  • Loading branch information
jwnimmer-tri committed Aug 14, 2023
1 parent bedd6b8 commit cb0babc
Show file tree
Hide file tree
Showing 2 changed files with 129 additions and 0 deletions.
19 changes: 19 additions & 0 deletions tools/workspace/drake_models/BUILD.bazel
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()
110 changes: 110 additions & 0 deletions tools/workspace/drake_models/test/parse_test.py
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)

0 comments on commit cb0babc

Please sign in to comment.