1 package ldevents
2
3 import (
4 "fmt"
5 "math/rand"
6 "testing"
7
8 "github.com/launchdarkly/go-sdk-common/v3/ldcontext"
9 "github.com/launchdarkly/go-sdk-common/v3/ldtime"
10 "github.com/launchdarkly/go-sdk-common/v3/lduser"
11 "github.com/launchdarkly/go-sdk-common/v3/ldvalue"
12 )
13
14 const benchmarkEventCount = 100
15
16
17
18
19
20
21 func BenchmarkEventProcessor(b *testing.B) {
22 configDefault := EventsConfiguration{Capacity: 1000}
23
24 doEvents := func(b *testing.B, config EventsConfiguration, sendEvents func(EventProcessor)) {
25 ep, es := createBenchmarkEventProcessorAndSender(config)
26 defer ep.Close()
27
28 b.ResetTimer()
29
30 for i := 0; i < b.N; i++ {
31 sendEvents(ep)
32 ep.Flush()
33 es.awaitPayload()
34 }
35
36 b.StopTimer()
37 }
38
39 b.Run("summarize feature events", func(b *testing.B) {
40 doEvents(b, configDefault, sendBenchmarkFeatureEvents(false))
41 })
42
43 b.Run("feature events with full tracking", func(b *testing.B) {
44 doEvents(b, configDefault, sendBenchmarkFeatureEvents(true))
45 })
46
47 b.Run("custom events", func(b *testing.B) {
48 doEvents(b, configDefault, sendBenchmarkCustomEvents())
49 })
50 }
51
52 func makeBenchmarkUsers() []ldcontext.Context {
53 numUsers := 10
54 ret := make([]ldcontext.Context, 0, numUsers)
55 for i := 0; i < numUsers; i++ {
56 user := lduser.NewUserBuilder(fmt.Sprintf("user%d", i)).
57 Name(fmt.Sprintf("name%d", i)).
58 Build()
59 ret = append(ret, user)
60 }
61 return ret
62 }
63
64 func sendBenchmarkFeatureEvents(tracking bool) func(EventProcessor) {
65 events := make([]EvaluationData, 0, benchmarkEventCount)
66 users := makeBenchmarkUsers()
67 flagCount := 10
68 flagVersions := 3
69 flagVariations := 2
70 rnd := rand.New(rand.NewSource(int64(ldtime.UnixMillisNow())))
71
72 for i := 0; i < benchmarkEventCount; i++ {
73 variation := rnd.Intn(flagVariations)
74 event := EvaluationData{
75 BaseEvent: BaseEvent{
76 Context: Context(users[rnd.Intn(len(users))]),
77 CreationDate: ldtime.UnixMillisNow(),
78 },
79 Key: fmt.Sprintf("flag%d", rnd.Intn(flagCount)),
80 Version: ldvalue.NewOptionalInt(rnd.Intn(flagVersions) + 1),
81 Variation: ldvalue.NewOptionalInt(variation),
82 Value: ldvalue.Int(variation),
83 RequireFullEvent: tracking,
84 }
85 events = append(events, event)
86 }
87
88 return func(ep EventProcessor) {
89 for _, e := range events {
90 ep.RecordEvaluation(e)
91 }
92 }
93 }
94
95 func sendBenchmarkCustomEvents() func(EventProcessor) {
96 events := make([]CustomEventData, 0, benchmarkEventCount)
97 users := makeBenchmarkUsers()
98 keyCount := 5
99 rnd := rand.New(rand.NewSource(int64(ldtime.UnixMillisNow())))
100
101 for i := 0; i < benchmarkEventCount; i++ {
102 event := CustomEventData{
103 BaseEvent: BaseEvent{
104 Context: Context(users[rnd.Intn(len(users))]),
105 CreationDate: ldtime.UnixMillisNow(),
106 },
107 Key: fmt.Sprintf("event%d", rnd.Intn(keyCount)),
108 Data: ldvalue.String("data"),
109 }
110 events = append(events, event)
111 }
112
113 return func(ep EventProcessor) {
114 for _, e := range events {
115 ep.RecordCustomEvent(e)
116 }
117 }
118 }
119
120
121
122 type benchmarkMockEventSender struct {
123 payloadCh chan []byte
124 }
125
126 func newBenchmarkMockEventSender() *benchmarkMockEventSender {
127 return &benchmarkMockEventSender{
128 payloadCh: make(chan []byte, 100),
129 }
130 }
131
132 func (ms *benchmarkMockEventSender) SendEventData(
133 kind EventDataKind,
134 data []byte,
135 eventCount int,
136 ) EventSenderResult {
137 ms.payloadCh <- data
138 return EventSenderResult{Success: true}
139 }
140
141 func (ms *benchmarkMockEventSender) awaitPayload() {
142 <-ms.payloadCh
143 }
144
145 func createBenchmarkEventProcessorAndSender(config EventsConfiguration) (EventProcessor, *benchmarkMockEventSender) {
146 sender := newBenchmarkMockEventSender()
147 config.EventSender = sender
148 return NewDefaultEventProcessor(config), sender
149 }
150
View as plain text