Skip to content

Commit

Permalink
Add taped test (#263)
Browse files Browse the repository at this point in the history
  • Loading branch information
nebraszka authored Apr 2, 2024
1 parent 6fb6224 commit c1f0a38
Show file tree
Hide file tree
Showing 7 changed files with 187 additions and 16 deletions.
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.")

# 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 = "[email protected]: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,
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 @@ -121,4 +121,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
}

0 comments on commit c1f0a38

Please sign in to comment.