Files
bifrost/framework/logstore/payload_test.go
Beyhan Oğur 880f412e2c first commit
2026-04-26 21:52:23 +03:00

157 lines
5.3 KiB
Go

package logstore
import (
"testing"
"time"
"github.com/maximhq/bifrost/core/schemas"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestExtractPayload_RoundTrip(t *testing.T) {
log := &Log{
ID: "test-1",
InputHistory: `[{"role":"user","content":"hello"}]`,
ResponsesInputHistory: `[{"role":"user","content":"hi"}]`,
OutputMessage: `{"role":"assistant","content":"world"}`,
ResponsesOutput: `[{"role":"assistant","content":"there"}]`,
EmbeddingOutput: `[{"embedding":[0.1]}]`,
RerankOutput: `[{"score":0.9}]`,
Params: `{"temperature":0.7}`,
Tools: `[{"name":"tool1"}]`,
ToolCalls: `[{"id":"tc1"}]`,
SpeechInput: `{"input":"text"}`,
TranscriptionInput: `{"file":"test.mp3"}`,
ImageGenerationInput: `{"prompt":"cat"}`,
ImageEditInput: `{"prompt":"edit cat"}`,
ImageVariationInput: `{"image":"base64img"}`,
VideoGenerationInput: `{"prompt":"dog"}`,
SpeechOutput: `{"audio":"base64"}`,
TranscriptionOutput: `{"text":"hello"}`,
ImageGenerationOutput: `{"url":"http://img"}`,
ListModelsOutput: `[{"id":"model1"}]`,
VideoGenerationOutput: `{"id":"vid1"}`,
VideoRetrieveOutput: `{"status":"ready"}`,
VideoDownloadOutput: `{"url":"http://vid"}`,
VideoListOutput: `{"videos":[]}`,
VideoDeleteOutput: `{"deleted":true}`,
CacheDebug: `{"hit":true}`,
TokenUsage: `{"total_tokens":100}`,
ErrorDetails: `{"error":"bad"}`,
RawRequest: `{"method":"POST"}`,
RawResponse: `{"status":200}`,
PassthroughRequestBody: `body-req`,
PassthroughResponseBody: `body-resp`,
RoutingEngineLogs: `routing log`,
}
payload := ExtractPayload(log)
assert.Equal(t, len(payloadFields), len(payload), "payload map should have all payload fields")
assert.Equal(t, `[{"role":"user","content":"hello"}]`, payload["input_history"])
assert.Equal(t, `{"role":"assistant","content":"world"}`, payload["output_message"])
assert.Equal(t, `routing log`, payload["routing_engine_logs"])
// Clear and verify.
ClearPayload(log)
assert.Empty(t, log.InputHistory)
assert.Empty(t, log.OutputMessage)
assert.Empty(t, log.RawRequest)
assert.Empty(t, log.RoutingEngineLogs)
// Marshal and merge back.
data, err := MarshalPayload(payload)
require.NoError(t, err)
err = MergePayloadFromJSON(log, data)
require.NoError(t, err)
assert.Equal(t, `[{"role":"user","content":"hello"}]`, log.InputHistory)
assert.Equal(t, `{"role":"assistant","content":"world"}`, log.OutputMessage)
assert.Equal(t, `routing log`, log.RoutingEngineLogs)
}
func TestClearPayload_DoesNotTouchIndexFields(t *testing.T) {
log := &Log{
ID: "test-1",
Provider: "anthropic",
Model: "claude-3",
Status: "success",
InputHistory: `[{"role":"user","content":"hello"}]`,
}
ClearPayload(log)
assert.Equal(t, "test-1", log.ID)
assert.Equal(t, "anthropic", log.Provider)
assert.Equal(t, "claude-3", log.Model)
assert.Equal(t, "success", log.Status)
assert.Empty(t, log.InputHistory)
}
func TestBuildInputContentSummary(t *testing.T) {
content := "What is the weather?"
log := &Log{
InputHistoryParsed: []schemas.ChatMessage{
{Role: schemas.ChatMessageRoleUser, Content: &schemas.ChatMessageContent{ContentStr: &content}},
},
OutputMessageParsed: &schemas.ChatMessage{
Content: &schemas.ChatMessageContent{ContentStr: strPtr("It's sunny")},
},
}
summary := log.BuildInputContentSummary()
assert.Contains(t, summary, "What is the weather?")
assert.NotContains(t, summary, "It's sunny", "BuildInputContentSummary should not include output")
}
func TestBuildTags(t *testing.T) {
vkID := "vk_123"
rrID := "rr_456"
log := &Log{
Provider: "anthropic",
Model: "claude-3-sonnet",
Status: "success",
Object: "chat.completion",
VirtualKeyID: &vkID,
SelectedKeyID: "sk_789",
RoutingRuleID: &rrID,
Stream: true,
Timestamp: time.Date(2026, 4, 3, 14, 0, 0, 0, time.UTC),
}
tags := BuildTags(log)
assert.Equal(t, "anthropic", tags["provider"])
assert.Equal(t, "claude-3-sonnet", tags["model"])
assert.Equal(t, "success", tags["status"])
assert.Equal(t, "chat.completion", tags["object_type"])
assert.Equal(t, "vk_123", tags["virtual_key_id"])
assert.Equal(t, "sk_789", tags["selected_key_id"])
assert.Equal(t, "rr_456", tags["routing_rule_id"])
assert.Equal(t, "true", tags["stream"])
assert.Equal(t, "false", tags["has_error"])
assert.Equal(t, "2026-04-03", tags["date"])
assert.LessOrEqual(t, len(tags), 10, "S3 allows max 10 tags")
}
func TestBuildTags_ErrorStatus(t *testing.T) {
log := &Log{Status: "error", Timestamp: time.Now()}
tags := BuildTags(log)
assert.Equal(t, "true", tags["has_error"])
}
func TestObjectKey(t *testing.T) {
ts := time.Date(2026, 4, 3, 14, 0, 0, 0, time.UTC)
key := ObjectKey("bifrost", ts, "req_abc123")
assert.Equal(t, "bifrost/logs/2026/04/03/14/req_abc123.json.gz", key)
}
func TestPayloadFieldNames(t *testing.T) {
fields := PayloadFieldNames()
assert.True(t, len(fields) > 0)
// Verify it's a copy.
fields[0] = "modified"
assert.NotEqual(t, "modified", payloadFields[0])
}
func strPtr(s string) *string {
return &s
}