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

Add taped test #263

Merged
merged 14 commits into from
Apr 2, 2024
27 changes: 19 additions & 8 deletions .github/workflows/build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,14 @@ jobs:
steps:
- name: Checkout repository code
uses: actions/checkout@v3
with:
clean: false
- name: Clean repository excluding taped test data
run: git clean -ffdx -e external/taped_test_data
- name: Import private extensions
run: vcs import < extensions.repos
- name: Install taped test dependencies
run: ./setup.py --install-taped-test-deps

load-env:
uses: ./.github/workflows/load-env-subworkflow.yml
Expand All @@ -42,7 +48,7 @@ jobs:
needs: [checkout-repository, load-env]
uses: ./.github/workflows/build-subworkflow.yml
with:
build-command: './setup.py --with-pcl --build-dir build-pcl'
build-command: './setup.py --with-pcl --build-taped-test --build-dir build-pcl'
self-hosted-user-id: ${{ needs.load-env.outputs.user-id }}
optix-install-dir: ${{ needs.load-env.outputs.optix-install-dir }}
docker-image: localhost:5000/rgl:latest
Expand Down Expand Up @@ -82,7 +88,7 @@ jobs:
with:
build-command: '
source /opt/ros/humble/setup.bash &&
./setup.py --with-pcl --with-ros2-standalone --with-udp --with-snow --build-dir build-all'
./setup.py --with-pcl --with-ros2-standalone --with-udp --with-snow --build-taped-test --build-dir build-all'
self-hosted-user-id: ${{ needs.load-env.outputs.user-id }}
optix-install-dir: ${{ needs.load-env.outputs.optix-install-dir }}
docker-image: localhost:5000/rgl:latest
Expand All @@ -99,7 +105,9 @@ jobs:
needs: [ build-pcl ]
uses: ./.github/workflows/test-subworkflow.yml
with:
test-command: 'cd build-pcl/test && ./RobotecGPULidar_test'
test-command: '
export RGL_TAPED_TEST_DATA_DIR=$(pwd)/external/taped_test_data &&
cd build-pcl/test && ./RobotecGPULidar_test && ./taped_test/RobotecGPULidar_taped_test'
docker-image: localhost:5000/rgl:latest

test-ros2-dev:
Expand Down Expand Up @@ -141,9 +149,10 @@ jobs:
source /opt/ros/humble/setup.bash &&
source /rgldep/radar_msgs/install/setup.bash &&
export RGL_TEST_VLP16_CALIB_FILE=$(pwd)/extensions/udp/test/resources/Ros2Vlp16Calib.yaml &&
export RGL_TAPED_TEST_DATA_DIR=$(pwd)/external/taped_test_data &&
cd build-all/test &&
export RMW_IMPLEMENTATION=rmw_fastrtps_cpp && ./RobotecGPULidar_test &&
export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp && ./RobotecGPULidar_test'
export RMW_IMPLEMENTATION=rmw_fastrtps_cpp && ./RobotecGPULidar_test && ./taped_test/RobotecGPULidar_taped_test &&
export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp && ./RobotecGPULidar_test && ./taped_test/RobotecGPULidar_taped_test'
docker-image: localhost:5000/rgl:latest

###### TEST WITH CLEAN UBUNTU DOCKER IMAGE ######
Expand All @@ -161,7 +170,8 @@ jobs:
# Additionally, install PCL extension dependent libraries for runtime
test-command: '
apt update && apt install -y libxcursor1 libgl1 &&
cd build-pcl/test && ./RobotecGPULidar_test'
export RGL_TAPED_TEST_DATA_DIR=$(pwd)/external/taped_test_data &&
cd build-pcl/test && ./RobotecGPULidar_test && ./taped_test/RobotecGPULidar_taped_test'
docker-image: nvidia/cuda:11.7.1-base-ubuntu22.04

