fix: Fetch API version validation and ListOffsets v2 parsing

- Updated Fetch API to support v0-v11 (was v0-v1)
- Fixed ListOffsets v2 request parsing (added replica_id and isolation_level fields)
- Added proper debug logging for Fetch and ListOffsets handlers
- Improved record batch construction with proper varint encoding
- Cross-client Produce compatibility confirmed (kafka-go and Sarama)

Next: Fix Fetch v5 response format for Sarama consumer compatibility
This commit is contained in:
chrislu committed 2025-09-11 07:09:56 -07:00
1 parent f2c533f734
commit f6da3b2920
4 files changed
+180 -64

No files matched your search

+45
View File
@@ -0,0 +1,45 @@
package kafka
import (
"context"
"fmt"
"testing"
"time"
"github.com/segmentio/kafka-go"
"github.com/seaweedfs/seaweedfs/weed/mq/kafka/gateway"
)
func TestKafkaGo_ProduceOnly(t *testing.T) {
// Start gateway
gatewayServer := gateway.NewServer(gateway.Options{Listen: "127.0.0.1:0"})
go func() {
if err := gatewayServer.Start(); err != nil {
t.Errorf("Failed to start gateway: %v", err)
}
}()
defer gatewayServer.Close()
time.Sleep(100 * time.Millisecond)
host, port := gatewayServer.GetListenerAddr()
addr := fmt.Sprintf("%s:%d", host, port)
topic := "kgo-produce-only"
gatewayServer.GetHandler().AddTopicForTesting(topic, 1)
w := &kafka.Writer{
Addr: kafka.TCP(addr),
Topic: topic,
Balancer: &kafka.LeastBytes{},
BatchTimeout: 50 * time.Millisecond,
}
defer w.Close()
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
err := w.WriteMessages(ctx, kafka.Message{Key: []byte("k"), Value: []byte("v")})
if err != nil {
t.Fatalf("kafka-go produce failed: %v", err)
}
}
+44 -3
View File
@@ -67,9 +67,50 @@ func TestSaramaE2EProduceConsume(t *testing.T) {
t.Logf("✅ Produced message %d: partition=%d, offset=%d", i, partition, offset)
}
// Temporarily skip consumer until Fetch batches are finalized
t.Logf("Skipping consumer verification for now (Fetch under construction)")
t.Logf("🎉 SUCCESS: Sarama E2E (produce-only) completed! Produced %d messages", len(messages))
t.Logf("=== Testing Sarama Consumer ===")
// Create consumer
consumer, err := sarama.NewConsumer([]string{brokerAddr}, config)
if err != nil {
t.Fatalf("Failed to create consumer: %v", err)
}
defer consumer.Close()
// Get partition consumer
partitionConsumer, err := consumer.ConsumePartition(topicName, 0, sarama.OffsetOldest)
if err != nil {
t.Fatalf("Failed to create partition consumer: %v", err)
}
defer partitionConsumer.Close()
// Consume messages
consumedCount := 0
timeout := time.After(5 * time.Second)
for consumedCount < len(messages) {
select {
case msg := <-partitionConsumer.Messages():
t.Logf("✅ Consumed message %d: key=%s, value=%s, offset=%d",
consumedCount, string(msg.Key), string(msg.Value), msg.Offset)
// Verify message content matches what we produced
expectedValue := messages[consumedCount]
if string(msg.Value) != expectedValue {
t.Errorf("Message %d mismatch: got %s, want %s",
consumedCount, string(msg.Value), expectedValue)
}
consumedCount++
case err := <-partitionConsumer.Errors():
t.Fatalf("Consumer error: %v", err)
case <-timeout:
t.Fatalf("Timeout waiting for messages. Consumed %d/%d", consumedCount, len(messages))
}
}
t.Logf("🎉 SUCCESS: Sarama E2E test completed! Produced and consumed %d messages", len(messages))
}
func TestSaramaConsumerGroup(t *testing.T) {