Skip to content

Commit e97d069

Browse files
authored
Merge pull request #7 from bdpiprava/feature/clone-support
feat: add tests
2 parents d9073bf + e99fcac commit e97d069

3 files changed

Lines changed: 249 additions & 0 deletions

File tree

test-integration/data.go

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,77 @@ func NewTestTraceEvent() *types.TraceEvent {
2929
}
3030
}
3131

32+
// NewTestGenerationEvent returns a sample GenerationEvent for testing purposes
33+
func NewTestGenerationEvent() *types.GenerationEvent {
34+
traceID := uuid.New()
35+
generationID := uuid.New()
36+
now := time.Now().UTC()
37+
38+
return &types.GenerationEvent{
39+
ID: &generationID,
40+
Name: "TestGeneration",
41+
TraceID: &traceID,
42+
StartTime: &now,
43+
Model: "gpt-3.5-turbo",
44+
Input: "Test input for generation",
45+
Output: "Test output for generation",
46+
Metadata: map[string]any{
47+
"test": "generation",
48+
"version": float64(1),
49+
},
50+
Level: types.Default,
51+
Usage: types.Usage{
52+
Input: 10,
53+
Output: 5,
54+
Total: 15,
55+
Unit: "TOKENS",
56+
},
57+
ModelParameters: map[string]any{
58+
"temperature": 0.7,
59+
"max_tokens": float64(100),
60+
},
61+
PromptName: "",
62+
PromptVersion: 0,
63+
}
64+
}
65+
66+
// NewTestSpanEvent returns a sample SpanEvent for testing purposes
67+
func NewTestSpanEvent() *types.SpanEvent {
68+
traceID := uuid.New()
69+
spanID := uuid.New()
70+
now := time.Now().UTC()
71+
72+
return &types.SpanEvent{
73+
ID: &spanID,
74+
Name: "TestSpan",
75+
TraceID: &traceID,
76+
StartTime: &now,
77+
Input: "Test input for span",
78+
Output: "Test output for span",
79+
Metadata: map[string]any{
80+
"test": "span",
81+
"operation": "test_operation",
82+
},
83+
Level: types.Default,
84+
Version: "1.0",
85+
}
86+
}
87+
88+
// NewTestScoreEvent returns a sample ScoreEvent for testing purposes
89+
func NewTestScoreEvent() *types.ScoreEvent {
90+
scoreID := uuid.New()
91+
traceID := uuid.New().String()
92+
comment := "Test score comment"
93+
94+
return &types.ScoreEvent{
95+
ID: &scoreID,
96+
Name: "TestScore",
97+
TraceID: &traceID,
98+
Value: 0.85,
99+
Comment: &comment,
100+
}
101+
}
102+
32103
// BuildSession constructs a Session from a slice of TraceEvents.
33104
func BuildSession(traceEvents ...*types.TraceEvent) *types.Session {
34105
if len(traceEvents) == 0 {

test-integration/data_test.go

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
package integration_test
2+
3+
import (
4+
"testing"
5+
"time"
6+
7+
"github.com/stretchr/testify/assert"
8+
"github.com/stretchr/testify/require"
9+
10+
"github.com/bdpiprava/GoLangfuse/types"
11+
)
12+
13+
func TestNewTestTraceEvent(t *testing.T) {
14+
traceEvent := NewTestTraceEvent()
15+
16+
require.NotNil(t, traceEvent)
17+
assert.NotNil(t, traceEvent.ID)
18+
assert.Equal(t, "SendTrace", traceEvent.Name)
19+
assert.NotEmpty(t, traceEvent.SessionID)
20+
assert.NotEmpty(t, traceEvent.UserID)
21+
assert.Equal(t, "Test input for SendTrace", traceEvent.Input)
22+
assert.Equal(t, "Test output for SendTrace", traceEvent.Output)
23+
assert.NotNil(t, traceEvent.Metadata)
24+
assert.Contains(t, traceEvent.Tags, "test")
25+
assert.Contains(t, traceEvent.Tags, "integration")
26+
assert.True(t, traceEvent.Public)
27+
}
28+
29+
func TestNewTestGenerationEvent(t *testing.T) {
30+
generationEvent := NewTestGenerationEvent()
31+
32+
require.NotNil(t, generationEvent)
33+
assert.NotNil(t, generationEvent.ID)
34+
assert.Equal(t, "TestGeneration", generationEvent.Name)
35+
assert.NotNil(t, generationEvent.TraceID)
36+
assert.NotNil(t, generationEvent.StartTime)
37+
assert.Equal(t, "gpt-3.5-turbo", generationEvent.Model)
38+
assert.Equal(t, "Test input for generation", generationEvent.Input)
39+
assert.Equal(t, "Test output for generation", generationEvent.Output)
40+
assert.NotNil(t, generationEvent.Metadata)
41+
assert.Equal(t, types.Default, generationEvent.Level)
42+
assert.Equal(t, 10, generationEvent.Usage.Input)
43+
assert.Equal(t, 5, generationEvent.Usage.Output)
44+
assert.Equal(t, 15, generationEvent.Usage.Total)
45+
assert.NotNil(t, generationEvent.ModelParameters)
46+
assert.Equal(t, 0, generationEvent.PromptVersion)
47+
}
48+
49+
func TestNewTestSpanEvent(t *testing.T) {
50+
spanEvent := NewTestSpanEvent()
51+
52+
require.NotNil(t, spanEvent)
53+
assert.NotNil(t, spanEvent.ID)
54+
assert.Equal(t, "TestSpan", spanEvent.Name)
55+
assert.NotNil(t, spanEvent.TraceID)
56+
assert.NotNil(t, spanEvent.StartTime)
57+
assert.Equal(t, "Test input for span", spanEvent.Input)
58+
assert.Equal(t, "Test output for span", spanEvent.Output)
59+
assert.NotNil(t, spanEvent.Metadata)
60+
assert.Equal(t, types.Default, spanEvent.Level)
61+
assert.Equal(t, "1.0", spanEvent.Version)
62+
}
63+
64+
func TestNewTestScoreEvent(t *testing.T) {
65+
scoreEvent := NewTestScoreEvent()
66+
67+
require.NotNil(t, scoreEvent)
68+
assert.NotNil(t, scoreEvent.ID)
69+
assert.Equal(t, "TestScore", scoreEvent.Name)
70+
assert.NotNil(t, scoreEvent.TraceID)
71+
assert.Equal(t, float32(0.85), scoreEvent.Value)
72+
assert.NotNil(t, scoreEvent.Comment)
73+
assert.Equal(t, "Test score comment", *scoreEvent.Comment)
74+
}
75+
76+
func TestBuildSession(t *testing.T) {
77+
traceEvent := NewTestTraceEvent()
78+
session := BuildSession(traceEvent)
79+
80+
require.NotNil(t, session)
81+
assert.Equal(t, traceEvent.SessionID, session.ID)
82+
assert.Equal(t, "test-project", session.ProjectID)
83+
assert.Len(t, session.Traces, 1)
84+
85+
trace := session.Traces[0]
86+
assert.Equal(t, traceEvent.ID.String(), trace.ID)
87+
assert.Equal(t, traceEvent.Name, trace.Name)
88+
assert.Equal(t, traceEvent.UserID, trace.UserID)
89+
assert.Equal(t, traceEvent.SessionID, trace.SessionID)
90+
assert.Equal(t, "test-project", trace.ProjectID)
91+
assert.Equal(t, traceEvent.Public, trace.Public)
92+
assert.Equal(t, traceEvent.Tags, trace.Tags)
93+
assert.Equal(t, traceEvent.Input, trace.Input)
94+
assert.Equal(t, traceEvent.Output, trace.Output)
95+
}
96+
97+
func TestBuildSessionEmpty(t *testing.T) {
98+
session := BuildSession()
99+
assert.Nil(t, session)
100+
}
101+
102+
func TestEventTimestamps(t *testing.T) {
103+
before := time.Now()
104+
105+
generationEvent := NewTestGenerationEvent()
106+
spanEvent := NewTestSpanEvent()
107+
108+
after := time.Now()
109+
110+
require.NotNil(t, generationEvent.StartTime)
111+
require.NotNil(t, spanEvent.StartTime)
112+
113+
assert.True(t, generationEvent.StartTime.After(before) || generationEvent.StartTime.Equal(before))
114+
assert.True(t, generationEvent.StartTime.Before(after) || generationEvent.StartTime.Equal(after))
115+
116+
assert.True(t, spanEvent.StartTime.After(before) || spanEvent.StartTime.Equal(before))
117+
assert.True(t, spanEvent.StartTime.Before(after) || spanEvent.StartTime.Equal(after))
118+
}

test-integration/integration_test.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,59 @@ func (s *LangfuseIntegrationTestSuite) Test_SendTrace() {
7373
}, 10*time.Second, 100*time.Millisecond, "Trace event should be sent successfully")
7474
}
7575

