Skip to content

Commit 06c3ee8

Browse files
CopilotBorda
andcommitted
Add tests for missing code coverage: exception handling and stale processing
- Added TestAsyncExceptionHandling: tests exception handling in _function_thread_async (line 65) - Added TestAsyncStaleProcessing: tests stale entry with next_time returning stale value (lines 476-478) - All 30 async tests passing - Addresses codecov comments 2736705629 and 2736707879 Co-authored-by: Borda <6035284+Borda@users.noreply.github.com>
1 parent a2cd7a6 commit 06c3ee8

1 file changed

Lines changed: 91 additions & 0 deletions

File tree

tests/test_async_core.py

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -917,3 +917,94 @@ async def async_func(x):
917917
assert call_count >= 2
918918

919919
async_func.clear_cache()
920+
921+
922+
# =============================================================================
923+
# Exception Handling and Edge Cases
924+
# =============================================================================
925+
926+
927+
class TestAsyncExceptionHandling:
928+
"""Tests for exception handling in async background tasks."""
929+
930+
@pytest.mark.memory
931+
@pytest.mark.asyncio
932+
async def test_function_thread_async_exception_handling(self):
933+
"""Test that exceptions in background async tasks are caught and handled."""
934+
935+
@cachier(backend="memory", stale_after=timedelta(seconds=1), next_time=True)
936+
async def async_func_that_fails(x):
937+
await asyncio.sleep(0.2)
938+
if x == 99:
939+
raise ValueError("Intentional test error")
940+
return x * 2
941+
942+
async_func_that_fails.clear_cache()
943+
944+
# First call with valid value
945+
result1 = await async_func_that_fails(5)
946+
assert result1 == 10
947+
948+
# Wait for stale
949+
await asyncio.sleep(1.5)
950+
951+
# Call with value that will fail in background - should return stale
952+
result2 = await async_func_that_fails(5)
953+
assert result2 == 10 # Returns stale value
954+
955+
# Wait for background task to complete and fail
956+
await asyncio.sleep(0.5)
957+
958+
# The error should be caught and handled silently in background
959+
# (no exception should propagate to this test)
960+
961+
async_func_that_fails.clear_cache()
962+
963+
964+
class TestAsyncStaleProcessing:
965+
"""Tests for stale entry processing with next_time."""
966+
967+
@pytest.mark.memory
968+
@pytest.mark.asyncio
969+
async def test_stale_entry_processing_returns_stale_with_next_time(self):
970+
"""Test that stale entry being processed returns stale value when next_time=True."""
971+
call_count = 0
972+
973+
@cachier(backend="memory", stale_after=timedelta(seconds=1), next_time=True)
974+
async def slow_async_func(x):
975+
nonlocal call_count
976+
call_count += 1
977+
await asyncio.sleep(0.8) # Long enough to be "processing"
978+
return call_count * 10
979+
980+
slow_async_func.clear_cache()
981+
call_count = 0
982+
983+
# First call - populate cache
984+
result1 = await slow_async_func(5)
985+
assert result1 == 10
986+
assert call_count == 1
987+
988+
# Wait for stale
989+
await asyncio.sleep(1.5)
990+
991+
# Launch two concurrent calls when stale
992+
# First will trigger background update, both should return stale
993+
results = await asyncio.gather(
994+
slow_async_func(5),
995+
slow_async_func(5),
996+
)
997+
998+
# Both should get the stale value (10)
999+
assert results[0] == 10
1000+
assert results[1] == 10
1001+
1002+
# Wait for background update to complete
1003+
await asyncio.sleep(1.5)
1004+
1005+
# Next call should get updated value
1006+
result_new = await slow_async_func(5)
1007+
assert result_new > 10 # Updated in background
1008+
1009+
slow_async_func.clear_cache()
1010+

0 commit comments

Comments
 (0)