diff --git a/.gitignore b/.gitignore index 10e3ab5..2a14b47 100644 --- a/.gitignore +++ b/.gitignore @@ -117,3 +117,4 @@ htmlcov/ **/*.svg !anybadge/templates/*.svg +test_files/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5aa7a66..64bdb7e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -145,12 +145,16 @@ Invoke tasks are defined in the `tasks/` directory in the project. Feel free to ## Running tests +### Local tests + You can run tests locally using: ```bash inv test.local ``` +### Containerised tests + When running locally, you will be running tests against the code in the project. This has some disadvantages, specifically running locally may not detect files that are not included in the package build, e.g. sub-modules, templates, examples, etc. For this reason we have a containerised test. This can be run using: @@ -163,6 +167,34 @@ This will clean up the project `dist` directory, build the package locally, buil spin up a docker container, install the package and run the tests. The tests should run using the installed package and not the project source code, so this method should be used as a final test before pushing. +### PyPi tests + +It is useful to validate PyPi releases when a new version is deployed. This should be done after every +release. + +#### Running tests + +To test the latest available PyPi package, run: + +```bash +inv test.pypi> +``` + +To test a specific version of a PyPi package, run: + +```bash +inv test.pypi --version=\ +``` + +When the tests run they will output test files into a `\_\` directory under `test_files/`. +After running tests, inspect the console output to see if there were any errors then inspect each file in the +`test_files` directory. + +#### Adding tests + +The PyPi tests are implemented in `docker/test/run_pypi_tests.sh`. If you find a bug, then adding a test to this script +could be useful, and quicker than adding a unittest. + ## Documentation The `README.md` file contains a table showing example badges for the different built-in colors. If you modify the diff --git a/docker/test/Dockerfile b/docker/test/Dockerfile index 93ed529..dd592e1 100644 --- a/docker/test/Dockerfile +++ b/docker/test/Dockerfile @@ -6,3 +6,4 @@ RUN apt update && pip install -U pip COPY requirements.txt ./ RUN pip install -r ./requirements.txt COPY run_docker_tests.sh ./ +COPY run_pypi_tests.sh ./ diff --git a/docker/test/run_pypi_tests.sh b/docker/test/run_pypi_tests.sh new file mode 100755 index 0000000..f503445 --- /dev/null +++ b/docker/test/run_pypi_tests.sh @@ -0,0 +1,78 @@ +#!/bin/bash + +error() { + echo "===============================================================================" + echo " An error was encountered." + echo "===============================================================================" + } + +check_rc() { + if [[ $? -ne 0 ]]; then + error + exit 1 + fi + } + +TEST_FILES="/test_files" + +if [[ -z {$VERSION} ]] || [[ ${VERSION} = latest ]]; then + version_str="" +else + version_str="==$VERSION" +fi + +echo -n "Installing anybadge${version_str}... " +pip install anybadge${version_str} > "${TEST_FILES}/pip_install.log" 2>&1 +check_rc +echo "OK" + +installed_version=$(pip freeze | grep -e "^anybadge==" | sed 's/^.*==//' ) +datestamp=$(date '+%Y-%m-%d_%H%M%S') + +TEST_FILES="${TEST_FILES}/${installed_version}_${datestamp}" +echo -n "Creating test directory: ${TEST_FILES} " +mkdir -p ${TEST_FILES} +check_rc +echo "OK" + +# Command line tests +anybadge --help > "${TEST_FILES}/test_help_text.txt" && check_rc +anybadge --label="Label" --value="Value" --file "${TEST_FILES}/test_command_line.svg" && check_rc + +# Python tests +python > "${TEST_FILES}/test_python_console.log" < "${TEST_FILES}/server_start.log" 2>&1 & +server_pid=$! +echo "OK - Started server with pid ${server_pid}" +sleep 1 + +kill -0 ${server_pid} +check_rc + +# Test server +echo -n "Testing server badge... " +curl "http://localhost:8000/?label=Project%20Awesomeness&value=110%" -o "${TEST_FILES}/test_server.svg" --silent +check_rc +echo "OK" + +echo -n "Testing server index page... " +curl "http://localhost:8000" -o "${TEST_FILES}/test_server_index.html" --silent +check_rc +echo "OK" + +# Stop server +echo -n "Stopping server... " +kill $server_pid +check_rc + +echo "OK" diff --git a/tasks/__init__.py b/tasks/__init__.py index 7e0fa0f..7548e47 100644 --- a/tasks/__init__.py +++ b/tasks/__init__.py @@ -5,7 +5,7 @@ import subprocess from pathlib import Path from invoke import task, Collection -from tasks import test, server +from tasks import test, server, housekeeping PROJECT_DIR = Path(__file__).parent.parent @@ -28,20 +28,6 @@ def examples(c): main() -def delete_files(files: str): - for file in glob.glob(files): - print(f" Deleting {file}") - subprocess.run(["rm", "-rf", file]) - - -@task() -def clean(c): - """Clean up the project area.""" - print("Cleaning the project directory...") - delete_files("dist/*") - delete_files("tests/test_*.svg") - - -namespace = Collection(test, server) -for fn in [build, examples, clean]: +namespace = Collection(test, server, housekeeping) +for fn in [build, examples]: namespace.add_task(fn) diff --git a/tasks/housekeeping.py b/tasks/housekeeping.py new file mode 100644 index 0000000..7f6ff69 --- /dev/null +++ b/tasks/housekeeping.py @@ -0,0 +1,18 @@ +import glob +import subprocess +from invoke import task + + +def delete_files(files: str): + for file in glob.glob(files): + print(f" Deleting {file}") + subprocess.run(["rm", "-rf", file]) + + +@task() +def clean(c): + """Clean up the project area.""" + print("Cleaning the project directory...") + delete_files("dist/*") + delete_files("tests/test_*.svg") + delete_files("test_files/*") diff --git a/tasks/server.py b/tasks/server.py index 647b55c..e173906 100644 --- a/tasks/server.py +++ b/tasks/server.py @@ -5,12 +5,14 @@ from invoke import task @task def docker_build(c): + """Build docker image for anybadge server.""" print("Building Docker image...") subprocess.run("docker build . -t anybadge:latest", shell=True) @task def docker_run(c, port=8000): + """Run containerised anybadge server.""" print("Running server in Docker container...") subprocess.run( f"docker run -it --rm -p{port}:{port}/tcp anybadge:latest --port={port}", @@ -20,5 +22,6 @@ def docker_run(c, port=8000): @task def run(c, port=8000): + """Run local anybadge server.""" print("Running server locally...") subprocess.run(f"python3 anybadge_server.py --port={port}", shell=True) diff --git a/tasks/test.py b/tasks/test.py index e26dfe0..1820904 100644 --- a/tasks/test.py +++ b/tasks/test.py @@ -3,6 +3,8 @@ from pathlib import Path from invoke import task +from tasks.housekeeping import clean + PROJECT_DIR = Path(__file__).parent.parent @@ -16,6 +18,12 @@ def local(c): ) +def build_test_docker_image(): + subprocess.run( + f"(cd docker/test && docker build . -t test-anybadge:latest)", shell=True + ) + + @task def docker(c): """Run dockerised tests.""" @@ -23,10 +31,24 @@ def docker(c): subprocess.run("invoke clean", shell=True) subprocess.run("invoke build", shell=True) - subprocess.run( - f"(cd docker/test && docker build . -t test-anybadge:latest)", shell=True - ) + build_test_docker_image() subprocess.run( f"docker run -v {PROJECT_DIR}:/app test-anybadge:latest /work/run_docker_tests.sh", shell=True, ) + + +@task +def pypi(c, version="latest"): + """Run tests against Pypi version.""" + print("Running tests against pypi version...") + + clean(c) + test_files = PROJECT_DIR / Path("test_files") + test_files.mkdir(exist_ok=True) + + build_test_docker_image() + subprocess.run( + f"docker run -e VERSION={version} -v {test_files.absolute()}:/test_files test-anybadge:latest /work/run_pypi_tests.sh", + shell=True, + )