76+
func (s *LangfuseIntegrationTestSuite) Test_SendGeneration() {
77+
generationEvent := NewTestGenerationEvent()
78+
79+
s.subject.AddEvent(context.TODO(), generationEvent)
80+
81+
s.Eventually(func() bool {
82+
observationPath := fmt.Sprintf("/api/public/observations/%s", generationEvent.ID.String())
83+
got, err := getEventType[types.GenerationEvent](s.cfg, observationPath)
84+
if err != nil {
85+
s.T().Logf("Failed to get generation event: %v", err)
86+
return false
87+
}
88+
89+
return s.Equal(generationEvent, got,
90+
cmpopts.IgnoreFields(types.GenerationEvent{}, "StartTime", "CompletionStartTime", "EndTime"))
91+
}, 10*time.Second, 100*time.Millisecond, "Generation event should be sent successfully")
92+
}
93+
94+
func (s *LangfuseIntegrationTestSuite) Test_SendSpan() {
95+
spanEvent := NewTestSpanEvent()
96+
97+
s.subject.AddEvent(context.TODO(), spanEvent)
98+
99+
s.Eventually(func() bool {
100+
observationPath := fmt.Sprintf("/api/public/observations/%s", spanEvent.ID.String())
101+
got, err := getEventType[types.SpanEvent](s.cfg, observationPath)
102+
if err != nil {
103+
s.T().Logf("Failed to get span event: %v", err)
104+
return false
105+
}
106+
107+
return s.Equal(spanEvent, got,
108+
cmpopts.IgnoreFields(types.SpanEvent{}, "StartTime", "EndTime"))
109+
}, 10*time.Second, 100*time.Millisecond, "Span event should be sent successfully")
110+
}
111+
112+
func (s *LangfuseIntegrationTestSuite) Test_SendScore() {
113+
scoreEvent := NewTestScoreEvent()
114+
115+
s.subject.AddEvent(context.TODO(), scoreEvent)
116+
117+
s.Eventually(func() bool {
118+
scorePath := fmt.Sprintf("/api/public/scores/%s", scoreEvent.ID.String())
119+
got, err := getEventType[types.ScoreEvent](s.cfg, scorePath)
120+
if err != nil {
121+
s.T().Logf("Failed to get score event: %v", err)
122+
return false
123+
}
124+
125+
return s.Equal(scoreEvent, got)
126+
}, 10*time.Second, 100*time.Millisecond, "Score event should be sent successfully")
127+
}
128+
76129
func (s *LangfuseIntegrationTestSuite) Equal(expected, got any, opts ...cmp.Option) bool {
77130
less := func(a, b string) bool { return a < b }
78131
opts = append(opts, cmpopts.SortSlices(less))
@@ -97,8 +150,15 @@ func getEventType[T any](cfg *config.Langfuse, path string) (*T, error) {
97150
return nil, fmt.Errorf("failed to get event type: %w", err)
98151
}
99152

153+
if r.StatusCode == 404 {
154+
return nil, fmt.Errorf("event not found")
155+
}
156+
100157
var t T
101158
err = json.Unmarshal(r.RawBody, &t)
159+
if err != nil {
160+
return nil, fmt.Errorf("failed to unmarshal response: %w, body: %s", err, string(r.RawBody))
161+
}
102162
return &t, err
103163
}
104164

0 commit comments

Comments
 (0)