From 22ccf9208c645e0bed3054cc640ed14e8db29894 Mon Sep 17 00:00:00 2001 From: Juan Lopez Fernandez Date: Thu, 26 Sep 2024 15:12:17 +0200 Subject: [PATCH] Add Docker tests Signed-off-by: Juan Lopez Fernandez --- .github/docker/Dockerfile | 22 +++ .../docker/linux_bisource_installation.bash | 142 ++++++++++++++ .github/docker/run.bash | 7 + .github/workflows/test_docker.yaml | 59 ++++++ .../scripts/linux_bisource_installation.bash | 142 ++++++++++++++ vulcanexus_test/CMakeLists.txt | 36 ++++ vulcanexus_test/compose/CMakeLists.txt | 51 ++++++ vulcanexus_test/compose/docker-compose.sh | 129 +++++++++++++ .../compose/scripts/execute_and_validate.py | 173 ++++++++++++++++++ vulcanexus_test/compose/scripts/log.py | 32 ++++ vulcanexus_test/compose/scripts/utils.py | 39 ++++ .../fastdds_cli/discovery_server/compose.yml | 12 ++ .../test_cases/fastdds_cli/shm/compose.yml | 12 ++ .../test_cases/fastdds_cli/xml/compose.yml | 12 ++ vulcanexus_test/package.xml | 21 +++ 15 files changed, 889 insertions(+) create mode 100644 .github/docker/Dockerfile create mode 100755 .github/docker/linux_bisource_installation.bash create mode 100644 .github/docker/run.bash create mode 100644 .github/workflows/test_docker.yaml create mode 100755 docs/resources/scripts/linux_bisource_installation.bash create mode 100644 vulcanexus_test/CMakeLists.txt create mode 100644 vulcanexus_test/compose/CMakeLists.txt create mode 100755 vulcanexus_test/compose/docker-compose.sh create mode 100644 vulcanexus_test/compose/scripts/execute_and_validate.py create mode 100644 vulcanexus_test/compose/scripts/log.py create mode 100644 vulcanexus_test/compose/scripts/utils.py create mode 100644 vulcanexus_test/compose/test_cases/fastdds_cli/discovery_server/compose.yml create mode 100644 vulcanexus_test/compose/test_cases/fastdds_cli/shm/compose.yml create mode 100644 vulcanexus_test/compose/test_cases/fastdds_cli/xml/compose.yml create mode 100644 vulcanexus_test/package.xml diff --git a/.github/docker/Dockerfile b/.github/docker/Dockerfile new file mode 100644 index 00000000..3794d1e6 --- /dev/null +++ b/.github/docker/Dockerfile @@ -0,0 +1,22 @@ +FROM ubuntu:22.04 +LABEL author=juanlopez@eprosima.com + +# Avoid interactuation with installation of some package that needs the locale. +ENV TZ=Europe/Madrid +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone + +# Avoids using interactions during building +ENV DEBIAN_FRONTEND=noninteractive + +# Use a bash shell so it is possigle to run things like `source` (required for colcon builds) +SHELL ["/bin/bash", "-c"] + +COPY linux_bisource_installation.bash /tmp/linux_bisource_installation.bash +RUN chmod +x /tmp/linux_bisource_installation.bash +RUN /tmp/linux_bisource_installation.bash +RUN rm /tmp/linux_bisource_installation.bash + +COPY run.bash /root/run.bash +RUN chmod +x /root/run.bash + +ENTRYPOINT ["/root/run.bash" ] diff --git a/.github/docker/linux_bisource_installation.bash b/.github/docker/linux_bisource_installation.bash new file mode 100755 index 00000000..ba75e510 --- /dev/null +++ b/.github/docker/linux_bisource_installation.bash @@ -0,0 +1,142 @@ +#!/bin/bash + +set -e + +if (( $EUID == 0 )); then + shopt -s expand_aliases + alias sudo='' +fi + +if !(locale | grep -e 'utf8' -e 'UTF-8') >/dev/null 2>&1; then + +##LINUX_BINARY_LOCALE +locale # check for UTF-8 + +sudo apt update && sudo apt install -y locales +# Any UTF-8 locale will work. Using en_US as an example +sudo locale-gen en_US en_US.UTF-8 +sudo update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 +export LANG=en_US.UTF-8 +##! + +locale + +fi + +##LINUX_BINARY_UBUNTU_UNIVERSE +apt-cache policy | grep universe + +# This should print something similar to: +# +# 500 http://us.archive.ubuntu.com/ubuntu jammy/universe amd64 Packages +# release v=22.04,o=Ubuntu,a=jammy,n=jammy,l=Ubuntu,c=universe,b=amd64 +# +# Otherwise run + +sudo apt install -y software-properties-common +sudo add-apt-repository universe -y +##! + +##LINUX_BINARY_KEYSTORE +sudo apt update && sudo apt install -y curl gnupg lsb-release +sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg +##! + +##LINUX_BINARY_REPO_SOURCELIST +echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu $(source /etc/os-release && echo $UBUNTU_CODENAME) main" | sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null +##! + +##LINUX_BINARY_ROS_UPDATE +sudo apt update -y +##! + +##LINUX_BINARY_ROS_INSTALL +sudo apt install -y ros-iron-desktop +##! + +##SETUP_ROS_ENV +source "/opt/ros/iron/setup.bash" +##! + +##CREATE_WORKSPACE +mkdir -p ~/vulcanexus_iron/src +cd ~/vulcanexus_iron +##! + +##LINUX_SOURCE_ROS2_DEPS +sudo apt update && sudo apt install -y \ + build-essential \ + cmake \ + git \ + python3-colcon-common-extensions \ + python3-flake8 \ + python3-flake8-blind-except \ + python3-flake8-builtins \ + python3-flake8-class-newline \ + python3-flake8-comprehensions \ + python3-flake8-deprecated \ + python3-flake8-docstrings \ + python3-flake8-import-order \ + python3-flake8-quotes \ + python3-pip \ + python3-pytest \ + python3-pytest-cov \ + python3-pytest-repeat \ + python3-pytest-rerunfailures \ + python3-rosdep \ + python3-setuptools \ + python3-vcstool \ + wget +##! + +##LINUX_SOURCE_VULCA_DEPS +sudo apt update && sudo apt install -y \ + libasio-dev \ + libdocopt-dev \ + libengine-pkcs11-openssl \ + liblog4cxx-dev \ + liblz4-dev \ + libp11-dev \ + libqt5charts5-dev \ + libssl-dev \ + libtinyxml2-dev \ + libxerces-c-dev \ + libyaml-cpp-dev \ + libzstd-dev \ + openjdk-8-jdk \ + python3-sphinx \ + python3-sphinx-rtd-theme \ + qtbase5-dev \ + qtdeclarative5-dev \ + qtquickcontrols2-5-dev \ + swig +##! + +# Get Vulcanexus sources +wget https://raw.githubusercontent.com/eProsima/vulcanexus/iron/vulcanexus.repos +wget https://raw.githubusercontent.com/eProsima/vulcanexus/iron/colcon.meta +vcs import --force src < vulcanexus.repos + +# Avoid compilation of some documentation and demo packages +touch src/eProsima/Fast-DDS-QoS-Profiles-Manager/docs/COLCON_IGNORE +touch src/eProsima/Vulcanexus-Base/docs/COLCON_IGNORE +touch src/eProsima/Vulcanexus-Base/code/COLCON_IGNORE +##! + +################################################################################################# +################################################################################################# +################################################################################################# +###### TEMP ###### +cd /tmp +git clone https://github.com/eProsima/vulcanexus.git +cd vulcanexus +git checkout feature/fastdds-cli-package +mv fastdds_cli ~/vulcanexus_iron/src/eProsima/Vulcanexus-Base +################################################################################################# +################################################################################################# +################################################################################################# + +##LINUX_SOURCE_VULCA_COMPILE +cd ~/vulcanexus_iron +colcon build --cmake-args -DBUILD_TESTING=OFF +##! diff --git a/.github/docker/run.bash b/.github/docker/run.bash new file mode 100644 index 00000000..b866d7d1 --- /dev/null +++ b/.github/docker/run.bash @@ -0,0 +1,7 @@ +#!/bin/bash + +# Setup environment +source "/opt/ros/iron/setup.bash" +source "/root/vulcanexus_iron/install/setup.bash" + +exec "$@" diff --git a/.github/workflows/test_docker.yaml b/.github/workflows/test_docker.yaml new file mode 100644 index 00000000..134fdfe6 --- /dev/null +++ b/.github/workflows/test_docker.yaml @@ -0,0 +1,59 @@ +name: test-docker-workflow +on: + workflow_dispatch: + pull_request: + push: + branches: + - main + - humble + - iron + - jazzy + + schedule: + - cron: '0 0 * * *' + +jobs: + docker-tests: + runs-on: ubuntu-22.04 + + env: + VULCANEXUS_COMPOSE_TEST_DOCKER_IMAGE: "vulcanexus:ci" + + steps: + + - name: Sync repository + uses: eProsima/eProsima-CI/external/checkout@v0 + with: + path: src + # ref: main + ref: feature/fastdds-cli-package + + - name: Build Vulcanexus Docker image + run: | + cd ./src/.github/docker + docker build \ + --no-cache \ + -t ${{ env.VULCANEXUS_COMPOSE_TEST_DOCKER_IMAGE }} \ + -f Dockerfile . + + - name: Check if Docker images exist + run: | + [ -n "$(docker images -q ${{ env.VULCANEXUS_COMPOSE_TEST_DOCKER_IMAGE }})" ] || echo "Vulcanexus Docker image does not exist" + + - name: Compile docker tests + uses: eProsima/eProsima-CI/multiplatform/colcon_build@v0 + with: + workspace: ${{ github.workspace }} + colcon_build_args: --packages-up-to vulcanexus_test + cmake_args: -DBUILD_COMPOSE_TESTS=ON + + - name: Run tests + run: | + export VULCANEXUS_COMPOSE_TEST_DOCKER_IMAGE=${{ env.VULCANEXUS_COMPOSE_TEST_DOCKER_IMAGE }} + source install/setup.bash + colcon test \ + --packages-select vulcanexus_test \ + --event-handlers console_direct+ \ + --return-code-on-test-failure \ + --ctest-args \ + --timeout 120 diff --git a/docs/resources/scripts/linux_bisource_installation.bash b/docs/resources/scripts/linux_bisource_installation.bash new file mode 100755 index 00000000..ba75e510 --- /dev/null +++ b/docs/resources/scripts/linux_bisource_installation.bash @@ -0,0 +1,142 @@ +#!/bin/bash + +set -e + +if (( $EUID == 0 )); then + shopt -s expand_aliases + alias sudo='' +fi + +if !(locale | grep -e 'utf8' -e 'UTF-8') >/dev/null 2>&1; then + +##LINUX_BINARY_LOCALE +locale # check for UTF-8 + +sudo apt update && sudo apt install -y locales +# Any UTF-8 locale will work. Using en_US as an example +sudo locale-gen en_US en_US.UTF-8 +sudo update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 +export LANG=en_US.UTF-8 +##! + +locale + +fi + +##LINUX_BINARY_UBUNTU_UNIVERSE +apt-cache policy | grep universe + +# This should print something similar to: +# +# 500 http://us.archive.ubuntu.com/ubuntu jammy/universe amd64 Packages +# release v=22.04,o=Ubuntu,a=jammy,n=jammy,l=Ubuntu,c=universe,b=amd64 +# +# Otherwise run + +sudo apt install -y software-properties-common +sudo add-apt-repository universe -y +##! + +##LINUX_BINARY_KEYSTORE +sudo apt update && sudo apt install -y curl gnupg lsb-release +sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg +##! + +##LINUX_BINARY_REPO_SOURCELIST +echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu $(source /etc/os-release && echo $UBUNTU_CODENAME) main" | sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null +##! + +##LINUX_BINARY_ROS_UPDATE +sudo apt update -y +##! + +##LINUX_BINARY_ROS_INSTALL +sudo apt install -y ros-iron-desktop +##! + +##SETUP_ROS_ENV +source "/opt/ros/iron/setup.bash" +##! + +##CREATE_WORKSPACE +mkdir -p ~/vulcanexus_iron/src +cd ~/vulcanexus_iron +##! + +##LINUX_SOURCE_ROS2_DEPS +sudo apt update && sudo apt install -y \ + build-essential \ + cmake \ + git \ + python3-colcon-common-extensions \ + python3-flake8 \ + python3-flake8-blind-except \ + python3-flake8-builtins \ + python3-flake8-class-newline \ + python3-flake8-comprehensions \ + python3-flake8-deprecated \ + python3-flake8-docstrings \ + python3-flake8-import-order \ + python3-flake8-quotes \ + python3-pip \ + python3-pytest \ + python3-pytest-cov \ + python3-pytest-repeat \ + python3-pytest-rerunfailures \ + python3-rosdep \ + python3-setuptools \ + python3-vcstool \ + wget +##! + +##LINUX_SOURCE_VULCA_DEPS +sudo apt update && sudo apt install -y \ + libasio-dev \ + libdocopt-dev \ + libengine-pkcs11-openssl \ + liblog4cxx-dev \ + liblz4-dev \ + libp11-dev \ + libqt5charts5-dev \ + libssl-dev \ + libtinyxml2-dev \ + libxerces-c-dev \ + libyaml-cpp-dev \ + libzstd-dev \ + openjdk-8-jdk \ + python3-sphinx \ + python3-sphinx-rtd-theme \ + qtbase5-dev \ + qtdeclarative5-dev \ + qtquickcontrols2-5-dev \ + swig +##! + +# Get Vulcanexus sources +wget https://raw.githubusercontent.com/eProsima/vulcanexus/iron/vulcanexus.repos +wget https://raw.githubusercontent.com/eProsima/vulcanexus/iron/colcon.meta +vcs import --force src < vulcanexus.repos + +# Avoid compilation of some documentation and demo packages +touch src/eProsima/Fast-DDS-QoS-Profiles-Manager/docs/COLCON_IGNORE +touch src/eProsima/Vulcanexus-Base/docs/COLCON_IGNORE +touch src/eProsima/Vulcanexus-Base/code/COLCON_IGNORE +##! + +################################################################################################# +################################################################################################# +################################################################################################# +###### TEMP ###### +cd /tmp +git clone https://github.com/eProsima/vulcanexus.git +cd vulcanexus +git checkout feature/fastdds-cli-package +mv fastdds_cli ~/vulcanexus_iron/src/eProsima/Vulcanexus-Base +################################################################################################# +################################################################################################# +################################################################################################# + +##LINUX_SOURCE_VULCA_COMPILE +cd ~/vulcanexus_iron +colcon build --cmake-args -DBUILD_TESTING=OFF +##! diff --git a/vulcanexus_test/CMakeLists.txt b/vulcanexus_test/CMakeLists.txt new file mode 100644 index 00000000..1b810400 --- /dev/null +++ b/vulcanexus_test/CMakeLists.txt @@ -0,0 +1,36 @@ +# Copyright 2024 Proyectos y Sistemas de Mantenimiento SL (eProsima). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +cmake_minimum_required(VERSION 3.8) +project(vulcanexus_test) + +# find dependencies +find_package(ament_cmake REQUIRED) + +############################################################################### +# Test +############################################################################### +# Compile tests if CMake options requires it +option(BUILD_COMPOSE_TESTS "Compile compose tests" OFF) + +if(BUILD_COMPOSE_TESTS) + message(STATUS "Compiling Compose Tests of ${PROJECT_NAME}") + add_subdirectory(compose) +endif() + +############################################################################### +# Packaging +############################################################################### +# Install package +ament_package() diff --git a/vulcanexus_test/compose/CMakeLists.txt b/vulcanexus_test/compose/CMakeLists.txt new file mode 100644 index 00000000..9201aa1d --- /dev/null +++ b/vulcanexus_test/compose/CMakeLists.txt @@ -0,0 +1,51 @@ +# Copyright 2022 Proyectos y Sistemas de Mantenimiento SL (eProsima). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Name of files to test +set(TESTS + fastdds_cli/discovery_server + fastdds_cli/shm + fastdds_cli/xml +) + +file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/test_cases DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/docker-compose.sh + ${CMAKE_CURRENT_BINARY_DIR}/docker-compose.sh + COPYONLY) + +file( + COPY + ${CMAKE_CURRENT_SOURCE_DIR}/scripts + DESTINATION + ${CMAKE_CURRENT_BINARY_DIR} + ) + +find_program (BASH_PROGRAM bash) + +# Populate the tests +foreach(TEST IN LISTS TESTS) + + set(TEST_NAME "vulcanexus.compose.${TEST}") + string(REPLACE "/" "_" TEST_NAME ${TEST_NAME}) + + message(STATUS "Building test ${TEST_NAME}") + + add_test( + NAME ${TEST_NAME} + COMMAND ${BASH_PROGRAM} ${CMAKE_CURRENT_BINARY_DIR}/docker-compose.sh + -t ${TEST_NAME} + -f ${CMAKE_CURRENT_BINARY_DIR}/test_cases/${TEST}/compose.yml) + +endforeach() diff --git a/vulcanexus_test/compose/docker-compose.sh b/vulcanexus_test/compose/docker-compose.sh new file mode 100755 index 00000000..49f65e46 --- /dev/null +++ b/vulcanexus_test/compose/docker-compose.sh @@ -0,0 +1,129 @@ +#!/bin/bash + +# Copyright 2024 Proyectos y Sistemas de Mantenimiento SL (eProsima). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +print_usage() +{ + echo "----------------------------------------------------------------------------------" + echo "Script that retrieves the exit code of the Vulcanexus docker compose tests." + echo "----------------------------------------------------------------------------------" + echo "REQUIRED ARGUMENTS:" + echo " -t --test-name [string] Name of the Vulcanexus test." + echo " -f --compose-file [filename] The Docker compose file" + echo "" + echo "OPTIONAL ARGUMENTS:" + echo " -d --debug Print debug traces." + echo " -h --help Print this same help." + echo "" + echo "EXAMPLE: bash docker-compose.sh -t -f " + echo "" + exit ${1} +} + +parse_options() +{ + + if (($# == 0)) ; then print_usage 1 ; fi + if [ $? != 0 ] ; then print_usage 1 ; fi + + TEMP=`getopt \ + -o t:f:hd \ + --long test-name:,compose-file:,help,debug \ + -n 'Error' \ + -- "$@"` + + eval set -- "${TEMP}" + + TEST_NAME= + COMPOSE_FILE= + DEBUG=false + while true; do + case "$1" in + # Mandatory args + -t | --test-name ) TEST_NAME="$2"; shift 2;; + -f | --compose-file ) COMPOSE_FILE="$2"; shift 2;; + # Optional args + -h | --help ) print_usage 0; shift ;; + -d | --debug ) DEBUG=true; shift ;; + # Wrong args + -- ) shift; break ;; + * ) break ;; + esac + done + + if [[ ${TEST_NAME} == "" ]] + then + echo "----------------------------------------------------------------------------------" + echo "No test name defined" + print_usage 1 + fi + + if [[ ${COMPOSE_FILE} == "" ]] + then + echo "----------------------------------------------------------------------------------" + echo "No Docker compose file provided" + print_usage 1 + fi + + if [[ ! -f "${COMPOSE_FILE}" ]] + then + echo "----------------------------------------------------------------------------------" + echo "-f --compose-file must specify an existing file" + print_usage 1 + fi +} + +full_path () +{ + if [[ -f ${1} ]] + then + echo "$(realpath ${1})" + else + echo "$(dirname ${1})" + fi +} + +main () +{ + SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" > /dev/null && pwd )" + parse_options ${@} + EXIT_CODE=0 + + set -e + + echo "Docker compose file: ${COMPOSE_FILE}" + + # Run docker compose + docker compose -f ${COMPOSE_FILE} up + + # First this command gets the ids of every container listed on the docker compose file. + # Then it checks the exist code of every container listed before, remove the exit codes equal + # to 0 and count how many containers exited with an exit code different than 0. + # As a result, the EXIT_CODE is the number of containers that exited with an exit code + # different than 0. + EXIT_CODE=$(docker compose -f ${COMPOSE_FILE} ps -aq | + xargs docker inspect -f '{{ .State.ExitCode }}' | + grep -vx "^0$" | wc -l | tr -d ' ') + + echo "${TEST_NAME} exited with code ${EXIT_CODE}" + + # Clean containers and networks before exiting and do not prompt for confirmation + docker container prune --force + docker network prune --force + + exit ${EXIT_CODE} +} + +main ${@} diff --git a/vulcanexus_test/compose/scripts/execute_and_validate.py b/vulcanexus_test/compose/scripts/execute_and_validate.py new file mode 100644 index 00000000..d8dd53b0 --- /dev/null +++ b/vulcanexus_test/compose/scripts/execute_and_validate.py @@ -0,0 +1,173 @@ +# Copyright 2024 Proyectos y Sistemas de Mantenimiento SL (eProsima). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from enum import Enum +from typing import List +import argparse +import signal +import subprocess +import time + +import log + +import utils + + +DESCRIPTION = """Script to run commands and validate their output.""" +USAGE = ('python3 execute_and_validate.py ' + '[-c ] [-t ] [-d]') + + +class ReturnCode(Enum): + """Enumeration for return codes of this script.""" + + SUCCESS = 0 + TIMEOUT = 1 + HARD_TIMEOUT = 2 + COMMAND_FAIL = 3 + STDERR_OUTPUT = 4 + + +def parse_options(): + """ + Parse arguments. + + :return: The arguments parsed. + """ + parser = argparse.ArgumentParser( + formatter_class=argparse.ArgumentDefaultsHelpFormatter, + add_help=True, + description=(DESCRIPTION), + usage=(USAGE) + ) + parser.add_argument( + '-c', + '--command', + type=str, + help='Command to execute.' + ) + parser.add_argument( + '-t', + '--timeout', + type=int, + default=5, + help='Timeout for the command execution.' + ) + parser.add_argument( + '--delay', + type=float, + default=0, + help='Time to wait before starting execution.' + ) + parser.add_argument( + '-d', + '--debug', + action='store_true', + help='Print test debugging info.' + ) + + return parser.parse_args() + + +def run_command( + command: 'list[str]', + timeout: float, + delay: float = 0, + timeout_as_error: bool = True): + """ + Run command with timeout. + + :param command: Command to run in list format + :param timeout: Timeout for the process + :return: + - ret_code - The process exit code + - stdout - Output of the process + - stderr - Error output of the process + """ + ret_code = ReturnCode.SUCCESS + + # Delay + utils.delay(delay) + + log.logger.debug(f'Running command: {command}') + + proc = subprocess.Popen(command, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + universal_newlines=True) + + try: + proc.wait(timeout=timeout) + + except subprocess.TimeoutExpired: + if timeout_as_error: + log.logger.error( + 'Timeout expired, killing process...') + proc.send_signal(signal.SIGINT) + ret_code = ReturnCode.TIMEOUT + + else: + proc.send_signal(signal.SIGINT) + + else: + if not timeout_as_error: + log.logger.error('Command finished before expected.') + ret_code = ReturnCode.COMMAND_FAIL + + # Wait a minimum elapsed time to the signal to be received + time.sleep(0.2) + + stdout, stderr = proc.communicate() + + # Check whether SIGINT was able to terminate the process + if proc.poll() is None: + # SIGINT couldn't terminate the process + log.logger.error( + 'SIGINT could not kill process. ' + 'Killing process hardly...') + proc.kill() + ret_code = ReturnCode.HARD_TIMEOUT + + log.logger.info(f'Process exited with code {proc.returncode}') + + # Set return code to COMMAND_FAIL if the process returned 1 + ret_code = ReturnCode.COMMAND_FAIL if proc.returncode == 1 else ret_code + + if not stdout: + stdout = '' + if not stderr: + stderr = '' + + return (ret_code, stdout, stderr) + + +if __name__ == '__main__': + + # Parse arguments + args = parse_options() + + # Set log level + if args.debug: + log.activate_debug() + + command = args.command.split() + + (ret_code, stdout, stderr) = run_command( + command=command, + timeout=args.timeout, + delay=args.delay) + + log.logger.info(f'Command exited with code {ret_code}') + + exit(ret_code.value) diff --git a/vulcanexus_test/compose/scripts/log.py b/vulcanexus_test/compose/scripts/log.py new file mode 100644 index 00000000..8ff5d317 --- /dev/null +++ b/vulcanexus_test/compose/scripts/log.py @@ -0,0 +1,32 @@ +# Copyright 2024 Proyectos y Sistemas de Mantenimiento SL (eProsima). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import logging + +# Create a custom logger +logger = logging.getLogger('VALIDATION') +# Create handlers +l_handler = logging.StreamHandler() +# Create formatters and add it to handlers +l_format = '[%(asctime)s][%(name)s][%(levelname)s] %(message)s' +l_format = logging.Formatter(l_format) +l_handler.setFormatter(l_format) +# Add handlers to the logger +logger.addHandler(l_handler) +logger.setLevel(logging.INFO) + + +def activate_debug(): + """Activate debug mode.""" + logger.setLevel(logging.DEBUG) diff --git a/vulcanexus_test/compose/scripts/utils.py b/vulcanexus_test/compose/scripts/utils.py new file mode 100644 index 00000000..605d8dd8 --- /dev/null +++ b/vulcanexus_test/compose/scripts/utils.py @@ -0,0 +1,39 @@ +# Copyright 2024 Proyectos y Sistemas de Mantenimiento SL (eProsima). +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import random +import time + + +def sleep_random_time( + min_time_seconds: int, + max_time_seconds: int): + """Sleep a random time between min_time_seconds and max_time in seconds.""" + time.sleep( + min_time_seconds + + ((max_time_seconds - min_time_seconds) * random.random())) + + +def print_with_timestamp( + msg: str): + """Print a message with a timestamp.""" + print(f'{time.time()}$ {msg}') + # This has been made by copilot... Respect + + +def delay( + time_s: float): + """Wait for time_s seconds.""" + if (time_s > 0): + time.sleep(time_s) diff --git a/vulcanexus_test/compose/test_cases/fastdds_cli/discovery_server/compose.yml b/vulcanexus_test/compose/test_cases/fastdds_cli/discovery_server/compose.yml new file mode 100644 index 00000000..03e46ace --- /dev/null +++ b/vulcanexus_test/compose/test_cases/fastdds_cli/discovery_server/compose.yml @@ -0,0 +1,12 @@ +# Test description: +# This test checks that running fastdds CLI discovery option results in no error (process return code is not 1). +# + +services: + + vulcanexus: + image: ${VULCANEXUS_COMPOSE_TEST_DOCKER_IMAGE} + container_name: vulcanexus + volumes: + - ../../../scripts:/scripts + command: python3 /scripts/execute_and_validate.py --command "timeout 1 ros2 run fastdds_cli discovery_server" diff --git a/vulcanexus_test/compose/test_cases/fastdds_cli/shm/compose.yml b/vulcanexus_test/compose/test_cases/fastdds_cli/shm/compose.yml new file mode 100644 index 00000000..6afc73e5 --- /dev/null +++ b/vulcanexus_test/compose/test_cases/fastdds_cli/shm/compose.yml @@ -0,0 +1,12 @@ +# Test description: +# This test checks that running fastdds CLI shm option results in no error (process return code is not 1). +# + +services: + + vulcanexus: + image: ${VULCANEXUS_COMPOSE_TEST_DOCKER_IMAGE} + container_name: vulcanexus + volumes: + - ../../../scripts:/scripts + command: python3 /scripts/execute_and_validate.py --command "ros2 run fastdds_cli shm" diff --git a/vulcanexus_test/compose/test_cases/fastdds_cli/xml/compose.yml b/vulcanexus_test/compose/test_cases/fastdds_cli/xml/compose.yml new file mode 100644 index 00000000..90b1f876 --- /dev/null +++ b/vulcanexus_test/compose/test_cases/fastdds_cli/xml/compose.yml @@ -0,0 +1,12 @@ +# Test description: +# This test checks that running fastdds CLI xml option results in no error (process return code is not 1). +# + +services: + + vulcanexus: + image: ${VULCANEXUS_COMPOSE_TEST_DOCKER_IMAGE} + container_name: vulcanexus + volumes: + - ../../../scripts:/scripts + command: python3 /scripts/execute_and_validate.py --command "ros2 run fastdds_cli xml" diff --git a/vulcanexus_test/package.xml b/vulcanexus_test/package.xml new file mode 100644 index 00000000..79bec96e --- /dev/null +++ b/vulcanexus_test/package.xml @@ -0,0 +1,21 @@ + + + + vulcanexus_test + 0.0.1 + + Vulcanexus tests. + + Juan López + Apache 2.0 + + https://www.eprosima.com/ + https://github.com/eProsima/vulcanexus/issues + https://github.com/eProsima/vulcanexus + + ament_cmake + + + ament_cmake + +