Skip to content

Commit 77e9086

Browse files
authored
Merge pull request #73 from zeromicro/chore/pushwithkey-tests
feat: support push with key
2 parents 319b750 + e93e27f commit 77e9086

File tree

5 files changed

+362
-31
lines changed

5 files changed

+362
-31
lines changed

go.mod

+1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ require (
4242
github.com/prometheus/procfs v0.12.0 // indirect
4343
github.com/redis/go-redis/v9 v9.5.3 // indirect
4444
github.com/spaolacci/murmur3 v1.1.0 // indirect
45+
github.com/stretchr/objx v0.5.2 // indirect
4546
go.opentelemetry.io/otel/exporters/jaeger v1.17.0 // indirect
4647
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 // indirect
4748
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0 // indirect

kq/pusher.go

+14-29
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,16 @@ type (
1616
PushOption func(options *pushOptions)
1717

1818
Pusher struct {
19-
producer *kafka.Writer
2019
topic string
20+
producer kafkaWriter
2121
executor *executors.ChunkExecutor
2222
}
2323

24+
kafkaWriter interface {
25+
Close() error
26+
WriteMessages(ctx context.Context, msgs ...kafka.Message) error
27+
}
28+
2429
pushOptions struct {
2530
// kafka.Writer options
2631
allowAutoTopicCreation bool
@@ -138,23 +143,17 @@ func (p *Pusher) PushWithKey(ctx context.Context, key, v string) error {
138143
}
139144
}
140145

141-
// SetWriterBalancer set kafka-go custom writer balancer.
142-
func (p *Pusher) SetWriterBalancer(balancer kafka.Balancer) {
143-
if p.producer != nil {
144-
p.producer.Balancer = balancer
146+
// WithAllowAutoTopicCreation allows the Pusher to create the given topic if it does not exist.
147+
func WithAllowAutoTopicCreation() PushOption {
148+
return func(options *pushOptions) {
149+
options.allowAutoTopicCreation = true
145150
}
146151
}
147152

148-
// PushWithKey sends a message to the Kafka topic with custom message key.
149-
func (p *Pusher) PushWithKey(k, v string) error {
150-
msg := kafka.Message{
151-
Key: []byte(k), // custom message key
152-
Value: []byte(v),
153-
}
154-
if p.executor != nil {
155-
return p.executor.Add(msg, len(v))
156-
} else {
157-
return p.producer.WriteMessages(context.Background(), msg)
153+
// WithBalancer customizes the Pusher with the given balancer.
154+
func WithBalancer(balancer kafka.Balancer) PushOption {
155+
return func(options *pushOptions) {
156+
options.balancer = balancer
158157
}
159158
}
160159

@@ -172,20 +171,6 @@ func WithFlushInterval(interval time.Duration) PushOption {
172171
}
173172
}
174173

175-
// WithAllowAutoTopicCreation allows the Pusher to create the given topic if it does not exist.
176-
func WithAllowAutoTopicCreation() PushOption {
177-
return func(options *pushOptions) {
178-
options.allowAutoTopicCreation = true
179-
}
180-
}
181-
182-
// WithBalancer customizes the Pusher with the given balancer.
183-
func WithBalancer(balancer kafka.Balancer) PushOption {
184-
return func(options *pushOptions) {
185-
options.balancer = balancer
186-
}
187-
}
188-
189174
// WithSyncPush enables the Pusher to push messages synchronously.
190175
func WithSyncPush() PushOption {
191176
return func(options *pushOptions) {

kq/pusher_test.go

+141
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
package kq
2+
3+
import (
4+
"context"
5+
"errors"
6+
"testing"
7+
"time"
8+
9+
"github.com/segmentio/kafka-go"
10+
"github.com/stretchr/testify/assert"
11+
"github.com/stretchr/testify/mock"
12+
)
13+
14+
// mockKafkaWriter is a mock for kafka.Writer
15+
type mockKafkaWriter struct {
16+
mock.Mock
17+
}
18+
19+
func (m *mockKafkaWriter) WriteMessages(ctx context.Context, msgs ...kafka.Message) error {
20+
args := m.Called(ctx, msgs)
21+
return args.Error(0)
22+
}
23+
24+
func (m *mockKafkaWriter) Close() error {
25+
args := m.Called()
26+
return args.Error(0)
27+
}
28+
29+
func TestNewPusher(t *testing.T) {
30+
addrs := []string{"localhost:9092"}
31+
topic := "test-topic"
32+
33+
t.Run("DefaultOptions", func(t *testing.T) {
34+
pusher := NewPusher(addrs, topic)
35+
assert.NotNil(t, pusher)
36+
assert.NotNil(t, pusher.producer)
37+
assert.Equal(t, topic, pusher.topic)
38+
assert.NotNil(t, pusher.executor)
39+
})
40+
41+
t.Run("WithSyncPush", func(t *testing.T) {
42+
pusher := NewPusher(addrs, topic, WithSyncPush())
43+
assert.NotNil(t, pusher)
44+
assert.NotNil(t, pusher.producer)
45+
assert.Equal(t, topic, pusher.topic)
46+
assert.Nil(t, pusher.executor)
47+
})
48+
49+
t.Run("WithChunkSize", func(t *testing.T) {
50+
pusher := NewPusher(addrs, topic, WithChunkSize(100))
51+
assert.NotNil(t, pusher)
52+
assert.NotNil(t, pusher.executor)
53+
})
54+
55+
t.Run("WithFlushInterval", func(t *testing.T) {
56+
pusher := NewPusher(addrs, topic, WithFlushInterval(time.Second))
57+
assert.NotNil(t, pusher)
58+
assert.NotNil(t, pusher.executor)
59+
})
60+
61+
t.Run("WithAllowAutoTopicCreation", func(t *testing.T) {
62+
pusher := NewPusher(addrs, topic, WithAllowAutoTopicCreation())
63+
assert.NotNil(t, pusher)
64+
assert.True(t, pusher.producer.(*kafka.Writer).AllowAutoTopicCreation)
65+
})
66+
}
67+
68+
func TestPusher_Close(t *testing.T) {
69+
mockWriter := new(mockKafkaWriter)
70+
pusher := &Pusher{
71+
producer: mockWriter,
72+
}
73+
74+
mockWriter.On("Close").Return(nil)
75+
76+
err := pusher.Close()
77+
assert.NoError(t, err)
78+
mockWriter.AssertExpectations(t)
79+
}
80+
81+
func TestPusher_Name(t *testing.T) {
82+
topic := "test-topic"
83+
pusher := &Pusher{topic: topic}
84+
85+
assert.Equal(t, topic, pusher.Name())
86+
}
87+
88+
func TestPusher_Push(t *testing.T) {
89+
mockWriter := new(mockKafkaWriter)
90+
pusher := &Pusher{
91+
producer: mockWriter,
92+
topic: "test-topic",
93+
}
94+
95+
ctx := context.Background()
96+
value := "test-value"
97+
98+
mockWriter.On("WriteMessages", mock.Anything, mock.AnythingOfType("[]kafka.Message")).Return(nil)
99+
100+
err := pusher.Push(ctx, value)
101+
assert.NoError(t, err)
102+
mockWriter.AssertExpectations(t)
103+
}
104+
105+
func TestPusher_PushWithKey(t *testing.T) {
106+
mockWriter := new(mockKafkaWriter)
107+
pusher := &Pusher{
108+
producer: mockWriter,
109+
topic: "test-topic",
110+
}
111+
112+
ctx := context.Background()
113+
key := "test-key"
114+
value := "test-value"
115+
116+
mockWriter.On("WriteMessages", mock.Anything, mock.AnythingOfType("[]kafka.Message")).Return(nil)
117+
118+
err := pusher.PushWithKey(ctx, key, value)
119+
assert.NoError(t, err)
120+
mockWriter.AssertExpectations(t)
121+
}
122+
123+
func TestPusher_PushWithKey_Error(t *testing.T) {
124+
mockWriter := new(mockKafkaWriter)
125+
pusher := &Pusher{
126+
producer: mockWriter,
127+
topic: "test-topic",
128+
}
129+
130+
ctx := context.Background()
131+
key := "test-key"
132+
value := "test-value"
133+
134+
expectedError := errors.New("write error")
135+
mockWriter.On("WriteMessages", mock.Anything, mock.AnythingOfType("[]kafka.Message")).Return(expectedError)
136+
137+
err := pusher.PushWithKey(ctx, key, value)
138+
assert.Error(t, err)
139+
assert.Equal(t, expectedError, err)
140+
mockWriter.AssertExpectations(t)
141+
}

kq/queue.go

+8-2
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,12 @@ type (
4242
Consume(ctx context.Context, key, value string) error
4343
}
4444

45+
kafkaReader interface {
46+
FetchMessage(ctx context.Context) (kafka.Message, error)
47+
CommitMessages(ctx context.Context, msgs ...kafka.Message) error
48+
Close() error
49+
}
50+
4551
queueOptions struct {
4652
commitInterval time.Duration
4753
queueCapacity int
@@ -54,7 +60,7 @@ type (
5460

5561
kafkaQueue struct {
5662
c KqConf
57-
consumer *kafka.Reader
63+
consumer kafkaReader
5864
handler ConsumeHandler
5965
channel chan kafka.Message
6066
producerRoutines *threading.RoutineGroup
@@ -191,7 +197,7 @@ func (q *kafkaQueue) Start() {
191197
q.producerRoutines.Wait()
192198
close(q.channel)
193199
q.consumerRoutines.Wait()
194-
200+
195201
logx.Infof("Consumer %s is closed", q.c.Name)
196202
}
197203
}

0 commit comments

Comments
 (0)