Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Default ROS_HOME and ROS_LOG_DIR env vars in ros2_cpp_test #100

Merged
merged 13 commits into from
May 7, 2023

Conversation

lalten
Copy link
Contributor

@lalten lalten commented Apr 21, 2023

Default ROS_HOME and ROS_LOG_DIR env vars in ros2_cpp_test to TEST_UNDECLARED_OUTPUTS_DIR.
This is of course inspired by

os.environ['ROS_HOME'] = test_outputs_dir
os.environ['ROS_LOG_DIR'] = test_outputs_dir

TEST_UNDECLARED_OUTPUTS_DIR is optional(https://bazel.build/reference/test-encyclopedia#initial-conditions), only TEST_TMPDIR is required to be present. However I would argue that currently users have to set this manually already via the env attribute, so there just would not be any change for users where the var is not available.

@lalten lalten force-pushed the set-bazel-test-env-for-ros2-cpp-test branch from bc07f3a to a4a0435 Compare April 21, 2023 16:27
@mvukov
Copy link
Owner

mvukov commented Apr 22, 2023

Your observation regarding TEST_UNDECLARED_OUTPUTS_DIR is spot-on. I would leave Bazel macro as-is, and change the templates (test.py.tpl and pytest_wrapper.py.tpl) directly instead. E.g.

test_outputs_dir = os.environ.get('TEST_UNDECLARED_OUTPUTS_DIR')
if test_outputs_dir is None:
    test_outputs_dir = os.environ.get('TEST_TMPDIR')
if test_outputs_dir is None:
    test_outputs_dir = os.getcwd()

os.environ['ROS_HOME'] = test_outputs_dir
os.environ['ROS_LOG_DIR'] = test_outputs_dir

The second if may still be needed if folks run tests with bazel run.

The rclcpp test is fine for me.

@lalten lalten force-pushed the set-bazel-test-env-for-ros2-cpp-test branch from 81118f5 to 1bfe4fb Compare April 22, 2023 23:43
@lalten
Copy link
Contributor Author

lalten commented Apr 22, 2023

leave Bazel macro as-is, and change the templates

Thanks for the feedback! This was a lot more difficult than I anticipated at first :D I wanted to make the setting up ROS_HOME in tests the default, but it wasn't super straightforward to just default set_up_ament to True to actually use the wrapper for all tests: There are some $(rootpath //pkg) that then would become $(rootpaths //pkg), which didn't work out.

Anyways, let me know what you think about this new version :)

Btw, I checked and when you bazel run instead of bazel test a test target you still get Bazel's test env setup, so all the env vars should always be there.

@lalten lalten force-pushed the set-bazel-test-env-for-ros2-cpp-test branch from 1bfe4fb to 54908cb Compare April 22, 2023 23:50
Copy link
Owner

@mvukov mvukov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I think you want to be able to override ROS_HOME and ROS_LOG_DIR, even outside the sandbox.

I think the following would do the job in templates (test.py.tpl and pytest_wrapper.py.tpl):

test_outputs_dir = os.environ.get('TEST_UNDECLARED_OUTPUTS_DIR')
if test_outputs_dir is None:
    test_outputs_dir = os.environ.get('TEST_TMPDIR')

if os.environ.get('ROS_HOME') is not None:
    os.environ['ROS_HOME'] = test_outputs_dir

if os.environ.get('ROS_LOG_DIR') is not None:
    os.environ['ROS_LOG_DIR'] = test_outputs_dir

then you can override the both with e.g. --test_env=ROS_HOME=/my/custom/path. This looks to me as a very general approach and avoids a lot of other changes in this PR.

ros2/cc_defs.bzl Show resolved Hide resolved
ros2/cc_defs.bzl Show resolved Hide resolved
ros2/test.py.tpl Outdated Show resolved Hide resolved
.bazelignore Outdated Show resolved Hide resolved
@lalten lalten requested a review from mvukov April 25, 2023 18:42
@mvukov
Copy link
Owner

mvukov commented Apr 25, 2023

Please take a look at my last comment, where I suggested another setup of relevant ROS env vars.

OK, I think you want to be able to override ROS_HOME and ROS_LOG_DIR, even outside the sandbox.

I think the following would do the job in templates (test.py.tpl and pytest_wrapper.py.tpl):

test_outputs_dir = os.environ.get('TEST_UNDECLARED_OUTPUTS_DIR')
if test_outputs_dir is None:
    test_outputs_dir = os.environ.get('TEST_TMPDIR')

if os.environ.get('ROS_HOME') is not None:
    os.environ['ROS_HOME'] = test_outputs_dir

if os.environ.get('ROS_LOG_DIR') is not None:
    os.environ['ROS_LOG_DIR'] = test_outputs_dir

