test_oa_wechat_notify_hook.py 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. """OA 微信服务号通知钩子单测。"""
  2. from unittest.mock import MagicMock, patch
  3. from app.services.oa_wechat_notify import (
  4. _build_matter_title,
  5. _send_one,
  6. build_oa_detail_pagepath,
  7. )
  8. def test_build_pagepath_no_leading_slash():
  9. p = build_oa_detail_pagepath(instance_id="i1", task_id="t1", mode="approve")
  10. assert p.startswith("pages/")
  11. assert "mode=approve" in p
  12. assert "instanceId=i1" in p
  13. assert "taskId=t1" in p
  14. def test_build_pagepath_three_notify_targets():
  15. """三种通知:审批待办 / 抄送查看 / 我发起查看,mode + returnPath 不同。"""
  16. from urllib.parse import parse_qs, urlparse
  17. from app.services.oa_wechat_notify import (
  18. RETURN_CC,
  19. RETURN_MINE,
  20. RETURN_PENDING,
  21. )
  22. appr = build_oa_detail_pagepath(
  23. instance_id="i1",
  24. task_id="t1",
  25. mode="approve",
  26. return_path=RETURN_PENDING,
  27. )
  28. q1 = parse_qs(urlparse("x://" + appr).query)
  29. assert q1["mode"] == ["approve"]
  30. assert q1["taskId"] == ["t1"]
  31. assert q1["returnPath"] == [RETURN_PENDING]
  32. cc = build_oa_detail_pagepath(
  33. instance_id="i1",
  34. task_id="t-cc",
  35. mode="view",
  36. return_path=RETURN_CC,
  37. )
  38. q2 = parse_qs(urlparse("x://" + cc).query)
  39. assert q2["mode"] == ["view"]
  40. assert q2["taskId"] == ["t-cc"]
  41. assert q2["returnPath"] == [RETURN_CC]
  42. mine = build_oa_detail_pagepath(
  43. instance_id="i1",
  44. task_id="",
  45. mode="view",
  46. return_path=RETURN_MINE,
  47. )
  48. q3 = parse_qs(urlparse("x://" + mine).query)
  49. assert q3["mode"] == ["view"]
  50. assert "taskId" not in q3
  51. assert q3["returnPath"] == [RETURN_MINE]
  52. def test_build_matter_title_applicant_process():
  53. assert _build_matter_title(
  54. applicant="李四", process_name="请假申请", fallback="x"
  55. ) == "李四 - 请假申请"
  56. assert _build_matter_title(applicant="", process_name="请假申请", fallback="x") == (
  57. "请假申请"
  58. )
  59. assert _build_matter_title(applicant="", process_name="", fallback="审批") == "审批"
  60. def test_send_one_routes_approval_vs_cc():
  61. db = MagicMock()
  62. user = MagicMock()
  63. user.wx_mp_openid = "mp-openid-1"
  64. user.nick_name = "张三"
  65. inst = MagicMock()
  66. inst.title = "请假"
  67. inst.initiator_user_id = "u-ini"
  68. inst.app_id = "app-1"
  69. ini = MagicMock()
  70. ini.nick_name = "李四"
  71. app = MagicMock()
  72. app.app_name = "请假申请"
  73. # approval + cc 各查 assignee、initiator
  74. user_results = [user, ini, user, ini]
  75. def query_side_effect(model):
  76. q = MagicMock()
  77. name = getattr(model, "__name__", "") or str(model)
  78. if "SysUser" in name:
  79. q.filter.return_value.first.side_effect = lambda: user_results.pop(0)
  80. elif "OaApp" in name:
  81. q.filter.return_value.first.return_value = app
  82. else:
  83. q.filter.return_value.first.return_value = inst
  84. return q
  85. db.query.side_effect = query_side_effect
  86. approval_task = MagicMock()
  87. approval_task.id = "t-appr"
  88. approval_task.instance_id = "i1"
  89. approval_task.assignee_user_id = "u1"
  90. approval_task.task_type = "approval"
  91. approval_task.status = "pending"
  92. approval_task.node_name = "主管审批"
  93. with patch(
  94. "app.services.oa_wechat_notify.send_oa_approval_notify"
  95. ) as send_appr, patch(
  96. "app.services.oa_wechat_notify.send_oa_cc_notify"
  97. ) as send_cc:
  98. _send_one(db, approval_task)
  99. send_appr.assert_called_once()
  100. send_cc.assert_not_called()
  101. kwargs = send_appr.call_args.kwargs
  102. assert kwargs["mp_openid"] == "mp-openid-1"
  103. assert "mode=approve" in kwargs["pagepath"]
  104. assert "returnPath=" in kwargs["pagepath"]
  105. assert "%2Fpages%2Foa%2Fpending%2Findex" in kwargs["pagepath"] or (
  106. "/pages/oa/pending/index" in kwargs["pagepath"]
  107. )
  108. assert kwargs["title"] == "李四 - 请假申请"
  109. assert kwargs["applicant"] == "李四"
  110. assert kwargs["process_name"] == "请假申请"
  111. assert kwargs["node_name"] == "主管审批"
  112. cc_task = MagicMock()
  113. cc_task.id = "t-cc"
  114. cc_task.instance_id = "i1"
  115. cc_task.assignee_user_id = "u1"
  116. cc_task.task_type = "cc"
  117. cc_task.status = "done"
  118. cc_task.node_name = "抄送"
  119. with patch(
  120. "app.services.oa_wechat_notify.send_oa_approval_notify"
  121. ) as send_appr, patch(
  122. "app.services.oa_wechat_notify.send_oa_cc_notify"
  123. ) as send_cc:
  124. _send_one(db, cc_task)
  125. send_cc.assert_called_once()
  126. send_appr.assert_not_called()
  127. kwargs = send_cc.call_args.kwargs
  128. assert "mode=view" in kwargs["pagepath"]
  129. assert (
  130. "%2Fpages%2Foa%2Fcc%2Findex" in kwargs["pagepath"]
  131. or "/pages/oa/cc/index" in kwargs["pagepath"]
  132. )
  133. assert kwargs["title"] == "李四 - 请假申请"
  134. assert kwargs["process_name"] == "请假申请"
  135. def test_schedule_oa_task_notifies_noop_when_disabled():
  136. with patch("app.services.oa_wechat_notify.settings") as st, patch(
  137. "app.services.oa_wechat_notify.threading.Thread"
  138. ) as th:
  139. st.WX_MP_NOTIFY_ENABLED = False
  140. from app.services.oa_wechat_notify import schedule_oa_task_notifies
  141. schedule_oa_task_notifies(["t1"])
  142. th.assert_not_called()
  143. def test_schedule_oa_applicant_progress_noop_when_disabled():
  144. with patch("app.services.oa_wechat_notify.settings") as st, patch(
  145. "app.services.oa_wechat_notify.threading.Thread"
  146. ) as th:
  147. st.WX_MP_NOTIFY_ENABLED = False
  148. from app.services.oa_wechat_notify import schedule_oa_applicant_progress
  149. schedule_oa_applicant_progress(
  150. instance_id="i1", actor_user_id="u1", action="approve"
  151. )
  152. th.assert_not_called()
  153. def test_notify_oa_tasks_sync_noop_when_disabled():
  154. with patch("app.services.oa_wechat_notify.settings") as st, patch(
  155. "app.services.oa_wechat_notify.SessionLocal"
  156. ) as session_local:
  157. st.WX_MP_NOTIFY_ENABLED = False
  158. from app.services.oa_wechat_notify import notify_oa_tasks_sync
  159. notify_oa_tasks_sync(["t1"])
  160. session_local.assert_not_called()