From 9166017204550684a8f917b7443e125fb1fcd0d9 Mon Sep 17 00:00:00 2001 From: Ritika Srivastava Date: Fri, 24 Jan 2025 10:45:14 -0800 Subject: [PATCH] Add test cases (#60) * Add test cases Signed-off-by: Ritika Srivastava * Move unexported functions Signed-off-by: Ritika Srivastava --------- Signed-off-by: Ritika Srivastava --- pkg/providers/baremetal/mnnvl.go | 88 ++++--- pkg/providers/baremetal/topology_test.go | 92 ++++++++ pkg/translate/output.go | 163 ------------- pkg/translate/output_test.go | 286 ++++++++++++++++++++++- 4 files changed, 429 insertions(+), 200 deletions(-) create mode 100644 pkg/providers/baremetal/topology_test.go diff --git a/pkg/providers/baremetal/mnnvl.go b/pkg/providers/baremetal/mnnvl.go index 0331974..4aa576a 100644 --- a/pkg/providers/baremetal/mnnvl.go +++ b/pkg/providers/baremetal/mnnvl.go @@ -2,6 +2,7 @@ package baremetal import ( "bufio" + "bytes" "context" "fmt" "strconv" @@ -12,7 +13,7 @@ import ( "github.com/NVIDIA/topograph/pkg/topology" ) -// domain contains map of each domainID(clusterUUID) -> list of nodeNames in that domain +// domain contains map of each domainID(clusterUUID) -> map of nodeNames in that domain // Each domain will be a separate NVL Domain type domain struct { nodeMap map[string]bool // nodeName: true @@ -39,22 +40,8 @@ func domainIDExists(id string, domainMap map[string]domain) bool { return false } -func getIbTree(ctx context.Context, _ []string) (*topology.Vertex, error) { - nodeVisited := make(map[string]bool) - treeRoot := &topology.Vertex{ - Vertices: make(map[string]*topology.Vertex), - } - ibPrefix := "IB" - ibCount := 0 +func populatePartitions(stdout *bytes.Buffer) (map[string][]string, error) { partitionNodeMap := make(map[string][]string) - partitionVisitedMap := make(map[string]bool) - - args := []string{"-h"} - stdout, err := exec.Exec(ctx, "sinfo", args, nil) - if err != nil { - return nil, fmt.Errorf("exec error in sinfo: %v", err) - } - // scan each line containing slurm partition and the nodes in it scanner := bufio.NewScanner(stdout) for scanner.Scan() { @@ -72,6 +59,28 @@ func getIbTree(ctx context.Context, _ []string) (*topology.Vertex, error) { // map of slurm partition name -> node names partitionNodeMap[partitionName] = append(partitionNodeMap[partitionName], nodesArr...) } + return partitionNodeMap, nil +} + +func getIbTree(ctx context.Context, _ []string) (*topology.Vertex, error) { + nodeVisited := make(map[string]bool) + treeRoot := &topology.Vertex{ + Vertices: make(map[string]*topology.Vertex), + } + ibPrefix := "IB" + ibCount := 0 + partitionVisitedMap := make(map[string]bool) + + args := []string{"-h"} + stdout, err := exec.Exec(ctx, "sinfo", args, nil) + if err != nil { + return nil, fmt.Errorf("exec error in sinfo: %v", err) + } + + partitionNodeMap, err := populatePartitions(stdout) + if err != nil { + return nil, fmt.Errorf("populatePartitions failed : %v", err) + } for pName, nodes := range partitionNodeMap { // for each partition in slurm, find the IB tree it belongs to if _, exists := partitionVisitedMap[pName]; !exists { @@ -116,15 +125,17 @@ func deCompressNodeNames(nodeList string) ([]string, error) { arr := strings.Split(nodeList, ",") prefix := "" var nodeName string + resetPrefix := false // example : nodename-1-[001-004 , 007, 91-99 , 100], nodename-2-89 for _, entry := range arr { // example : nodename-1-[001-004 if strings.Contains(entry, "[") { - // example : 100] + // example : nodename-1-[001-004] entryWithoutSuffix := strings.TrimSuffix(entry, "]") tuple := strings.Split(entryWithoutSuffix, "[") prefix = tuple[0] + resetPrefix = false // example : nodename-1-[001-004 if strings.Contains(tuple[1], "-") { nr := strings.Split(tuple[1], "-") @@ -153,10 +164,10 @@ func deCompressNodeNames(nodeList string) ([]string, error) { // example: 100], nodename-2-89, 90 if len(prefix) > 0 { //prefix exists, so must be a suffix. if strings.HasSuffix(entry, "]") { //if suffix has ], reset prefix - nv := strings.Split(entry, "]") - nodeName = prefix + nv[0] - prefix = "" - } else if strings.Contains(entry, "-") { // suffix containing range of nodes + entry = strings.TrimSuffix(entry, "]") + resetPrefix = true + } + if strings.Contains(entry, "-") { // suffix containing range of nodes // example: 100-102] nr := strings.Split(entry, "-") w := len(nr[0]) @@ -173,11 +184,17 @@ func deCompressNodeNames(nodeList string) ([]string, error) { nodeName = prefix + suffixNum nodeArr = append(nodeArr, nodeName) } + if resetPrefix { + prefix = "" + } // avoid another nodename append at the end continue } else { //example: 90 nodeName = prefix + entry + if resetPrefix { + prefix = "" + } } } else { // no prefix yet, must be whole nodename //example: nodename-2-89 @@ -189,14 +206,8 @@ func deCompressNodeNames(nodeList string) ([]string, error) { return nodeArr, nil } -// getClusterOutput reads output from nodeInfo and populates the structs -func getClusterOutput(ctx context.Context, domainMap map[string]domain, nodes []string, cmd string) error { - args := []string{"-R", "ssh", "-w", strings.Join(nodes, ","), cmd} - stdout, err := exec.Exec(ctx, "pdsh", args, nil) - if err != nil { - return fmt.Errorf("exec error while pdsh: %v", err) - } - +func populateDomains(stdout *bytes.Buffer) (map[string]domain, error) { + domainMap := make(map[string]domain) // domainID: domain scanner := bufio.NewScanner(stdout) cliqueId := "" clusterUUID := "" @@ -204,7 +215,7 @@ func getClusterOutput(ctx context.Context, domainMap map[string]domain, nodes [] for scanner.Scan() { nodeLine := scanner.Text() arr := strings.Split(nodeLine, ":") - nodeName := arr[0] + nodeName := strings.TrimSpace(arr[0]) itemName := strings.TrimSpace(arr[1]) if itemName == "CliqueId" { cliqueId = strings.TrimSpace(arr[2]) @@ -221,10 +232,19 @@ func getClusterOutput(ctx context.Context, domainMap map[string]domain, nodes [] nodeMap[nodeName] = true } if err := scanner.Err(); err != nil { - return fmt.Errorf("scanner error while reading pdsh output: %v", err) + return nil, fmt.Errorf("scanner error while reading pdsh output: %v", err) } + return domainMap, nil +} - return nil +// getClusterOutput reads output from nodeInfo and populates the structs +func getClusterOutput(ctx context.Context, nodes []string, cmd string) (map[string]domain, error) { + args := []string{"-R", "ssh", "-w", strings.Join(nodes, ","), cmd} + stdout, err := exec.Exec(ctx, "pdsh", args, nil) + if err != nil { + return nil, fmt.Errorf("exec error while pdsh: %v", err) + } + return populateDomains(stdout) } func toGraph(domainMap map[string]domain, treeRoot *topology.Vertex) *topology.Vertex { @@ -251,9 +271,9 @@ func toGraph(domainMap map[string]domain, treeRoot *topology.Vertex) *topology.V } func generateTopologyConfig(ctx context.Context, cis []topology.ComputeInstances) (*topology.Vertex, error) { - domainMap := make(map[string]domain) // domainID: domain + nodes := getNodeList(cis) - err := getClusterOutput(ctx, domainMap, nodes, `nvidia-smi -q | grep "ClusterUUID\|CliqueId"`) + domainMap, err := getClusterOutput(ctx, nodes, `nvidia-smi -q | grep "ClusterUUID\|CliqueId"`) if err != nil { return nil, fmt.Errorf("getClusterOutput failed: %v", err) } diff --git a/pkg/providers/baremetal/topology_test.go b/pkg/providers/baremetal/topology_test.go new file mode 100644 index 0000000..04b39c9 --- /dev/null +++ b/pkg/providers/baremetal/topology_test.go @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2024, NVIDIA CORPORATION. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package baremetal + +import ( + "bytes" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestClique(t *testing.T) { + cliqueOutput := `node-10: CliqueId : 4000000004 + node-10: ClusterUUID : 50000000-0000-0000-0000-000000000005 + node-10: CliqueId : 4000000004 + node-10: ClusterUUID : 50000000-0000-0000-0000-000000000005 + node-07: CliqueId : 4000000005 + node-07: ClusterUUID : 50000000-0000-0000-0000-000000000004 + node-07: CliqueId : 4000000005 + node-07: ClusterUUID : 50000000-0000-0000-0000-000000000004 + node-08: CliqueId : 4000000005 + node-08: ClusterUUID : 50000000-0000-0000-0000-000000000004 + node-08: CliqueId : 4000000005 + node-08: ClusterUUID : 50000000-0000-0000-0000-000000000004 + node-09: CliqueId : 4000000005 + node-09: ClusterUUID : 50000000-0000-0000-0000-000000000005 + node-09: CliqueId : 4000000005 + node-09: ClusterUUID : 50000000-0000-0000-0000-000000000005` + + domainObj45 := domain{ + nodeMap: map[string]bool{ + "node-07": true, + "node-08": true, + }, + } + + domainObj54 := domain{ + nodeMap: map[string]bool{ + "node-10": true, + }, + } + + domainObj55 := domain{ + nodeMap: map[string]bool{ + "node-09": true, + }, + } + + expectedDomainMap := map[string]domain{ + "50000000-0000-0000-0000-0000000000044000000005": domainObj45, + "50000000-0000-0000-0000-0000000000054000000004": domainObj54, + "50000000-0000-0000-0000-0000000000054000000005": domainObj55, + } + + domainMap, err := populateDomains(bytes.NewBufferString(cliqueOutput)) + require.NoError(t, err) + require.Equal(t, expectedDomainMap, domainMap) +} + +func TestSlurmPartition(t *testing.T) { + partitions := `cq up 6:00:00 1 down* node2-14 + cq up 6:00:00 1 drain node1-01 + cq up 6:00:00 30 idle node1-[02-16],node2-[01-13,15-16] + c1q up 8:00:00 1 drain node1-01 + c1q up 8:00:00 15 idle node1-[02-16] + c2q up 8:00:00 1 down* node2-14 + c2q up 8:00:00 15 idle node2-[01-13,15-16]` + + expectedPartitionMap := map[string][]string{ + "cq": {"node2-14", "node1-01", "node1-02", "node1-03", "node1-04", "node1-05", "node1-06", "node1-07", "node1-08", "node1-09", "node1-10", "node1-11", "node1-12", "node1-13", "node1-14", "node1-15", "node1-16", "node2-01", "node2-02", "node2-03", "node2-04", "node2-05", "node2-06", "node2-07", "node2-08", "node2-09", "node2-10", "node2-11", "node2-12", "node2-13", "node2-15", "node2-16"}, + "c1q": {"node1-01", "node1-02", "node1-03", "node1-04", "node1-05", "node1-06", "node1-07", "node1-08", "node1-09", "node1-10", "node1-11", "node1-12", "node1-13", "node1-14", "node1-15", "node1-16"}, + "c2q": {"node2-14", "node2-01", "node2-02", "node2-03", "node2-04", "node2-05", "node2-06", "node2-07", "node2-08", "node2-09", "node2-10", "node2-11", "node2-12", "node2-13", "node2-15", "node2-16"}, + } + + partitionMap, err := populatePartitions(bytes.NewBufferString(partitions)) + require.NoError(t, err) + require.Equal(t, expectedPartitionMap, partitionMap) +} diff --git a/pkg/translate/output.go b/pkg/translate/output.go index de55503..b86a164 100644 --- a/pkg/translate/output.go +++ b/pkg/translate/output.go @@ -513,166 +513,3 @@ func GetBlockWithMultiIBTestSet() (*topology.Vertex, map[string]string) { } return root, instance2node } - -func GetBlockWithIBTestSet() (*topology.Vertex, map[string]string) { - instance2node := map[string]string{ - "I14": "Node104", "I15": "Node105", "I16": "Node106", - "I21": "Node201", "I22": "Node202", "I25": "Node205", - } - - n14 := &topology.Vertex{ID: "I14", Name: "Node104"} - n15 := &topology.Vertex{ID: "I15", Name: "Node105"} - n16 := &topology.Vertex{ID: "I16", Name: "Node106"} - - n21 := &topology.Vertex{ID: "I21", Name: "Node201"} - n22 := &topology.Vertex{ID: "I22", Name: "Node202"} - n25 := &topology.Vertex{ID: "I25", Name: "Node205"} - - sw2 := &topology.Vertex{ - ID: "S2", - Vertices: map[string]*topology.Vertex{"I14": n14, "I15": n15, "I16": n16}, - } - sw3 := &topology.Vertex{ - ID: "S3", - Vertices: map[string]*topology.Vertex{"I21": n21, "I22": n22, "I25": n25}, - } - sw1 := &topology.Vertex{ - ID: "S1", - Vertices: map[string]*topology.Vertex{"S2": sw2, "S3": sw3}, - } - treeRoot := &topology.Vertex{ - Vertices: map[string]*topology.Vertex{"S1": sw1}, - } - - block1 := &topology.Vertex{ - ID: "B1", - Vertices: map[string]*topology.Vertex{"I14": n14, "I15": n15, "I16": n16}, - } - block2 := &topology.Vertex{ - ID: "B2", - Vertices: map[string]*topology.Vertex{"I21": n21, "I22": n22, "I25": n25}, - } - - blockRoot := &topology.Vertex{ - Vertices: map[string]*topology.Vertex{"B1": block1, "B2": block2}, - } - - root := &topology.Vertex{ - Vertices: map[string]*topology.Vertex{topology.TopologyBlock: blockRoot, topology.TopologyTree: treeRoot}, - Metadata: map[string]string{ - topology.KeyPlugin: topology.TopologyBlock, - topology.KeyBlockSizes: "3", - }, - } - return root, instance2node -} - -func GetBlockWithDFSIBTestSet() (*topology.Vertex, map[string]string) { - instance2node := map[string]string{ - "I14": "Node104", "I15": "Node105", - "I22": "Node202", "I25": "Node205", - } - - n14 := &topology.Vertex{ID: "I14", Name: "Node104"} - n15 := &topology.Vertex{ID: "I15", Name: "Node105"} - - n22 := &topology.Vertex{ID: "I22", Name: "Node202"} - n25 := &topology.Vertex{ID: "I25", Name: "Node205"} - - sw2 := &topology.Vertex{ - ID: "S2", - Vertices: map[string]*topology.Vertex{"I14": n14, "I15": n15}, - } - - sw4 := &topology.Vertex{ - ID: "S4", - Vertices: map[string]*topology.Vertex{"I22": n22}, - } - - sw5 := &topology.Vertex{ - ID: "S5", - Vertices: map[string]*topology.Vertex{"I25": n25}, - } - - sw3 := &topology.Vertex{ - ID: "S3", - Vertices: map[string]*topology.Vertex{"S5": sw5}, - } - sw1 := &topology.Vertex{ - ID: "S1", - Vertices: map[string]*topology.Vertex{"S4": sw4}, - } - - sw0 := &topology.Vertex{ - ID: "S0", - Vertices: map[string]*topology.Vertex{"S1": sw1, "S2": sw2, "S3": sw3}, - } - - treeRoot := &topology.Vertex{ - Vertices: map[string]*topology.Vertex{"S0": sw0}, - } - - block2 := &topology.Vertex{ - ID: "B2", - Vertices: map[string]*topology.Vertex{"I14": n14, "I15": n15}, - } - block1 := &topology.Vertex{ - ID: "B1", - Vertices: map[string]*topology.Vertex{"I22": n22}, - } - - block3 := &topology.Vertex{ - ID: "B3", - Vertices: map[string]*topology.Vertex{"I25": n25}, - } - - blockRoot := &topology.Vertex{ - Vertices: map[string]*topology.Vertex{"B1": block1, "B2": block2, "B3": block3}, - } - - root := &topology.Vertex{ - Vertices: map[string]*topology.Vertex{topology.TopologyBlock: blockRoot, topology.TopologyTree: treeRoot}, - Metadata: map[string]string{ - topology.KeyPlugin: topology.TopologyBlock, - topology.KeyBlockSizes: "1", - }, - } - return root, instance2node -} - -func GetBlockTestSet() (*topology.Vertex, map[string]string) { - instance2node := map[string]string{ - "I14": "Node104", "I15": "Node105", "I16": "Node106", - "I21": "Node201", "I22": "Node202", "I25": "Node205", - } - - n14 := &topology.Vertex{ID: "I14", Name: "Node104"} - n15 := &topology.Vertex{ID: "I15", Name: "Node105"} - n16 := &topology.Vertex{ID: "I16", Name: "Node106"} - - n21 := &topology.Vertex{ID: "I21", Name: "Node201"} - n22 := &topology.Vertex{ID: "I22", Name: "Node202"} - n25 := &topology.Vertex{ID: "I25", Name: "Node205"} - - block1 := &topology.Vertex{ - ID: "B1", - Vertices: map[string]*topology.Vertex{"I14": n14, "I15": n15, "I16": n16}, - } - block2 := &topology.Vertex{ - ID: "B2", - Vertices: map[string]*topology.Vertex{"I21": n21, "I22": n22, "I25": n25}, - } - - blockRoot := &topology.Vertex{ - Vertices: map[string]*topology.Vertex{"B1": block1, "B2": block2}, - } - - root := &topology.Vertex{ - Vertices: map[string]*topology.Vertex{topology.TopologyBlock: blockRoot}, - Metadata: map[string]string{ - topology.KeyPlugin: topology.TopologyBlock, - topology.KeyBlockSizes: "3", - }, - } - return root, instance2node -} diff --git a/pkg/translate/output_test.go b/pkg/translate/output_test.go index e175038..c7cd233 100644 --- a/pkg/translate/output_test.go +++ b/pkg/translate/output_test.go @@ -34,6 +34,11 @@ SwitchName=S3 Nodes=Node[304-306] testBlockConfig = `BlockName=B1 Nodes=Node[104-106] BlockName=B2 Nodes=Node[201-202],Node205 BlockSizes=3 +` + + testBlockConfigDiffNumNodes = `BlockName=B1 Nodes=Node[104-106] +BlockName=B2 Nodes=Node[201-202],Node[205-206] +BlockSizes=2 ` testBlockConfig2 = `BlockName=B3 Nodes=Node[301-303] @@ -71,7 +76,7 @@ func TestToTreeTopology(t *testing.T) { } func TestToBlockTopology(t *testing.T) { - v, _ := GetBlockTestSet() + v, _ := getBlockTestSet() buf := &bytes.Buffer{} err := Write(buf, v) require.NoError(t, err) @@ -92,7 +97,7 @@ func TestToBlockMultiIBTopology(t *testing.T) { } func TestToBlockIBTopology(t *testing.T) { - v, _ := GetBlockWithIBTestSet() + v, _ := getBlockWithIBTestSet() buf := &bytes.Buffer{} err := Write(buf, v) require.NoError(t, err) @@ -104,8 +109,21 @@ func TestToBlockIBTopology(t *testing.T) { } } +func TestToBlockDiffNumNode(t *testing.T) { + v, _ := getBlockWithDiffNumNodeTestSet() + buf := &bytes.Buffer{} + err := Write(buf, v) + require.NoError(t, err) + switch buf.String() { + case testBlockConfigDiffNumNodes: + // nop + default: + t.Errorf("unexpected result %s", buf.String()) + } +} + func TestToBlockDFSIBTopology(t *testing.T) { - v, _ := GetBlockWithDFSIBTestSet() + v, _ := getBlockWithDFSIBTestSet() buf := &bytes.Buffer{} err := Write(buf, v) require.NoError(t, err) @@ -255,3 +273,265 @@ func TestSplit(t *testing.T) { }) } } + +func getBlockWithIBTestSet() (*topology.Vertex, map[string]string) { + // + // ibRoot1 + // | + // S1 + // / \ + // S2 S3 + // | | + // --- --- + // I14\ I21\ + // I15-B1 I22-B2 + // I16/ I25/ + // --- --- + // + instance2node := map[string]string{ + "I14": "Node104", "I15": "Node105", "I16": "Node106", + "I21": "Node201", "I22": "Node202", "I25": "Node205", + } + + n14 := &topology.Vertex{ID: "I14", Name: "Node104"} + n15 := &topology.Vertex{ID: "I15", Name: "Node105"} + n16 := &topology.Vertex{ID: "I16", Name: "Node106"} + + n21 := &topology.Vertex{ID: "I21", Name: "Node201"} + n22 := &topology.Vertex{ID: "I22", Name: "Node202"} + n25 := &topology.Vertex{ID: "I25", Name: "Node205"} + + sw2 := &topology.Vertex{ + ID: "S2", + Vertices: map[string]*topology.Vertex{"I14": n14, "I15": n15, "I16": n16}, + } + sw3 := &topology.Vertex{ + ID: "S3", + Vertices: map[string]*topology.Vertex{"I21": n21, "I22": n22, "I25": n25}, + } + sw1 := &topology.Vertex{ + ID: "S1", + Vertices: map[string]*topology.Vertex{"S2": sw2, "S3": sw3}, + } + treeRoot := &topology.Vertex{ + Vertices: map[string]*topology.Vertex{"S1": sw1}, + } + + block1 := &topology.Vertex{ + ID: "B1", + Vertices: map[string]*topology.Vertex{"I14": n14, "I15": n15, "I16": n16}, + } + block2 := &topology.Vertex{ + ID: "B2", + Vertices: map[string]*topology.Vertex{"I21": n21, "I22": n22, "I25": n25}, + } + + blockRoot := &topology.Vertex{ + Vertices: map[string]*topology.Vertex{"B1": block1, "B2": block2}, + } + + root := &topology.Vertex{ + Vertices: map[string]*topology.Vertex{topology.TopologyBlock: blockRoot, topology.TopologyTree: treeRoot}, + Metadata: map[string]string{ + topology.KeyPlugin: topology.TopologyBlock, + topology.KeyBlockSizes: "3", + }, + } + return root, instance2node +} + +func getBlockWithDFSIBTestSet() (*topology.Vertex, map[string]string) { + // + // ibRoot1 + // / | \ + // S1 S2 S3 + // | | | + // S4 --- S5 + // | I14\ | + // --- B2 --- + // I22-B1 I15/ I25-B3 + // --- --- --- + // + instance2node := map[string]string{ + "I14": "Node104", "I15": "Node105", + "I22": "Node202", "I25": "Node205", + } + + n14 := &topology.Vertex{ID: "I14", Name: "Node104"} + n15 := &topology.Vertex{ID: "I15", Name: "Node105"} + + n22 := &topology.Vertex{ID: "I22", Name: "Node202"} + n25 := &topology.Vertex{ID: "I25", Name: "Node205"} + + sw2 := &topology.Vertex{ + ID: "S2", + Vertices: map[string]*topology.Vertex{"I14": n14, "I15": n15}, + } + + sw4 := &topology.Vertex{ + ID: "S4", + Vertices: map[string]*topology.Vertex{"I22": n22}, + } + + sw5 := &topology.Vertex{ + ID: "S5", + Vertices: map[string]*topology.Vertex{"I25": n25}, + } + + sw3 := &topology.Vertex{ + ID: "S3", + Vertices: map[string]*topology.Vertex{"S5": sw5}, + } + sw1 := &topology.Vertex{ + ID: "S1", + Vertices: map[string]*topology.Vertex{"S4": sw4}, + } + + sw0 := &topology.Vertex{ + ID: "S0", + Vertices: map[string]*topology.Vertex{"S1": sw1, "S2": sw2, "S3": sw3}, + } + + treeRoot := &topology.Vertex{ + Vertices: map[string]*topology.Vertex{"S0": sw0}, + } + + block2 := &topology.Vertex{ + ID: "B2", + Vertices: map[string]*topology.Vertex{"I14": n14, "I15": n15}, + } + block1 := &topology.Vertex{ + ID: "B1", + Vertices: map[string]*topology.Vertex{"I22": n22}, + } + + block3 := &topology.Vertex{ + ID: "B3", + Vertices: map[string]*topology.Vertex{"I25": n25}, + } + + blockRoot := &topology.Vertex{ + Vertices: map[string]*topology.Vertex{"B1": block1, "B2": block2, "B3": block3}, + } + + root := &topology.Vertex{ + Vertices: map[string]*topology.Vertex{topology.TopologyBlock: blockRoot, topology.TopologyTree: treeRoot}, + Metadata: map[string]string{ + topology.KeyPlugin: topology.TopologyBlock, + topology.KeyBlockSizes: "1", + }, + } + return root, instance2node +} + +func getBlockTestSet() (*topology.Vertex, map[string]string) { + // + // --- --- + // I14\ I21\ + // I15-B1 I22-B2 + // I16/ I25/ + // --- --- + // + instance2node := map[string]string{ + "I14": "Node104", "I15": "Node105", "I16": "Node106", + "I21": "Node201", "I22": "Node202", "I25": "Node205", + } + + n14 := &topology.Vertex{ID: "I14", Name: "Node104"} + n15 := &topology.Vertex{ID: "I15", Name: "Node105"} + n16 := &topology.Vertex{ID: "I16", Name: "Node106"} + + n21 := &topology.Vertex{ID: "I21", Name: "Node201"} + n22 := &topology.Vertex{ID: "I22", Name: "Node202"} + n25 := &topology.Vertex{ID: "I25", Name: "Node205"} + + block1 := &topology.Vertex{ + ID: "B1", + Vertices: map[string]*topology.Vertex{"I14": n14, "I15": n15, "I16": n16}, + } + block2 := &topology.Vertex{ + ID: "B2", + Vertices: map[string]*topology.Vertex{"I21": n21, "I22": n22, "I25": n25}, + } + + blockRoot := &topology.Vertex{ + Vertices: map[string]*topology.Vertex{"B1": block1, "B2": block2}, + } + + root := &topology.Vertex{ + Vertices: map[string]*topology.Vertex{topology.TopologyBlock: blockRoot}, + Metadata: map[string]string{ + topology.KeyPlugin: topology.TopologyBlock, + topology.KeyBlockSizes: "3", + }, + } + return root, instance2node +} + +func getBlockWithDiffNumNodeTestSet() (*topology.Vertex, map[string]string) { + // + // ibRoot1 + // | + // S1 + // / \ + // S2 S3 + // | | + // --- --- + // I14\ I21\ + // I15-B1 I22-B2 + // I16/ I25 / + // I26 / + // --- --- + // + instance2node := map[string]string{ + "I14": "Node104", "I15": "Node105", "I16": "Node106", + "I21": "Node201", "I22": "Node202", "I25": "Node205", "I26": "Node206", + } + + n14 := &topology.Vertex{ID: "I14", Name: "Node104"} + n15 := &topology.Vertex{ID: "I15", Name: "Node105"} + n16 := &topology.Vertex{ID: "I16", Name: "Node106"} + + n21 := &topology.Vertex{ID: "I21", Name: "Node201"} + n22 := &topology.Vertex{ID: "I22", Name: "Node202"} + n25 := &topology.Vertex{ID: "I25", Name: "Node205"} + n26 := &topology.Vertex{ID: "I26", Name: "Node206"} + + sw2 := &topology.Vertex{ + ID: "S2", + Vertices: map[string]*topology.Vertex{"I14": n14, "I15": n15, "I16": n16}, + } + sw3 := &topology.Vertex{ + + ID: "S3", + Vertices: map[string]*topology.Vertex{"I21": n21, "I22": n22, "I25": n25, "I26": n26}, + } + sw1 := &topology.Vertex{ + ID: "S1", + Vertices: map[string]*topology.Vertex{"S2": sw2, "S3": sw3}, + } + treeRoot := &topology.Vertex{ + Vertices: map[string]*topology.Vertex{"S1": sw1}, + } + + block1 := &topology.Vertex{ + ID: "B1", + Vertices: map[string]*topology.Vertex{"I14": n14, "I15": n15, "I16": n16}, + } + block2 := &topology.Vertex{ + ID: "B2", + Vertices: map[string]*topology.Vertex{"I21": n21, "I22": n22, "I25": n25, "I26": n26}, + } + + blockRoot := &topology.Vertex{ + Vertices: map[string]*topology.Vertex{"B1": block1, "B2": block2}, + } + + root := &topology.Vertex{ + Vertices: map[string]*topology.Vertex{topology.TopologyBlock: blockRoot, topology.TopologyTree: treeRoot}, + Metadata: map[string]string{ + topology.KeyPlugin: topology.TopologyBlock, + }, + } + return root, instance2node +}