From 2779d1eac0d0ab8517644c6d29c70ac55a999bd2 Mon Sep 17 00:00:00 2001 From: Steven Bal Date: Fri, 21 Mar 2025 13:05:02 +0100 Subject: [PATCH 1/2] :construction_worker: Use pytest-django in performance tests instead of running the app in a docker container --- .github/workflows/ci.yml | 31 ++++++++++++++++++--------- performance_test/conftest.py | 22 +++++++++++++++++++ performance_test/test_objects_list.py | 6 +++--- requirements/ci.txt | 3 +++ requirements/dev.txt | 5 +++++ requirements/test-tools.in | 1 + setup.cfg | 4 ++++ 7 files changed, 59 insertions(+), 13 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 371664e6..6d38c5b8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -69,23 +69,34 @@ jobs: name: Run the performance test suite runs-on: ubuntu-latest + services: + postgres: + image: postgis/postgis:${{ matrix.postgres }}-${{ matrix.postgis }} + env: + POSTGRES_HOST_AUTH_METHOD: trust + ports: + - 5432:5432 + # needed because the postgres container does not provide a healthcheck + options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 + steps: - uses: actions/checkout@v4 - - name: Bring up docker compose and load data - run: | - docker compose up -d --build || ( docker compose logs >&2 && exit 1; ) - until docker compose logs web | grep -q "spawned uWSGI worker"; do - echo "uWSGI not running yet, waiting..." - sleep 3 - done - docker compose exec --user root web pip install factory-boy - cat performance_test/create_data.py | docker compose exec -T web src/manage.py shell + - name: Set up backend environment + uses: maykinmedia/setup-django-backend@v1.3 + with: + apt-packages: 'libgdal-dev gdal-bin' + python-version: '3.11' + setup-node: false - name: Run tests run: | - pip install -r requirements/ci.txt pytest performance_test/ --benchmark-json output.json + env: + DJANGO_SETTINGS_MODULE: objects.conf.ci + SECRET_KEY: dummy + DB_USER: postgres + DB_PASSWORD: '' docs: runs-on: ubuntu-latest diff --git a/performance_test/conftest.py b/performance_test/conftest.py index 02cff041..20e1be17 100644 --- a/performance_test/conftest.py +++ b/performance_test/conftest.py @@ -1,5 +1,8 @@ import pytest +from objects.core.tests.factories import ObjectRecordFactory, ObjectTypeFactory +from objects.token.tests.factories import TokenAuthFactory + @pytest.fixture def benchmark_assertions(benchmark): @@ -11,3 +14,22 @@ def wrapper(**kwargs): ), f"{name} {getattr(stats, name)}s exceeded {value}s" return wrapper + + +@pytest.fixture(scope="session") +def setup(django_db_setup, django_db_blocker): + with django_db_blocker.unblock(): + object_type = ObjectTypeFactory.create( + service__api_root="http://localhost:8001/api/v2/", + uuid="f1220670-8ab7-44f1-a318-bd0782e97662", + ) + + TokenAuthFactory(token="secret", is_superuser=True) + + ObjectRecordFactory.create_batch( + 5000, + object__object_type=object_type, + start_at="2020-01-01", + version=1, + data={"kiemjaar": "1234"}, + ) diff --git a/performance_test/test_objects_list.py b/performance_test/test_objects_list.py index 8cfc0676..19a2acf9 100644 --- a/performance_test/test_objects_list.py +++ b/performance_test/test_objects_list.py @@ -1,13 +1,13 @@ import pytest -import requests from furl import furl BASE_URL = furl("http://localhost:8000/api/v2/") AUTH_HEADERS = {"Authorization": "Token secret"} +@pytest.mark.django_db @pytest.mark.benchmark(max_time=60, min_rounds=5) -def test_objects_api_list(benchmark, benchmark_assertions): +def test_objects_api_list(benchmark, benchmark_assertions, client, setup): """ Regression test for maykinmedia/objects-api#538 """ @@ -19,7 +19,7 @@ def test_objects_api_list(benchmark, benchmark_assertions): } def make_request(): - return requests.get((BASE_URL / "objects").set(params), headers=AUTH_HEADERS) + return client.get((BASE_URL / "objects").set(params), headers=AUTH_HEADERS) result = benchmark(make_request) diff --git a/requirements/ci.txt b/requirements/ci.txt index 187a78ee..67353e88 100644 --- a/requirements/ci.txt +++ b/requirements/ci.txt @@ -589,8 +589,11 @@ pytest==8.3.3 # via # -r requirements/test-tools.in # pytest-benchmark + # pytest-django pytest-benchmark==5.1.0 # via -r requirements/test-tools.in +pytest-django==4.10.0 + # via -r requirements/test-tools.in python-dateutil==2.9.0.post0 # via # -c requirements/base.txt diff --git a/requirements/dev.txt b/requirements/dev.txt index fd701307..79adb54f 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -717,10 +717,15 @@ pytest==8.3.3 # -c requirements/ci.txt # -r requirements/ci.txt # pytest-benchmark + # pytest-django pytest-benchmark==5.1.0 # via # -c requirements/ci.txt # -r requirements/ci.txt +pytest-django==4.10.0 + # via + # -c requirements/ci.txt + # -r requirements/ci.txt python-dateutil==2.9.0.post0 # via # -c requirements/ci.txt diff --git a/requirements/test-tools.in b/requirements/test-tools.in index 120cdd00..fc3a5616 100644 --- a/requirements/test-tools.in +++ b/requirements/test-tools.in @@ -5,6 +5,7 @@ codecov pytest pytest-benchmark +pytest-django coverage < 5.0 django-webtest factory-boy diff --git a/setup.cfg b/setup.cfg index 91adacab..345b9afb 100644 --- a/setup.cfg +++ b/setup.cfg @@ -14,3 +14,7 @@ skip_glob = **/migrations/** known_django=django known_first_party=objects sections=FUTURE,STDLIB,DJANGO,THIRDPARTY,FIRSTPARTY,LOCALFOLDER + +[tool:pytest] +DJANGO_SETTINGS_MODULE = objects.conf.ci +pythonpath = . src From 35f413696385c55795af485cd993d901b986ea43 Mon Sep 17 00:00:00 2001 From: Steven Bal Date: Fri, 21 Mar 2025 13:12:58 +0100 Subject: [PATCH 2/2] tmp --- .github/workflows/ci.yml | 227 ++++++++++++++++++++------------------- 1 file changed, 114 insertions(+), 113 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6d38c5b8..2b1f16e4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,57 +13,57 @@ env: IMAGE_NAME: maykinmedia/objects-api jobs: - tests: - strategy: - matrix: - postgres: ['13', '15', '16', '17'] - postgis: ['3.2', '3.5'] - exclude: - # postgis 3.2 is not compatible with recent postgres versions - - postgres: '17' - postgis: '3.2' - - postgres: '16' - postgis: '3.2' - - postgres: '15' - postgis: '3.2' - - name: Run the Django test suite (PG ${{ matrix.postgres }}, postgis ${{ matrix.postgis }}) - - runs-on: ubuntu-latest - - services: - postgres: - image: postgis/postgis:${{ matrix.postgres }}-${{ matrix.postgis }} - env: - POSTGRES_HOST_AUTH_METHOD: trust - ports: - - 5432:5432 - # needed because the postgres container does not provide a healthcheck - options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 - - steps: - - uses: actions/checkout@v4 - - name: Set up backend environment - uses: maykinmedia/setup-django-backend@v1.3 - with: - apt-packages: 'libgdal-dev gdal-bin' - python-version: '3.11' - setup-node: true - - - name: Run tests - run: | - python src/manage.py collectstatic --noinput --link - coverage run src/manage.py test src - env: - DJANGO_SETTINGS_MODULE: objects.conf.ci - SECRET_KEY: dummy - DB_USER: postgres - DB_PASSWORD: '' - - - name: Publish coverage report - uses: codecov/codecov-action@v4 - with: - token: ${{ secrets.CODECOV_TOKEN }} + # tests: + # strategy: + # matrix: + # postgres: ['13', '15', '16', '17'] + # postgis: ['3.2', '3.5'] + # exclude: + # # postgis 3.2 is not compatible with recent postgres versions + # - postgres: '17' + # postgis: '3.2' + # - postgres: '16' + # postgis: '3.2' + # - postgres: '15' + # postgis: '3.2' + + # name: Run the Django test suite (PG ${{ matrix.postgres }}, postgis ${{ matrix.postgis }}) + + # runs-on: ubuntu-latest + + # services: + # postgres: + # image: postgis/postgis:${{ matrix.postgres }}-${{ matrix.postgis }} + # env: + # POSTGRES_HOST_AUTH_METHOD: trust + # ports: + # - 5432:5432 + # # needed because the postgres container does not provide a healthcheck + # options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 + + # steps: + # - uses: actions/checkout@v4 + # - name: Set up backend environment + # uses: maykinmedia/setup-django-backend@v1.3 + # with: + # apt-packages: 'libgdal-dev gdal-bin' + # python-version: '3.11' + # setup-node: true + + # - name: Run tests + # run: | + # python src/manage.py collectstatic --noinput --link + # coverage run src/manage.py test src + # env: + # DJANGO_SETTINGS_MODULE: objects.conf.ci + # SECRET_KEY: dummy + # DB_USER: postgres + # DB_PASSWORD: '' + + # - name: Publish coverage report + # uses: codecov/codecov-action@v4 + # with: + # token: ${{ secrets.CODECOV_TOKEN }} performance-tests: name: Run the performance test suite @@ -71,7 +71,7 @@ jobs: services: postgres: - image: postgis/postgis:${{ matrix.postgres }}-${{ matrix.postgis }} + image: postgis/postgis:17-3.5 env: POSTGRES_HOST_AUTH_METHOD: trust ports: @@ -97,64 +97,65 @@ jobs: SECRET_KEY: dummy DB_USER: postgres DB_PASSWORD: '' - - docs: - runs-on: ubuntu-latest - name: Documentation build - - steps: - - uses: actions/checkout@v4 - - name: Set up backend environment - uses: maykinmedia/setup-django-backend@v1.3 - with: - apt-packages: 'libgdal-dev gdal-bin' - python-version: '3.11' - setup-node: false - - - name: Generate environment variable documentation using OAf and check if it was updated - run: | - bin/generate_envvar_docs.sh - changes=$(git diff docs/installation/config.rst) - if [ ! -z "$changes" ]; then - echo $changes - echo "Please update the environment documentation by running \`bin/generate_envvar_docs.sh\`" - exit 1 - fi - env: - DJANGO_SETTINGS_MODULE: objects.conf.ci - - store-reusable-workflow-vars: - name: create values which can be passed through a reusable workflow - runs-on: ubuntu-latest - outputs: - image-name: ${{ steps.image-name.outputs.image-name }} - - steps: - - run: echo "image-name=$IMAGE_NAME" >> $GITHUB_OUTPUT - name: 'Store the docker image name' - id: image-name - - open-api-ci: - uses: maykinmedia/open-api-workflows/.github/workflows/ci.yml@v5 - needs: - - store-reusable-workflow-vars - with: - main-branch: 'master' - apt-packages: 'libgdal-dev gdal-bin' - run-docs: true - django-settings-module: objects.conf.ci - python-version: '3.11' - docker-image-name: ${{ needs.store-reusable-workflow-vars.outputs.image-name }} - - open-api-publish: - uses: maykinmedia/open-api-workflows/.github/workflows/publish.yml@v5 - needs: - - store-reusable-workflow-vars - - open-api-ci - - tests - with: - docker-image-name: ${{ needs.store-reusable-workflow-vars.outputs.image-name }} - repository-owner: 'maykinmedia' - secrets: - docker-username: ${{ secrets.DOCKER_USERNAME }} - docker-token: ${{ secrets.DOCKER_TOKEN }} + DEBUG: False + + # docs: + # runs-on: ubuntu-latest + # name: Documentation build + + # steps: + # - uses: actions/checkout@v4 + # - name: Set up backend environment + # uses: maykinmedia/setup-django-backend@v1.3 + # with: + # apt-packages: 'libgdal-dev gdal-bin' + # python-version: '3.11' + # setup-node: false + + # - name: Generate environment variable documentation using OAf and check if it was updated + # run: | + # bin/generate_envvar_docs.sh + # changes=$(git diff docs/installation/config.rst) + # if [ ! -z "$changes" ]; then + # echo $changes + # echo "Please update the environment documentation by running \`bin/generate_envvar_docs.sh\`" + # exit 1 + # fi + # env: + # DJANGO_SETTINGS_MODULE: objects.conf.ci + + # store-reusable-workflow-vars: + # name: create values which can be passed through a reusable workflow + # runs-on: ubuntu-latest + # outputs: + # image-name: ${{ steps.image-name.outputs.image-name }} + + # steps: + # - run: echo "image-name=$IMAGE_NAME" >> $GITHUB_OUTPUT + # name: 'Store the docker image name' + # id: image-name + + # open-api-ci: + # uses: maykinmedia/open-api-workflows/.github/workflows/ci.yml@v5 + # needs: + # - store-reusable-workflow-vars + # with: + # main-branch: 'master' + # apt-packages: 'libgdal-dev gdal-bin' + # run-docs: true + # django-settings-module: objects.conf.ci + # python-version: '3.11' + # docker-image-name: ${{ needs.store-reusable-workflow-vars.outputs.image-name }} + + # open-api-publish: + # uses: maykinmedia/open-api-workflows/.github/workflows/publish.yml@v5 + # needs: + # - store-reusable-workflow-vars + # - open-api-ci + # - tests + # with: + # docker-image-name: ${{ needs.store-reusable-workflow-vars.outputs.image-name }} + # repository-owner: 'maykinmedia' + # secrets: + # docker-username: ${{ secrets.DOCKER_USERNAME }} + # docker-token: ${{ secrets.DOCKER_TOKEN }}