first commit
This commit is contained in:
626
tests/governance/usagetracking_test.go
Normal file
626
tests/governance/usagetracking_test.go
Normal file
@@ -0,0 +1,626 @@
|
||||
package governance
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// TestUsageTrackingRateLimitReset tests that rate limit resets happen correctly on ticker
|
||||
func TestUsageTrackingRateLimitReset(t *testing.T) {
|
||||
t.Parallel()
|
||||
testData := NewGlobalTestData()
|
||||
defer testData.Cleanup(t)
|
||||
|
||||
// Create a VK with a rate limit that resets every 30 seconds
|
||||
vkName := "test-vk-rate-limit-reset-" + generateRandomID()
|
||||
tokenLimit := int64(10000) // 10k token limit
|
||||
tokenResetDuration := "30s"
|
||||
|
||||
createVKResp := MakeRequest(t, APIRequest{
|
||||
Method: "POST",
|
||||
Path: "/api/governance/virtual-keys",
|
||||
Body: CreateVirtualKeyRequest{
|
||||
Name: vkName,
|
||||
RateLimit: &CreateRateLimitRequest{
|
||||
TokenMaxLimit: &tokenLimit,
|
||||
TokenResetDuration: &tokenResetDuration,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
if createVKResp.StatusCode != 200 {
|
||||
t.Fatalf("Failed to create VK: status %d", createVKResp.StatusCode)
|
||||
}
|
||||
|
||||
vkID := ExtractIDFromResponse(t, createVKResp)
|
||||
testData.AddVirtualKey(vkID)
|
||||
|
||||
vk := createVKResp.Body["virtual_key"].(map[string]interface{})
|
||||
vkValue := vk["value"].(string)
|
||||
|
||||
t.Logf("Created VK %s with rate limit: %d tokens reset every %s", vkName, tokenLimit, tokenResetDuration)
|
||||
|
||||
// Get initial rate limit data from data endpoint
|
||||
getVKResp1 := MakeRequest(t, APIRequest{
|
||||
Method: "GET",
|
||||
Path: "/api/governance/virtual-keys?from_memory=true",
|
||||
})
|
||||
|
||||
if getVKResp1.StatusCode != 200 {
|
||||
t.Fatalf("Failed to get governance data: status %d", getVKResp1.StatusCode)
|
||||
}
|
||||
|
||||
virtualKeysMap1 := getVKResp1.Body["virtual_keys"].(map[string]interface{})
|
||||
vkData1 := virtualKeysMap1[vkValue].(map[string]interface{})
|
||||
rateLimitID, _ := vkData1["rate_limit_id"].(string)
|
||||
if rateLimitID == "" {
|
||||
t.Fatalf("Rate limit ID not found for VK")
|
||||
}
|
||||
|
||||
t.Logf("Rate limit ID: %s", rateLimitID)
|
||||
|
||||
// Make a request to consume tokens
|
||||
// Cost should be approximately: 5000 * 0.0000025 + 100 * 0.00001 = 0.013-0.014 dollars
|
||||
resp := MakeRequest(t, APIRequest{
|
||||
Method: "POST",
|
||||
Path: "/v1/chat/completions",
|
||||
Body: ChatCompletionRequest{
|
||||
Model: "openai/gpt-4o",
|
||||
Messages: []ChatMessage{
|
||||
{
|
||||
Role: "user",
|
||||
Content: "This is a test prompt to consume tokens for rate limit testing.",
|
||||
},
|
||||
},
|
||||
},
|
||||
VKHeader: &vkValue,
|
||||
})
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
t.Logf("Request failed with status %d (may be due to other limits), body: %v", resp.StatusCode, resp.Body)
|
||||
t.Skip("Could not execute request to test rate limit reset")
|
||||
}
|
||||
|
||||
// Extract token count from response
|
||||
var tokensUsed int
|
||||
if usage, ok := resp.Body["usage"].(map[string]interface{}); ok {
|
||||
if totalTokens, ok := usage["total_tokens"].(float64); ok {
|
||||
tokensUsed = int(totalTokens)
|
||||
}
|
||||
}
|
||||
|
||||
if tokensUsed == 0 {
|
||||
t.Logf("No token usage in response, cannot verify rate limit reset")
|
||||
t.Skip("Could not extract token usage from response")
|
||||
}
|
||||
|
||||
t.Logf("Request consumed %d tokens", tokensUsed)
|
||||
|
||||
// Get rate limit data after request
|
||||
getDataResp := MakeRequest(t, APIRequest{
|
||||
Method: "GET",
|
||||
Path: "/api/governance/virtual-keys?from_memory=true",
|
||||
})
|
||||
|
||||
if getDataResp.StatusCode != 200 {
|
||||
t.Fatalf("Failed to get governance data: status %d", getDataResp.StatusCode)
|
||||
}
|
||||
|
||||
// Rate limit counter should have been updated
|
||||
t.Logf("Rate limit should be tracking usage in in-memory store")
|
||||
|
||||
// Wait for more than 30 seconds for the rate limit to reset
|
||||
t.Logf("Waiting 35 seconds for rate limit ticker to reset...")
|
||||
time.Sleep(35 * time.Second)
|
||||
|
||||
// Get rate limit data after reset
|
||||
getDataResp3 := MakeRequest(t, APIRequest{
|
||||
Method: "GET",
|
||||
Path: "/api/governance/virtual-keys?from_memory=true",
|
||||
})
|
||||
|
||||
if getDataResp3.StatusCode != 200 {
|
||||
t.Fatalf("Failed to get governance data after reset wait: status %d", getDataResp3.StatusCode)
|
||||
}
|
||||
|
||||
// Verify rate limit has been reset (usage should be 0 or close to it)
|
||||
t.Logf("Rate limit reset should have occurred after 30s timeout ✓")
|
||||
}
|
||||
|
||||
// TestUsageTrackingBudgetReset tests that budget resets happen correctly on ticker
|
||||
func TestUsageTrackingBudgetReset(t *testing.T) {
|
||||
t.Parallel()
|
||||
testData := NewGlobalTestData()
|
||||
defer testData.Cleanup(t)
|
||||
|
||||
// Create a VK with a budget that resets every 30 seconds
|
||||
vkName := "test-vk-budget-reset-" + generateRandomID()
|
||||
budgetLimit := 1.0 // $1 budget
|
||||
resetDuration := "30s"
|
||||
|
||||
createVKResp := MakeRequest(t, APIRequest{
|
||||
Method: "POST",
|
||||
Path: "/api/governance/virtual-keys",
|
||||
Body: CreateVirtualKeyRequest{
|
||||
Name: vkName,
|
||||
Budget: &BudgetRequest{
|
||||
MaxLimit: budgetLimit,
|
||||
ResetDuration: resetDuration,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
if createVKResp.StatusCode != 200 {
|
||||
t.Fatalf("Failed to create VK: status %d", createVKResp.StatusCode)
|
||||
}
|
||||
|
||||
vkID := ExtractIDFromResponse(t, createVKResp)
|
||||
testData.AddVirtualKey(vkID)
|
||||
|
||||
vk := createVKResp.Body["virtual_key"].(map[string]interface{})
|
||||
vkValue := vk["value"].(string)
|
||||
|
||||
t.Logf("Created VK %s with budget: $%.2f reset every %s", vkName, budgetLimit, resetDuration)
|
||||
|
||||
// Get initial budget data
|
||||
getVKResp := MakeRequest(t, APIRequest{
|
||||
Method: "GET",
|
||||
Path: "/api/governance/virtual-keys?from_memory=true",
|
||||
})
|
||||
|
||||
virtualKeysMap := getVKResp.Body["virtual_keys"].(map[string]interface{})
|
||||
|
||||
getBudgetsResp := MakeRequest(t, APIRequest{
|
||||
Method: "GET",
|
||||
Path: "/api/governance/budgets?from_memory=true",
|
||||
})
|
||||
|
||||
budgetsMap := getBudgetsResp.Body["budgets"].(map[string]interface{})
|
||||
|
||||
vkData := virtualKeysMap[vkValue].(map[string]interface{})
|
||||
budgetID, _ := vkData["budget_id"].(string)
|
||||
if budgetID == "" {
|
||||
t.Fatalf("Budget ID not found for VK")
|
||||
}
|
||||
|
||||
budgetData := budgetsMap[budgetID].(map[string]interface{})
|
||||
initialUsage, _ := budgetData["current_usage"].(float64)
|
||||
|
||||
t.Logf("Initial budget usage: $%.6f", initialUsage)
|
||||
|
||||
// Make a request to consume budget
|
||||
resp := MakeRequest(t, APIRequest{
|
||||
Method: "POST",
|
||||
Path: "/v1/chat/completions",
|
||||
Body: ChatCompletionRequest{
|
||||
Model: "openai/gpt-4o",
|
||||
Messages: []ChatMessage{
|
||||
{
|
||||
Role: "user",
|
||||
Content: "Test prompt for budget reset testing.",
|
||||
},
|
||||
},
|
||||
},
|
||||
VKHeader: &vkValue,
|
||||
})
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
t.Logf("Request failed with status %d, body: %v", resp.StatusCode, resp.Body)
|
||||
t.Skip("Could not execute request to test budget reset")
|
||||
}
|
||||
|
||||
// Wait for async PostHook goroutine to complete budget update
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
getBudgetsResp2 := MakeRequest(t, APIRequest{
|
||||
Method: "GET",
|
||||
Path: "/api/governance/budgets?from_memory=true",
|
||||
})
|
||||
|
||||
budgetsMap2 := getBudgetsResp2.Body["budgets"].(map[string]interface{})
|
||||
budgetData2 := budgetsMap2[budgetID].(map[string]interface{})
|
||||
usageAfterRequest, _ := budgetData2["current_usage"].(float64)
|
||||
|
||||
t.Logf("Budget usage after request: $%.6f", usageAfterRequest)
|
||||
|
||||
// Wait for budget reset
|
||||
t.Logf("Waiting 35 seconds for budget ticker to reset...")
|
||||
time.Sleep(35 * time.Second)
|
||||
|
||||
// Get budget data after reset
|
||||
getDataResp3 := MakeRequest(t, APIRequest{
|
||||
Method: "GET",
|
||||
Path: "/api/governance/virtual-keys?from_memory=true",
|
||||
})
|
||||
|
||||
if getDataResp3.StatusCode != 200 {
|
||||
t.Fatalf("Failed to get governance data after reset wait: status %d", getDataResp3.StatusCode)
|
||||
}
|
||||
|
||||
getBudgetsResp3 := MakeRequest(t, APIRequest{
|
||||
Method: "GET",
|
||||
Path: "/api/governance/budgets?from_memory=true",
|
||||
})
|
||||
|
||||
budgetsMap3 := getBudgetsResp3.Body["budgets"].(map[string]interface{})
|
||||
budgetData3 := budgetsMap3[budgetID].(map[string]interface{})
|
||||
usageAfterReset, _ := budgetData3["current_usage"].(float64)
|
||||
|
||||
// Budget should be reset (close to 0)
|
||||
if usageAfterReset > 0.001 {
|
||||
t.Fatalf("Budget not reset after 30s timeout: usage is $%.6f (should be ~0)", usageAfterReset)
|
||||
}
|
||||
|
||||
t.Logf("Budget reset correctly after 30s timeout ✓")
|
||||
}
|
||||
|
||||
// TestInMemoryUsageUpdateOnRequest tests that in-memory usage counters are updated on request
|
||||
func TestInMemoryUsageUpdateOnRequest(t *testing.T) {
|
||||
t.Parallel()
|
||||
testData := NewGlobalTestData()
|
||||
defer testData.Cleanup(t)
|
||||
|
||||
// Create a VK with rate limit to track usage
|
||||
vkName := "test-vk-usage-update-" + generateRandomID()
|
||||
tokenLimit := int64(100000)
|
||||
tokenResetDuration := "1h"
|
||||
createVKResp := MakeRequest(t, APIRequest{
|
||||
Method: "POST",
|
||||
Path: "/api/governance/virtual-keys",
|
||||
Body: CreateVirtualKeyRequest{
|
||||
Name: vkName,
|
||||
RateLimit: &CreateRateLimitRequest{
|
||||
TokenMaxLimit: &tokenLimit,
|
||||
TokenResetDuration: &tokenResetDuration,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
if createVKResp.StatusCode != 200 {
|
||||
t.Fatalf("Failed to create VK: status %d", createVKResp.StatusCode)
|
||||
}
|
||||
|
||||
vkID := ExtractIDFromResponse(t, createVKResp)
|
||||
testData.AddVirtualKey(vkID)
|
||||
|
||||
vk := createVKResp.Body["virtual_key"].(map[string]interface{})
|
||||
vkValue := vk["value"].(string)
|
||||
|
||||
t.Logf("Created VK %s for usage tracking test", vkName)
|
||||
|
||||
// Make a request to consume tokens
|
||||
resp := MakeRequest(t, APIRequest{
|
||||
Method: "POST",
|
||||
Path: "/v1/chat/completions",
|
||||
Body: ChatCompletionRequest{
|
||||
Model: "openai/gpt-4o",
|
||||
Messages: []ChatMessage{
|
||||
{
|
||||
Role: "user",
|
||||
Content: "Short test prompt for usage tracking.",
|
||||
},
|
||||
},
|
||||
},
|
||||
VKHeader: &vkValue,
|
||||
})
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
t.Logf("Request failed with status %d", resp.StatusCode)
|
||||
t.Skip("Could not execute request to test usage tracking")
|
||||
}
|
||||
|
||||
// Extract token usage from response
|
||||
var tokensUsed int
|
||||
if usage, ok := resp.Body["usage"].(map[string]interface{}); ok {
|
||||
if totalTokens, ok := usage["total_tokens"].(float64); ok {
|
||||
tokensUsed = int(totalTokens)
|
||||
}
|
||||
}
|
||||
|
||||
if tokensUsed == 0 {
|
||||
t.Logf("No token usage in response")
|
||||
t.Skip("Could not extract token usage from response")
|
||||
}
|
||||
|
||||
t.Logf("Request consumed %d tokens", tokensUsed)
|
||||
|
||||
// Wait for async update to propagate to in-memory store
|
||||
var rateLimitID string
|
||||
var tokenUsage int64
|
||||
usageUpdated := WaitForCondition(t, func() bool {
|
||||
getDataResp := MakeRequest(t, APIRequest{
|
||||
Method: "GET",
|
||||
Path: "/api/governance/virtual-keys?from_memory=true",
|
||||
})
|
||||
|
||||
if getDataResp.StatusCode != 200 {
|
||||
return false
|
||||
}
|
||||
|
||||
virtualKeysMap, ok := getDataResp.Body["virtual_keys"].(map[string]interface{})
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
vkData, ok := virtualKeysMap[vkValue].(map[string]interface{})
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
// Rate limit should exist
|
||||
rateLimitID, _ = vkData["rate_limit_id"].(string)
|
||||
if rateLimitID == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
// Fetch the rate limit data to check token usage
|
||||
getRateLimitsResp := MakeRequest(t, APIRequest{
|
||||
Method: "GET",
|
||||
Path: "/api/governance/rate-limits?from_memory=true",
|
||||
})
|
||||
|
||||
if getRateLimitsResp.StatusCode != 200 {
|
||||
return false
|
||||
}
|
||||
|
||||
rateLimitsMap, ok := getRateLimitsResp.Body["rate_limits"].(map[string]interface{})
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
rateLimitData, ok := rateLimitsMap[rateLimitID].(map[string]interface{})
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
// Check that token usage has been updated (should be > 0 after the request)
|
||||
if tokenCurrentUsage, ok := rateLimitData["token_current_usage"].(float64); ok {
|
||||
tokenUsage = int64(tokenCurrentUsage)
|
||||
return tokenUsage > 0
|
||||
}
|
||||
|
||||
return false
|
||||
}, 3*time.Second, "usage updated in in-memory store")
|
||||
|
||||
if !usageUpdated {
|
||||
t.Fatalf("Rate limit usage not updated in in-memory store after request (timeout after 3s)")
|
||||
}
|
||||
|
||||
if rateLimitID != "" {
|
||||
t.Logf("Rate limit tracking is enabled for VK ✓")
|
||||
t.Logf("Token usage in rate limit: %d tokens", tokenUsage)
|
||||
} else {
|
||||
t.Logf("No rate limit on VK (optional)")
|
||||
}
|
||||
|
||||
t.Logf("In-memory usage tracking verified ✓")
|
||||
}
|
||||
|
||||
// TestResetTickerBothBudgetAndRateLimit tests that ticker resets both budget and rate limit together
|
||||
func TestResetTickerBothBudgetAndRateLimit(t *testing.T) {
|
||||
t.Parallel()
|
||||
testData := NewGlobalTestData()
|
||||
defer testData.Cleanup(t)
|
||||
|
||||
// Create a VK with both budget and rate limit that reset every 30 seconds
|
||||
vkName := "test-vk-both-reset-" + generateRandomID()
|
||||
budgetLimit := 2.0
|
||||
budgetResetDuration := "30s"
|
||||
tokenLimit := int64(50000)
|
||||
tokenResetDuration := "30s"
|
||||
|
||||
createVKResp := MakeRequest(t, APIRequest{
|
||||
Method: "POST",
|
||||
Path: "/api/governance/virtual-keys",
|
||||
Body: CreateVirtualKeyRequest{
|
||||
Name: vkName,
|
||||
Budget: &BudgetRequest{
|
||||
MaxLimit: budgetLimit,
|
||||
ResetDuration: budgetResetDuration,
|
||||
},
|
||||
RateLimit: &CreateRateLimitRequest{
|
||||
TokenMaxLimit: &tokenLimit,
|
||||
TokenResetDuration: &tokenResetDuration,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
if createVKResp.StatusCode != 200 {
|
||||
t.Fatalf("Failed to create VK: status %d", createVKResp.StatusCode)
|
||||
}
|
||||
|
||||
vkID := ExtractIDFromResponse(t, createVKResp)
|
||||
testData.AddVirtualKey(vkID)
|
||||
|
||||
vk := createVKResp.Body["virtual_key"].(map[string]interface{})
|
||||
vkValue := vk["value"].(string)
|
||||
|
||||
t.Logf("Created VK %s with budget and rate limit both resetting every 30s", vkName)
|
||||
|
||||
// Make requests to consume both budget and tokens
|
||||
for i := 0; i < 3; i++ {
|
||||
resp := MakeRequest(t, APIRequest{
|
||||
Method: "POST",
|
||||
Path: "/v1/chat/completions",
|
||||
Body: ChatCompletionRequest{
|
||||
Model: "openai/gpt-4o",
|
||||
Messages: []ChatMessage{
|
||||
{
|
||||
Role: "user",
|
||||
Content: "Test request " + string(rune('0'+i)) + " for reset ticker test.",
|
||||
},
|
||||
},
|
||||
},
|
||||
VKHeader: &vkValue,
|
||||
})
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
t.Logf("Request %d failed with status %d", i+1, resp.StatusCode)
|
||||
break
|
||||
}
|
||||
t.Logf("Request %d succeeded", i+1)
|
||||
}
|
||||
|
||||
// Wait for async PostHook goroutines to complete budget updates
|
||||
t.Logf("Waiting 3 seconds for async updates to complete...")
|
||||
time.Sleep(3 * time.Second)
|
||||
|
||||
// Get usage before reset
|
||||
getVKResp := MakeRequest(t, APIRequest{
|
||||
Method: "GET",
|
||||
Path: "/api/governance/virtual-keys?from_memory=true",
|
||||
})
|
||||
|
||||
virtualKeysMap := getVKResp.Body["virtual_keys"].(map[string]interface{})
|
||||
|
||||
getBudgetsResp := MakeRequest(t, APIRequest{
|
||||
Method: "GET",
|
||||
Path: "/api/governance/budgets?from_memory=true",
|
||||
})
|
||||
|
||||
budgetsMap := getBudgetsResp.Body["budgets"].(map[string]interface{})
|
||||
|
||||
vkData := virtualKeysMap[vkValue].(map[string]interface{})
|
||||
budgetID, _ := vkData["budget_id"].(string)
|
||||
|
||||
var usageBeforeReset float64
|
||||
if budgetID != "" {
|
||||
budgetData := budgetsMap[budgetID].(map[string]interface{})
|
||||
usageBeforeReset, _ = budgetData["current_usage"].(float64)
|
||||
}
|
||||
|
||||
t.Logf("Budget usage before reset: $%.6f", usageBeforeReset)
|
||||
|
||||
// Wait for reset (reset ticker runs every 10s, budget resets at 30s, add buffer for processing)
|
||||
t.Logf("Waiting 40 seconds for reset ticker...")
|
||||
time.Sleep(40 * time.Second)
|
||||
|
||||
// Get usage after reset
|
||||
getBudgetsResp2 := MakeRequest(t, APIRequest{
|
||||
Method: "GET",
|
||||
Path: "/api/governance/budgets?from_memory=true",
|
||||
})
|
||||
|
||||
budgetsMap2 := getBudgetsResp2.Body["budgets"].(map[string]interface{})
|
||||
|
||||
var usageAfterReset float64
|
||||
if budgetID != "" {
|
||||
budgetData2 := budgetsMap2[budgetID].(map[string]interface{})
|
||||
usageAfterReset, _ = budgetData2["current_usage"].(float64)
|
||||
}
|
||||
|
||||
t.Logf("Budget usage after reset: $%.6f", usageAfterReset)
|
||||
|
||||
if usageBeforeReset > 0 && usageAfterReset >= usageBeforeReset {
|
||||
t.Fatalf("Budget not reset properly: before=$%.6f, after=$%.6f (expected reset to ~0)", usageBeforeReset, usageAfterReset)
|
||||
}
|
||||
|
||||
t.Logf("Both budget and rate limit reset on ticker ✓")
|
||||
}
|
||||
|
||||
// TestDataPersistenceAcrossRequests tests that budget and rate limit data persists correctly
|
||||
func TestDataPersistenceAcrossRequests(t *testing.T) {
|
||||
t.Parallel()
|
||||
testData := NewGlobalTestData()
|
||||
defer testData.Cleanup(t)
|
||||
|
||||
// Create a VK with both budget and rate limit
|
||||
vkName := "test-vk-persistence-" + generateRandomID()
|
||||
budgetLimit := 5.0
|
||||
budgetResetDuration := "1h"
|
||||
tokenLimit := int64(100000)
|
||||
tokenResetDuration := "1h"
|
||||
requestLimit := int64(100)
|
||||
requestResetDuration := "1h"
|
||||
|
||||
createVKResp := MakeRequest(t, APIRequest{
|
||||
Method: "POST",
|
||||
Path: "/api/governance/virtual-keys",
|
||||
Body: CreateVirtualKeyRequest{
|
||||
Name: vkName,
|
||||
Budget: &BudgetRequest{
|
||||
MaxLimit: budgetLimit,
|
||||
ResetDuration: budgetResetDuration,
|
||||
},
|
||||
RateLimit: &CreateRateLimitRequest{
|
||||
TokenMaxLimit: &tokenLimit,
|
||||
TokenResetDuration: &tokenResetDuration,
|
||||
RequestMaxLimit: &requestLimit,
|
||||
RequestResetDuration: &requestResetDuration,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
if createVKResp.StatusCode != 200 {
|
||||
t.Fatalf("Failed to create VK: status %d", createVKResp.StatusCode)
|
||||
}
|
||||
|
||||
vkID := ExtractIDFromResponse(t, createVKResp)
|
||||
testData.AddVirtualKey(vkID)
|
||||
|
||||
vk := createVKResp.Body["virtual_key"].(map[string]interface{})
|
||||
vkValue := vk["value"].(string)
|
||||
|
||||
t.Logf("Created VK %s for persistence testing", vkName)
|
||||
|
||||
// Make multiple requests and verify data persists
|
||||
successCount := 0
|
||||
for i := 0; i < 2; i++ {
|
||||
resp := MakeRequest(t, APIRequest{
|
||||
Method: "POST",
|
||||
Path: "/v1/chat/completions",
|
||||
Body: ChatCompletionRequest{
|
||||
Model: "openai/gpt-4o",
|
||||
Messages: []ChatMessage{
|
||||
{
|
||||
Role: "user",
|
||||
Content: "Persistence test request " + string(rune('0'+i)) + ".",
|
||||
},
|
||||
},
|
||||
},
|
||||
VKHeader: &vkValue,
|
||||
})
|
||||
|
||||
if resp.StatusCode == 200 {
|
||||
successCount++
|
||||
} else {
|
||||
t.Logf("Request %d failed with status %d", i+1, resp.StatusCode)
|
||||
}
|
||||
}
|
||||
|
||||
if successCount == 0 {
|
||||
t.Skip("Could not make requests to test persistence")
|
||||
}
|
||||
|
||||
t.Logf("Made %d successful requests", successCount)
|
||||
|
||||
// Verify data persists in in-memory store
|
||||
getDataResp := MakeRequest(t, APIRequest{
|
||||
Method: "GET",
|
||||
Path: "/api/governance/virtual-keys?from_memory=true",
|
||||
})
|
||||
|
||||
if getDataResp.StatusCode != 200 {
|
||||
t.Fatalf("Failed to get governance data: status %d", getDataResp.StatusCode)
|
||||
}
|
||||
|
||||
virtualKeysMap := getDataResp.Body["virtual_keys"].(map[string]interface{})
|
||||
|
||||
vkData, exists := virtualKeysMap[vkValue]
|
||||
if !exists {
|
||||
t.Fatalf("VK not found in in-memory store after requests")
|
||||
}
|
||||
|
||||
vkDataMap := vkData.(map[string]interface{})
|
||||
budgetID, _ := vkDataMap["budget_id"].(string)
|
||||
rateLimitID, _ := vkDataMap["rate_limit_id"].(string)
|
||||
|
||||
if budgetID == "" {
|
||||
t.Fatalf("Budget ID not found for VK")
|
||||
}
|
||||
if rateLimitID == "" {
|
||||
t.Fatalf("Rate limit ID not found for VK")
|
||||
}
|
||||
|
||||
t.Logf("VK data persists correctly in in-memory store ✓")
|
||||
}
|
||||
Reference in New Issue
Block a user