test_spoolman_extra_lock.py 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
  1. """T-Gap 6: WeakValueDictionary lock concurrency tests for merge_spool_extra."""
  2. import asyncio
  3. import pytest
  4. from backend.app.services.spoolman import SpoolmanClient
  5. class TestExtraLock:
  6. """Verify extra_lock uses WeakValueDictionary and same object is returned within scope."""
  7. def test_extra_lock_same_instance_within_scope(self):
  8. """Two calls with the same spool_id return the same lock object."""
  9. client = SpoolmanClient("http://localhost:7912")
  10. lock_a = client.extra_lock(1)
  11. lock_b = client.extra_lock(1)
  12. assert lock_a is lock_b
  13. def test_extra_lock_different_ids_different_instances(self):
  14. """Different spool IDs return different locks."""
  15. client = SpoolmanClient("http://localhost:7912")
  16. lock_1 = client.extra_lock(1)
  17. lock_2 = client.extra_lock(2)
  18. assert lock_1 is not lock_2
  19. # Keep references alive
  20. _ = lock_1, lock_2
  21. def test_extra_lock_released_when_no_reference(self):
  22. """Lock is garbage-collected once no reference is held (WeakValueDictionary)."""
  23. import gc
  24. import weakref
  25. client = SpoolmanClient("http://localhost:7912")
  26. lock = client.extra_lock(42)
  27. ref = weakref.ref(lock)
  28. del lock
  29. gc.collect()
  30. # Lock should have been evicted from the WeakValueDictionary
  31. assert ref() is None
  32. assert 42 not in client._extra_locks
  33. @pytest.mark.asyncio
  34. async def test_concurrent_calls_serialized(self):
  35. """Concurrent calls to extra_lock with same spool_id are serialized."""
  36. client = SpoolmanClient("http://localhost:7912")
  37. results = []
  38. async def hold_lock():
  39. lock = client.extra_lock(99)
  40. async with lock:
  41. results.append("enter")
  42. await asyncio.sleep(0.01)
  43. results.append("exit")
  44. await asyncio.gather(hold_lock(), hold_lock())
  45. # enter/exit pairs must not interleave
  46. assert results == ["enter", "exit", "enter", "exit"]