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 (
cfsservice) and a test runner (gswservice) interact. The following screen captures illustrate this mechanism by comparing a passing test with a failing one.gswservice: the test runnercfsservice: the system under test (i.e. a containerized cFS executable)NOOPcommand 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 gswWhen 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
READMEfile located intools/e2eTestssubdirectory.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
gswtest runner (tools/e2eTests/gsw/gsw.py):NOOPcommand (for the SAMPLE app) packet to the cFSSAMPLE: NOOP commandevent 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.ymlfile to make them interact. This Docker Compose file makes reference to two services:cfs(the system under test) andgsw(the test runner).cFS Dockerfiles -
cfsserviceThe cFS Dockerfiles have a multistage structure. The first stage builds the
core-cpu1executable file. The second one corresponds to the runtime environment for this executable.Pseudo-GSW (test runner) -
gswserviceThe 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
cfsandgswservices are interacting on their own internal network managed by Docker Compose (docker-compose.yml, lines 27-29):Their IPs are dynamic. In order for
gswto getcfsIP 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_RESOURCELinux 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_QueueGetIdByNameandOS_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: truewould 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