balancer/randomsubsetting: Extend the unit tests in the randomsubsetting package#9059
balancer/randomsubsetting: Extend the unit tests in the randomsubsetting package#9059marek-szews wants to merge 7 commits intogrpc:masterfrom
Conversation
…ackage. RELEASE NOTES: balancer/randomsubsetting: Implementation of additional UT.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #9059 +/- ##
==========================================
+ Coverage 83.08% 83.13% +0.05%
==========================================
Files 413 413
Lines 33269 33476 +207
==========================================
+ Hits 27642 27831 +189
- Misses 4215 4226 +11
- Partials 1412 1419 +7
🚀 New features to boost your workflow:
|
|
This pull request is a continuation of the work started in PR#8781. Due to a high volume of merge conflicts that made the previous PR impossible to merge cleanly, I have decided to close the old one and start fresh here with the latest changes. |
Pranjali-2501
left a comment
There was a problem hiding this comment.
@marek-szews, PTAL at the comments.
marek-szews
left a comment
There was a problem hiding this comment.
Would you refer to my answers to the asked questions ?
| { | ||
| eps: 16, | ||
| subsetSize: 4, | ||
| iteration: 10, |
There was a problem hiding this comment.
Why are we using such a small value for iterations here.
There was a problem hiding this comment.
That explains the situation perfectly! Using a hardcoded seed in your tests creates a deterministic environment where the algorithm's choices are fixed for every run.
While this is excellent for reproducibility, it can create a "false sense of randomness" if the specific seed happens to generate a sequence that fits your distribution criteria perfectly, even with low iterations.
| positive: true, | ||
| }, | ||
| { | ||
| eps: 4, |
There was a problem hiding this comment.
When the subset size equals the total number of endpoints (eps == subsetSize), the algorithm returns all endpoints every time.
We can remove this testcase.
There was a problem hiding this comment.
I agree with your point regarding the first part of the statement; however, the successful outcome of the verification process is not entirely definitive. It primarily depends on the number of repetitions to ensure the sample is statistically representative.
The distribution will only begin to align once this specific threshold is exceeded. If we wish to examine the Load Balancer algorithm's actual output, a relevant test can be found in the TestCalculateSubset_Simple() function, specifically under the test name SubsetSizeEqualToNumberOfEndpoints.
It was my underlying objective to demonstrate the correlation between EPs, subsetSize, and the total iteration count. As subsetSize converges with EPs, the number of iterations required for successful verification increases significantly.
EndPoints |16 | 8 | 4 |
subsetSize | 4 | 4 | 4 |
repetition 1600 -> 3200 -> 6400
| iteration: 6400, | ||
| positive: true, | ||
| }, | ||
| { |
There was a problem hiding this comment.
I think we don't need the false assertion here. IMO, just having testcases that are expected to pass is sufficient.
There was a problem hiding this comment.
The fact that your tests do not fail is actually the point—it confirms that the algorithm is operationally sound. However, checking for a uniform distribution serves a different purpose than simply checking for a "pass/fail" result.
marek-szews
left a comment
There was a problem hiding this comment.
All of your comments have been reviewed and addressed. Please find my response below.
| for i := 0; i < K; i++ { | ||
| lb := &subsettingBalancer{ | ||
| cfg: &lbConfig{SubsetSize: uint32(L)}, | ||
| hashSeed: uint64(i ^ 3 + K*i + L), |
There was a problem hiding this comment.
What is the significance of the way this seed value is computed? Why can't it just be i?
| N := len(endpoints) | ||
| L := int(tc.subsetSize) | ||
| K := int(tc.iteration) | ||
| p := float64(L) / float64(N) // Probability of x ∈ N being drawn p(x) = L / N | ||
| E := float64(K) * p // Expected Value (Mean) E(N) = K * p |
There was a problem hiding this comment.
Having single letter variable names that are spread through the function does not help with readability at all. Please get rid of these variables and instead use the RHS of these variables directly in the code.
| p := float64(L) / float64(N) // Probability of x ∈ N being drawn p(x) = L / N | ||
| E := float64(K) * p // Expected Value (Mean) E(N) = K * p | ||
|
|
||
| EndpointCount := make(map[string]int, N) |
There was a problem hiding this comment.
s/EndpointCount/endpointCount
| expectedCounts[k] = E | ||
| } | ||
|
|
||
| err := roundrobin.PearsonsChiSquareTest(t, observedCounts, expectedCounts, 0.05) |
There was a problem hiding this comment.
How was the value of 0.05 arrived at?
| // TestUniformDistributionOfEndpoints verifies that the random subsetting | ||
| // policy achieves a uniform distribution across backends. From a set of N | ||
| // numbers, it randomly selects K-times a subset of L numbers, where L < N. | ||
| // Then it calculates how many times each number belonging to set N appears, | ||
| // compute the variance and standard deviation, and use a Chi-Square test to | ||
| // check whether the distribution is uniform. |
There was a problem hiding this comment.
From what I can see, this test is actually testing the hashing function. If we really want to test the functionality in the policy, we should be overriding the hashing function in some deterministic fashion, so that we can verify the algorithm in the policy.
I'm concerned about a bunch of things in this test, but most importantly, if this test fails, how would one go about debugging? What do the scenarios in the different table entries correspond to, how were they arrived at?
Add more unit tests to increase test coverage of 'randomsubsetting' package.
RELEASE NOTES: none