(t *testing.T)
| 252 | } |
| 253 | |
| 254 | func TestPartitionRing_ShuffleShard_Shuffling(t *testing.T) { |
| 255 | var ( |
| 256 | numTenants = 1000 |
| 257 | numActivePartitions = 90 |
| 258 | shardSize = 3 |
| 259 | |
| 260 | // This is the expected theoretical distribution of matching partitions |
| 261 | // between different shards, given the settings above. It has been computed |
| 262 | // using this spreadsheet: |
| 263 | // https://docs.google.com/spreadsheets/d/1FXbiWTXi6bdERtamH-IfmpgFq1fNL4GP_KX_yJvbRi4/edit |
| 264 | theoreticalMatchings = map[int]float64{ |
| 265 | 0: 90.2239, |
| 266 | 1: 9.55312, |
| 267 | 2: 0.22217, |
| 268 | 3: 0.00085, |
| 269 | } |
| 270 | ) |
| 271 | |
| 272 | // Initialise the ring. |
| 273 | ring := createPartitionRingWithPartitions(DefaultPartitionRingOptions(), numActivePartitions, 0, 0) |
| 274 | |
| 275 | // Compute the shard for each tenant. |
| 276 | partitionsByTenant := map[string][]int32{} |
| 277 | |
| 278 | for i := 1; i <= numTenants; i++ { |
| 279 | tenantID := fmt.Sprintf("%d", i) |
| 280 | |
| 281 | subring, err := ring.ShuffleShard(tenantID, shardSize) |
| 282 | require.NoError(t, err) |
| 283 | |
| 284 | partitionsByTenant[tenantID] = subring.PartitionIDs() |
| 285 | } |
| 286 | |
| 287 | // Compute the distribution of matching partitions between every combination of shards. |
| 288 | // The shards comparison is not optimized, but it's fine for a test. |
| 289 | distribution := map[int]int{} |
| 290 | |
| 291 | for currTenant, currPartitions := range partitionsByTenant { |
| 292 | for otherTenant, otherPartitions := range partitionsByTenant { |
| 293 | if currTenant == otherTenant { |
| 294 | continue |
| 295 | } |
| 296 | |
| 297 | numMatching := 0 |
| 298 | for _, c := range currPartitions { |
| 299 | if slices.Contains(otherPartitions, c) { |
| 300 | numMatching++ |
| 301 | } |
| 302 | } |
| 303 | |
| 304 | distribution[numMatching]++ |
| 305 | } |
| 306 | } |
| 307 | |
| 308 | maxCombinations := int(math.Pow(float64(numTenants), 2)) - numTenants |
| 309 | for numMatching, probability := range theoreticalMatchings { |
| 310 | // We allow a max deviance of 10% compared to the theoretical probability, |
| 311 | // clamping it between 1% and 0.2% boundaries. |
nothing calls this directly
no test coverage detected