1 package ldclient
2
3 import (
4 "fmt"
5 "testing"
6
7 "github.com/launchdarkly/go-sdk-common/v3/ldcontext"
8 "github.com/launchdarkly/go-sdk-common/v3/ldtime"
9 "github.com/launchdarkly/go-sdk-common/v3/lduser"
10 "github.com/launchdarkly/go-sdk-common/v3/ldvalue"
11 ldevents "github.com/launchdarkly/go-sdk-events/v2"
12 )
13
14
15
16
17
18
19
20
21 type mockEventSender struct {
22 sentCh chan struct{}
23 }
24
25 func (m *mockEventSender) SendEventData(kind ldevents.EventDataKind, data []byte, eventCount int) ldevents.EventSenderResult {
26 m.sentCh <- struct{}{}
27 return ldevents.EventSenderResult{Success: true}
28 }
29
30 type eventsBenchmarkEnv struct {
31 eventProcessor ldevents.EventProcessor
32 mockEventSender *mockEventSender
33 targetFeatureKey string
34 users []ldcontext.Context
35 variations []ldvalue.Value
36 }
37
38 func newEventsBenchmarkEnv() *eventsBenchmarkEnv {
39 return &eventsBenchmarkEnv{}
40 }
41
42 func (env *eventsBenchmarkEnv) setUp(bc eventsBenchmarkCase) {
43 env.mockEventSender = &mockEventSender{sentCh: make(chan struct{}, 10)}
44
45 config := ldevents.EventsConfiguration{
46 Capacity: bc.bufferSize,
47 EventSender: env.mockEventSender,
48 }
49 env.eventProcessor = ldevents.NewDefaultEventProcessor(config)
50
51 env.targetFeatureKey = "flag-key"
52
53 env.variations = make([]ldvalue.Value, bc.numVariations)
54 for i := 0; i < bc.numVariations; i++ {
55 env.variations[i] = ldvalue.Int(i)
56 }
57
58 env.users = make([]ldcontext.Context, bc.numUsers)
59 for i := 0; i < bc.numUsers; i++ {
60 env.users[i] = lduser.NewUser(makeEvalBenchmarkTargetUserKey(i))
61 }
62 }
63
64 func (env *eventsBenchmarkEnv) tearDown() {
65 env.eventProcessor.Close()
66 env.eventProcessor = nil
67 }
68
69 func (env *eventsBenchmarkEnv) waitUntilEventsSent() {
70 <-env.mockEventSender.sentCh
71 }
72
73 type eventsBenchmarkCase struct {
74 bufferSize int
75 numEvents int
76 numVariations int
77 numUsers int
78 }
79
80 var eventsBenchmarkCases = []eventsBenchmarkCase{
81 {
82 bufferSize: 1000,
83 numEvents: 100,
84 numVariations: 2,
85 numUsers: 10,
86 },
87 {
88 bufferSize: 1000,
89 numEvents: 100,
90 numVariations: 2,
91 numUsers: 100,
92 },
93 {
94 bufferSize: 1000,
95 numEvents: 1000,
96 numVariations: 2,
97 numUsers: 10,
98 },
99 {
100 bufferSize: 1000,
101 numEvents: 1000,
102 numVariations: 2,
103 numUsers: 100,
104 },
105 }
106
107 func benchmarkEvents(b *testing.B, cases []eventsBenchmarkCase, action func(*eventsBenchmarkEnv, eventsBenchmarkCase)) {
108 env := newEventsBenchmarkEnv()
109 for _, bc := range cases {
110 env.setUp(bc)
111
112 b.Run(fmt.Sprintf("%+v", bc), func(b *testing.B) {
113 for i := 0; i < b.N; i++ {
114 action(env, bc)
115 }
116 })
117 env.tearDown()
118 }
119 }
120
121 func BenchmarkFeatureRequestEventsSummaryOnly(b *testing.B) {
122 benchmarkEvents(b, eventsBenchmarkCases, func(env *eventsBenchmarkEnv, bc eventsBenchmarkCase) {
123 for i := 0; i < bc.numEvents; i++ {
124 user := env.users[i%bc.numUsers]
125 variation := i % bc.numVariations
126 value := env.variations[variation]
127 event := ldevents.EvaluationData{
128 BaseEvent: ldevents.BaseEvent{
129 CreationDate: ldtime.UnixMillisNow(),
130 Context: ldevents.Context(user),
131 },
132 Key: env.targetFeatureKey,
133 Variation: ldvalue.NewOptionalInt(variation),
134 Value: value,
135 }
136 env.eventProcessor.RecordEvaluation(event)
137 }
138 env.eventProcessor.Flush()
139 env.waitUntilEventsSent()
140 })
141 }
142
143 func BenchmarkFeatureRequestEventsWithFullTracking(b *testing.B) {
144 benchmarkEvents(b, eventsBenchmarkCases, func(env *eventsBenchmarkEnv, bc eventsBenchmarkCase) {
145 for i := 0; i < bc.numEvents; i++ {
146 user := env.users[i%bc.numUsers]
147 variation := i % bc.numVariations
148 value := env.variations[variation]
149 event := ldevents.EvaluationData{
150 BaseEvent: ldevents.BaseEvent{
151 CreationDate: ldtime.UnixMillisNow(),
152 Context: ldevents.Context(user),
153 },
154 Key: env.targetFeatureKey,
155 Variation: ldvalue.NewOptionalInt(variation),
156 Value: value,
157 RequireFullEvent: true,
158 }
159 env.eventProcessor.RecordEvaluation(event)
160 }
161 env.eventProcessor.Flush()
162 env.waitUntilEventsSent()
163 })
164 }
165
166 func BenchmarkCustomEvents(b *testing.B) {
167 data := ldvalue.ObjectBuild().SetString("eventData", "value").Build()
168 benchmarkEvents(b, eventsBenchmarkCases, func(env *eventsBenchmarkEnv, bc eventsBenchmarkCase) {
169 for i := 0; i < bc.numEvents; i++ {
170 user := env.users[i%bc.numUsers]
171 event := ldevents.CustomEventData{
172 BaseEvent: ldevents.BaseEvent{
173 CreationDate: ldtime.UnixMillisNow(),
174 Context: ldevents.Context(user),
175 },
176 Key: "event-key",
177 Data: data,
178 }
179 env.eventProcessor.RecordCustomEvent(event)
180 }
181 env.eventProcessor.Flush()
182 env.waitUntilEventsSent()
183 })
184 }
185
View as plain text