# -*- coding: utf-8 -*- """发送互斥锁的边界行为测试。 这把锁是双引擎唯一的仲裁点:抢不到就跳过本轮发送。所以它的失败方式必须是 "这一轮没发",绝不能是抛异常打断轮询,更不能把锁吞掉再也不还。 """ import threading from unittest import TestCase, main import send_lock class FallbackLockTest(TestCase): """强制走非 Windows 回退分支(CI / macOS / Linux 开发机走的就是这条)。""" def setUp(self): self._saved = ( send_lock._init_done, send_lock._handle, send_lock._holder_tid, ) send_lock._init_done = True send_lock._handle = None send_lock._holder_tid = None while send_lock._FALLBACK_LOCK.locked(): try: send_lock._FALLBACK_LOCK.release() except RuntimeError: break def tearDown(self): send_lock._holder_tid = None while send_lock._FALLBACK_LOCK.locked(): try: send_lock._FALLBACK_LOCK.release() except RuntimeError: break send_lock._init_done, send_lock._handle, send_lock._holder_tid = self._saved def test_default_zero_timeout_acquires_instead_of_raising(self): # threading.Lock 不接受"非阻塞 + 超时"的组合;默认参数正好是这一种 self.assertTrue(send_lock.try_acquire("engine_a", 0)) send_lock.release() def test_a_second_thread_is_turned_away_without_blocking(self): self.assertTrue(send_lock.try_acquire("engine_a", 0)) result = {} def other(): result["acquired"] = send_lock.try_acquire("engine_b", 0) thread = threading.Thread(target=other) thread.start() thread.join(timeout=2.0) self.assertFalse(thread.is_alive()) self.assertFalse(result["acquired"]) send_lock.release() def test_release_makes_the_lock_available_again(self): self.assertTrue(send_lock.try_acquire("engine_a", 0)) send_lock.release() self.assertTrue(send_lock.try_acquire("engine_b", 0)) send_lock.release() def test_same_thread_can_never_nest_a_send(self): self.assertTrue(send_lock.try_acquire("engine_a", 0)) self.assertFalse(send_lock.try_acquire("engine_a", 0)) send_lock.release() def test_positive_timeout_waits_and_still_succeeds(self): self.assertTrue(send_lock.try_acquire("engine_a", 0.05)) send_lock.release() def test_a_foreign_thread_cannot_release_someone_elses_lock(self): self.assertTrue(send_lock.try_acquire("engine_a", 0)) def other(): send_lock.release() thread = threading.Thread(target=other) thread.start() thread.join(timeout=2.0) self.assertTrue(send_lock._FALLBACK_LOCK.locked()) send_lock.release() def test_context_manager_releases_on_exception(self): with self.assertRaises(RuntimeError): with send_lock.lock("engine_a", 0) as acquired: self.assertTrue(acquired) raise RuntimeError("发送过程中崩了") self.assertTrue(send_lock.try_acquire("engine_b", 0)) send_lock.release() class WaitCodeTest(TestCase): def test_abandoned_wait_is_treated_as_ownership(self): # 上一个持有者崩溃退出时 Windows 返回 WAIT_ABANDONED:锁已经归本线程, # 必须当成"抢到了",否则谁也不会去释放它。 self.assertEqual(send_lock._WAIT_ABANDONED, 0x80) self.assertEqual(send_lock._WAIT_OBJECT_0, 0) self.assertEqual(send_lock._WAIT_TIMEOUT, 0x102) if __name__ == "__main__": main()