"""Performance benchmarks with P95 targets, tagged 'benchmark'. These tests are not part of the default test run; they execute when invoked explicitly with --test-tags 'post_install,benchmark' (or just 'benchmark'). Targets (Phase 2 ship): compute_pnl <2000ms p95 compute_balance_sheet <2000ms p95 compute_trial_balance <1000ms p95 compute_gl <3000ms p95 drill_down <500ms p95 controller.run <2500ms p95 Hard assertions are set to ~5x the target so a flaky CI run doesn't break the build. The PERF lines printed to stdout are the source of truth for tracking. """ import json import statistics import time from datetime import date from odoo.tests.common import HttpCase, TransactionCase, tagged, new_test_user from odoo.addons.fusion_accounting_reports.services.date_periods import Period def _percentile(samples, p): if not samples: return 0 if len(samples) == 1: return samples[0] sorted_s = sorted(samples) idx = int(len(sorted_s) * p / 100) return sorted_s[min(idx, len(sorted_s) - 1)] @tagged('post_install', '-at_install', 'benchmark') class TestEngineBenchmarks(TransactionCase): def setUp(self): super().setUp() self.period = Period( date(2026, 1, 1), date(2026, 12, 31), 'Bench 2026', ) self.engine = self.env['fusion.report.engine'] def test_compute_pnl_p95(self): timings = [] for _ in range(5): start = time.perf_counter() self.engine.compute_pnl(self.period, company_id=self.env.company.id) timings.append((time.perf_counter() - start) * 1000) p95 = _percentile(timings, 95) median = statistics.median(timings) msg = f"compute_pnl: median={median:.0f}ms p95={p95:.0f}ms" print(f"\n PERF: {msg} (target <2000ms)") self.assertLess(p95, 10000, f"way over budget: {msg}") def test_compute_balance_sheet_p95(self): timings = [] for _ in range(5): start = time.perf_counter() self.engine.compute_balance_sheet( date(2026, 12, 31), company_id=self.env.company.id, ) timings.append((time.perf_counter() - start) * 1000) p95 = _percentile(timings, 95) median = statistics.median(timings) msg = f"compute_balance_sheet: median={median:.0f}ms p95={p95:.0f}ms" print(f"\n PERF: {msg} (target <2000ms)") self.assertLess(p95, 10000, f"way over budget: {msg}") def test_compute_trial_balance_p95(self): timings = [] for _ in range(5): start = time.perf_counter() self.engine.compute_trial_balance( self.period, company_id=self.env.company.id, ) timings.append((time.perf_counter() - start) * 1000) p95 = _percentile(timings, 95) median = statistics.median(timings) msg = f"compute_trial_balance: median={median:.0f}ms p95={p95:.0f}ms" print(f"\n PERF: {msg} (target <1000ms)") self.assertLess(p95, 5000, f"way over budget: {msg}") def test_compute_gl_p95(self): timings = [] for _ in range(3): # GL is heavier; fewer iterations start = time.perf_counter() self.engine.compute_gl(self.period, company_id=self.env.company.id) timings.append((time.perf_counter() - start) * 1000) median = statistics.median(timings) p95 = _percentile(timings, 95) msg = f"compute_gl: median={median:.0f}ms p95={p95:.0f}ms (3 runs)" print(f"\n PERF: {msg} (target <3000ms)") self.assertLess(median, 15000, f"way over budget: {msg}") def test_drill_down_p95(self): line = self.env['account.move.line'].search([ ('parent_state', '=', 'posted'), ], limit=1) if not line: self.skipTest("No posted journal lines available") timings = [] for _ in range(10): start = time.perf_counter() self.engine.drill_down( account_id=line.account_id.id, period=self.period, company_id=line.company_id.id, ) timings.append((time.perf_counter() - start) * 1000) p95 = _percentile(timings, 95) median = statistics.median(timings) msg = f"drill_down: median={median:.0f}ms p95={p95:.0f}ms" print(f"\n PERF: {msg} (target <500ms)") self.assertLess(p95, 2500, f"way over budget: {msg}") @tagged('post_install', '-at_install', 'benchmark') class TestControllerBenchmarks(HttpCase): def test_run_endpoint_p95(self): new_test_user( self.env, login='perf_user', groups='base.group_user,account.group_account_invoice', ) self.authenticate('perf_user', 'perf_user') timings = [] for _ in range(5): start = time.perf_counter() response = self.url_open( '/fusion/reports/run', data=json.dumps({ 'jsonrpc': '2.0', 'method': 'call', 'id': 1, 'params': { 'report_type': 'pnl', 'date_from': '2026-01-01', 'date_to': '2026-12-31', 'company_id': self.env.company.id, }, }), headers={'Content-Type': 'application/json'}, ) timings.append((time.perf_counter() - start) * 1000) self.assertEqual(response.status_code, 200) p95 = _percentile(timings, 95) median = statistics.median(timings) msg = f"controller.run: median={median:.0f}ms p95={p95:.0f}ms" print(f"\n PERF: {msg} (target <2500ms)") self.assertLess(p95, 12500, f"way over budget: {msg}")