Dockerized End-To-End Tests (Proof of Concept) #97
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Describe the contribution
A tool to perform dockerized end-to-end tests of cFS.
This tool simulates network-based interactions between containerized cFS executables and a pseudo-ground system software acting as a test runner.
(General context: #56)
Quick Overview
The tool makes a containerized cFS executable (
cfs
service) and a test runner (gsw
service) interact. The following screen captures illustrate this mechanism by comparing a passing test with a failing one.gsw
service: the test runnercfs
service: the system under test (i.e. a containerized cFS executable)NOOP
command does not emit the expected eventQuick Start
Requirements
Usage
From the cFS top-level directory, run the following command:
docker-compose up --abort-on-container-exit --exit-code-from gsw
When executed for the first time, this command builds the cFS with the options set in
docker-compose.yml
(by default: Ubuntu 18.04, unit tests disabled, simulation native, debug build, and deprecated omitted) as well as a pseudo-ground system software that attempts to enable the telemetry and, if successful, runs a simple assertion.The default build-time options can be found (and, if needed, modified) in
docker-compose.yml
(lines 7-12):For more details, please refer to the
README
file located intools/e2eTests
subdirectory.Goal
The purpose of this working proof of concept is to demonstrate the potential as well as the limitations of using Docker to perform end-to-end tests.
This approach has several advantages.
First, it aims at enabling the future incorporation of end-to-end tests in the continuous integration process, automatically ensuring that the executable is working as expected in the scope of these tests. In this regard, it should be noted that Travis can run Docker Compose commands (see: https://docs.travis-ci.com/user/docker/#using-docker-compose).
Second, it allows for more granular control of the testing environment by pinning the operating systems and the required dependencies to a specific version. Therefore, it makes the tests highly reproducible. It follows that the versions of the packages are explicitly specified in all cFS Dockerfiles. For instance (
tools/e2eTests/platforms/Ubuntu/18.04/Dockerfile
, lines 19-27):Third, it facilitates the compilation of cFS executables using different combinations of built-time options. In other words, it potentially permits the automatic generation of matrixed cFS executables.
Limitations
The purpose of this pull request, which introduces a working proof of concept, is not per se to provide a complete end-to-end testing solution. As a consequence, this tool is not yet integrated into the existing Travis configuration, and the test runner performs a simple assertion.
This contribution is also limited by the technical characteristics of Docker. In particular:
It should also be noted that an Alpine image is included (
./tools/e2eTests/platforms/Alpine/3/Dockerfile
) but is currently not operational, mainly because of the following error:/usr/include/sys/signal.h:1:2: error: #warning redirecting incorrect #include <sys/signal.h> to <signal.h> [-Werror=cpp]
(see: nasa/osal#438 (comment)). I have decided to keep it because it is conceivable that it becomes operational in the future.Testing performed
In the context of this proof of context, a simple flow is tested by the
gsw
test runner (tools/e2eTests/gsw/gsw.py
):NOOP
command (for the SAMPLE app) packet to the cFSSAMPLE: NOOP command
event appears in the telemetry message sent by the cFS, the test passesExpected behavior changes
This contribution does not modify the existing code. Therefore, no behavior changes are expected.
System(s) tested on
Hosts
Ubuntu
macOS
Docker
Additional context
Components
The tool consists of:
docker-compose.yml
file to make them interact. This Docker Compose file makes reference to two services:cfs
(the system under test) andgsw
(the test runner).cFS Dockerfiles -
cfs
serviceThe cFS Dockerfiles have a multistage structure. The first stage builds the
core-cpu1
executable file. The second one corresponds to the runtime environment for this executable.Pseudo-GSW (test runner) -
gsw
serviceThe pseudo-GSW is a Python program, running in its own container, that, at this stage, performs a simple assertion and returns a zero (success) or non-zero (failure) exit code.
It is a proof of concept which, obviously, and if the present proposal is accepted, will have to be reworked and replaced by a more robust test runner.
cFS<>GSW interactions
cfs
andgsw
services are interacting on their own internal network managed by Docker Compose (docker-compose.yml
, lines 27-29):Their IPs are dynamic. In order for
gsw
to getcfs
IP as well as its own, it uses the names of the corresponding Docker Compose services, benefiting therefore from the Docker DNS lookup feature (tools/e2eTests/gsw/gsw.py
, lines 35 and 42):Unit Tests Failures
As evoked above, the unit tests fail during the building stage (i.e. at compile-time, but not at runtime). This is due to a Docker limitation vis à vis POSIX message queues that is explainable by the fact that Docker disables, among other things, the
CAP_SYS_RESOURCE
Linux capability. When a cFS image is being built with unit tests enabled, the unit tests that fail areosal-core-test
(OS_QueueCreate
,OS_QueueDelete
,OS_QueueGetIdByName
andOS_QueueGetInfo
) as well asqueue-timeout-test
.There are four possible approaches to overcome this issue:
Disable unit tests at build time. In the context of continuous integration testing, that would make sense as the unit tests would continue to be performed in a preliminary and separate job.
Allow unit tests to fail at build time.
Modify the unit tests to make them fully compatible with Docker. Not necessarily desirable as it would affect the characteristics of the system under test.
Run unit tests at runtime. Indeed, the solution requires the Docker containers to run with capability
CAP_SYS_RESOURCE
(It should be noted thatprivileged: true
would have the same effect but with a more extensive scope) (docker-compose.yml
, lines 13-14):Such an approach would however blur the line between unit testing and end-to-end testing. For this reason, I would mostly recommend against it.
Suggestions for Future Improvements
Third party code
None
Contributor Info - All information REQUIRED for consideration of pull request
Guillaume Lethuillier
Personal, individual CLA submitted