package cluster import ( "testing" ) func TestDefaultHashRingConfig(t *testing.T) { config := DefaultHashRingConfig() if config.VirtualNodes != DefaultVirtualNodes { t.Errorf("expected VirtualNodes=%d, got %d", DefaultVirtualNodes, config.VirtualNodes) } } func TestDefaultShardConfig(t *testing.T) { config := DefaultShardConfig() if config.ShardCount != DefaultNumShards { t.Errorf("expected ShardCount=%d, got %d", DefaultNumShards, config.ShardCount) } if config.ReplicationFactor != 1 { t.Errorf("expected ReplicationFactor=1, got %d", config.ReplicationFactor) } } func TestNewConsistentHashRingWithConfig(t *testing.T) { t.Run("custom virtual nodes", func(t *testing.T) { config := HashRingConfig{VirtualNodes: 50} ring := NewConsistentHashRingWithConfig(config) ring.AddNode("test-node") if len(ring.sortedHashes) != 50 { t.Errorf("expected 50 virtual nodes, got %d", len(ring.sortedHashes)) } if ring.GetVirtualNodes() != 50 { t.Errorf("expected GetVirtualNodes()=50, got %d", ring.GetVirtualNodes()) } }) t.Run("zero value uses default", func(t *testing.T) { config := HashRingConfig{VirtualNodes: 0} ring := NewConsistentHashRingWithConfig(config) ring.AddNode("test-node") if len(ring.sortedHashes) != DefaultVirtualNodes { t.Errorf("expected %d virtual nodes, got %d", DefaultVirtualNodes, len(ring.sortedHashes)) } }) t.Run("default constructor uses default config", func(t *testing.T) { ring := NewConsistentHashRing() ring.AddNode("test-node") if len(ring.sortedHashes) != DefaultVirtualNodes { t.Errorf("expected %d virtual nodes, got %d", DefaultVirtualNodes, len(ring.sortedHashes)) } }) } func TestNewShardManagerWithConfig(t *testing.T) { t.Run("custom shard count", func(t *testing.T) { config := ShardConfig{ShardCount: 256, ReplicationFactor: 2} sm := NewShardManagerWithConfig(config) if sm.GetShardCount() != 256 { t.Errorf("expected shard count 256, got %d", sm.GetShardCount()) } if sm.GetReplicationFactor() != 2 { t.Errorf("expected replication factor 2, got %d", sm.GetReplicationFactor()) } }) t.Run("zero values use defaults", func(t *testing.T) { config := ShardConfig{ShardCount: 0, ReplicationFactor: 0} sm := NewShardManagerWithConfig(config) if sm.GetShardCount() != DefaultNumShards { t.Errorf("expected shard count %d, got %d", DefaultNumShards, sm.GetShardCount()) } if sm.GetReplicationFactor() != 1 { t.Errorf("expected replication factor 1, got %d", sm.GetReplicationFactor()) } }) t.Run("legacy constructor still works", func(t *testing.T) { sm := NewShardManager(512, 3) if sm.GetShardCount() != 512 { t.Errorf("expected shard count 512, got %d", sm.GetShardCount()) } if sm.GetReplicationFactor() != 3 { t.Errorf("expected replication factor 3, got %d", sm.GetReplicationFactor()) } }) } func TestShardManagerGetShard_DifferentShardCounts(t *testing.T) { testCases := []struct { shardCount int }{ {shardCount: 16}, {shardCount: 64}, {shardCount: 256}, {shardCount: 1024}, {shardCount: 4096}, } for _, tc := range testCases { t.Run("shardCount="+string(rune(tc.shardCount)), func(t *testing.T) { sm := NewShardManagerWithConfig(ShardConfig{ShardCount: tc.shardCount}) // Verify all actor IDs map to valid shard range for i := 0; i < 1000; i++ { actorID := "actor-" + string(rune(i)) shard := sm.GetShard(actorID) if shard < 0 || shard >= tc.shardCount { t.Errorf("shard %d out of range [0, %d)", shard, tc.shardCount) } } }) } }