test_ad_creation_status.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. import sys
  2. import unittest
  3. from pathlib import Path
  4. from unittest.mock import patch
  5. ROOT = Path(__file__).resolve().parent
  6. if str(ROOT) not in sys.path:
  7. sys.path.insert(0, str(ROOT))
  8. PROJECT_ROOT = ROOT.parents[1]
  9. if str(PROJECT_ROOT) not in sys.path:
  10. sys.path.insert(0, str(PROJECT_ROOT))
  11. from tools.ad_creation import AdCandidate, build_ad_request_body
  12. from tools.delivery_config import (
  13. BID_MODE_AVERAGE_COST,
  14. BID_MODE_MAX_CONVERSION,
  15. parse_bid_scene,
  16. parse_placement_config,
  17. )
  18. def _candidate() -> AdCandidate:
  19. return AdCandidate(
  20. account_id=123,
  21. adgroup_name="test-ad",
  22. site_set=["SITE_SET_WECHAT"],
  23. custom_audience=None,
  24. bid_amount_fen=35,
  25. audience_tier_label="泛人群",
  26. age=[{"min": 45, "max": 66}],
  27. location_types=["LIVE_IN"],
  28. region_ids=[1],
  29. daily_budget_fen=10000,
  30. time_series="1" * 48,
  31. delivery_version="miniapp_user_growth_v1",
  32. fingerprint="fp",
  33. wechat_position=None,
  34. )
  35. class AdCreationStatusTest(unittest.TestCase):
  36. def test_ad_request_defaults_to_normal_status(self):
  37. with patch("tools.ad_creation.get_account_feedback_id", return_value=6700001):
  38. body = build_ad_request_body(_candidate(), begin_date="2026-07-01")
  39. self.assertEqual(body["configured_status"], "AD_STATUS_NORMAL")
  40. def test_max_conversion_uses_systematic_bid_with_custom_cost_cap(self):
  41. candidate = _candidate()
  42. candidate.bid_scene = BID_MODE_MAX_CONVERSION
  43. candidate.custom_cost_cap_fen = 48
  44. with patch("tools.ad_creation.get_account_feedback_id", return_value=6700001):
  45. body = build_ad_request_body(candidate, begin_date="2026-07-01")
  46. self.assertEqual("SMART_BID_TYPE_SYSTEMATIC", body["smart_bid_type"])
  47. self.assertEqual(0, body["bid_amount"])
  48. self.assertEqual("COST_CONSTRAINT_SCENE_OPEN", body["cost_constraint_scene"])
  49. self.assertEqual(48, body["custom_cost_cap"])
  50. self.assertNotIn("bid_scene", body)
  51. def test_aim_placement_uses_automatic_site_without_site_set(self):
  52. candidate = _candidate()
  53. candidate.automatic_site_enabled = True
  54. candidate.site_set = []
  55. with patch("tools.ad_creation.get_account_feedback_id", return_value=6700001):
  56. body = build_ad_request_body(candidate, begin_date="2026-07-01")
  57. self.assertTrue(body["automatic_site_enabled"])
  58. self.assertNotIn("site_set", body)
  59. def test_parse_feishu_bid_scene_and_placement(self):
  60. self.assertEqual(BID_MODE_AVERAGE_COST, parse_bid_scene(""))
  61. self.assertEqual(BID_MODE_MAX_CONVERSION, parse_bid_scene("最大转化量"))
  62. placement = parse_placement_config(
  63. "微信朋友圈,微信公众号与小程序,腾讯平台与内容媒体,腾讯营销联盟"
  64. )
  65. self.assertFalse(placement.automatic_site_enabled)
  66. self.assertEqual(
  67. [
  68. "SITE_SET_MOMENTS",
  69. "SITE_SET_WECHAT",
  70. "SITE_SET_WECHAT_PLUGIN",
  71. "SITE_SET_TENCENT_NEWS",
  72. "SITE_SET_TENCENT_VIDEO",
  73. "SITE_SET_KANDIAN",
  74. "SITE_SET_QQ_MUSIC_GAME",
  75. "SITE_SET_MOBILE_UNION",
  76. ],
  77. placement.site_set,
  78. )
  79. aim = parse_placement_config("AIM+")
  80. self.assertTrue(aim.automatic_site_enabled)
  81. self.assertEqual([], aim.site_set)
  82. if __name__ == "__main__":
  83. unittest.main()