1313from langfuse .model import ChatPromptClient , TextPromptClient
1414from tests .utils import create_uuid , get_api
1515
16+ import os
17+ from langfuse ._client .environment_variables import LANGFUSE_PROMPT_CACHE_DEFAULT_TTL_SECONDS
1618
1719def test_create_prompt ():
1820 langfuse = Langfuse ()
@@ -688,6 +690,16 @@ def langfuse():
688690
689691 return langfuse_instance
690692
693+ @pytest .fixture
694+ def langfuse_with_override_default_cache ():
695+ langfuse_instance = Langfuse (
696+ public_key = "test-public-key" ,
697+ secret_key = "test-secret-key" ,
698+ host = "https://mock-host.com" ,
699+ default_cache_ttl_seconds = OVERRIDE_DEFAULT_PROMPT_CACHE_TTL_SECONDS ,
700+ )
701+ langfuse_instance .api = Mock ()
702+ return langfuse_instance
691703
692704# Fetching a new prompt when nothing in cache
693705def test_get_fresh_prompt (langfuse ):
@@ -1416,6 +1428,174 @@ def test_update_prompt():
14161428 assert sorted (updated_prompt .labels ) == expected_labels
14171429
14181430
1431+ def test_environment_variable_override_prompt_cache_ttl ():
1432+ """Test that LANGFUSE_PROMPT_CACHE_DEFAULT_TTL_SECONDS environment variable overrides default TTL."""
1433+ import os
1434+ from unittest .mock import patch
1435+
1436+ # Set environment variable to override default TTL
1437+ os .environ [LANGFUSE_PROMPT_CACHE_DEFAULT_TTL_SECONDS ] = "120"
1438+
1439+ # Create a new Langfuse instance to pick up the environment variable
1440+ langfuse = Langfuse (
1441+ public_key = "test-public-key" ,
1442+ secret_key = "test-secret-key" ,
1443+ host = "https://mock-host.com" ,
1444+ )
1445+ langfuse .api = Mock ()
1446+
1447+ prompt_name = "test_env_override_ttl"
1448+ prompt = Prompt_Text (
1449+ name = prompt_name ,
1450+ version = 1 ,
1451+ prompt = "Test prompt with env override" ,
1452+ type = "text" ,
1453+ labels = [],
1454+ config = {},
1455+ tags = [],
1456+ )
1457+ prompt_client = TextPromptClient (prompt )
1458+
1459+ mock_server_call = langfuse .api .prompts .get
1460+ mock_server_call .return_value = prompt
1461+
1462+ # Mock time to control cache expiration
1463+ with patch .object (PromptCacheItem , "get_epoch_seconds" ) as mock_time :
1464+ mock_time .return_value = 0
1465+
1466+ # First call - should cache the prompt
1467+ result1 = langfuse .get_prompt (prompt_name )
1468+ assert mock_server_call .call_count == 1
1469+ assert result1 == prompt_client
1470+
1471+ # Check that prompt is cached
1472+ cached_item = langfuse ._resources .prompt_cache .get (
1473+ langfuse ._resources .prompt_cache .generate_cache_key (prompt_name , version = None , label = None )
1474+ )
1475+ assert cached_item is not None
1476+ assert cached_item .value == prompt_client
1477+
1478+ # Debug: check the cache item's expiry time
1479+ print (f"DEBUG: Cache item expiry: { cached_item ._expiry } " )
1480+ print (f"DEBUG: Current mock time: { mock_time .return_value } " )
1481+ print (f"DEBUG: Is expired? { cached_item .is_expired ()} " )
1482+
1483+ # Set time to 60 seconds (before new TTL of 120 seconds)
1484+ mock_time .return_value = 60
1485+
1486+ # Second call - should still use cache
1487+ result2 = langfuse .get_prompt (prompt_name )
1488+ assert mock_server_call .call_count == 1 # No new server call
1489+ assert result2 == prompt_client
1490+
1491+ # Set time to 120 seconds (at TTL expiration)
1492+ mock_time .return_value = 120
1493+
1494+ # Third call - should still use cache (stale cache behavior)
1495+ result3 = langfuse .get_prompt (prompt_name )
1496+ assert result3 == prompt_client
1497+
1498+ # Wait for background refresh to complete
1499+ while True :
1500+ if langfuse ._resources .prompt_cache ._task_manager .active_tasks () == 0 :
1501+ break
1502+ sleep (0.1 )
1503+
1504+ # Should have made a new server call for refresh
1505+ assert mock_server_call .call_count == 2
1506+
1507+ # Set time to 121 seconds (after TTL expiration)
1508+ mock_time .return_value = 121
1509+
1510+ # Fourth call - should use refreshed cache
1511+ result4 = langfuse .get_prompt (prompt_name )
1512+ assert result4 == prompt_client
1513+
1514+ # Clean up environment variable
1515+ if LANGFUSE_PROMPT_CACHE_DEFAULT_TTL_SECONDS in os .environ :
1516+ del os .environ [LANGFUSE_PROMPT_CACHE_DEFAULT_TTL_SECONDS ]
1517+
1518+
1519+ @patch .object (PromptCacheItem , "get_epoch_seconds" )
1520+ def test_default_ttl_when_environment_variable_not_set (mock_time ):
1521+ """Test that default 60-second TTL is used when LANGFUSE_PROMPT_CACHE_DEFAULT_TTL_SECONDS is not set."""
1522+ from unittest .mock import patch
1523+
1524+ # Ensure environment variable is not set
1525+ if LANGFUSE_PROMPT_CACHE_DEFAULT_TTL_SECONDS in os .environ :
1526+ del os .environ [LANGFUSE_PROMPT_CACHE_DEFAULT_TTL_SECONDS ]
1527+
1528+ # Set initial time to 0
1529+ mock_time .return_value = 0
1530+
1531+ # Create a new Langfuse instance to pick up the default TTL
1532+ langfuse = Langfuse (
1533+ public_key = "test-public-key" ,
1534+ secret_key = "test-secret-key" ,
1535+ host = "https://mock-host.com" ,
1536+ )
1537+ langfuse .api = Mock ()
1538+
1539+ prompt_name = "test_default_ttl"
1540+ prompt = Prompt_Text (
1541+ name = prompt_name ,
1542+ version = 1 ,
1543+ prompt = "Test prompt with default TTL" ,
1544+ type = "text" ,
1545+ labels = [],
1546+ config = {},
1547+ tags = [],
1548+ )
1549+ prompt_client = TextPromptClient (prompt )
1550+
1551+ mock_server_call = langfuse .api .prompts .get
1552+ mock_server_call .return_value = prompt
1553+
1554+ # First call - should cache the prompt
1555+ result1 = langfuse .get_prompt (prompt_name )
1556+ assert mock_server_call .call_count == 1
1557+ assert result1 == prompt_client
1558+
1559+ # Check that prompt is cached
1560+ cached_item = langfuse ._resources .prompt_cache .get (
1561+ langfuse ._resources .prompt_cache .generate_cache_key (prompt_name , version = None , label = None )
1562+ )
1563+ assert cached_item is not None
1564+ assert cached_item .value == prompt_client
1565+
1566+ # Set time to just before default TTL expiration
1567+ mock_time .return_value = DEFAULT_PROMPT_CACHE_TTL_SECONDS - 1
1568+
1569+ # Second call - should still use cache
1570+ result2 = langfuse .get_prompt (prompt_name )
1571+ assert mock_server_call .call_count == 1 # No new server call
1572+ assert result2 == prompt_client
1573+
1574+ # Set time to just after default TTL expiration to trigger cache expiry
1575+ # Use the actual DEFAULT_PROMPT_CACHE_TTL_SECONDS value that was imported
1576+ mock_time .return_value = DEFAULT_PROMPT_CACHE_TTL_SECONDS + 1
1577+
1578+ # Third call - should still use cache (stale cache behavior)
1579+ result3 = langfuse .get_prompt (prompt_name )
1580+ assert result3 == prompt_client
1581+
1582+ # Wait for background refresh to complete
1583+ while True :
1584+ if langfuse ._resources .prompt_cache ._task_manager .active_tasks () == 0 :
1585+ break
1586+ sleep (0.1 )
1587+
1588+ # Should have made a new server call for refresh
1589+ assert mock_server_call .call_count == 2
1590+
1591+ # Set time to just after default TTL expiration
1592+ mock_time .return_value = DEFAULT_PROMPT_CACHE_TTL_SECONDS + 1
1593+
1594+ # Fourth call - should use refreshed cache
1595+ result4 = langfuse .get_prompt (prompt_name )
1596+ assert result4 == prompt_client
1597+
1598+
14191599def test_clear_prompt_cache (langfuse ):
14201600 """Test clearing the entire prompt cache."""
14211601 prompt_name = create_uuid ()
@@ -1460,4 +1640,4 @@ def test_clear_prompt_cache(langfuse):
14601640
14611641 # Verify data integrity
14621642 assert prompt_client .name == prompt_name
1463- assert cached_prompt .name == prompt_name
1643+ assert cached_prompt .name == prompt_name
0 commit comments