kra-new/pkg/mq/kafka_integration_test.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{}
}
}