then you can override the both with e.g. --test_env=ROS_HOME=/my/custom/path. This looks to me as a very general approach and avoids a lot of other changes in this PR.

@lalten
Copy link
Contributor Author

lalten commented Apr 25, 2023

Please take a look at my last comment, where I suggested another setup of relevant ROS env vars.

This is in the templates now:

    test_outputs_dir = os.environ.get('TEST_UNDECLARED_OUTPUTS_DIR')
    if test_outputs_dir is None:
        test_outputs_dir = os.environ.get('TEST_TMPDIR')
    if test_outputs_dir:
        if 'ROS_HOME' not in os.environ and 'ROS_LOG_DIR' not in os.environ:
            os.environ['ROS_HOME'] = test_outputs_dir
            os.environ['ROS_LOG_DIR'] = test_outputs_dir

(I'm now seeing that the second if should also get the is None explicit check)

The fallback from TEST_UNDECLARED_OUTPUTS_DIR to TEST_TMPDIR is as you suggested.

What's different is that I set both ROS_HOME and ROS_LOG_DIR iff neither is set. The reason is that if either one of them is set, rclcpp (and rclpy) will work (ROS_LOG_DIR defaults to $ROS_HOME/.log). The issue I'm trying to fix will only appear if both env vars are unset. The reason I'm setting both, and to the same value, is that this is the current behavior in the pytest wrapper. If it's ok to break backwards compatibility (which we could certainly consider) it would be ok to set ROS_HOME only.

Copy link
Owner

@mvukov mvukov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, set_up_ros_home arg in set_up_ros_home can be avoided. Please take a look at my comments.

ros2/cc_defs.bzl Outdated Show resolved Hide resolved
ros2/test.py.tpl Outdated Show resolved Hide resolved
ros2/test.py.tpl Outdated
Comment on lines 24 to 26
if 'ROS_HOME' not in os.environ and 'ROS_LOG_DIR' not in os.environ:
os.environ['ROS_HOME'] = test_outputs_dir
os.environ['ROS_LOG_DIR'] = test_outputs_dir
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not treat them separately as I suggested?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tbh I think the best way would be to set only ROS_HOME when neither ROS_HOME nor ROS_LOG_DIR is set. But as I said, this isn't the current behavior of the pytest wrapper template, and it seems like a good idea to be consistent with that

ros2/pytest_wrapper.py.tpl Outdated Show resolved Hide resolved
ros2/launch.sh.tpl Outdated Show resolved Hide resolved
ros2/launch.sh.tpl Outdated Show resolved Hide resolved
@lalten
Copy link
Contributor Author

lalten commented Apr 26, 2023

I've simplified the wrapper setup to remove the setup_ros_home arg, and changed the tests to make sure each of the three test drivers is verified:

  • ros2_cpp_test: launch.sh.tpl
  • ros2_py_test: launch.sh.tpl
  • ros2_test with use_pytest = True: launch.py.tpl
  • ros2_test with use_pytest = False: pytest_wrapper.py.tpl

@lalten
Copy link
Contributor Author

lalten commented Apr 26, 2023

Btw, I think something is wrong with the CI setup, maybe you could check?

ERROR: The Build Event Protocol upload failed: Not retrying publishBuildEvents, no more attempts left: status='Status{code=UNAUTHENTICATED, description=failed to parse API key: missing API Key, cause=null}' UNAUTHENTICATED: UNAUTHENTICATED: failed to parse API key: missing API Key UNAUTHENTICATED: UNAUTHENTICATED: failed to parse API key: missing API Key

@mvukov
Copy link
Owner

mvukov commented Apr 27, 2023

https://github.com/mvukov/rules_ros2/pull/102/files might make problems... I need to investigate this further. The API key for buildbuddy remote cache is stored as a GH secret and it might be that with the new config it's not not available any more -- hence, the error.

You can try to revert that in your branch and see if the CI works then.

@mvukov
Copy link
Owner

mvukov commented Apr 27, 2023

Just took a look at https://github.com/aspect-build/rules_js/blob/main/.github/workflows/ci.yaml. I need to fix CI config to work on pull requests from forks w/o github secrets.

@mvukov mvukov force-pushed the set-bazel-test-env-for-ros2-cpp-test branch from ab04275 to 8362e00 Compare April 29, 2023 20:19
@lalten lalten requested a review from mvukov April 30, 2023 09:15
Copy link
Owner

@mvukov mvukov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To summarize, this PR addresses 3 issues:

  1. Test size routing in custom test macros was missing, this is fixed now.
  2. Without proper handling of ROS_HOME and ROS_LOGGING_DIR, some tests could escape the sandbox. This PR will fix that.
  3. Besides this, it looks like there are cases when users want to set ROS_HOME and ROS_LOGGING_DIR explicitly in tests. This PR will also allow that.

ros2/cc_defs.bzl Outdated
@@ -112,7 +114,7 @@ def ros2_cpp_binary(name, ros2_package_name = None, set_up_ament = False, **kwar
"""
_ros2_cpp_exec(cc_binary, name, ros2_package_name, set_up_ament, **kwargs)

def ros2_cpp_test(name, ros2_package_name = None, set_up_ament = False, **kwargs):
def ros2_cpp_test(name, ros2_package_name = None, set_up_ament = True, **kwargs):
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, this change is irrelevant to this PR and we can discuss it in a follow up.

@@ -2,6 +2,13 @@

set -o errexit -o nounset -o pipefail

if [ -z "${ROS_HOME:-}" ] && [ -z "${ROS_LOG_DIR:-}" ]; then
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For relation(s) between ROS_HOME and ROS_LOG_DIR folks should read ROS docs, not docs/impl of this repo. Here we should tend to be as general as possible and avoid introducing hidden functionality. Therefore, I'd ask again for separate setup of those two env vars like I explained earlier.

Next to this, this piece of code is only relevant for tests. Thus, this should look like (for better explicitness IMO):

if [[ ! -z "${BAZEL_TEST}" ]]; then
  bazel_test_output_dir="${TEST_UNDECLARED_OUTPUTS_DIR:-${TEST_TMPDIR}}"
  if [[ -z "${ROS_HOME:-}" ]]; then
    export ROS_HOME="${bazel_test_output_dir}" 
  fi
  if [[ -z "${ROS_LOG_DIR:-}" ]]; then
    export ROS_LOG_DIR="${bazel_test_output_dir}" 
  fi
fi

ros2/py_defs.bzl Outdated
@@ -59,7 +61,7 @@ def ros2_py_binary(name, srcs, main, set_up_ament = False, **kwargs):
"""
_ros2_py_exec(py_binary, name, srcs, main, set_up_ament, **kwargs)

def ros2_py_test(name, srcs, main, set_up_ament = False, **kwargs):
def ros2_py_test(name, srcs, main, set_up_ament = True, **kwargs):
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here: this is for a follow-up PR.

Comment on lines 36 to 41
if 'ROS_HOME' not in os.environ and 'ROS_LOG_DIR' not in os.environ:
ros_output_dir = os.environ.get('TEST_UNDECLARED_OUTPUTS_DIR')
if ros_output_dir is None:
ros_output_dir = os.environ.get('TEST_TMPDIR')
if ros_output_dir is not None:
os.environ['ROS_HOME'] = ros_output_dir
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use a snippet I posted earlier. Same reasoning as for launch.sh.tpl.

ros2/test.py.tpl Outdated
if test_outputs_dir:
os.environ['ROS_HOME'] = test_outputs_dir
os.environ['ROS_LOG_DIR'] = test_outputs_dir
if 'ROS_HOME' not in os.environ and 'ROS_LOG_DIR' not in os.environ:
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use a snippet I posted earlier.

)
load("@com_github_mvukov_rules_ros2//ros2:cc_defs.bzl", "ros2_cpp_test")
load("@com_github_mvukov_rules_ros2//ros2:interfaces.bzl", "py_ros2_interface_library", "ros2_interface_library")
load("@com_github_mvukov_rules_ros2//ros2:py_defs.bzl", "ros2_py_test")
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not needed.

"ros2_interface_library",
)
load("@com_github_mvukov_rules_ros2//ros2:cc_defs.bzl", "ros2_cpp_test")
load("@com_github_mvukov_rules_ros2//ros2:interfaces.bzl", "py_ros2_interface_library", "ros2_interface_library")
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please revert formatting as in original.

ros_output_dir = os.environ.get('TEST_UNDECLARED_OUTPUTS_DIR')
if ros_output_dir is None:
ros_output_dir = os.environ.get('TEST_TMPDIR')
if ros_output_dir is not None:
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TEST_TMPDIR is always defined, we don't need this if-clause here. The previous line should read: ros_output_dir = os.environ['TEST_TMPDIR'].

BTW, I would rename ros_output_dir to bazel_test_output_dir for more explicitness.

// 'Failed to get logging directory, at external/ros2_rcl_logging/rcl_logging_spdlog/src/rcl_logging_spdlog.cpp:83' // NOLINT
// clang-format on
rclcpp::init(argc, argv);
return 0;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe return rclcpp::shutdown()?

@lalten lalten requested a review from mvukov May 5, 2023 09:41
@mvukov mvukov merged commit bad3cd0 into mvukov:main May 7, 2023
@mvukov
Copy link
Owner

mvukov commented May 7, 2023

The PR is in good shape now IMO. Thanks for your efforts!

@lalten lalten deleted the set-bazel-test-env-for-ros2-cpp-test branch May 8, 2023 07:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants