diff --git a/.docker/README.md b/.docker/README.md new file mode 100644 index 00000000000..074038e0d49 --- /dev/null +++ b/.docker/README.md @@ -0,0 +1,194 @@ +QGIS Docker images +================== + +The QGIS project provides a few official docker images that can be +used for testing purposes. + +These dockers are currently used to run continuous integration +tests for the QGIS project itself and to run continuous integration +tests for several third party Python plugins. + +The images are automatically built every day and pushed on docker hub +to the QGIS account: https://hub.docker.com/r/qgis/ + +# Available images + +## Dependencies image + +`qgis/qgis3-build-deps` + +This is a simple base image that contains all the dependencies required to build +QGIS, it is used by the other images. + +Multiple versions of this image may be available: the suffix in the image name indicates the Ubuntu version they are based on. + +## Main QGIS image + +`qgis/qgis` + +This is the main image containing a build of QGIS. + + +### Features + +The docker file builds QGIS from the current directory +sets up a testing environment and to run tests inside QGIS. + +You can use this docker to test QGIS or to run unit tests inside QGIS, +`xvfb` (A fake X server) is available and running as a service inside the +container to allow for fully automated headless testing in CI pipelines +such as Travis or Circle-CI. + +### Building + +You can build the image from the main directory of the QGIS source tree with: + +``` +$ docker build -t qgis/qgis:latest \ + --build-arg DOCKER_TAG=latest \ + -f .docker/qgis.dockerfile \ + . +``` + +The `DOCKER_TAG` argument, can be used to specify the tag of the dependencies image. + + +### Running QGIS + +You can also use this image to run QGIS on your desktop. + +To run a QGIS container, assuming that you want to use your current +display to use QGIS and the image is tagged `qgis/qgis:latest` you can use a script like the one here below: + +``` +# Allow connections from any host +$ xhost + +$ docker run --rm -it --name qgis -v /tmp/.X11-unix:/tmp/.X11-unix \ + -e DISPLAY=unix$DISPLAY qgis/qgis:latest qgis +``` + +This code snippet will launch QGIS inside a container and display the +application on your screen. + +### Running unit tests inside QGIS + +Suppose that you have local directory containing the tests you want to execute into QGIS: + +``` +/my_tests/travis_tests/ +├── __init__.py +└── test_TravisTest.py +``` + +To run the tests inside the container, you must mount the directory that +contains the tests (e.g. your local directory `/my_tests`) into a volume +that is accessible by the container, see `-v /my_tests/:/tests_directory` +in the example below: + +``` +$ docker run -d --name qgis -v /tmp/.X11-unix:/tmp/.X11-unix \ + -v /my_tests/:/tests_directory \ + -e DISPLAY=:99 \ + qgis/qgis:latest +``` + + +When done, you can invoke the test runnner by specifying the test +that you want to run, for instance: + +``` +$ docker exec -it qgis sh -c "cd /tests_directory && qgis_testrunner.sh travis_tests.test_TravisTest.run_fail" + +``` + +The test can be specified by using a dotted notation, similar to Python +import notation, by default the function named `run_all` will be executed +but you can pass another function name as the last item in the dotted syntax: + +``` +# Call the default function "run_all" inside test_TravisTest module +qgis_testrunner.sh travis_tests.test_TravisTest +# Call the function "run_fail" inside test_TravisTest module +qgis_testrunner.sh travis_tests.test_TravisTest.run_fail +``` + +Please note that in order to make the test script accessible to Python +the calling command must ensure that the tests are in Python path. +Common patterns are: +- change directory to the one containing the tests (like in the examples above) +- add to `PYTHONPATH` the directory contaning the tests + +#### Running tests for a Python plugin + +All the above considerations applies to this case too, however in order +to simulate the installation of the plugin inside QGIS, you'll need to +make an additional step: call `qgis_setup.sh ` in the +docker container before actually running the tests (see the paragraph +about Running on Travis for a complete example). + +The `qgis_setup.sh` script prepares QGIS to run in headless mode and +simulate the plugin installation process: + +- creates the QGIS profile folders +- installs `startup.py` monkey patches to prevent blocking dialogs +- enables the plugin + +#### Options for the test runner + +The env var `QGIS_EXTRA_OPTIONS` defaults to an empty string and can +contains extra parameters that are passed to QGIS by the test runner. + + +#### Running on Travis + +Here is a simple example for running unit tests of a small QGIS plugin (named *QuickWKT*), assuming that the tests are in `tests/test_Plugin.py` under +the main directory of the QuickWKT plugin: + +``` +services: + - docker +install: + - docker run -d --name qgis-testing-environment -v ${TRAVIS_BUILD_DIR}:/tests_directory -e DISPLAY=:99 qgis/qgis:latest + - sleep 10 # This is required to allow xvfb to start + # Setup qgis and enables the plugin + - docker exec -it qgis-testing-environment sh -c "qgis_setup.sh QuickWKT" + # Additional steps (for example make or paver setup) here + # Link the plugin to the tests_directory + # (this mimicks the plugin download and installation process) + - docker exec -it qgis-testing-environment sh -c "ln -s /tests_directory/ /root/.local/share/QGIS/QGIS3/profiles/default/python/plugins/QuickWKT" + +script: + - docker exec -it qgis-testing-environment sh -c "cd /tests_directory &&qgis_testrunner.sh QuickWKT.tests.test_Plugin" +``` + +Please note that `cd /tests_directory && ` before the call to `qgis_testrunner.sh` could be avoided here, because QGIS automatically +adds the plugin main directory to Python path. + + +#### Implementation notes + +The main goal of the test runner in this image is to execute unit tests +inside a real instance of QGIS (not a mocked one). + +The QGIS tests should be runnable from a Travis/Circle-CI CI job. + +The implementation is: + +- run the docker, mounting as volumes the unit tests folder in `/tests_directory` + (or the QGIS plugin folder if the unit tests belong to a plugin and the + plugin is needed to run the tests) +- execute `qgis_setup.sh MyPluginName` script in docker that sets up QGIS to + avoid blocking modal dialogs and installs the plugin into QGIS if needed + - create config and python plugin folders for QGIS + - enable the plugin in the QGIS configuration file + - install the `startup.py` script to disable python exception modal dialogs +- execute the tests by running `qgis_testrunner.sh MyPluginName.tests.tests_MyTestModule.run_my_tests_function` +- the output of the tests is captured by the `test_runner.sh` script and + searched for `FAILED` (that is in the standard unit tests output) and other + string that indicate a failure or success condition, if a failure condition + is identified, the script exists with `1` otherwise it exits with `0`. + +`qgis_testrunner.sh` accepts a dotted notation path to the test module that +can end with the function that has to be called inside the module to run the +tests. The last part (`.run_my_tests_function`) can be omitted and defaults to +`run_all`.