Skip to content
Merged
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
55 changes: 55 additions & 0 deletions tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,61 @@ def test_pr2(self):
rp.models.PR2()


class TestModelSmoke(unittest.TestCase):
"""Generic smoke test: every model exported from DH/URDF/ETS must
construct with no arguments.

The tests above are hand-written per model, so a model can be added to
__all__ and never get a dedicated test -- Valkyrie, Fetch, KinovaGen3,
FetchCamera and LBR all sat with zero test coverage this way, three of
them silently broken (see tech-debt.md for details/history). Iterating
__all__ directly means newly-added models are covered automatically.
"""

# (category, class name) pairs known to currently fail to construct.
# Remove an entry once its underlying issue is actually fixed -- if you
# don't, this test starts failing for the *opposite* reason (a listed
# failure unexpectedly started passing).
EXPECTED_FAILURES = {
# Bundled rtb-data xacro tree names this directory "kuka_lbr_iiwa",
# but the xacro file's own $(find kuka_lbr_iiwa_support) expects
# the "_support" suffix -- needs an rtb-data rename + republish.
# See tech-debt.md, "rtb-data" section.
("URDF", "LBR"),
}

def test_all_models_construct(self):
unexpected_failures = []
unexpected_passes = []

for category_name in ("DH", "URDF", "ETS"):
category = getattr(rp.models, category_name)
for name in category.__all__:
cls = getattr(category, name)
key = (category_name, name)
try:
cls()
except Exception as e:
if key not in self.EXPECTED_FAILURES:
unexpected_failures.append(
f"{category_name}.{name}: {type(e).__name__}: {e}"
)
else:
if key in self.EXPECTED_FAILURES:
unexpected_passes.append(f"{category_name}.{name}")

if unexpected_failures:
self.fail(
"Model(s) failed to construct:\n" + "\n".join(unexpected_failures)
)
if unexpected_passes:
self.fail(
"Model(s) in EXPECTED_FAILURES now construct successfully -- "
"remove from EXPECTED_FAILURES (and close out the matching "
"tech-debt.md entry):\n" + "\n".join(unexpected_passes)
)


if __name__ == "__main__": # pragma nocover
unittest.main()
# pytest.main(['tests/test_SerialLink.py'])
Loading