diff --git a/ci/create-new-project b/ci/create-new-project index 62b07fcfd1c..f8d0304c5e9 100755 --- a/ci/create-new-project +++ b/ci/create-new-project @@ -1,5 +1,7 @@ #!/bin/bash -eux +echo ::group::Create the project + TAG=$(scripts/get-version --major) DOCKER_TAG=${TAG} make build-tools DOCKER_TAG=${TAG} make build-runner @@ -37,8 +39,6 @@ if [ $BASE_APP != true ]; then mv ${WORKSPACE}/${PACKAGE}/geoportal/vars.yaml ${WORKSPACE}/${PACKAGE}/geoportal/vars_origin.yaml cp ci/vars.yaml ${WORKSPACE}/${PACKAGE}/geoportal/ mkdir -p ${WORKSPACE}/${PACKAGE}/geoportal/ci - cp ci/waitwsgi ${WORKSPACE}/${PACKAGE}/geoportal/ci - cp ci/test-new-project ${WORKSPACE}/${PACKAGE}/geoportal/ci mkdir -p ${WORKSPACE}/${PACKAGE}/ci echo "PGSSLMODE=prefer" >> ${WORKSPACE}/${PACKAGE}/env.project fi @@ -75,12 +75,15 @@ git add --all git commit --quiet --message='Initial commit' mv ci/config.yaml{,_} +echo ::endgroup:: c2cciutils-checks --fix --check=isort c2cciutils-checks --fix --check=black c2cciutils-checks --fix --check=prettier mv ci/config.yaml{_,} +echo ::group::Diff git --no-pager diff +echo ::endgroup:: git add --all git commit --quiet --message='Format' git clean -fX diff --git a/ci/test-app b/ci/test-app index 6fb66707ed4..61c79355899 100755 --- a/ci/test-app +++ b/ci/test-app @@ -3,8 +3,9 @@ rm -rf "${HOME}/workspace/testgeomapfishapp" ci/create-new-project "${HOME}/workspace" + +# Copy the files needed to run the tests cp ci/docker-compose.override.yaml "${HOME}/workspace/testgeomapfishapp/" -cp ci/waitwsgi "${HOME}/workspace/testgeomapfishapp/ci/" cp ci/empty.qgz "${HOME}/workspace/testgeomapfishapp/qgisserver/project.qgz" cp -r ci/test-app-db "${HOME}/workspace/testgeomapfishapp/ci/" cp -r ci/test-external-db "${HOME}/workspace/testgeomapfishapp/ci/" @@ -14,12 +15,21 @@ cd "${HOME}/workspace/testgeomapfishapp/" folder=geoportal/interfaces cp -r CONST_create_template/${folder} ${folder} +file=tests/test_testapp.py +cp CONST_create_template/${file} ${file} +# Check if the `c2cciutils-checks` pass c2cciutils-checks cp "${PROJECT_DIR}/ci/project-config.yaml" ci/config.yaml c2cciutils-checks + +# Build +echo ::group::Build CI=true ./build +echo ::endgroup:: +# Lint +echo ::group::Lint docker-compose run --entrypoint= --no-deps --rm --volume=$(pwd)/geoportal:/app geoportal \ prospector --output-format=pylint --die-on-tool-error docker-compose run --entrypoint= --no-deps --rm --volume=$(pwd)/geoportal:/app geoportal \ @@ -28,69 +38,124 @@ docker-compose run --entrypoint= --no-deps --rm --volume=$(pwd)/geoportal:/app g eslint $(find testgeomapfishapp -type f -name '*.ts' -print 2> /dev/null) docker-compose down --volumes +echo ::endgroup:: + +# Start +echo ::group::Start docker-compose up -d docker-compose exec -T geoportal bash -c 'PGHOST=externaldb PGDATABASE=test wait-db;' docker-compose exec -T geoportal wait-db -docker-compose ps +echo ::endgroup:: +c2cciutils-docker-logs + +# Run alembic +echo ::group::Run alembic docker-compose exec -T geoportal alembic --config=alembic.ini --name=main upgrade head docker-compose exec -T geoportal alembic --config=alembic.ini --name=static upgrade head +docker-compose start alembic +echo ::endgroup:: +c2cciutils-docker-logs + +# Create the Theme +echo ::group::Create the Theme docker-compose exec -T geoportal create-demo-theme +echo ::endgroup:: c2cciutils-docker-logs + +# Test `theme2fts` +echo ::group::Test theme2fts docker-compose exec -T geoportal theme2fts +echo ::endgroup:: + +# Test `update-po` +echo ::group::Test update-po make update-po +echo ::endgroup:: -docker-compose exec -T geoportal ci/waitwsgi https://front/themes -for path in c2c/health_check c2c/health_check?max_level=9 c2c/health_check?checks=check_collector "layers/test/values/type enum" admin/layertree admin/layertree/children; do - docker-compose exec -T geoportal ci/test-new-project https://front/${path} +# Test the checker and QGIS +echo ::group::Test the checker and QGIS +for url in 'https://front/c2c/health_check?max_level=9' 'http://qgisserver:8080/mapserv_proxy?SERVICE=WMS&REQUEST=GetCapabilities'; do + docker-compose exec -T geoportal curl --fail --insecure "${url}" \ + || (docker-compose exec -T geoportal curl --insecure "${url}" && false) done -docker-compose exec -T geoportal ci/test-new-project 'http://qgisserver:8080/mapserv_proxy?SERVICE=WMS&REQUEST=GetCapabilities' -docker-compose exec -T geoportal curl --insecure https://front/admin/ | grep Login -docker-compose exec -T geoportal curl --insecure 'https://front/dynamic.json?interface=desktop&query=&path=%2F' -docker-compose exec -T geoportal curl --insecure https://front/static-geomapfish/0/locales/fr.json -docker-compose exec -T geoportal curl --insecure https://front/desktop_alt -docker-compose exec -T geoportal curl --insecure https://front/desktop_alt \ - | grep '' -docker-compose exec -T geoportal curl --insecure https://front/desktop_alt \ - | grep ' /tmp/locale.pot - if [ "$(wc -l < /tmp/locale.pot)" -eq "$(wc -l < geoportal/testgeomapfishapp_geoportal/locale/testgeomapfishapp_geoportal-client.pot)" ]; then - echo 'View locale.pot match in size with update-po' - else - echo 'Error: View locale.pot does not match in size with update-po' - sed -i 's%/app/%./geoportal/%g' /tmp/locale.pot - diff geoportal/testgeomapfishapp_geoportal/locale/testgeomapfishapp_geoportal-client.pot /tmp/locale.pot - exit 1 - fi -} -test_pot -# A second time to check that the initialisation is working -test_pot +echo ::endgroup:: +# Test the `proutes` and `pviews` commands +echo ::group::Test the proutes command with development.ini docker-compose exec -T geoportal proutes c2c://development.ini +echo ::endgroup:: +echo ::group::Test the pviews command with development.ini docker-compose exec -T geoportal pviews c2c://development.ini / +echo ::endgroup:: +echo ::group::Test the proutes command with production.ini docker-compose exec -T geoportal proutes c2c://production.ini +echo ::endgroup:: +echo ::group::Test the pviews command with production.ini docker-compose exec -T geoportal pviews c2c://production.ini / +echo ::endgroup:: -docker-compose stop qgisserver -docker-compose exec -T geoportal alembic --config=alembic.ini --name=static downgrade base -docker-compose exec -T geoportal alembic --config=alembic.ini --name=main downgrade base - +# Test the `db-backup` and `db-restore` commands +echo ::group::Test the db-backup command cp .env env.int echo PGHOST_SLAVE="$(ip -4 addr show docker0 | grep -Po 'inet \K[\d.]+')" >> env.int echo PGPORT_SLAVE=54321 >> env.int scripts/db-backup --env=env.int dump.backup -scripts/db-backup --env=env.int --arg=--schema=main dump.backup +scripts/db-backup --env=env.int --arg=--schema=main main-dump.backup +echo ::endgroup:: + +echo ::group::Test the db-restore command docker-compose exec -T tools psql --command="ALTER SCHEMA main RENAME TO main_old" docker-compose exec -T tools psql --command="CREATE SCHEMA main" scripts/db-restore --arg=--schema=main dump.backup +echo ::endgroup:: +# Empty the database +echo ::group::Empty the database +docker-compose exec -T geoportal alembic --config=alembic.ini --name=static downgrade base +docker-compose exec -T geoportal alembic --config=alembic.ini --name=main downgrade base +echo ::endgroup:: + +# Test the `mappyfile validate` command +echo ::group::Test the mappyfile validate command docker-compose exec -T tools rm /etc/mapserver/demo.map docker-compose exec -T tools mappyfile validate --version=7.6 /etc/mapserver/*.map +echo ::endgroup:: c2cciutils-docker-logs + +# Run the acceptances tests +echo ::group::Stop docker-compose down -sudo rm -rf "${HOME}/workspace/testgeomapfishapp" +mv docker-compose.override.yaml docker-compose.test.yaml +echo ::endgroup:: + +echo ::group::Init acceptance tests +make acceptance-init +docker-compose \ + --file=docker-compose.yaml \ + --file=docker-compose-db.yaml \ + --file=docker-compose.test.yaml up -d +echo ::endgroup:: +c2cciutils-docker-logs + +echo ::group::Run acceptance tests +make acceptance +echo ::endgroup:: +c2cciutils-docker-logs +echo ::group::Run acceptance tests in dev mode +docker-compose \ + --file=docker-compose.yaml \ + --file=docker-compose-db.yaml \ + --file=docker-compose.test.yaml \ + --file=docker-compose.override.sample.yaml up -d +make acceptance +echo ::endgroup:: +c2cciutils-docker-logs + +# Remove the test project +echo ::group::Remove the test project +docker-compose down --remove-orphans || true +cd - +sudo rm -rf "${HOME}/workspace/testgeomapfishapp" docker rmi camptocamp/testgeomapfishapp-config:latest +echo ::endgroup:: diff --git a/ci/test-new-project b/ci/test-new-project deleted file mode 100755 index 0efb5f47371..00000000000 --- a/ci/test-new-project +++ /dev/null @@ -1,63 +0,0 @@ -#!/usr/bin/env python3 - -# Copyright (c) 2011-2017, Camptocamp SA -# All rights reserved. - -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: - -# 1. Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. - -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -# The views and conclusions contained in the software and documentation are those -# of the authors and should not be interpreted as representing official policies, -# either expressed or implied, of the FreeBSD Project. - -import sys -import time - -import requests - -initial_error_length = 0 -initial_access_length = 0 - -url = sys.argv[1] - -for _ in range(10): - print(f"Query {url}") - # See also: - # ci/vars.yaml geoportal/GUNICORN_PARAMS - result = requests.get(url, timeout=240, verify=False) # nosec - if result.ok: - break - time.sleep(1) - -if len(sys.argv) == 3 and sys.argv[2] == "enum": - if result.ok and result.json() == {"items": [{"value": "car"}, {"value": "train"}]}: - print("enum OK") - sys.exit() - else: - print(f"Incorrect result ({result.status_code}):") - print(result.text) - sys.exit(2) - -if result.ok: - print("OK") -else: - print("NOT OK") - print(result.text) - sys.exit(2) diff --git a/ci/waitwsgi b/ci/waitwsgi deleted file mode 100755 index 1ca4d4c13f0..00000000000 --- a/ci/waitwsgi +++ /dev/null @@ -1,51 +0,0 @@ -#!/usr/bin/env python3 - -# Copyright (c) 2011-2017, Camptocamp SA -# All rights reserved. - -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: - -# 1. Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. - -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -# The views and conclusions contained in the software and documentation are those -# of the authors and should not be interpreted as representing official policies, -# either expressed or implied, of the FreeBSD Project. - -import sys -import time - -import requests - -sleep_time = 1 -max_sleep = 30 - -# Wait for the WSGI to be UP -while sleep_time < max_sleep: - print("Waiting for the WSGI server to be reachable") - sys.stdout.flush() - try: - requests.get(sys.argv[1], timeout=1, verify=False) # nosec - sys.exit(0) - except Exception as e: - print(str(e)) - print("Waiting for the WSGI server to be reachable") - sys.stdout.flush() - time.sleep(sleep_time) - sleep_time *= 2 -sys.exit(1) diff --git a/doc/integrator/create_application.rst b/doc/integrator/create_application.rst index a2a09393fcd..28d6de3693f 100644 --- a/doc/integrator/create_application.rst +++ b/doc/integrator/create_application.rst @@ -294,7 +294,57 @@ Then follow the sections in the install application guide: Dynamic configuration --------------------- -Several files are generated on runtime, their content depending of the variables you +Several files are generated on runtime, their content depending on the variables you have set as environment variables. The files can have the extension ``.tmpl`` and it use bash syntax (``${VARIABLE}``). + +GitHub workflows +---------------- + +With the application we have some predefined workflows. + +`.github/workflows/main.yaml` +............................. + +The workflow that will run on all your commits, he will: +- Run some code style checks on your code. +- Build you application. +- Run the acceptance tests (if configured). +- Publish the application on DockerHub. +- Trigger another workflow (on ArgoCD repository) to deploy you new application. + +`.github/workflows/rebuild.yaml` +................................ + +This workflow run on each night to rebuild the application with the new version of the base images. + +Be careful, GitHub will read only the file present on the main branch. + +`.github/workflows/update_l10n.yaml` +.................................... + +This workflow will query on of your server on the URL configured in the `Makefile` as +`PROJECT_PUBLIC_URL` the get the available list of string that should be translated (`.pot`) +and open a pull request with the new translations key tin your localized files (`.po`). + +Be careful, GitHub will read only the file present on the main branch. + +Acceptance tests +................ + +To have some acceptance tests you need to have a minimal dump of your application in the repository, +it can be obtained with: + +.. prompt:: bash + + scripts/db-backup --arg=--schema= ../dump.backup + +In the `Makefile` you should configure the dump file as `DUMP_FILE`, the `db-restore` call in `acceptance-init` +should probably also be updated. + +In the file `.github/workflows/main.yaml` you should uncomment all the lines related to the +acceptance tests. + +The acceptance tests will test that we didn't have any service in error, test the response of some URL, +see in the file `tests/test_app.py`. diff --git a/geoportal/c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.github/workflows/main.yaml b/geoportal/c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.github/workflows/main.yaml index a2d8bdcf18e..43aab613815 100644 --- a/geoportal/c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.github/workflows/main.yaml +++ b/geoportal/c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/.github/workflows/main.yaml @@ -6,10 +6,6 @@ on: env: PROJECT: {{cookiecutter.package}} - # Requires CI_GPG_PRIVATE_KEY and GOPASS_CI_GITHUB_TOKEN secrets. - # OPENSHIFT_PROJECT: gs-gmf-{{cookiecutter.package}} - # The release branches - HELM_RELEASE_NAMES: int-{{cookiecutter.geomapfish_main_version_dash}},prod-{{cookiecutter.geomapfish_main_version_dash}} jobs: main: @@ -30,9 +26,23 @@ jobs: - run: echo "${HOME}/.local/bin" >> ${GITHUB_PATH} - run: python3 -m pip install --user --requirement=ci/requirements.txt + # Can be used to have some secrets (with mask) + # - run: make secrets + # - run: cat env.secrets |grep '^[# A-Z0-9_]\+='|sed -e 's/^[# A-Z0-9_]\+=\(.*\)/::add-mask::\1/g' + - name: Checks run: c2cciutils-checks + # - name: Initialize the acceptance tests + # run: make acceptance-init + # - run: c2cciutils-docker-logs + # if: always() + + # - name: Run the acceptance tests + # run: make acceptance + # - run: c2cciutils-docker-logs + # if: always() + - name: Build run: ./build diff --git a/geoportal/c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/Makefile b/geoportal/c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/Makefile index 0f507275ca6..eb89f66a711 100644 --- a/geoportal/c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/Makefile +++ b/geoportal/c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/Makefile @@ -1,4 +1,5 @@ PROJECT_PUBLIC_URL=https://example.camptocamp.com/ +DUMP_FILE=dump.backup PACKAGE={{cookiecutter.package}} LANGUAGES=en fr de it @@ -34,3 +35,34 @@ eslint: ## Runs the eslint checks eslint $(find {{cookiecutter.package}} -type f -name '*.js' -print 2> /dev/null) docker-compose run --entrypoint= --no-deps --rm --volume=$(pwd)/geoportal:/app geoportal \ eslint $(find {{cookiecutter.package}} -type f -name '*.ts' -print 2> /dev/null) + +.PHONY: qgis +qgis: ## Run QGIS desktop + docker-compose -f docker-compose.yaml -f docker-compose-qgis.yaml run --rm qgis + +secrets.tar.bz2.gpg: env.secrets ## Create the secrets.tar.bz2.gpg files we depends on + tar -jcf secrets.tar.bz2 $^ + rm -f $@ + gpg --symmetric --cipher-algo AES256 --batch \ + --passphrase=$(shell gopass show gs/ci/large-secret-passphrase) secrets.tar.bz2 + rm secrets.tar.bz2 + +.PHONY: secrets +secrets: ## Decript the sectrets.tar.bz2.gpg file + gpg --quiet --batch --yes --decrypt --passphrase=$(shell gopass show gs/ci/large-secret-passphrase) \ + --output secrets.tar.bz2 secrets.tar.bz2.gpg + tar --touch -jxf secrets.tar.bz2 + rm secrets.tar.bz2 + +.PHONY: acceptance-init +acceptance-init: ## Initialize the acceptance tests + docker-compose --file=docker-compose.yaml --file=docker-compose-db.yaml up -d + docker-compose exec -T geoportal wait-db + docker-compose exec -T tools psql --command="DROP EXTENSION IF EXISTS postgis CASCADE" + scripts/db-restore --docker-compose-file=docker-compose.yaml --docker-compose-file=docker-compose-db.yaml \ + --arg=--clean --arg=--if-exists --arg=--verbose $(DUMP_FILE) + +.PHONY: acceptance +acceptance: ## Run the acceptance tests + docker-compose exec -T tools pytest -vv tests/ + ci/docker-compose-check diff --git a/geoportal/c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/ci/docker-compose-check b/geoportal/c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/ci/docker-compose-check new file mode 100755 index 00000000000..5feb9c31b3c --- /dev/null +++ b/geoportal/c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/ci/docker-compose-check @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 + +import argparse +import subprocess +import sys + + +def _main() -> None: + argparser = argparse.ArgumentParser("Tests that's all the services are running") + argparser.parse_args() + + services = [ + s.strip() + for s in subprocess.run(["docker-compose", "ps"], check=True, stdout=subprocess.PIPE) + .stdout.decode("utf-8") + .splitlines() + ] + errors_statuses = [s for s in services if " Exit " in s and not s.endswith(" Exit 0")] + if errors_statuses: + print("\n".join(errors_statuses)) + sys.exit(1) + + +if __name__ == "__main__": + _main() diff --git a/geoportal/c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/docker-compose-db.yaml b/geoportal/c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/docker-compose-db.yaml new file mode 100644 index 00000000000..6e5e992218d --- /dev/null +++ b/geoportal/c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/docker-compose-db.yaml @@ -0,0 +1,26 @@ +# This file is used by the acceptance tests to have a local database. + +version: '2.3' + +volumes: + postgresql_data: + +services: + config: &db-config + environment: + - PGHOST=db + - PGHOST_SLAVE=db + - PGSSLMODE=prefer + geoportal: *db-config + # geoportal-advance: *db-config + tools: *db-config + alembic: *db-config + # alembic-advance: *db-config + # webpack_dev_server: *db-config + + db: + extends: + file: docker-compose-lib.yaml + service: db + volumes: + - postgresql_data:/var/lib/postgresql/data diff --git a/geoportal/c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/docker-compose-lib.yaml b/geoportal/c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/docker-compose-lib.yaml index 19aac8d7704..febefadfeb8 100644 --- a/geoportal/c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/docker-compose-lib.yaml +++ b/geoportal/c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/docker-compose-lib.yaml @@ -1,4 +1,5 @@ ---- +# This files is managed by c2cgeoportal, he contains the default services configuration + version: '2.3' services: diff --git a/geoportal/c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/docker-compose-qgis.yaml b/geoportal/c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/docker-compose-qgis.yaml new file mode 100644 index 00000000000..af3860dd718 --- /dev/null +++ b/geoportal/c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/docker-compose-qgis.yaml @@ -0,0 +1,23 @@ +# This file is used to run QGIS client from the Docker image + +version: '2' + +services: + qgis: + extends: + file: docker-compose-lib.yaml + service: qgisserver + image: camptocamp/qgis-server:${QGIS_VERSION}-desktop + user: root + volumes_from: + - config + volumes: + - ${HOME}:${HOME} + - /tmp/.X11-unix:/tmp/.X11-unix + environment: + - PGSERVICEFILE=/etc/qgisserver/pg_service.conf + - DISPLAY=unix${DISPLAY} + - QGIS_DEBUG=0 + - QGIS_LOG_FILE=/dev/null + - PGOPTIONS=-c statement_timeout=30000 + - AZURE_STORAGE_CONNECTION_STRING diff --git a/geoportal/c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/docker-compose.override.sample.yaml b/geoportal/c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/docker-compose.override.sample.yaml index c346b42afc0..cb1a9227ad3 100644 --- a/geoportal/c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/docker-compose.override.sample.yaml +++ b/geoportal/c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/docker-compose.override.sample.yaml @@ -1,4 +1,3 @@ ---- # This file can be renamed as `docker-compose.override.yaml` and uncomment the desired lines for # development. The file `docker-compose.override.yaml` is ignored by Git by default. diff --git a/geoportal/c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/docker-compose.yaml b/geoportal/c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/docker-compose.yaml index 46a3f639302..a9e110330da 100644 --- a/geoportal/c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/docker-compose.yaml +++ b/geoportal/c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/docker-compose.yaml @@ -1,5 +1,4 @@ ---- -# The project Docker compose file for development. +# The project Docker compose file. version: '2.3' diff --git a/geoportal/c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/tests/__init__.py b/geoportal/c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/tests/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/geoportal/c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/tests/test_app.py b/geoportal/c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/tests/test_app.py new file mode 100644 index 00000000000..fa59c6164d2 --- /dev/null +++ b/geoportal/c2cgeoportal_geoportal/scaffolds/create/{{cookiecutter.project}}/tests/test_app.py @@ -0,0 +1,43 @@ +import time +from typing import Dict + +import pytest +import requests + + +@pytest.mark.parametrize( + "url,params", + [ + ("https://front", {}), + ("https://front/themes", {}), + ("https://front/static-geomapfish/0/locales/fr.json", {}), + ("https://front/dynamic.json", {"interface": "desktop"}), + ("https://front/dynamic.json", {"interface": "desktop", "query": "", "path": "/"}), + ("https://front/c2c/health_check", {}), + ("https://front/c2c/health_check", {"max_level": "1"}), + ("https://front/c2c/health_check", {"checker": "check_collector"}), + ("https://front/admin/layertree", {}), + ("https://front/admin/layertree/children", {}), + ("http://mapserver:8080/mapserv_proxy", {"SERVICE": "WMS", "REQUEST": "GetCapabilities"}), + ( + "https://front/mapserv_proxy", + {"ogcserver": "source for image/png", "SERVICE": "WMS", "REQUEST": "GetCapabilities"}, + ), + ], +) +def test_url(url: str, params: Dict[str, str]) -> None: + """Tests that some URL didn't return an error.""" + for _ in range(60): + response = requests.get(url, params=params, verify=False, timeout=240) # nosec + if response.status_code == 503: + time.sleep(1) + continue + break + assert response.status_code == 200, response.text + + +def test_admin() -> None: + """Tests that the admin page will provide the login page.""" + response = requests.get("https://front/admin/", verify=False, timeout=240) # nosec + assert response.status_code == 200, response.text + assert "Login" in response.text diff --git a/geoportal/c2cgeoportal_geoportal/scaffolds/update/{{cookiecutter.project}}/.upgrade.yaml b/geoportal/c2cgeoportal_geoportal/scaffolds/update/{{cookiecutter.project}}/.upgrade.yaml index efa803582a1..1e4868ac0bd 100644 --- a/geoportal/c2cgeoportal_geoportal/scaffolds/update/{{cookiecutter.project}}/.upgrade.yaml +++ b/geoportal/c2cgeoportal_geoportal/scaffolds/update/{{cookiecutter.project}}/.upgrade.yaml @@ -44,6 +44,7 @@ extra: - geoportal/{{cookiecutter.package}}_geoportal/static-ngeo/js/apps/sass/vars_oeedit\.scss - geoportal/interfaces/desktop_alt\.html\.mako - geoportal/{{cookiecutter.package}}_geoportal/static/images/background-layer-button\.png + - tests/test_testapp.py # Automated file system operations: # Remove some files or directories: diff --git a/geoportal/c2cgeoportal_geoportal/scaffolds/update/{{cookiecutter.project}}/CONST_create_template/tests/test_testapp.py b/geoportal/c2cgeoportal_geoportal/scaffolds/update/{{cookiecutter.project}}/CONST_create_template/tests/test_testapp.py new file mode 100644 index 00000000000..48d5c0f87cc --- /dev/null +++ b/geoportal/c2cgeoportal_geoportal/scaffolds/update/{{cookiecutter.project}}/CONST_create_template/tests/test_testapp.py @@ -0,0 +1,49 @@ +# This file should be used only on the test project in the c2cgeoportal CI + +import re + +import polib +import pytest +import requests + + +@pytest.mark.parametrize("test_number", [0, 1]) +def test_po(test_number: int) -> None: + """Tests that the generated pot files are identical between the command lin and the view.""" + del test_number + + response = requests.get("https://front/locale.pot", verify=False, timeout=240) # nosec + assert response.status_code == 200, response.text + response_keys = {e.msgid for e in polib.pofile(response.text)} + + with open( + "geoportal/{{cookiecutter.package}}_geoportal/locale/{{cookiecutter.package}}_geoportal-client.pot", + "r", + encoding="utf-8", + ) as current_file: + current_content = current_file.read() + current_content_keys = {e.msgid for e in polib.pofile(current_content)} + + if response_keys != current_content_keys: + assert response.text == current_content + + +@pytest.mark.parametrize("url", ["https://front/desktop_alt"]) +def test_desktop_alt(url: str) -> None: + """Tests the desktop alt page.""" + response = requests.get(url, verify=False, timeout=240) # nosec + assert response.status_code == 200, response.text + + assert re.search( + r'', + response.text, + ), response.text + assert re.search(r' None: + """Test the enumerations view""" + response = requests.get("https://front/layers/test/values/type", verify=False, timeout=240) # nosec + assert response.status_code == 200, response.text + + assert response.json() == {"items": [{"value": "car"}, {"value": "train"}]}, response.text