Skip to content

Commit

Permalink
[pybind] Moves a historically flaky RenderEngine test into its own te…
Browse files Browse the repository at this point in the history
…st (RobotLocomotion#14724)

The test that confirmed derived RenderEngines are informed if they fail
to implement the rendering API has proven to be flaky on the mac. This
moves that test into its own "test" that can be marked flaky.

No new code is written. The old test just received some new doc strings
to provide a bit more context.
  • Loading branch information
SeanCurtis-TRI authored Mar 2, 2021
1 parent e925535 commit 5a7203e
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 65 deletions.
10 changes: 10 additions & 0 deletions bindings/pydrake/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,16 @@ drake_py_unittest(
],
)

drake_py_unittest(
name = "geometry_render_engine_subclass_test",
flaky = True,
deps = [
":geometry_py",
"//bindings/pydrake/common/test_utilities",
"//bindings/pydrake/systems:sensors_py",
],
)

drake_py_unittest(
name = "lcm_test",
deps = [
Expand Down
88 changes: 88 additions & 0 deletions bindings/pydrake/test/geometry_render_engine_subclass_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
"""For reasons not yet understood (see issue #14686), the unit tests where we
confirm the semantics of deriving a RenderEngine implementation in python are
flaky and are therefore being isolated (see issue #14720)."""

import pydrake.geometry as mut

from math import pi
import unittest

from pydrake.math import RigidTransform, RigidTransform_
from pydrake.systems.sensors import (
CameraInfo,
ImageRgba8U,
ImageDepth32F,
ImageLabel16I,
)


class TestRenderEngineSubclass(unittest.TestCase):

def test_unimplemented_rendering(self):
"""The RenderEngine API throws exceptions for derived implementations
that don't override DoRender*Image (or Render*Image for the deprecated
API). This test confirms that behavior propagates down to Python."""
class MinimalEngine(mut.render.RenderEngine):
"""Minimal implementation of the RenderEngine virtual API"""
def UpdateViewpoint(self, X_WC):
pass

def DoRegisterVisual(self, id, shape, properties, X_WG):
pass

def DoUpdateVisualPose(self, id, X_WG):
pass

def DoRemoveGeometry(self, id):
pass

def DoClone(self):
pass

class ColorOnlyEngine(MinimalEngine):
"""Rendering Depth and Label images should throw"""
def DoRenderColorImage(self, camera, image_out):
pass

class DepthOnlyEngine(MinimalEngine):
"""Rendering Color and Label images should throw"""
def DoRenderDepthImage(self, camera, image_out):
pass

class LabelOnlyEngine(MinimalEngine):
"""Rendering Color and Depth images should throw"""
def DoRenderLabelImage(self, camera, image_out):
pass

identity = RigidTransform_[float]()
intrinsics = CameraInfo(10, 10, pi / 4)
core = mut.render.RenderCameraCore("n/a", intrinsics,
mut.render.ClippingRange(0.1, 10),
identity)
color_cam = mut.render.ColorRenderCamera(core, False)
depth_cam = mut.render.DepthRenderCamera(
core, mut.render.DepthRange(0.1, 9))
color_image = ImageRgba8U(intrinsics.width(), intrinsics.height())
depth_image = ImageDepth32F(intrinsics.width(), intrinsics.height())
label_image = ImageLabel16I(intrinsics.width(), intrinsics.height())

color_only = ColorOnlyEngine()
color_only.RenderColorImage(color_cam, color_image)
with self.assertRaisesRegex(RuntimeError, ".+pure virtual function.+"):
color_only.RenderDepthImage(depth_cam, depth_image)
with self.assertRaisesRegex(RuntimeError, ".+pure virtual function.+"):
color_only.RenderLabelImage(color_cam, label_image)

depth_only = DepthOnlyEngine()
with self.assertRaisesRegex(RuntimeError, ".+pure virtual function.+"):
depth_only.RenderColorImage(color_cam, color_image)
depth_only.RenderDepthImage(depth_cam, depth_image)
with self.assertRaisesRegex(RuntimeError, ".+pure virtual function.+"):
depth_only.RenderLabelImage(color_cam, label_image)

label_only = LabelOnlyEngine()
with self.assertRaisesRegex(RuntimeError, ".+pure virtual function.+"):
label_only.RenderColorImage(color_cam, color_image)
with self.assertRaisesRegex(RuntimeError, ".+pure virtual function.+"):
label_only.RenderDepthImage(depth_cam, depth_image)
label_only.RenderLabelImage(color_cam, label_image)
65 changes: 0 additions & 65 deletions bindings/pydrake/test/geometry_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -797,71 +797,6 @@ def test_value_instantiations(self, T):
Value[mut.Rgba]
Value[mut.render.RenderLabel]

def test_unimplemented_rendering(self):
# Test that a derived RenderEngine has implementations of
# DoRender*Image that throw something suggestive of "not implemented"
# and that they are overridable.
class MinimalEngine(mut.render.RenderEngine):
def UpdateViewpoint(self, X_WC):
pass

def DoRegisterVisual(self, id, shae, properties, X_WG):
pass

def DoUpdateVisualPose(self, id, X_WG):
pass

def DoRemoveGeometry(self, id):
pass

def DoClone(self):
pass

class ColorOnlyEngine(MinimalEngine):
def DoRenderColorImage(self, camera, image_out):
pass

class DepthOnlyEngine(MinimalEngine):
def DoRenderDepthImage(self, camera, image_out):
pass

class LabelOnlyEngine(MinimalEngine):
def DoRenderLabelImage(self, camera, image_out):
pass

identity = RigidTransform_[float]()
intrinsics = CameraInfo(10, 10, np.pi / 4)
core = mut.render.RenderCameraCore("n/a", intrinsics,
mut.render.ClippingRange(0.1, 10),
identity)
color_cam = mut.render.ColorRenderCamera(core, False)
depth_cam = mut.render.DepthRenderCamera(
core, mut.render.DepthRange(0.1, 9))
color_image = ImageRgba8U(intrinsics.width(), intrinsics.height())
depth_image = ImageDepth32F(intrinsics.width(), intrinsics.height())
label_image = ImageLabel16I(intrinsics.width(), intrinsics.height())

color_only = ColorOnlyEngine()
color_only.RenderColorImage(color_cam, color_image)
with self.assertRaisesRegex(RuntimeError, ".+pure virtual function.+"):
color_only.RenderDepthImage(depth_cam, depth_image)
with self.assertRaisesRegex(RuntimeError, ".+pure virtual function.+"):
color_only.RenderLabelImage(color_cam, label_image)

depth_only = DepthOnlyEngine()
with self.assertRaisesRegex(RuntimeError, ".+pure virtual function.+"):
depth_only.RenderColorImage(color_cam, color_image)
depth_only.RenderDepthImage(depth_cam, depth_image)
with self.assertRaisesRegex(RuntimeError, ".+pure virtual function.+"):
depth_only.RenderLabelImage(color_cam, label_image)

label_only = LabelOnlyEngine()
with self.assertRaisesRegex(RuntimeError, ".+pure virtual function.+"):
label_only.RenderColorImage(color_cam, color_image)
with self.assertRaisesRegex(RuntimeError, ".+pure virtual function.+"):
label_only.RenderDepthImage(depth_cam, depth_image)
label_only.RenderLabelImage(color_cam, label_image)

def test_render_engine_api(self):
class DummyRenderEngine(mut.render.RenderEngine):
"""Mirror of C++ DummyRenderEngine."""
Expand Down

0 comments on commit 5a7203e

Please sign in to comment.