Files
seaweedfs/test/kafka
Chris LuandGitHub 86c5e815d2 fix(kafka): make consumer-group rebalancing work end-to-end (#9143)
* fix(kafka): make consumer-group rebalancing work end-to-end

TestConsumerGroups was failing every run since the job was added
(2026-04-17) but the failures were masked by a `|| echo ...` trailer on
the go test invocation, so the CI reported green. Removing the mask
exposes several real bugs in the gateway's group-coordinator code:

1. JoinGroup deduplicated members by ClientID, which collapsed two
   Sarama consumers that share the default ClientID ("sarama") into a
   single member slot and broke rebalancing. Key dedup off the TCP
   ConnectionID instead; keep ClientID on the member for DescribeGroup
   fidelity.

2. Every JoinGroup replaced the *GroupMember struct, wiping the
   Assignment the leader had just published in its SyncGroup and leaving
   non-leader consumers with 0 partitions after a rebalance. Update the
   existing member in place on rejoin.

3. Non-leader SyncGroup returned an empty assignment while the leader
   was mid-rebalance, so consumers silently came up with no partitions.
   Return REBALANCE_IN_PROGRESS when the group is not Stable so Sarama
   retries the join/sync cycle (4 retries x 2s backoff by default).

4. Heartbeat returned ILLEGAL_GENERATION on a gen mismatch even when
   the group was in PreparingRebalance/CompletingRebalance. Return
   REBALANCE_IN_PROGRESS in that case so the heartbeat loop cleanly
   cancels the session instead of tearing it down on a fatal error.

5. LeaveGroup parser only handled v0-v2. Sarama at V2_8_0_0 sends v3
   (Members array) by default, so the gateway silently rejected the
   request as InvalidGroupID and dead consumers stayed in the group as
   phantom leaders. Added v3 (Members array) and v4+ (flexible/compact/
   tagged-fields) parsing.

The rebalancing integration tests called Consume() once per consumer,
which cannot survive a rebalance (heartbeat RBIP cancels the session
and Consume() returns - this is documented Sarama behaviour; callers
are expected to loop). Added a runConsumeLoop helper and used it in the
four affected sub-tests. RebalanceTestHandler.Setup now overwrites
stale entries in its assignments channel so the test observes the
settled post-rebalance snapshot rather than whatever arrived first.

* fix(kafka): address PR review feedback

- JoinGroup now snapshots existing members before mutating and restores
  the snapshot on INCONSISTENT_GROUP_PROTOCOL rollback. Previously the
  rollback path always deleted the entry, corrupting group state when
  an existing member rejoined with an incompatible protocol.

- handleLeaveGroup iterates request.Members instead of processing only
  the first entry, so v3+ batch departures (KIP-345 style) correctly
  remove every listed member and build a per-member response. A single
  group-state transition runs after the loop, with leader election
  only triggered if the actual group leader was among the departures.

- Added buildLeaveGroupFlexibleResponse for v4+ clients. The parser
  already decoded flexible versions, but the response still went out in
  non-flexible encoding (4-byte array lengths, 2-byte strings, no
  tagged fields), which v4+ clients could not parse. Route flexible
  versions through the new builder; v1-v3 keep buildLeaveGroupFullResponse.

- BasicFunctionality gives each consumer its own
  ConsumerGroupHandler/ready channel. The previous shared handler
  closed ready once, so readyCount advanced to numConsumers from a
  single signal; the test could proceed without the other consumers
  actually reaching Setup.

- RebalanceTestHandler.assignments is now a size-1 channel, so readers
  always observe the most recent rebalance snapshot instead of an
  intermediate one from an earlier round.
2026-04-20 10:11:45 -07:00
..
2025-10-13 18:05:17 -07:00
2026-03-23 19:36:14 -07:00
2025-11-18 12:06:56 -08:00
2025-10-13 18:05:17 -07:00
2026-03-09 23:10:27 -07:00
2026-03-09 23:10:27 -07:00
2026-03-09 23:10:27 -07:00
2025-10-13 18:05:17 -07:00
2025-11-18 12:06:56 -08:00

Kafka Gateway Tests with SMQ Integration

This directory contains tests for the SeaweedFS Kafka Gateway with full SeaweedMQ (SMQ) integration.

Test Types

Unit Tests (./unit/)

  • Basic gateway functionality
  • Protocol compatibility
  • No SeaweedFS backend required
  • Uses mock handlers

Integration Tests (./integration/)

  • Mock Mode (default): Uses in-memory handlers for protocol testing
  • SMQ Mode (with SEAWEEDFS_MASTERS): Uses real SeaweedFS backend for full integration

E2E Tests (./e2e/)

  • End-to-end workflows
  • Automatically detects SMQ availability
  • Falls back to mock mode if SMQ unavailable

Running Tests Locally

Quick Protocol Testing (Mock Mode)

# Run all integration tests with mock backend
cd test/kafka
go test ./integration/...

# Run specific test
go test -v ./integration/ -run TestClientCompatibility

Full Integration Testing (SMQ Mode)

Requires running SeaweedFS instance:

  1. Start SeaweedFS with MQ support:
# Terminal 1: Start SeaweedFS server
weed server -ip="127.0.0.1" -ip.bind="0.0.0.0" -dir=/tmp/seaweedfs-data -master.port=9333 -volume.port=8081 -filer.port=8888 -filer=true -master.peers=none

# Terminal 2: Start MQ broker  
weed mq.broker -master="127.0.0.1:9333" -ip="127.0.0.1" -port=17777
  1. Run tests with SMQ backend:
cd test/kafka
SEAWEEDFS_MASTERS=127.0.0.1:9333 go test ./integration/...

# Run specific SMQ integration tests
SEAWEEDFS_MASTERS=127.0.0.1:9333 go test -v ./integration/ -run TestSMQIntegration

Test Broker Startup

If you're having broker startup issues:

# Debug broker startup locally
./scripts/test-broker-startup.sh

CI/CD Integration

GitHub Actions Jobs

  1. Unit Tests - Fast protocol tests with mock backend
  2. Integration Tests - Mock mode by default
  3. E2E Tests (with SMQ) - Full SeaweedFS + MQ broker stack
  4. Client Compatibility (with SMQ) - Tests different Kafka clients against real backend
  5. Consumer Group Tests (with SMQ) - Tests consumer group persistence
  6. SMQ Integration Tests - Dedicated SMQ-specific functionality tests

What Gets Tested with SMQ

When SEAWEEDFS_MASTERS is available, tests exercise:

  • Real Message Persistence - Messages stored in SeaweedFS volumes
  • Offset Persistence - Consumer group offsets stored in SeaweedFS filer
  • Topic Persistence - Topic metadata persisted in SeaweedFS filer
  • Consumer Group Coordination - Distributed coordinator assignment
  • Cross-Client Compatibility - Sarama, kafka-go with real backend
  • Broker Discovery - Gateway discovers MQ brokers via masters

Test Infrastructure

testutil.NewGatewayTestServerWithSMQ(t, mode)

Smart gateway creation that automatically:

  • Detects SMQ availability via SEAWEEDFS_MASTERS
  • Uses production handler when available
  • Falls back to mock when unavailable
  • Provides timeout protection against hanging

Modes:

  • SMQRequired - Skip test if SMQ unavailable
  • SMQAvailable - Use SMQ if available, otherwise mock
  • SMQUnavailable - Always use mock

Timeout Protection

Gateway creation includes timeout protection to prevent CI hanging:

  • 20 second timeout for SMQRequired mode
  • 15 second timeout for SMQAvailable mode
  • Clear error messages when broker discovery fails

Debugging Failed Tests

CI Logs to Check

  1. "SeaweedFS master is up" - Master started successfully
  2. "SeaweedFS filer is up" - Filer ready
  3. "SeaweedFS MQ broker is up" - Broker started successfully
  4. Broker/Server logs - Shown on broker startup failure

Local Debugging

  1. Run ./scripts/test-broker-startup.sh to test broker startup
  2. Check logs at /tmp/weed-*.log
  3. Test individual components:
    # Test master
    curl http://127.0.0.1:9333/cluster/status
    
    # Test filer  
    curl http://127.0.0.1:8888/status
    
    # Test broker
    nc -z 127.0.0.1 17777
    

Common Issues

  • Broker fails to start: Check filer is ready before starting broker
  • Gateway timeout: Broker discovery fails, check broker is accessible
  • Test hangs: Timeout protection not working, reduce timeout values

Architecture

┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│   Kafka Client  │───▶│  Kafka Gateway  │───▶│ SeaweedMQ Broker│
│   (Sarama,      │    │   (Protocol     │    │   (Message      │
│    kafka-go)    │    │    Handler)     │    │   Persistence)  │
└─────────────────┘    └─────────────────┘    └─────────────────┘
                                │                      │
                                ▼                      ▼
                       ┌─────────────────┐    ┌─────────────────┐
                       │ SeaweedFS Filer │    │ SeaweedFS Master│
                       │ (Offset Storage)│    │ (Coordination)  │
                       └─────────────────┘    └─────────────────┘
                                │                      │
                                ▼                      ▼  
                       ┌─────────────────────────────────────────┐
                       │        SeaweedFS Volumes                │
                       │      (Message Storage)                  │
                       └─────────────────────────────────────────┘

This architecture ensures full integration testing of the entire Kafka → SeaweedFS message path.