first commit
This commit is contained in:
326
plugins/semanticcache/plugin_no_store_test.go
Normal file
326
plugins/semanticcache/plugin_no_store_test.go
Normal file
@@ -0,0 +1,326 @@
|
||||
package semanticcache
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/maximhq/bifrost/core/schemas"
|
||||
)
|
||||
|
||||
// TestCacheNoStoreBasicFunctionality tests that CacheNoStoreKey prevents caching
|
||||
func TestCacheNoStoreBasicFunctionality(t *testing.T) {
|
||||
setup := NewTestSetup(t)
|
||||
defer setup.Cleanup()
|
||||
|
||||
testRequest := CreateBasicChatRequest("What is artificial intelligence?", 0.7, 100)
|
||||
|
||||
// Test 1: Normal caching (control test)
|
||||
ctx1 := CreateContextWithCacheKey("test-no-store-control")
|
||||
t.Log("Making normal request (should be cached)...")
|
||||
response1, err1 := setup.Client.ChatCompletionRequest(ctx1, testRequest)
|
||||
if err1 != nil {
|
||||
return // Test will be skipped by retry function
|
||||
}
|
||||
AssertNoCacheHit(t, &schemas.BifrostResponse{ChatResponse: response1}) // Fresh request
|
||||
|
||||
WaitForCache(setup.Plugin)
|
||||
|
||||
// Verify it got cached
|
||||
t.Log("Verifying normal caching worked...")
|
||||
response2, err2 := setup.Client.ChatCompletionRequest(ctx1, testRequest)
|
||||
if err2 != nil {
|
||||
if err2.Error != nil {
|
||||
t.Fatalf("Second request failed: %v", err2.Error.Message)
|
||||
} else {
|
||||
t.Fatalf("Second request failed: %v", err2)
|
||||
}
|
||||
}
|
||||
AssertCacheHit(t, &schemas.BifrostResponse{ChatResponse: response2}, "direct") // Should be cached
|
||||
|
||||
// Test 2: NoStore = true (should not cache)
|
||||
ctx2 := CreateContextWithCacheKeyAndNoStore("test-no-store-disabled", true)
|
||||
t.Log("Making request with CacheNoStoreKey=true (should not be cached)...")
|
||||
response3, err3 := setup.Client.ChatCompletionRequest(ctx2, testRequest)
|
||||
if err3 != nil {
|
||||
return // Test will be skipped by retry function
|
||||
}
|
||||
AssertNoCacheHit(t, &schemas.BifrostResponse{ChatResponse: response3}) // Fresh request
|
||||
|
||||
WaitForCache(setup.Plugin)
|
||||
|
||||
// Verify it was NOT cached
|
||||
t.Log("Verifying no-store request was not cached...")
|
||||
response4, err4 := setup.Client.ChatCompletionRequest(ctx2, testRequest)
|
||||
if err4 != nil {
|
||||
return // Test will be skipped by retry function
|
||||
}
|
||||
AssertNoCacheHit(t, &schemas.BifrostResponse{ChatResponse: response4}) // Should still be fresh (not cached)
|
||||
|
||||
// Test 3: NoStore = false (should cache normally)
|
||||
ctx3 := CreateContextWithCacheKeyAndNoStore("test-no-store-enabled", false)
|
||||
t.Log("Making request with CacheNoStoreKey=false (should be cached)...")
|
||||
response5, err5 := setup.Client.ChatCompletionRequest(ctx3, testRequest)
|
||||
if err5 != nil {
|
||||
return // Test will be skipped by retry function
|
||||
}
|
||||
AssertNoCacheHit(t, &schemas.BifrostResponse{ChatResponse: response5}) // Fresh request
|
||||
|
||||
WaitForCache(setup.Plugin)
|
||||
|
||||
// Verify it got cached
|
||||
t.Log("Verifying no-store=false request was cached...")
|
||||
response6, err6 := setup.Client.ChatCompletionRequest(ctx3, testRequest)
|
||||
if err6 != nil {
|
||||
t.Fatalf("Sixth request failed: %v", err6)
|
||||
}
|
||||
AssertCacheHit(t, &schemas.BifrostResponse{ChatResponse: response6}, "direct") // Should be cached
|
||||
|
||||
t.Log("✅ CacheNoStoreKey basic functionality works correctly")
|
||||
}
|
||||
|
||||
// TestCacheNoStoreWithDifferentRequestTypes tests NoStore with various request types
|
||||
func TestCacheNoStoreWithDifferentRequestTypes(t *testing.T) {
|
||||
t.Skip("Skipping Embedding Tests")
|
||||
|
||||
setup := NewTestSetup(t)
|
||||
defer setup.Cleanup()
|
||||
|
||||
// Test with chat completion
|
||||
chatRequest := CreateBasicChatRequest("Test no-store with chat", 0.7, 50)
|
||||
ctx1 := CreateContextWithCacheKeyAndNoStore("test-no-store-chat", true)
|
||||
|
||||
t.Log("Testing no-store with chat completion...")
|
||||
response1, err1 := setup.Client.ChatCompletionRequest(ctx1, chatRequest)
|
||||
if err1 != nil {
|
||||
return // Test will be skipped by retry function
|
||||
}
|
||||
AssertNoCacheHit(t, &schemas.BifrostResponse{ChatResponse: response1})
|
||||
|
||||
WaitForCache(setup.Plugin)
|
||||
|
||||
// Verify not cached
|
||||
response2, err2 := setup.Client.ChatCompletionRequest(ctx1, chatRequest)
|
||||
if err2 != nil {
|
||||
return // Test will be skipped by retry function
|
||||
}
|
||||
AssertNoCacheHit(t, &schemas.BifrostResponse{ChatResponse: response2}) // Should not be cached
|
||||
|
||||
// Test with embedding request
|
||||
embeddingRequest := CreateEmbeddingRequest([]string{"Test no-store with embeddings"})
|
||||
ctx2 := CreateContextWithCacheKeyAndNoStore("test-no-store-embedding", true)
|
||||
|
||||
t.Log("Testing no-store with embedding request...")
|
||||
response3, err3 := setup.Client.EmbeddingRequest(ctx2, embeddingRequest)
|
||||
if err3 != nil {
|
||||
return // Test will be skipped by retry function
|
||||
}
|
||||
AssertNoCacheHit(t, &schemas.BifrostResponse{EmbeddingResponse: response3})
|
||||
|
||||
WaitForCache(setup.Plugin)
|
||||
|
||||
// Verify not cached
|
||||
response4, err4 := setup.Client.EmbeddingRequest(ctx2, embeddingRequest)
|
||||
if err4 != nil {
|
||||
return // Test will be skipped by retry function
|
||||
}
|
||||
AssertNoCacheHit(t, &schemas.BifrostResponse{EmbeddingResponse: response4}) // Should not be cached
|
||||
|
||||
t.Log("✅ CacheNoStoreKey works with different request types")
|
||||
}
|
||||
|
||||
// TestCacheNoStoreWithConversationHistory tests NoStore with conversation context
|
||||
func TestCacheNoStoreWithConversationHistory(t *testing.T) {
|
||||
setup := NewTestSetup(t)
|
||||
defer setup.Cleanup()
|
||||
|
||||
// Create conversation context
|
||||
conversation := BuildConversationHistory(
|
||||
"You are a helpful assistant",
|
||||
[]string{"Hello", "Hi! How can I help?"},
|
||||
)
|
||||
messages := AddUserMessage(conversation, "What is machine learning?")
|
||||
request := CreateConversationRequest(messages, 0.7, 100)
|
||||
|
||||
// Test with no-store enabled
|
||||
ctx := CreateContextWithCacheKeyAndNoStore("test-no-store-conversation", true)
|
||||
|
||||
t.Log("Testing no-store with conversation history...")
|
||||
response1, err1 := setup.Client.ChatCompletionRequest(ctx, request)
|
||||
if err1 != nil {
|
||||
return // Test will be skipped by retry function
|
||||
}
|
||||
AssertNoCacheHit(t, &schemas.BifrostResponse{ChatResponse: response1})
|
||||
|
||||
WaitForCache(setup.Plugin)
|
||||
|
||||
// Verify not cached (same conversation should not hit cache)
|
||||
response2, err2 := setup.Client.ChatCompletionRequest(ctx, request)
|
||||
if err2 != nil {
|
||||
return // Test will be skipped by retry function
|
||||
}
|
||||
AssertNoCacheHit(t, &schemas.BifrostResponse{ChatResponse: response2}) // Should not be cached due to no-store
|
||||
|
||||
t.Log("✅ CacheNoStoreKey works with conversation history")
|
||||
}
|
||||
|
||||
// TestCacheNoStoreWithCacheTypes tests NoStore interaction with CacheTypeKey
|
||||
func TestCacheNoStoreWithCacheTypes(t *testing.T) {
|
||||
setup := NewTestSetup(t)
|
||||
defer setup.Cleanup()
|
||||
|
||||
testRequest := CreateBasicChatRequest("Test no-store with cache types", 0.7, 50)
|
||||
|
||||
// Test no-store with direct cache type
|
||||
ctx1 := CreateContextWithCacheKey("test-no-store-cache-types")
|
||||
ctx1 = ctx1.WithValue(CacheNoStoreKey, true)
|
||||
ctx1 = ctx1.WithValue(CacheTypeKey, CacheTypeDirect)
|
||||
|
||||
t.Log("Testing no-store with CacheTypeKey=direct...")
|
||||
response1, err1 := setup.Client.ChatCompletionRequest(ctx1, testRequest)
|
||||
if err1 != nil {
|
||||
return // Test will be skipped by retry function
|
||||
}
|
||||
AssertNoCacheHit(t, &schemas.BifrostResponse{ChatResponse: response1})
|
||||
|
||||
WaitForCache(setup.Plugin)
|
||||
|
||||
// Should not be cached
|
||||
response2, err2 := setup.Client.ChatCompletionRequest(ctx1, testRequest)
|
||||
if err2 != nil {
|
||||
return // Test will be skipped by retry function
|
||||
}
|
||||
AssertNoCacheHit(t, &schemas.BifrostResponse{ChatResponse: response2}) // No-store should override cache type
|
||||
|
||||
// Test no-store with semantic cache type
|
||||
ctx2 := CreateContextWithCacheKey("test-no-store-cache-types")
|
||||
ctx2 = ctx2.WithValue(CacheNoStoreKey, true)
|
||||
ctx2 = ctx2.WithValue(CacheTypeKey, CacheTypeSemantic)
|
||||
|
||||
t.Log("Testing no-store with CacheTypeKey=semantic...")
|
||||
response3, err3 := setup.Client.ChatCompletionRequest(ctx2, testRequest)
|
||||
if err3 != nil {
|
||||
return // Test will be skipped by retry function
|
||||
}
|
||||
AssertNoCacheHit(t, &schemas.BifrostResponse{ChatResponse: response3})
|
||||
|
||||
WaitForCache(setup.Plugin)
|
||||
|
||||
// Should not be cached
|
||||
response4, err4 := setup.Client.ChatCompletionRequest(ctx2, testRequest)
|
||||
if err4 != nil {
|
||||
return // Test will be skipped by retry function
|
||||
}
|
||||
AssertNoCacheHit(t, &schemas.BifrostResponse{ChatResponse: response4}) // No-store should override cache type
|
||||
|
||||
t.Log("✅ CacheNoStoreKey correctly overrides cache type settings")
|
||||
}
|
||||
|
||||
// TestCacheNoStoreErrorHandling tests error scenarios with NoStore
|
||||
func TestCacheNoStoreErrorHandling(t *testing.T) {
|
||||
setup := NewTestSetup(t)
|
||||
defer setup.Cleanup()
|
||||
|
||||
testRequest := CreateBasicChatRequest("Test no-store error handling", 0.7, 50)
|
||||
|
||||
// Test with invalid no-store value (non-boolean)
|
||||
ctx1 := CreateContextWithCacheKey("test-no-store-errors")
|
||||
ctx1 = ctx1.WithValue(CacheNoStoreKey, "invalid")
|
||||
|
||||
t.Log("Testing no-store with invalid value (should cache normally)...")
|
||||
response1, err1 := setup.Client.ChatCompletionRequest(ctx1, testRequest)
|
||||
if err1 != nil {
|
||||
return // Test will be skipped by retry function
|
||||
}
|
||||
AssertNoCacheHit(t, &schemas.BifrostResponse{ChatResponse: response1})
|
||||
|
||||
WaitForCache(setup.Plugin)
|
||||
|
||||
// Should be cached (invalid value should be ignored)
|
||||
response2, err2 := setup.Client.ChatCompletionRequest(ctx1, testRequest)
|
||||
if err2 != nil {
|
||||
if err2.Error != nil {
|
||||
t.Fatalf("Second request failed: %v", err2.Error.Message)
|
||||
} else {
|
||||
t.Fatalf("Second request failed: %v", err2)
|
||||
}
|
||||
}
|
||||
AssertCacheHit(t, &schemas.BifrostResponse{ChatResponse: response2}, "direct") // Should be cached (invalid value ignored)
|
||||
|
||||
// Test with nil value (should cache normally)
|
||||
ctx2 := CreateContextWithCacheKey("test-no-store-nil")
|
||||
ctx2 = ctx2.WithValue(CacheNoStoreKey, nil)
|
||||
|
||||
t.Log("Testing no-store with nil value (should cache normally)...")
|
||||
response3, err3 := setup.Client.ChatCompletionRequest(ctx2, testRequest)
|
||||
if err3 != nil {
|
||||
return // Test will be skipped by retry function
|
||||
}
|
||||
AssertNoCacheHit(t, &schemas.BifrostResponse{ChatResponse: response3})
|
||||
|
||||
WaitForCache(setup.Plugin)
|
||||
|
||||
// Should be cached (nil should be treated as normal caching)
|
||||
response4, err4 := setup.Client.ChatCompletionRequest(ctx2, testRequest)
|
||||
if err4 != nil {
|
||||
t.Fatalf("Fourth request failed: %v", err4)
|
||||
}
|
||||
AssertCacheHit(t, &schemas.BifrostResponse{ChatResponse: response4}, "direct") // Should be cached (nil ignored)
|
||||
|
||||
t.Log("✅ CacheNoStoreKey error handling works correctly")
|
||||
}
|
||||
|
||||
// TestCacheNoStoreReadButNoWrite tests that NoStore allows reading cache but prevents writing
|
||||
func TestCacheNoStoreReadButNoWrite(t *testing.T) {
|
||||
setup := NewTestSetup(t)
|
||||
defer setup.Cleanup()
|
||||
|
||||
testRequest := CreateBasicChatRequest("Describe Isaac Newton's three laws of motion", 0.7, 50)
|
||||
|
||||
// Step 1: Cache a response normally
|
||||
ctx1 := CreateContextWithCacheKey("test-no-store-read")
|
||||
t.Log("Caching response normally...")
|
||||
response1, err1 := setup.Client.ChatCompletionRequest(ctx1, testRequest)
|
||||
if err1 != nil {
|
||||
return // Test will be skipped by retry function
|
||||
}
|
||||
AssertNoCacheHit(t, &schemas.BifrostResponse{ChatResponse: response1})
|
||||
|
||||
WaitForCache(setup.Plugin)
|
||||
|
||||
// Step 2: Try to read with no-store enabled (should still read from cache)
|
||||
ctx2 := CreateContextWithCacheKeyAndNoStore("test-no-store-read", true)
|
||||
t.Log("Reading with no-store enabled (should still hit cache for reads)...")
|
||||
response2, err2 := setup.Client.ChatCompletionRequest(ctx2, testRequest)
|
||||
if err2 != nil {
|
||||
if err2.Error != nil {
|
||||
t.Fatalf("Second request failed: %v", err2.Error.Message)
|
||||
} else {
|
||||
t.Fatalf("Second request failed: %v", err2)
|
||||
}
|
||||
}
|
||||
// The current implementation should still read from cache even with no-store
|
||||
// (no-store only affects writing, not reading)
|
||||
AssertCacheHit(t, &schemas.BifrostResponse{ChatResponse: response2}, "direct")
|
||||
|
||||
// Step 3: Make a semantically similar request with no-store (strong paraphrase for deterministic semantic hit)
|
||||
newRequest := CreateBasicChatRequest("Describe the three laws of motion by Isaac Newton", 0.7, 50)
|
||||
t.Log("Making semantically similar request with no-store (should get semantic hit, but not cache response)...")
|
||||
response3, err3 := setup.Client.ChatCompletionRequest(ctx2, newRequest)
|
||||
if err3 != nil {
|
||||
t.Fatalf("Third request failed: %v", err3)
|
||||
}
|
||||
// Should get semantic cache hit (no-store allows reads, just prevents writes)
|
||||
AssertCacheHit(t, &schemas.BifrostResponse{ChatResponse: response3}, "semantic")
|
||||
|
||||
WaitForCache(setup.Plugin)
|
||||
|
||||
// Step 4: Repeat similar request with no-store (should still get semantic hit)
|
||||
t.Log("Repeating similar request with no-store (should still get semantic hit)...")
|
||||
response4, err4 := setup.Client.ChatCompletionRequest(ctx2, newRequest)
|
||||
if err4 != nil {
|
||||
t.Fatalf("Fourth request failed: %v", err4)
|
||||
}
|
||||
// Should get semantic cache hit again (consistent behavior)
|
||||
AssertCacheHit(t, &schemas.BifrostResponse{ChatResponse: response4}, "semantic")
|
||||
|
||||
t.Log("✅ CacheNoStoreKey allows reading but prevents writing")
|
||||
}
|
||||
Reference in New Issue
Block a user