diff --git a/internal/querycoordv2/balance/channel_level_score_balancer_test.go b/internal/querycoordv2/balance/channel_level_score_balancer_test.go index 2188940ec7..40e1886afb 100644 --- a/internal/querycoordv2/balance/channel_level_score_balancer_test.go +++ b/internal/querycoordv2/balance/channel_level_score_balancer_test.go @@ -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) } diff --git a/internal/querycoordv2/balance/rowcount_based_balancer_test.go b/internal/querycoordv2/balance/rowcount_based_balancer_test.go index 1c7ce6ea35..39c23f8211 100644 --- a/internal/querycoordv2/balance/rowcount_based_balancer_test.go +++ b/internal/querycoordv2/balance/rowcount_based_balancer_test.go @@ -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)) +} diff --git a/internal/querycoordv2/balance/score_based_balancer_test.go b/internal/querycoordv2/balance/score_based_balancer_test.go index 470603d67b..b265ba9096 100644 --- a/internal/querycoordv2/balance/score_based_balancer_test.go +++ b/internal/querycoordv2/balance/score_based_balancer_test.go @@ -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) } @@ -1699,8 +1699,9 @@ func (suite *ScoreBasedBalancerTestSuite) TestAssignChannel() { {CollectionID: 1, ChannelName: "channel1"}, {CollectionID: 1, ChannelName: "channel2"}, }, - states: []session.State{session.NodeStateNormal, session.NodeStateNormal, session.NodeStateNormal}, - distributions: map[int64][]*meta.DmChannel{}, + 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) }