test: [skip e2e] fix unstable assignment tests in balancer (#46042)

issue: #46038

- Add assertSegmentPlanNumAndTargetNodeMatch and
assertChannelPlanNumAndTargetNodeMatch helper functions to validate plan
count and target node membership for unstable assignment tests
- Mark "test assigning channels with resource exhausted nodes" as
unstable since node 2 and 3 have equal priority after filtering
- Replace simple length check with target node validation to ensure
plans assign to expected node set even when order is non-deterministic

Signed-off-by: Wei Liu <wei.liu@zilliz.com>
This commit is contained in:
wei liu 2025-12-04 16:17:11 +08:00 committed by GitHub
parent 64d19fb4f3
commit 0c63ed95bb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 56 additions and 5 deletions

View File

@ -245,7 +245,7 @@ func (suite *ChannelLevelScoreBalancerTestSuite) TestAssignSegment() {
for i := range c.collectionIDs {
plans := balancer.AssignSegment(ctx, c.collectionIDs[i], c.assignments[i], c.nodes, false)
if c.unstableAssignment {
suite.Equal(len(plans), len(c.expectPlans[i]))
assertSegmentPlanNumAndTargetNodeMatch(&suite.Suite, c.expectPlans[i], plans)
} else {
assertSegmentAssignPlanElementMatch(&suite.Suite, c.expectPlans[i], plans)
}

View File

@ -1258,6 +1258,31 @@ func assertSegmentAssignPlanElementMatch(suite *suite.Suite, left []SegmentAssig
}
}
// assertSegmentPlanNumAndTargetNodeMatch checks that:
// 1. The number of plans matches the expected count
// 2. Each plan's target node is in the expected target nodes set (extracted from expectPlans)
// 3. The number of unique target nodes matches between expected and actual plans
func assertSegmentPlanNumAndTargetNodeMatch(suite *suite.Suite, expectPlans []SegmentAssignPlan, plans []SegmentAssignPlan) {
suite.Len(plans, len(expectPlans))
// Extract expected target nodes from expectPlans
expectedSet := make(map[int64]struct{})
for _, p := range expectPlans {
expectedSet[p.To] = struct{}{}
}
// Extract actual target nodes from plans
actualSet := make(map[int64]struct{})
for _, plan := range plans {
_, ok := expectedSet[plan.To]
suite.True(ok, "target node %d not in expected set", plan.To)
actualSet[plan.To] = struct{}{}
}
// Check that the number of unique target nodes matches
suite.Len(actualSet, len(expectedSet), "number of unique target nodes mismatch: expected %d, got %d", len(expectedSet), len(actualSet))
}
// remove it after resource group enhancement.
func assertChannelAssignPlanElementMatch(suite *suite.Suite, left []ChannelAssignPlan, right []ChannelAssignPlan, subset ...bool) {
type comparablePlan struct {
@ -1300,3 +1325,28 @@ func assertChannelAssignPlanElementMatch(suite *suite.Suite, left []ChannelAssig
suite.ElementsMatch(leftPlan, rightPlan)
}
}
// assertChannelPlanNumAndTargetNodeMatch checks that:
// 1. The number of plans matches the expected count
// 2. Each plan's target node is in the expected target nodes set (extracted from expectPlans)
// 3. The number of unique target nodes matches between expected and actual plans
func assertChannelPlanNumAndTargetNodeMatch(suite *suite.Suite, expectPlans []ChannelAssignPlan, plans []ChannelAssignPlan) {
suite.Len(plans, len(expectPlans))
// Extract expected target nodes from expectPlans
expectedSet := make(map[int64]struct{})
for _, p := range expectPlans {
expectedSet[p.To] = struct{}{}
}
// Extract actual target nodes from plans
actualSet := make(map[int64]struct{})
for _, plan := range plans {
_, ok := expectedSet[plan.To]
suite.True(ok, "target node %d not in expected set", plan.To)
actualSet[plan.To] = struct{}{}
}
// Check that the number of unique target nodes matches
suite.Len(actualSet, len(expectedSet), "number of unique target nodes mismatch: expected %d, got %d", len(expectedSet), len(actualSet))
}

View File

@ -282,7 +282,7 @@ func (suite *ScoreBasedBalancerTestSuite) TestAssignSegment() {
for i := range c.collectionIDs {
plans := balancer.AssignSegment(ctx, c.collectionIDs[i], c.assignments[i], c.nodes, false)
if c.unstableAssignment {
suite.Len(plans, len(c.expectPlans[i]))
assertSegmentPlanNumAndTargetNodeMatch(&suite.Suite, c.expectPlans[i], plans)
} else {
assertSegmentAssignPlanElementMatch(&suite.Suite, c.expectPlans[i], plans)
}
@ -1701,6 +1701,7 @@ func (suite *ScoreBasedBalancerTestSuite) TestAssignChannel() {
},
states: []session.State{session.NodeStateNormal, session.NodeStateNormal, session.NodeStateNormal},
distributions: map[int64][]*meta.DmChannel{},
unstableAssignment: true,
expectPlans: []ChannelAssignPlan{
{Channel: &meta.DmChannel{VchannelInfo: &datapb.VchannelInfo{CollectionID: 1, ChannelName: "channel1"}}, From: -1, To: 2},
{Channel: &meta.DmChannel{VchannelInfo: &datapb.VchannelInfo{CollectionID: 1, ChannelName: "channel2"}}, From: -1, To: 3},
@ -1771,7 +1772,7 @@ func (suite *ScoreBasedBalancerTestSuite) TestAssignChannel() {
// Test channel assignment
plans := balancer.AssignChannel(ctx, c.collectionID, dmChannels, c.nodes, true)
if c.unstableAssignment {
suite.Len(plans, len(c.expectPlans))
assertChannelPlanNumAndTargetNodeMatch(&suite.Suite, c.expectPlans, plans)
} else {
assertChannelAssignPlanElementMatch(&suite.Suite, c.expectPlans, plans)
}