test_oa_list_apps_perf.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. """OA 审批应用列表:避免按应用 N+1 拉取版本大字段。"""
  2. import json
  3. import unittest
  4. from datetime import datetime
  5. from sqlalchemy import create_engine, event
  6. from sqlalchemy.orm import sessionmaker
  7. class TestListAppsPerf(unittest.TestCase):
  8. def setUp(self):
  9. from app.models.models import OaApp, OaAppGroup, OaAppVersion
  10. self.engine = create_engine("sqlite:///:memory:")
  11. OaAppGroup.__table__.create(self.engine)
  12. OaApp.__table__.create(self.engine)
  13. OaAppVersion.__table__.create(self.engine)
  14. Session = sessionmaker(bind=self.engine, autoflush=False, autocommit=False)
  15. self.db = Session()
  16. self.OaApp = OaApp
  17. self.OaAppGroup = OaAppGroup
  18. self.OaAppVersion = OaAppVersion
  19. self.now = datetime.now()
  20. self.query_count = 0
  21. @event.listens_for(self.engine, "before_cursor_execute")
  22. def _count(_conn, _cursor, _statement, _parameters, _context, _executemany):
  23. self.query_count += 1
  24. self._listener = _count
  25. def tearDown(self):
  26. event.remove(self.engine, "before_cursor_execute", self._listener)
  27. self.db.close()
  28. self.engine.dispose()
  29. def _seed_apps(self, n: int = 8):
  30. bulky = json.dumps({"rule": [{"x": "y" * 2000}] * 50}, ensure_ascii=False)
  31. self.db.add(
  32. self.OaAppGroup(
  33. id="g1",
  34. group_name="人事",
  35. tenant_no="zkxw",
  36. create_dept_id="",
  37. create_time=self.now,
  38. update_time=self.now,
  39. del_flag=0,
  40. )
  41. )
  42. for i in range(n):
  43. app_id = f"app{i}"
  44. self.db.add(
  45. self.OaApp(
  46. id=app_id,
  47. group_id="g1",
  48. app_name=f"应用{i}",
  49. initiator_scope="all",
  50. admin_scope="all_oa_admin",
  51. status="1",
  52. tenant_no="zkxw",
  53. order_num=i,
  54. create_dept_id="",
  55. create_time=self.now,
  56. update_time=self.now,
  57. del_flag=0,
  58. )
  59. )
  60. self.db.add(
  61. self.OaAppVersion(
  62. id=f"draft{i}",
  63. app_id=app_id,
  64. version_no=0,
  65. status="draft",
  66. is_latest_published="0",
  67. form_schema_json=bulky,
  68. flow_tree_json=bulky,
  69. advanced_settings_json="{}",
  70. tenant_no="zkxw",
  71. create_dept_id="",
  72. create_time=self.now,
  73. update_time=self.now,
  74. del_flag=0,
  75. )
  76. )
  77. self.db.add(
  78. self.OaAppVersion(
  79. id=f"pub{i}",
  80. app_id=app_id,
  81. version_no=i + 1,
  82. status="published",
  83. is_latest_published="1",
  84. form_schema_json=bulky,
  85. flow_tree_json=bulky,
  86. advanced_settings_json="{}",
  87. tenant_no="zkxw",
  88. create_dept_id="",
  89. create_time=self.now,
  90. update_time=self.now,
  91. del_flag=0,
  92. )
  93. )
  94. self.db.commit()
  95. def test_list_apps_query_count_bounded_and_fields_correct(self):
  96. from app.crud.oa_approval import list_apps
  97. n = 8
  98. self._seed_apps(n)
  99. self.query_count = 0
  100. items = list_apps(self.db, tenant_no="zkxw")
  101. self.assertEqual(len(items), n)
  102. self.assertTrue(all(it["hasDraft"] for it in items))
  103. self.assertEqual(
  104. {it["id"]: it["latestPublishedVersion"] for it in items},
  105. {f"app{i}": i + 1 for i in range(n)},
  106. )
  107. self.assertEqual(items[0]["groupName"], "人事")
  108. # apps + groups + drafts batch + published batch(不应随应用数线性增长)
  109. self.assertLessEqual(self.query_count, 5)
  110. self.assertLess(self.query_count, 2 + 2 * n)
  111. if __name__ == "__main__":
  112. unittest.main()