Skip to content

Commit 09ccf70

Browse files
committed
👷 [#538] Add performance test for objects API list
1 parent e7bff7b commit 09ccf70

File tree

7 files changed

+105
-0
lines changed

7 files changed

+105
-0
lines changed

.github/workflows/ci.yml

+29
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,35 @@ jobs:
4949
- name: Publish coverage report
5050
uses: codecov/codecov-action@v4
5151

52+
performance-tests:
53+
name: Run the performance test suite
54+
runs-on: ubuntu-latest
55+
56+
steps:
57+
- uses: actions/checkout@v4
58+
59+
- name: Bring up docker compose and load data
60+
run: |
61+
docker compose up -d --build || ( docker compose logs >&2 && exit 1; )
62+
until docker compose logs web | grep -q "spawned uWSGI worker"; do
63+
echo "uWSGI not running yet, waiting..."
64+
sleep 3
65+
done
66+
docker compose exec --user root web pip install factory-boy
67+
cat performance-test/create_data.py | docker compose exec -T web src/manage.py shell
68+
69+
- name: Run tests
70+
run: |
71+
pip install -r requirements/ci.txt
72+
pytest performance-test/ --benchmark-json output.json
73+
74+
- name: Store benchmark result
75+
uses: benchmark-action/github-action-benchmark@v1.20.4
76+
with:
77+
tool: 'pytest'
78+
output-file-path: output.json
79+
github-token: ${{ secrets.GITHUB_TOKEN }}
80+
5281
docs:
5382
runs-on: ubuntu-latest
5483
name: Documentation build

performance_test/conftest.py

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import pytest
2+
3+
4+
@pytest.fixture
5+
def benchmark_assertions(benchmark):
6+
def wrapper(**kwargs):
7+
stats = benchmark.stats["stats"]
8+
for name, value in kwargs.items():
9+
assert (
10+
getattr(stats, name) < value
11+
), f"{name} {getattr(stats, name)} exceeded {value} s"
12+
13+
return wrapper

performance_test/create_data.py

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
from objects.core.tests.factories import ObjectRecordFactory, ObjectTypeFactory
2+
from objects.token.tests.factories import TokenAuthFactory
3+
4+
object_type = ObjectTypeFactory.create(
5+
service__api_root="http://localhost:8001/api/v2/",
6+
uuid="f1220670-8ab7-44f1-a318-bd0782e97662",
7+
)
8+
9+
token = TokenAuthFactory(token="secret", is_superuser=True)
10+
11+
ObjectRecordFactory.create_batch(
12+
5000,
13+
object__object_type=object_type,
14+
start_at="2020-01-01",
15+
version=1,
16+
data={"kiemjaar": "1234"},
17+
)

performance_test/test_objects_list.py

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import pytest
2+
import requests
3+
from furl import furl
4+
5+
BASE_URL = furl("http://localhost:8000/api/v2/")
6+
AUTH_HEADERS = {"Authorization": "Token secret"}
7+
8+
9+
@pytest.mark.benchmark(max_time=60, min_rounds=5)
10+
def test_objects_api_list(benchmark, benchmark_assertions):
11+
"""
12+
Regression test for maykinmedia/objects-api#538
13+
"""
14+
params = {
15+
"pageSize": 1000,
16+
"type": "http://localhost:8001/api/v2/objecttypes/f1220670-8ab7-44f1-a318-bd0782e97662",
17+
"data_attrs": "kiemjaar__exact__1234",
18+
"ordering": "-record__data__contactmoment__datumContact",
19+
}
20+
21+
def make_request():
22+
return requests.get((BASE_URL / "objects").set(params), headers=AUTH_HEADERS)
23+
24+
result = benchmark(make_request)
25+
26+
assert result.status_code == 200
27+
assert result.json()["count"] == 5000
28+
29+
benchmark_assertions(mean=1, max=1)

requirements/ci.txt

+6
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,8 @@ psycopg2==2.9.9
534534
# -c requirements/base.txt
535535
# -r requirements/base.txt
536536
# open-api-framework
537+
py-cpuinfo==9.0.0
538+
# via pytest-benchmark
537539
pycodestyle==2.12.1
538540
# via flake8
539541
pycparser==2.20
@@ -584,6 +586,10 @@ pyrsistent==0.17.3
584586
# -r requirements/base.txt
585587
# jsonschema
586588
pytest==8.3.3
589+
# via
590+
# -r requirements/test-tools.in
591+
# pytest-benchmark
592+
pytest-benchmark==5.1.0
587593
# via -r requirements/test-tools.in
588594
python-dateutil==2.9.0.post0
589595
# via

requirements/dev.txt

+10
Original file line numberDiff line numberDiff line change
@@ -640,6 +640,11 @@ psycopg2==2.9.9
640640
# -c requirements/ci.txt
641641
# -r requirements/ci.txt
642642
# open-api-framework
643+
py-cpuinfo==9.0.0
644+
# via
645+
# -c requirements/ci.txt
646+
# -r requirements/ci.txt
647+
# pytest-benchmark
643648
pycodestyle==2.12.1
644649
# via
645650
# -c requirements/ci.txt
@@ -711,6 +716,11 @@ pytest==8.3.3
711716
# via
712717
# -c requirements/ci.txt
713718
# -r requirements/ci.txt
719+
# pytest-benchmark
720+
pytest-benchmark==5.1.0
721+
# via
722+
# -c requirements/ci.txt
723+
# -r requirements/ci.txt
714724
python-dateutil==2.9.0.post0
715725
# via
716726
# -c requirements/ci.txt

requirements/test-tools.in

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
# Dependencies only relevant for (unit) testing
55
codecov
66
pytest
7+
pytest-benchmark
78
coverage < 5.0
89
django-webtest
910
factory-boy

0 commit comments

Comments
 (0)