Skip to content

Commit 0456630

Browse files
committed
test: add message_chunking_test.go for chunk consume/produce test
1 parent ed7915d commit 0456630

1 file changed

Lines changed: 312 additions & 0 deletions

File tree

pulsar/message_chunking_test.go

Lines changed: 312 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,312 @@
1+
package pulsar
2+
3+
import (
4+
"context"
5+
"errors"
6+
"math/rand"
7+
"sync"
8+
"testing"
9+
"time"
10+
11+
"github.com/stretchr/testify/assert"
12+
)
13+
14+
var _brokerMaxMessageSize = 1024 * 1024
15+
16+
func TestInvalidChunkingConfig(t *testing.T) {
17+
client, err := NewClient(ClientOptions{
18+
URL: lookupURL,
19+
})
20+
21+
assert.Nil(t, err)
22+
defer client.Close()
23+
24+
// create producer
25+
producer, err := client.CreateProducer(ProducerOptions{
26+
Topic: newTopicName(),
27+
DisableBatching: false,
28+
EnableChunking: true,
29+
})
30+
31+
assert.Error(t, err, "producer creation should have fail")
32+
assert.Nil(t, producer)
33+
}
34+
35+
func TestLargeMessage(t *testing.T) {
36+
rand.Seed(time.Now().Unix())
37+
38+
client, err := NewClient(ClientOptions{
39+
URL: lookupURL,
40+
})
41+
42+
assert.Nil(t, err)
43+
defer client.Close()
44+
45+
topic := newTopicName()
46+
47+
// create producer without ChunkMaxMessageSize
48+
producer1, err := client.CreateProducer(ProducerOptions{
49+
Topic: topic,
50+
DisableBatching: true,
51+
EnableChunking: true,
52+
})
53+
assert.NoError(t, err)
54+
assert.NotNil(t, producer1)
55+
defer producer1.Close()
56+
57+
// create producer with ChunkMaxMessageSize
58+
producer2, err := client.CreateProducer(ProducerOptions{
59+
Topic: topic,
60+
DisableBatching: true,
61+
EnableChunking: true,
62+
ChunkMaxMessageSize: 5,
63+
})
64+
assert.NoError(t, err)
65+
assert.NotNil(t, producer2)
66+
defer producer2.Close()
67+
68+
consumer, err := client.Subscribe(ConsumerOptions{
69+
Topic: topic,
70+
Type: Exclusive,
71+
SubscriptionName: "chunk-subscriber",
72+
})
73+
assert.NoError(t, err)
74+
assert.NotNil(t, consumer)
75+
defer consumer.Close()
76+
77+
expectMsgs := make([][]byte, 0, 10)
78+
79+
// test send chunk with serverMaxMessageSize limit
80+
for i := 0; i < 5; i++ {
81+
msg := createTestMessagePayload(_brokerMaxMessageSize + 1)
82+
expectMsgs = append(expectMsgs, msg)
83+
ID, err := producer1.Send(context.Background(), &ProducerMessage{
84+
Payload: msg,
85+
})
86+
assert.NoError(t, err)
87+
assert.NotNil(t, ID)
88+
}
89+
90+
// test receive chunk with serverMaxMessageSize limit
91+
for i := 0; i < 5; i++ {
92+
msg, err := consumer.Receive(context.Background())
93+
assert.NoError(t, err)
94+
95+
expectMsg := expectMsgs[i]
96+
97+
assert.Equal(t, expectMsg, msg.Payload())
98+
// ack message
99+
err = consumer.Ack(msg)
100+
assert.NoError(t, err)
101+
}
102+
103+
// test send chunk with ChunkMaxMessageSize limit
104+
for i := 0; i < 5; i++ {
105+
msg := createTestMessagePayload(50)
106+
expectMsgs = append(expectMsgs, msg)
107+
ID, err := producer2.Send(context.Background(), &ProducerMessage{
108+
Payload: msg,
109+
})
110+
assert.NoError(t, err)
111+
assert.NotNil(t, ID)
112+
}
113+
114+
// test receive chunk with ChunkMaxMessageSize limit
115+
for i := 5; i < 10; i++ {
116+
msg, err := consumer.Receive(context.Background())
117+
assert.NoError(t, err)
118+
119+
expectMsg := expectMsgs[i]
120+
121+
assert.Equal(t, expectMsg, msg.Payload())
122+
// ack message
123+
err = consumer.Ack(msg)
124+
assert.NoError(t, err)
125+
}
126+
}
127+
128+
func TestPublishChunkWithFailure(t *testing.T) {
129+
rand.Seed(time.Now().Unix())
130+
131+
client, err := NewClient(ClientOptions{
132+
URL: lookupURL,
133+
})
134+
135+
assert.Nil(t, err)
136+
defer client.Close()
137+
138+
topic := newTopicName()
139+
140+
// create producer without ChunkMaxMessageSize
141+
producer, err := client.CreateProducer(ProducerOptions{
142+
Topic: topic,
143+
})
144+
assert.NoError(t, err)
145+
assert.NotNil(t, producer)
146+
defer producer.Close()
147+
148+
ID, err := producer.Send(context.Background(), &ProducerMessage{
149+
Payload: createTestMessagePayload(_brokerMaxMessageSize + 1),
150+
})
151+
assert.Error(t, err)
152+
assert.Nil(t, ID)
153+
}
154+
155+
func TestMaxPendingChunkMessages(t *testing.T) {
156+
rand.Seed(time.Now().Unix())
157+
158+
client, err := NewClient(ClientOptions{
159+
URL: lookupURL,
160+
})
161+
assert.Nil(t, err)
162+
defer client.Close()
163+
164+
topic := newTopicName()
165+
166+
totalProducers := 5
167+
producers := make([]Producer, 0, 20)
168+
defer func() {
169+
for _, p := range producers {
170+
p.Close()
171+
}
172+
}()
173+
174+
clients := make([]Client, 0, 20)
175+
defer func() {
176+
for _, c := range clients {
177+
c.Close()
178+
}
179+
}()
180+
181+
for j := 0; j < totalProducers; j++ {
182+
pc, err := NewClient(ClientOptions{
183+
URL: lookupURL,
184+
})
185+
assert.Nil(t, err)
186+
clients = append(clients, pc)
187+
producer, err := pc.CreateProducer(ProducerOptions{
188+
Topic: topic,
189+
DisableBatching: true,
190+
EnableChunking: true,
191+
ChunkMaxMessageSize: 10,
192+
})
193+
assert.NoError(t, err)
194+
assert.NotNil(t, producer)
195+
producers = append(producers, producer)
196+
}
197+
198+
consumer, err := client.Subscribe(ConsumerOptions{
199+
Topic: topic,
200+
Type: Exclusive,
201+
SubscriptionName: "chunk-subscriber",
202+
MaxPendingChunkedMessage: 1,
203+
})
204+
assert.NoError(t, err)
205+
assert.NotNil(t, consumer)
206+
defer consumer.Close()
207+
208+
totalMsgs := 40
209+
wg := sync.WaitGroup{}
210+
wg.Add(totalMsgs * totalProducers)
211+
for i := 0; i < totalMsgs; i++ {
212+
for j := 0; j < totalProducers; j++ {
213+
p := producers[j]
214+
go func() {
215+
ID, err := p.Send(context.Background(), &ProducerMessage{
216+
Payload: createTestMessagePayload(50),
217+
})
218+
assert.NoError(t, err)
219+
assert.NotNil(t, ID)
220+
wg.Done()
221+
}()
222+
}
223+
}
224+
wg.Wait()
225+
226+
received := 0
227+
for i := 0; i < totalMsgs*totalProducers; i++ {
228+
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
229+
msg, err := consumer.Receive(ctx)
230+
cancel()
231+
if msg == nil || (err != nil && errors.Is(err, context.DeadlineExceeded)) {
232+
break
233+
}
234+
235+
received++
236+
237+
err = consumer.Ack(msg)
238+
assert.NoError(t, err)
239+
}
240+
241+
assert.NotEqual(t, totalMsgs*totalProducers, received)
242+
}
243+
244+
func TestExpireIncompleteChunks(t *testing.T) {
245+
rand.Seed(time.Now().Unix())
246+
client, err := NewClient(ClientOptions{
247+
URL: lookupURL,
248+
})
249+
250+
assert.Nil(t, err)
251+
defer client.Close()
252+
253+
topic := newTopicName()
254+
255+
c, err := client.Subscribe(ConsumerOptions{
256+
Topic: topic,
257+
Type: Exclusive,
258+
SubscriptionName: "chunk-subscriber",
259+
ExpireTimeOfIncompleteChunk: time.Millisecond * 300,
260+
})
261+
defer c.Close()
262+
263+
uuid := "test-uuid"
264+
chunkCtxMap := c.(*consumer).consumers[0].chunkedMsgCtxMap
265+
chunkCtxMap.addIfAbsent(uuid, 2, 100)
266+
ctx := chunkCtxMap.get(uuid)
267+
assert.NotNil(t, ctx)
268+
269+
time.Sleep(400 * time.Millisecond)
270+
271+
ctx = chunkCtxMap.get(uuid)
272+
assert.Nil(t, ctx)
273+
}
274+
275+
func TestChunksEnqueueFailed(t *testing.T) {
276+
rand.Seed(time.Now().Unix())
277+
278+
client, err := NewClient(ClientOptions{
279+
URL: lookupURL,
280+
})
281+
282+
assert.Nil(t, err)
283+
defer client.Close()
284+
285+
topic := newTopicName()
286+
287+
producer, err := client.CreateProducer(ProducerOptions{
288+
Topic: topic,
289+
EnableChunking: true,
290+
DisableBatching: true,
291+
MaxPendingMessages: 10,
292+
ChunkMaxMessageSize: 50,
293+
DisableBlockIfQueueFull: true,
294+
})
295+
assert.NoError(t, err)
296+
assert.NotNil(t, producer)
297+
defer producer.Close()
298+
299+
ID, err := producer.Send(context.Background(), &ProducerMessage{
300+
Payload: createTestMessagePayload(1000),
301+
})
302+
assert.Error(t, err)
303+
assert.Nil(t, ID)
304+
}
305+
306+
func createTestMessagePayload(size int) []byte {
307+
payload := make([]byte, size)
308+
for i := range payload {
309+
payload[i] = byte(rand.Intn(100))
310+
}
311+
return payload
312+
}

0 commit comments

Comments
 (0)