117 lines
3.9 KiB
Go
117 lines
3.9 KiB
Go
package mq
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestKafkaRoundTripIntegration(t *testing.T) {
|
|
rawBrokers := strings.TrimSpace(os.Getenv("KRA_KAFKA_TEST_BROKERS"))
|
|
if rawBrokers == "" {
|
|
t.Skip("KRA_KAFKA_TEST_BROKERS is not configured")
|
|
}
|
|
brokers := []string{"127.0.0.1:1"}
|
|
for _, broker := range strings.Split(rawBrokers, ",") {
|
|
if broker = strings.TrimSpace(broker); broker != "" {
|
|
brokers = append(brokers, broker)
|
|
}
|
|
}
|
|
if len(brokers) == 1 {
|
|
t.Fatal("KRA_KAFKA_TEST_BROKERS contains no broker addresses")
|
|
}
|
|
|
|
suffix := fmt.Sprintf("%d", time.Now().UnixNano())
|
|
topics := []string{"kra-review-qos1-" + suffix, "kra-review-qos0-" + suffix}
|
|
groupID := "kra-review-" + suffix
|
|
newClient := func(clientID string) *Kafka {
|
|
client, err := NewKafka(KafkaConfig{
|
|
Enabled: true,
|
|
Brokers: brokers,
|
|
ClientID: clientID,
|
|
GroupID: groupID,
|
|
StartOffset: "earliest",
|
|
MinBytes: 1,
|
|
MaxBytes: 1 << 20,
|
|
MaxWait: 100 * time.Millisecond,
|
|
ConnectTimeout: 5 * time.Second,
|
|
ReconnectInterval: 500 * time.Millisecond,
|
|
AllowAutoTopicCreation: true,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("NewKafka(%s): %v", clientID, err)
|
|
}
|
|
return client
|
|
}
|
|
|
|
client := newClient("kra-review-producer-" + suffix)
|
|
t.Cleanup(func() { _ = client.Close() })
|
|
firstPayloads := [][]byte{[]byte("qos1-first"), []byte("qos0-first")}
|
|
qosValues := []byte{AtLeastOnce, AtMostOnce}
|
|
for index, topic := range topics {
|
|
if err := client.Publish(context.Background(), topic, firstPayloads[index], qosValues[index], false); err != nil {
|
|
t.Fatalf("publish first message to %s: %v", topic, err)
|
|
}
|
|
}
|
|
|
|
firstReceived := []chan Message{make(chan Message, 1), make(chan Message, 1)}
|
|
for index, topic := range topics {
|
|
index := index
|
|
if err := client.Subscribe(context.Background(), topic, qosValues[index], func(_ context.Context, message Message) {
|
|
firstReceived[index] <- message
|
|
}); err != nil {
|
|
t.Fatalf("subscribe to %s: %v", topic, err)
|
|
}
|
|
}
|
|
for index, received := range firstReceived {
|
|
message := waitKafkaMessage(t, received, 30*time.Second)
|
|
if string(message.Payload) != string(firstPayloads[index]) || message.QoS != qosValues[index] {
|
|
t.Fatalf("first message[%d] = payload %q qos %d", index, message.Payload, message.QoS)
|
|
}
|
|
}
|
|
// QoS 1 commits after the handler returns. Give the synchronous commit time
|
|
// to finish before closing the readers and rejoining the same group.
|
|
time.Sleep(500 * time.Millisecond)
|
|
if err := client.Unsubscribe(context.Background(), topics...); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
replayClient := newClient("kra-review-replay-" + suffix)
|
|
t.Cleanup(func() { _ = replayClient.Close() })
|
|
replayed := []chan Message{make(chan Message, 2), make(chan Message, 2)}
|
|
for index, topic := range topics {
|
|
index := index
|
|
if err := replayClient.Subscribe(context.Background(), topic, qosValues[index], func(_ context.Context, message Message) {
|
|
replayed[index] <- message
|
|
}); err != nil {
|
|
t.Fatalf("replay subscribe to %s: %v", topic, err)
|
|
}
|
|
}
|
|
secondPayloads := [][]byte{[]byte("qos1-second"), []byte("qos0-second")}
|
|
for index, topic := range topics {
|
|
if err := replayClient.Publish(context.Background(), topic, secondPayloads[index], qosValues[index], false); err != nil {
|
|
t.Fatalf("publish second message to %s: %v", topic, err)
|
|
}
|
|
}
|
|
for index, received := range replayed {
|
|
message := waitKafkaMessage(t, received, 30*time.Second)
|
|
if string(message.Payload) != string(secondPayloads[index]) {
|
|
t.Fatalf("message[%d] replayed uncommitted payload %q, want %q", index, message.Payload, secondPayloads[index])
|
|
}
|
|
}
|
|
}
|
|
|
|
func waitKafkaMessage(t *testing.T, messages <-chan Message, timeout time.Duration) Message {
|
|
t.Helper()
|
|
select {
|
|
case message := <-messages:
|
|
return message
|
|
case <-time.After(timeout):
|
|
t.Fatal("timed out waiting for kafka message")
|
|
return Message{}
|
|
}
|
|
}
|