You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							351 lines
						
					
					
						
							9.5 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							351 lines
						
					
					
						
							9.5 KiB
						
					
					
				
								package broker
							 | 
						|
								
							 | 
						|
								import (
							 | 
						|
									"testing"
							 | 
						|
									"time"
							 | 
						|
								
							 | 
						|
									"github.com/seaweedfs/seaweedfs/weed/mq/topic"
							 | 
						|
									"github.com/seaweedfs/seaweedfs/weed/pb/schema_pb"
							 | 
						|
								)
							 | 
						|
								
							 | 
						|
								func createTestTopic() topic.Topic {
							 | 
						|
									return topic.Topic{
							 | 
						|
										Namespace: "test",
							 | 
						|
										Name:      "offset-test",
							 | 
						|
									}
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								func createTestPartition() topic.Partition {
							 | 
						|
									return topic.Partition{
							 | 
						|
										RingSize:   1024,
							 | 
						|
										RangeStart: 0,
							 | 
						|
										RangeStop:  31,
							 | 
						|
										UnixTimeNs: time.Now().UnixNano(),
							 | 
						|
									}
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								func TestBrokerOffsetManager_AssignOffset(t *testing.T) {
							 | 
						|
									storage := NewInMemoryOffsetStorageForTesting()
							 | 
						|
									manager := NewBrokerOffsetManagerWithStorage(storage)
							 | 
						|
									testTopic := createTestTopic()
							 | 
						|
									testPartition := createTestPartition()
							 | 
						|
								
							 | 
						|
									// Test sequential offset assignment
							 | 
						|
									for i := int64(0); i < 10; i++ {
							 | 
						|
										assignedOffset, err := manager.AssignOffset(testTopic, testPartition)
							 | 
						|
										if err != nil {
							 | 
						|
											t.Fatalf("Failed to assign offset %d: %v", i, err)
							 | 
						|
										}
							 | 
						|
								
							 | 
						|
										if assignedOffset != i {
							 | 
						|
											t.Errorf("Expected offset %d, got %d", i, assignedOffset)
							 | 
						|
										}
							 | 
						|
									}
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								func TestBrokerOffsetManager_AssignBatchOffsets(t *testing.T) {
							 | 
						|
									storage := NewInMemoryOffsetStorageForTesting()
							 | 
						|
									manager := NewBrokerOffsetManagerWithStorage(storage)
							 | 
						|
									testTopic := createTestTopic()
							 | 
						|
									testPartition := createTestPartition()
							 | 
						|
								
							 | 
						|
									// Assign batch of offsets
							 | 
						|
									baseOffset, lastOffset, err := manager.AssignBatchOffsets(testTopic, testPartition, 5)
							 | 
						|
									if err != nil {
							 | 
						|
										t.Fatalf("Failed to assign batch offsets: %v", err)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									if baseOffset != 0 {
							 | 
						|
										t.Errorf("Expected base offset 0, got %d", baseOffset)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									if lastOffset != 4 {
							 | 
						|
										t.Errorf("Expected last offset 4, got %d", lastOffset)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// Assign another batch
							 | 
						|
									baseOffset2, lastOffset2, err := manager.AssignBatchOffsets(testTopic, testPartition, 3)
							 | 
						|
									if err != nil {
							 | 
						|
										t.Fatalf("Failed to assign second batch offsets: %v", err)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									if baseOffset2 != 5 {
							 | 
						|
										t.Errorf("Expected base offset 5, got %d", baseOffset2)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									if lastOffset2 != 7 {
							 | 
						|
										t.Errorf("Expected last offset 7, got %d", lastOffset2)
							 | 
						|
									}
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								func TestBrokerOffsetManager_GetHighWaterMark(t *testing.T) {
							 | 
						|
									storage := NewInMemoryOffsetStorageForTesting()
							 | 
						|
									manager := NewBrokerOffsetManagerWithStorage(storage)
							 | 
						|
									testTopic := createTestTopic()
							 | 
						|
									testPartition := createTestPartition()
							 | 
						|
								
							 | 
						|
									// Initially should be 0
							 | 
						|
									hwm, err := manager.GetHighWaterMark(testTopic, testPartition)
							 | 
						|
									if err != nil {
							 | 
						|
										t.Fatalf("Failed to get initial high water mark: %v", err)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									if hwm != 0 {
							 | 
						|
										t.Errorf("Expected initial high water mark 0, got %d", hwm)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// Assign some offsets
							 | 
						|
									manager.AssignBatchOffsets(testTopic, testPartition, 10)
							 | 
						|
								
							 | 
						|
									// High water mark should be updated
							 | 
						|
									hwm, err = manager.GetHighWaterMark(testTopic, testPartition)
							 | 
						|
									if err != nil {
							 | 
						|
										t.Fatalf("Failed to get high water mark after assignment: %v", err)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									if hwm != 10 {
							 | 
						|
										t.Errorf("Expected high water mark 10, got %d", hwm)
							 | 
						|
									}
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								func TestBrokerOffsetManager_CreateSubscription(t *testing.T) {
							 | 
						|
									storage := NewInMemoryOffsetStorageForTesting()
							 | 
						|
									manager := NewBrokerOffsetManagerWithStorage(storage)
							 | 
						|
									testTopic := createTestTopic()
							 | 
						|
									testPartition := createTestPartition()
							 | 
						|
								
							 | 
						|
									// Assign some offsets first
							 | 
						|
									manager.AssignBatchOffsets(testTopic, testPartition, 5)
							 | 
						|
								
							 | 
						|
									// Create subscription
							 | 
						|
									sub, err := manager.CreateSubscription(
							 | 
						|
										"test-sub",
							 | 
						|
										testTopic,
							 | 
						|
										testPartition,
							 | 
						|
										schema_pb.OffsetType_RESET_TO_EARLIEST,
							 | 
						|
										0,
							 | 
						|
									)
							 | 
						|
								
							 | 
						|
									if err != nil {
							 | 
						|
										t.Fatalf("Failed to create subscription: %v", err)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									if sub.ID != "test-sub" {
							 | 
						|
										t.Errorf("Expected subscription ID 'test-sub', got %s", sub.ID)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									if sub.StartOffset != 0 {
							 | 
						|
										t.Errorf("Expected start offset 0, got %d", sub.StartOffset)
							 | 
						|
									}
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								func TestBrokerOffsetManager_GetPartitionOffsetInfo(t *testing.T) {
							 | 
						|
									storage := NewInMemoryOffsetStorageForTesting()
							 | 
						|
									manager := NewBrokerOffsetManagerWithStorage(storage)
							 | 
						|
									testTopic := createTestTopic()
							 | 
						|
									testPartition := createTestPartition()
							 | 
						|
								
							 | 
						|
									// Test empty partition
							 | 
						|
									info, err := manager.GetPartitionOffsetInfo(testTopic, testPartition)
							 | 
						|
									if err != nil {
							 | 
						|
										t.Fatalf("Failed to get partition offset info: %v", err)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									if info.EarliestOffset != 0 {
							 | 
						|
										t.Errorf("Expected earliest offset 0, got %d", info.EarliestOffset)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									if info.LatestOffset != -1 {
							 | 
						|
										t.Errorf("Expected latest offset -1 for empty partition, got %d", info.LatestOffset)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// Assign offsets and test again
							 | 
						|
									manager.AssignBatchOffsets(testTopic, testPartition, 5)
							 | 
						|
								
							 | 
						|
									info, err = manager.GetPartitionOffsetInfo(testTopic, testPartition)
							 | 
						|
									if err != nil {
							 | 
						|
										t.Fatalf("Failed to get partition offset info after assignment: %v", err)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									if info.LatestOffset != 4 {
							 | 
						|
										t.Errorf("Expected latest offset 4, got %d", info.LatestOffset)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									if info.HighWaterMark != 5 {
							 | 
						|
										t.Errorf("Expected high water mark 5, got %d", info.HighWaterMark)
							 | 
						|
									}
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								func TestBrokerOffsetManager_MultiplePartitions(t *testing.T) {
							 | 
						|
									storage := NewInMemoryOffsetStorageForTesting()
							 | 
						|
									manager := NewBrokerOffsetManagerWithStorage(storage)
							 | 
						|
									testTopic := createTestTopic()
							 | 
						|
								
							 | 
						|
									// Create different partitions
							 | 
						|
									partition1 := topic.Partition{
							 | 
						|
										RingSize:   1024,
							 | 
						|
										RangeStart: 0,
							 | 
						|
										RangeStop:  31,
							 | 
						|
										UnixTimeNs: time.Now().UnixNano(),
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									partition2 := topic.Partition{
							 | 
						|
										RingSize:   1024,
							 | 
						|
										RangeStart: 32,
							 | 
						|
										RangeStop:  63,
							 | 
						|
										UnixTimeNs: time.Now().UnixNano(),
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// Assign offsets to different partitions
							 | 
						|
									assignedOffset1, err := manager.AssignOffset(testTopic, partition1)
							 | 
						|
									if err != nil {
							 | 
						|
										t.Fatalf("Failed to assign offset to partition1: %v", err)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									assignedOffset2, err := manager.AssignOffset(testTopic, partition2)
							 | 
						|
									if err != nil {
							 | 
						|
										t.Fatalf("Failed to assign offset to partition2: %v", err)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// Both should start at 0
							 | 
						|
									if assignedOffset1 != 0 {
							 | 
						|
										t.Errorf("Expected offset 0 for partition1, got %d", assignedOffset1)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									if assignedOffset2 != 0 {
							 | 
						|
										t.Errorf("Expected offset 0 for partition2, got %d", assignedOffset2)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// Assign more offsets to partition1
							 | 
						|
									assignedOffset1_2, err := manager.AssignOffset(testTopic, partition1)
							 | 
						|
									if err != nil {
							 | 
						|
										t.Fatalf("Failed to assign second offset to partition1: %v", err)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									if assignedOffset1_2 != 1 {
							 | 
						|
										t.Errorf("Expected offset 1 for partition1, got %d", assignedOffset1_2)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// Partition2 should still be at 0 for next assignment
							 | 
						|
									assignedOffset2_2, err := manager.AssignOffset(testTopic, partition2)
							 | 
						|
									if err != nil {
							 | 
						|
										t.Fatalf("Failed to assign second offset to partition2: %v", err)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									if assignedOffset2_2 != 1 {
							 | 
						|
										t.Errorf("Expected offset 1 for partition2, got %d", assignedOffset2_2)
							 | 
						|
									}
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								func TestOffsetAwarePublisher(t *testing.T) {
							 | 
						|
									storage := NewInMemoryOffsetStorageForTesting()
							 | 
						|
									manager := NewBrokerOffsetManagerWithStorage(storage)
							 | 
						|
									testTopic := createTestTopic()
							 | 
						|
									testPartition := createTestPartition()
							 | 
						|
								
							 | 
						|
									// Create a mock local partition (simplified for testing)
							 | 
						|
									localPartition := &topic.LocalPartition{}
							 | 
						|
								
							 | 
						|
									// Create offset assignment function
							 | 
						|
									assignOffsetFn := func() (int64, error) {
							 | 
						|
										return manager.AssignOffset(testTopic, testPartition)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// Create offset-aware publisher
							 | 
						|
									publisher := topic.NewOffsetAwarePublisher(localPartition, assignOffsetFn)
							 | 
						|
								
							 | 
						|
									if publisher.GetPartition() != localPartition {
							 | 
						|
										t.Error("Publisher should return the correct partition")
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// Test would require more setup to actually publish messages
							 | 
						|
									// This tests the basic structure
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								func TestBrokerOffsetManager_GetOffsetMetrics(t *testing.T) {
							 | 
						|
									storage := NewInMemoryOffsetStorageForTesting()
							 | 
						|
									manager := NewBrokerOffsetManagerWithStorage(storage)
							 | 
						|
									testTopic := createTestTopic()
							 | 
						|
									testPartition := createTestPartition()
							 | 
						|
								
							 | 
						|
									// Initial metrics
							 | 
						|
									metrics := manager.GetOffsetMetrics()
							 | 
						|
									if metrics.TotalOffsets != 0 {
							 | 
						|
										t.Errorf("Expected 0 total offsets initially, got %d", metrics.TotalOffsets)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// Assign some offsets
							 | 
						|
									manager.AssignBatchOffsets(testTopic, testPartition, 5)
							 | 
						|
								
							 | 
						|
									// Create subscription
							 | 
						|
									manager.CreateSubscription("test-sub", testTopic, testPartition, schema_pb.OffsetType_RESET_TO_EARLIEST, 0)
							 | 
						|
								
							 | 
						|
									// Check updated metrics
							 | 
						|
									metrics = manager.GetOffsetMetrics()
							 | 
						|
									if metrics.PartitionCount != 1 {
							 | 
						|
										t.Errorf("Expected 1 partition, got %d", metrics.PartitionCount)
							 | 
						|
									}
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								func TestBrokerOffsetManager_AssignOffsetsWithResult(t *testing.T) {
							 | 
						|
									storage := NewInMemoryOffsetStorageForTesting()
							 | 
						|
									manager := NewBrokerOffsetManagerWithStorage(storage)
							 | 
						|
									testTopic := createTestTopic()
							 | 
						|
									testPartition := createTestPartition()
							 | 
						|
								
							 | 
						|
									// Assign offsets with result
							 | 
						|
									result := manager.AssignOffsetsWithResult(testTopic, testPartition, 3)
							 | 
						|
								
							 | 
						|
									if result.Error != nil {
							 | 
						|
										t.Fatalf("Expected no error, got: %v", result.Error)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									if result.BaseOffset != 0 {
							 | 
						|
										t.Errorf("Expected base offset 0, got %d", result.BaseOffset)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									if result.LastOffset != 2 {
							 | 
						|
										t.Errorf("Expected last offset 2, got %d", result.LastOffset)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									if result.Count != 3 {
							 | 
						|
										t.Errorf("Expected count 3, got %d", result.Count)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									if result.Topic != testTopic {
							 | 
						|
										t.Error("Topic mismatch in result")
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									if result.Partition != testPartition {
							 | 
						|
										t.Error("Partition mismatch in result")
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									if result.Timestamp <= 0 {
							 | 
						|
										t.Error("Timestamp should be set")
							 | 
						|
									}
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								func TestBrokerOffsetManager_Shutdown(t *testing.T) {
							 | 
						|
									storage := NewInMemoryOffsetStorageForTesting()
							 | 
						|
									manager := NewBrokerOffsetManagerWithStorage(storage)
							 | 
						|
									testTopic := createTestTopic()
							 | 
						|
									testPartition := createTestPartition()
							 | 
						|
								
							 | 
						|
									// Assign some offsets and create subscriptions
							 | 
						|
									manager.AssignBatchOffsets(testTopic, testPartition, 5)
							 | 
						|
									manager.CreateSubscription("test-sub", testTopic, testPartition, schema_pb.OffsetType_RESET_TO_EARLIEST, 0)
							 | 
						|
								
							 | 
						|
									// Shutdown should not panic
							 | 
						|
									manager.Shutdown()
							 | 
						|
								
							 | 
						|
									// After shutdown, operations should still work (using new managers)
							 | 
						|
									offset, err := manager.AssignOffset(testTopic, testPartition)
							 | 
						|
									if err != nil {
							 | 
						|
										t.Fatalf("Operations should still work after shutdown: %v", err)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// Should start from 0 again (new manager)
							 | 
						|
									if offset != 0 {
							 | 
						|
										t.Errorf("Expected offset 0 after shutdown, got %d", offset)
							 | 
						|
									}
							 | 
						|
								}
							 |