fix(server): 显式 target_hosts 时主机指向用户指定的主节点

- 显式列表校验通过后令 host = nodes[0],task.TargetHost/IP、台账、
  CloudDM 注册与凭据地址不再指向此前默认挑选的空闲主机
- 显式列表解析抽为纯函数 resolvePinnedPrimaryReplicaNodes,
  行为与原内联逻辑一致(校验失败终态/单机上限 defer 重试)
- 新增测试覆盖主节点非池首空闲节点及数量/池外/重复/占满场景
This commit is contained in:
Hungerdream
2026-07-31 18:49:34 +08:00
parent 454df86021
commit 95c3e98611
2 changed files with 72 additions and 26 deletions
+29
View File
@@ -138,6 +138,35 @@ func TestFirstFreeHost(t *testing.T) {
}
}
func TestResolvePinnedPrimaryReplicaNodes(t *testing.T) {
pool := []targetHost{{Name: "node-a", IP: "10.0.0.1"}, {Name: "node-b", IP: "10.0.0.2"}, {Name: "node-c", IP: "10.0.0.3"}}
// 主节点不是池首空闲节点(firstFreeHost 会选 node-a):首节点必须以用户列表为准。
nodes, validationMsg, err := resolvePinnedPrimaryReplicaNodes(pool, []string{"node-c", "node-a"}, nil, 4, 2, "")
if err != nil || validationMsg != "" {
t.Fatalf("unexpected rejection: msg=%q err=%v", validationMsg, err)
}
if nodes[0].Name != "node-c" || nodes[0].IP != "10.0.0.3" || nodes[1].Name != "node-a" {
t.Fatalf("primary must follow the user-specified order, got %+v", nodes)
}
if _, msg, _ := resolvePinnedPrimaryReplicaNodes(pool, []string{"node-a"}, nil, 4, 2, ""); msg == "" {
t.Fatal("host count mismatch was accepted")
}
if _, msg, _ := resolvePinnedPrimaryReplicaNodes(pool, []string{"node-a", "node-x"}, nil, 4, 2, ""); msg == "" {
t.Fatal("host outside the pool was accepted")
}
if _, msg, _ := resolvePinnedPrimaryReplicaNodes(pool, []string{"node-a", "node-a"}, nil, 4, 2, ""); msg == "" {
t.Fatal("duplicate host was accepted")
}
if _, msg, _ := resolvePinnedPrimaryReplicaNodes(pool, []string{"node-b", "node-c"}, nil, 4, 2, "node-a"); msg == "" {
t.Fatal("target_host mismatching the first entry was accepted")
}
if _, _, err := resolvePinnedPrimaryReplicaNodes(pool, []string{"node-a", "node-b"}, []string{"node-b"}, 1, 2, ""); err == nil {
t.Fatal("saturated pinned host must defer scheduling")
}
}
func TestAllocatePort(t *testing.T) {
if port, err := allocatePort(0, nil); err != nil || port != mysqlPortPoolStart {
t.Fatalf("expected first pool port %d, got %d err=%v", mysqlPortPoolStart, port, err)