Skip to content

Commit c28ddcc

Browse files
committed
test: basic perf test for rps on get_list
1 parent bcb5fe9 commit c28ddcc

File tree

2 files changed

+40
-1
lines changed

2 files changed

+40
-1
lines changed

frappe/tests/test_perf.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,21 @@
1616
>>> get_controller("User")
1717
1818
"""
19+
import time
1920
import unittest
2021

22+
from tenacity import retry, retry_if_exception_type, stop_after_attempt, wait_fixed
23+
2124
import frappe
25+
from frappe.frappeclient import FrappeClient
2226
from frappe.model.base_document import get_controller
27+
from frappe.query_builder.utils import db_type_is
28+
from frappe.tests.test_query_builder import run_only_if
2329
from frappe.tests.utils import FrappeTestCase
2430
from frappe.website.path_resolver import PathResolver
2531

2632

33+
@run_only_if(db_type_is.MARIADB)
2734
class TestPerformance(FrappeTestCase):
2835
def reset_request_specific_caches(self):
2936
# To simulate close to request level of handling
@@ -33,6 +40,8 @@ def reset_request_specific_caches(self):
3340
frappe.clear_cache()
3441

3542
def setUp(self) -> None:
43+
self.HOST = frappe.utils.get_site_url(frappe.local.site)
44+
3645
self.reset_request_specific_caches()
3746

3847
def test_meta_caching(self):
@@ -55,6 +64,36 @@ def test_db_value_cache(self):
5564
with self.assertQueryCount(0):
5665
doc.get_invalid_links()
5766

67+
@retry(
68+
retry=retry_if_exception_type(AssertionError),
69+
stop=stop_after_attempt(3),
70+
wait=wait_fixed(0.5),
71+
reraise=True,
72+
)
73+
def test_req_per_seconds_basic(self):
74+
"""Ideally should be ran against gunicorn worker, though I have not seen any difference
75+
when using werkzeug's run_simple for synchronous requests."""
76+
77+
EXPECTED_RPS = 55 # measured on GHA
78+
FAILURE_THREASHOLD = 0.1
79+
80+
req_count = 1000
81+
client = FrappeClient(self.HOST, "Administrator", self.ADMIN_PASSWORD)
82+
83+
start = time.perf_counter()
84+
for _ in range(req_count):
85+
client.get_list("ToDo", limit_page_length=1)
86+
end = time.perf_counter()
87+
88+
rps = req_count / (end - start)
89+
90+
print(f"Completed {req_count} in {end - start} @ {rps} requests per seconds")
91+
self.assertGreaterEqual(
92+
rps,
93+
EXPECTED_RPS * (1 - FAILURE_THREASHOLD),
94+
f"Possible performance regression in basic /api/Resource list requests",
95+
)
96+
5897
@unittest.skip("Not implemented")
5998
def test_homepage_resolver(self):
6099
paths = ["/", "/app"]

frappe/tests/utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ class FrappeTestCase(unittest.TestCase):
2626
@classmethod
2727
def setUpClass(cls) -> None:
2828
cls.TEST_SITE = getattr(frappe.local, "site", None) or cls.TEST_SITE
29+
cls.ADMIN_PASSWORD = frappe.get_conf(cls.TEST_SITE).admin_password
2930
# flush changes done so far to avoid flake
3031
frappe.db.commit()
31-
frappe.db.begin()
3232
if cls.SHOW_TRANSACTION_COMMIT_WARNINGS:
3333
frappe.db.add_before_commit(_commit_watcher)
3434

0 commit comments

Comments
 (0)