13
13
from langfuse .model import ChatPromptClient , TextPromptClient
14
14
from tests .utils import create_uuid , get_api
15
15
16
+ import os
17
+ from langfuse ._client .environment_variables import LANGFUSE_PROMPT_CACHE_DEFAULT_TTL_SECONDS
16
18
17
19
def test_create_prompt ():
18
20
langfuse = Langfuse ()
@@ -688,6 +690,16 @@ def langfuse():
688
690
689
691
return langfuse_instance
690
692
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
691
703
692
704
# Fetching a new prompt when nothing in cache
693
705
def test_get_fresh_prompt (langfuse ):
@@ -1416,6 +1428,174 @@ def test_update_prompt():
1416
1428
assert sorted (updated_prompt .labels ) == expected_labels
1417
1429
1418
1430
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
+
1419
1599
def test_clear_prompt_cache (langfuse ):
1420
1600
"""Test clearing the entire prompt cache."""
1421
1601
prompt_name = create_uuid ()
@@ -1460,4 +1640,4 @@ def test_clear_prompt_cache(langfuse):
1460
1640
1461
1641
# Verify data integrity
1462
1642
assert prompt_client .name == prompt_name
1463
- assert cached_prompt .name == prompt_name
1643
+ assert cached_prompt .name == prompt_name
0 commit comments