fix: complete Douyin release remediation

This commit is contained in:
2026-09-16 01:51:14 +08:00
parent 977e541fef
commit 9095920a5b
56 changed files with 4530 additions and 518 deletions
+67 -14
View File
@@ -885,6 +885,18 @@ class BrowserTests(unittest.TestCase):
subscription.ack([first[0]["delivery_id"]])
self.assertEqual(subscription.poll(10, 0), [])
def test_subscription_connection_failure_requests_recovery(self) -> None:
subscription = DouyinSubscription.__new__(DouyinSubscription)
subscription.alias = "safe"
subscription.browser = Mock()
subscription.browser._connect.side_effect = DouyinError("browser unavailable")
subscription._put = Mock()
subscription._request_recovery = Mock()
subscription._browser_inflight_lock = threading.Lock()
subscription._browser_inflight = set()
subscription._process_push_async({"delivery_id": "delivery-1"}, 0, False)
subscription._request_recovery.assert_called_once_with()
def test_subscription_detail_failure_does_not_discard_siblings(self) -> None:
bad = json.dumps(
{
@@ -2244,18 +2256,21 @@ class AdditionalGatewayCoverageTests(unittest.TestCase):
def test_identity_and_message_history_reject_invalid_values(self) -> None:
browser = DouyinBrowser()
for server_now in (0, float("nan")):
cast(Any, browser).get = lambda alias, target, now=server_now: BrowserResponse(
200,
json.dumps(
{
"status_code": 0,
"extra": {"now": now},
"user": {"uid": "123", "sec_uid": "sec"},
}
),
cast(Any, browser).get = lambda alias, target, now=server_now: (
BrowserResponse(
200,
json.dumps(
{
"status_code": 0,
"extra": {"now": now},
"user": {"uid": "123", "sec_uid": "sec"},
}
),
)
)
with self.subTest(server_now=server_now), self.assertRaisesRegex(
DouyinError, "platform clock"
with (
self.subTest(server_now=server_now),
self.assertRaisesRegex(DouyinError, "platform clock"),
):
browser.identity("safe")
@@ -2273,9 +2288,12 @@ class AdditionalGatewayCoverageTests(unittest.TestCase):
("123", "456", 0),
("123", "456", 201),
):
with self.subTest(
expected_uid=expected_uid, target_uid=target_uid, limit=limit
), self.assertRaises(DouyinError):
with (
self.subTest(
expected_uid=expected_uid, target_uid=target_uid, limit=limit
),
self.assertRaises(DouyinError),
):
browser.message_history("safe", expected_uid, target_uid, limit)
evaluate.return_value = "bad"
with self.assertRaisesRegex(DouyinError, "message history response"):
@@ -2432,5 +2450,40 @@ class AdditionalGatewayCoverageTests(unittest.TestCase):
load_config({**base, "BROWSER_CDP_ALIAS": "bad alias"})
class DouyinReleaseRemediationTests(unittest.TestCase):
def test_browser_action_marker_is_persisted_in_profile_storage(self) -> None:
browser = DouyinBrowser()
browser._evaluate = Mock(side_effect=[{"runtime_id": "old"}, True, True])
self.assertEqual(browser.action_ownership("safe"), {"runtime_id": "old"})
browser.set_action_ownership(
"safe", {"runtime_id": "new", "operation_id": "op-1"}
)
browser.clear_action_ownership("safe", "op-1")
self.assertEqual(browser._evaluate.call_count, 3)
self.assertIn(
"__creatorhub_action_ownership_v1",
browser._evaluate.call_args_list[1].args[1],
)
def test_gateway_action_claim_rejects_marker_from_any_runtime(self) -> None:
gateway = Gateway.__new__(Gateway)
gateway._action_ownership_lock = threading.Lock()
gateway._uncertain_actions = {}
gateway.browser = Mock()
gateway.browser.action_ownership.return_value = {"runtime_id": "old-runtime"}
with self.assertRaises(RequestError):
gateway._claim_action("safe", "new-runtime", "op-1")
gateway.browser.clear_action_ownership.assert_not_called()
gateway.browser.set_action_ownership.assert_not_called()
def test_notice_keeps_raw_gateway_receipt_time(self) -> None:
notice = normalize_notice(
{"dm": {"message_id": "1", "from_user": {"uid": "2"}, "text": "hi"}},
"2026-09-15T00:00:00+00:00",
)
assert notice is not None
self.assertEqual(notice["gateway_received_at"], "2026-09-15T00:00:00+00:00")
if __name__ == "__main__":
unittest.main()