test-ros2-prod:
Expand Down Expand Up @@ -200,8 +210,9 @@ jobs:
# Run tests twice, each for different RMW implementation
test-command: '
apt update && apt install -y libxcursor1 libgl1 &&
export RGL_TAPED_TEST_DATA_DIR=$(pwd)/external/taped_test_data &&
cd build-all/test &&
cp -r ../ros2_standalone/*.so* ../ &&
export RMW_IMPLEMENTATION=rmw_fastrtps_cpp && ./RobotecGPULidar_test &&
export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp && ./RobotecGPULidar_test'
export RMW_IMPLEMENTATION=rmw_fastrtps_cpp && ./RobotecGPULidar_test && ./taped_test/RobotecGPULidar_taped_test &&
export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp && ./RobotecGPULidar_test && ./taped_test/RobotecGPULidar_taped_test'
docker-image: nvidia/cuda:11.7.1-base-ubuntu22.04
16 changes: 13 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ set(RGL_AUTO_TAPE_PATH "" CACHE STRING # STRING prevents from expanding relativ
# Test configuration
set(RGL_BUILD_TESTS ON CACHE BOOL
"Enables building test. GTest will be automatically downloaded")
set(RGL_BUILD_TAPED_TESTS OFF CACHE BOOL
"Enables building taped test.")
nebraszka marked this conversation as resolved.
Show resolved Hide resolved

# Tools configuration
set(RGL_BUILD_TOOLS ON CACHE BOOL "Enables building RGL executable tools")
Expand Down Expand Up @@ -176,7 +178,7 @@ if (NOT ("RGL_LOG_LEVEL_${RGL_LOG_LEVEL}" IN_LIST RGL_AVAILABLE_LOG_LEVELS))
message(FATAL_ERROR "Incorrect RGL_LOG_LEVEL value: ${RGL_LOG_LEVEL}")
endif()

if (WIN32 AND RGL_AUTO_TAPE_PATH)
if (WIN32 AND (RGL_AUTO_TAPE_PATH OR RGL_BUILD_TAPED_TESTS))
message(FATAL_ERROR "(Auto)Tape not supported on Windows")
endif()

Expand All @@ -190,11 +192,19 @@ target_compile_definitions(RobotecGPULidar
)

# Include tests
if (RGL_BUILD_TESTS)
if (RGL_BUILD_TESTS OR RGL_BUILD_TAPED_TESTS)
enable_testing()
add_subdirectory(test)

if (RGL_BUILD_TESTS)
add_subdirectory(test)
endif()

if (RGL_BUILD_TAPED_TESTS)
add_subdirectory(test/taped_test)
endif()
endif()


# Include tools
if (RGL_BUILD_TOOLS)
add_subdirectory(tools)
Expand Down
2 changes: 1 addition & 1 deletion external/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ if (UNIX)
set_target_properties(spdlog PROPERTIES POSITION_INDEPENDENT_CODE ON)
endif()

if (${RGL_BUILD_TESTS})
if (${RGL_BUILD_TESTS} OR ${RGL_BUILD_TAPED_TESTS})
set(INSTALL_GTEST OFF CACHE INTERNAL "Disable installation of googletest")
FetchContent_Declare(
googletest
Expand Down
66 changes: 63 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ class Config:
VCPKG_EXEC = "vcpkg"
VCPKG_BOOTSTRAP = "bootstrap-vcpkg.sh"
VCPKG_TRIPLET = "x64-linux"
TAPED_TEST_DATA_DIR = os.path.join("external", "taped_test_data")
TAPED_TEST_DATA_REPO = "git@github.com:RobotecAI/RGL-blobs.git"
TAPED_TEST_DATA_BRANCH = "main"

def __init__(self):
# Platform-dependent configuration
Expand Down Expand Up @@ -69,6 +72,10 @@ def main():
help="Pass arguments to make. Usage: --make=\"args...\". Defaults to \"-j <cpu count>\"")
parser.add_argument("--lib-rpath", type=str, nargs='*',
help="Add run-time search path(s) for RGL library. $ORIGIN (actual library path) is added by default.")
parser.add_argument("--install-taped-test-deps", action='store_true',
help="Install dependencies for taped test and exit (closed-source dependencies)")
parser.add_argument("--build-taped-test", action='store_true',
help="Build taped test")
if on_windows():
parser.add_argument("--ninja", type=str, default=f"-j{os.cpu_count()}", dest="build_args",
help="Pass arguments to ninja. Usage: --ninja=\"args...\". Defaults to \"-j <cpu count>\"")
Expand Down Expand Up @@ -100,6 +107,17 @@ def main():
print('Installed ROS2 deps, exiting...')
return 0

# Install taped test dependencies
if args.install_taped_test_deps:
install_taped_test_deps(cfg)
print('Installed dependencies for taped test, exiting...')
return 0

# Check taped test requirements
if args.build_taped_test and not args.with_pcl:
raise RuntimeError(
"Taped test requires PCL extension to be built: run this script with --with-pcl flag")

# Check CUDA
if not is_cuda_version_ok(cfg):
raise RuntimeError(
Expand Down Expand Up @@ -137,6 +155,7 @@ def main():
f"-DRGL_BUILD_ROS2_EXTENSION={'ON' if args.with_ros2 else 'OFF'}",
f"-DRGL_BUILD_UDP_EXTENSION={'ON' if args.with_udp else 'OFF'}",
f"-DRGL_BUILD_SNOW_EXTENSION={'ON' if args.with_snow else 'OFF'}",
f"-DRGL_BUILD_TAPED_TESTS={'ON' if args.build_taped_test else 'OFF'}"
]

if on_linux():
Expand Down Expand Up @@ -233,15 +252,15 @@ def install_pcl_deps(cfg):
f"{os.path.join(cfg.VCPKG_DIR, cfg.VCPKG_EXEC)} install --clean-after-build pcl[core,visualization]:{cfg.VCPKG_TRIPLET}")


def has_colcon():
process = subprocess.Popen("colcon --help", shell=True, stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL)
def is_command_available(command):
process = subprocess.Popen(f"{command}", shell=True, stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL)
process.wait()
return process.returncode == 0


def install_ros2_deps(cfg):
# Install colcon if needed
if not has_colcon():
if not is_command_available("colcon --help"):
if on_windows():
run_system_command("pip install colcon-common-extensions")
elif not inside_docker(): # Linux; Inside docker already installed
Expand All @@ -261,6 +280,47 @@ def install_ros2_deps(cfg):
# TODO: cyclonedds rmw may be installed here (instead of manually in readme)


def ensure_git_lfs_installed():
if not is_command_available("git-lfs --help"):
print("Installing git-lfs...")
run_subprocess_command(
"curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | sudo bash")
run_subprocess_command("sudo apt install git-lfs")


def clone_taped_test_data_repo(cfg):
run_subprocess_command(
f"git clone -b {cfg.TAPED_TEST_DATA_BRANCH} --single-branch --depth 1 {cfg.TAPED_TEST_DATA_REPO} {cfg.TAPED_TEST_DATA_DIR}")
os.chdir(cfg.TAPED_TEST_DATA_DIR)
# Set up git-lfs for this repository
run_subprocess_command("git-lfs install && git-lfs pull")


def is_taped_data_up_to_date(cfg):
result = subprocess.Popen("git fetch --dry-run --verbose", shell=True, stdout=subprocess.PIPE,
msz-rai marked this conversation as resolved.
Show resolved Hide resolved
stderr=subprocess.STDOUT)
stdout, _ = result.communicate()
return f"[up to date] {cfg.TAPED_TEST_DATA_BRANCH}" in stdout.decode()


def update_taped_test_data_repo(cfg):
if not is_taped_data_up_to_date(cfg):
print("Updating taped test benchmark data repository...")
run_subprocess_command("git pull && git-lfs pull")


def install_taped_test_deps(cfg):
# Cloning and updating taped test benchmark data repo requires git-lfs to be installed
ensure_git_lfs_installed()
if not os.path.isdir(cfg.TAPED_TEST_DATA_DIR):
print("Cloning taped test benchmark data repository...")
clone_taped_test_data_repo(cfg)
else:
print("Checking for updates in taped test benchmark data repository...")
os.chdir(cfg.TAPED_TEST_DATA_DIR)
update_taped_test_data_repo(cfg)


# Returns a dict with env variables visible for a command after running in a system shell
# Used to capture effects of sourcing file such as ros2 setup
def capture_environment(command="cd ."):
Expand Down
2 changes: 1 addition & 1 deletion test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -117,4 +117,4 @@ endif()

include(GoogleTest)

gtest_discover_tests(RobotecGPULidar_test)
gtest_discover_tests(RobotecGPULidar_test)
27 changes: 27 additions & 0 deletions test/taped_test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
cmake_minimum_required(VERSION 3.16)

if(WIN32)
message(FATAL_ERROR "Tape not supported on Windows")
endif()

set(RGL_TAPED_TEST_FILES
src/AwsimMeshToPcdTest.cpp
)

include(GoogleTest)

add_executable(RobotecGPULidar_taped_test ${RGL_TAPED_TEST_FILES})

target_link_libraries(RobotecGPULidar_taped_test PRIVATE
gtest_main
gmock_main
spdlog
RobotecGPULidar
)

target_include_directories(RobotecGPULidar_taped_test PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/../include
${CMAKE_CURRENT_SOURCE_DIR}/../../include
)

gtest_discover_tests(RobotecGPULidar_taped_test)
63 changes: 63 additions & 0 deletions test/taped_test/src/AwsimMeshToPcdTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#include <helpers/commonHelpers.hpp>
#include <rgl/api/extensions/tape.h>

#include <filesystem>
#include <spdlog/fmt/ostr.h>

#if RGL_BUILD_PCL_EXTENSION
#include <pcl/point_cloud.h>
#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
#endif

class AwsimMeshToPcdTest : public RGLTest
{
protected:
const std::string benchmarkDataDirEnvVariableName = "RGL_TAPED_TEST_DATA_DIR";

const std::string testTapeFileName = "awsim-mesh2pcd";
const std::string expectedOutputDirName = "expected-output";
const std::string expectedOutputFileName = testTapeFileName + ".pcd";

const float epsilon = 1e-2f;
};

TEST_F(AwsimMeshToPcdTest, validate_point_cloud_equivalence)
{
#if RGL_BUILD_PCL_EXTENSION

// It is necessary to set environment variable on benchmark data directory
if (std::getenv(benchmarkDataDirEnvVariableName.c_str()) == nullptr) {
const std::string msg = fmt::format(
"Skipping Taped Test - benchmark data directory must be provided in environment variable '{}'",
benchmarkDataDirEnvVariableName);
GTEST_SKIP() << msg;
}

const std::string benchmarkDataDir = std::getenv(benchmarkDataDirEnvVariableName.c_str());
const std::string testTapePath{(std::filesystem::path(benchmarkDataDir) / testTapeFileName).string()};
const std::string expectedOutputPath{
(std::filesystem::path(benchmarkDataDir) / expectedOutputDirName / expectedOutputFileName).string()};
const std::string outputPath{(std::filesystem::current_path() / "output.pcd").string()};

ASSERT_RGL_SUCCESS(rgl_tape_play(testTapePath.c_str()));

pcl::PointCloud<pcl::PointXYZ>::Ptr expectedCloud(new pcl::PointCloud<pcl::PointXYZ>);
pcl::PointCloud<pcl::PointXYZ>::Ptr outputCloud(new pcl::PointCloud<pcl::PointXYZ>);

pcl::io::loadPCDFile(expectedOutputPath, *expectedCloud);
pcl::io::loadPCDFile(outputPath, *outputCloud);

ASSERT_TRUE(expectedCloud->size() == outputCloud->size());

for (size_t i = 0; i < expectedCloud->size(); ++i) {
EXPECT_NEAR(expectedCloud->points[i].x, outputCloud->points[i].x, epsilon);
EXPECT_NEAR(expectedCloud->points[i].y, outputCloud->points[i].y, epsilon);
EXPECT_NEAR(expectedCloud->points[i].z, outputCloud->points[i].z, epsilon);
}

#else
const std::string msg = fmt::format("Skipping Taped Test - RGL compiled without PCL extension.");
GTEST_SKIP() << msg;
#endif
}
Loading