|
| 1 | +package gorums_test |
| 2 | + |
| 3 | +import ( |
| 4 | + "fmt" |
| 5 | + "testing" |
| 6 | + |
| 7 | + "github.com/relab/gorums" |
| 8 | +) |
| 9 | + |
| 10 | +// TODO check if okay to use node id 0? the Node.ID() function returns 0 if node == nil. |
| 11 | + |
| 12 | +func TestTreeConfiguration(t *testing.T) { |
| 13 | + const branchFactor = 2 |
| 14 | + tests := []struct { |
| 15 | + nodeIDs map[string]uint32 // all nodes in the configuration |
| 16 | + id uint32 // my ID to create subconfigurations from |
| 17 | + wantConfig [][]uint32 // index: tree level, value: list of node IDs in the configuration |
| 18 | + }{ |
| 19 | + {nodeIDs: nodeMapIDs(0, 8), id: 0, wantConfig: [][]uint32{{1}, {2, 3}, {4, 5, 6, 7}}}, |
| 20 | + {nodeIDs: nodeMapIDs(0, 8), id: 1, wantConfig: [][]uint32{{0}, {2, 3}, {4, 5, 6, 7}}}, |
| 21 | + {nodeIDs: nodeMapIDs(0, 8), id: 2, wantConfig: [][]uint32{{3}, {0, 1}, {4, 5, 6, 7}}}, |
| 22 | + {nodeIDs: nodeMapIDs(0, 8), id: 3, wantConfig: [][]uint32{{2}, {0, 1}, {4, 5, 6, 7}}}, |
| 23 | + {nodeIDs: nodeMapIDs(0, 8), id: 4, wantConfig: [][]uint32{{5}, {6, 7}, {0, 1, 2, 3}}}, |
| 24 | + {nodeIDs: nodeMapIDs(0, 8), id: 5, wantConfig: [][]uint32{{4}, {6, 7}, {0, 1, 2, 3}}}, |
| 25 | + {nodeIDs: nodeMapIDs(0, 8), id: 6, wantConfig: [][]uint32{{7}, {4, 5}, {0, 1, 2, 3}}}, |
| 26 | + {nodeIDs: nodeMapIDs(0, 8), id: 7, wantConfig: [][]uint32{{6}, {4, 5}, {0, 1, 2, 3}}}, |
| 27 | + // |
| 28 | + {nodeIDs: nodeMapIDs(0, 16), id: 0, wantConfig: [][]uint32{{1}, {2, 3}, {4, 5, 6, 7}, {8, 9, 10, 11, 12, 13, 14, 15}}}, |
| 29 | + {nodeIDs: nodeMapIDs(0, 16), id: 1, wantConfig: [][]uint32{{0}, {2, 3}, {4, 5, 6, 7}, {8, 9, 10, 11, 12, 13, 14, 15}}}, |
| 30 | + {nodeIDs: nodeMapIDs(0, 16), id: 2, wantConfig: [][]uint32{{3}, {0, 1}, {4, 5, 6, 7}, {8, 9, 10, 11, 12, 13, 14, 15}}}, |
| 31 | + {nodeIDs: nodeMapIDs(0, 16), id: 3, wantConfig: [][]uint32{{2}, {0, 1}, {4, 5, 6, 7}, {8, 9, 10, 11, 12, 13, 14, 15}}}, |
| 32 | + {nodeIDs: nodeMapIDs(0, 16), id: 4, wantConfig: [][]uint32{{5}, {6, 7}, {0, 1, 2, 3}, {8, 9, 10, 11, 12, 13, 14, 15}}}, |
| 33 | + {nodeIDs: nodeMapIDs(0, 16), id: 5, wantConfig: [][]uint32{{4}, {6, 7}, {0, 1, 2, 3}, {8, 9, 10, 11, 12, 13, 14, 15}}}, |
| 34 | + {nodeIDs: nodeMapIDs(0, 16), id: 6, wantConfig: [][]uint32{{7}, {4, 5}, {0, 1, 2, 3}, {8, 9, 10, 11, 12, 13, 14, 15}}}, |
| 35 | + {nodeIDs: nodeMapIDs(0, 16), id: 7, wantConfig: [][]uint32{{6}, {4, 5}, {0, 1, 2, 3}, {8, 9, 10, 11, 12, 13, 14, 15}}}, |
| 36 | + // |
| 37 | + {nodeIDs: nodeMapIDs(0, 16), id: 8, wantConfig: [][]uint32{{9}, {10, 11}, {12, 13, 14, 15}, {0, 1, 2, 3, 4, 5, 6, 7}}}, |
| 38 | + {nodeIDs: nodeMapIDs(0, 16), id: 9, wantConfig: [][]uint32{{8}, {10, 11}, {12, 13, 14, 15}, {0, 1, 2, 3, 4, 5, 6, 7}}}, |
| 39 | + {nodeIDs: nodeMapIDs(0, 16), id: 10, wantConfig: [][]uint32{{11}, {8, 9}, {12, 13, 14, 15}, {0, 1, 2, 3, 4, 5, 6, 7}}}, |
| 40 | + {nodeIDs: nodeMapIDs(0, 16), id: 11, wantConfig: [][]uint32{{10}, {8, 9}, {12, 13, 14, 15}, {0, 1, 2, 3, 4, 5, 6, 7}}}, |
| 41 | + {nodeIDs: nodeMapIDs(0, 16), id: 12, wantConfig: [][]uint32{{13}, {14, 15}, {8, 9, 10, 11}, {0, 1, 2, 3, 4, 5, 6, 7}}}, |
| 42 | + {nodeIDs: nodeMapIDs(0, 16), id: 13, wantConfig: [][]uint32{{12}, {14, 15}, {8, 9, 10, 11}, {0, 1, 2, 3, 4, 5, 6, 7}}}, |
| 43 | + {nodeIDs: nodeMapIDs(0, 16), id: 14, wantConfig: [][]uint32{{15}, {12, 13}, {8, 9, 10, 11}, {0, 1, 2, 3, 4, 5, 6, 7}}}, |
| 44 | + {nodeIDs: nodeMapIDs(0, 16), id: 15, wantConfig: [][]uint32{{14}, {12, 13}, {8, 9, 10, 11}, {0, 1, 2, 3, 4, 5, 6, 7}}}, |
| 45 | + } |
| 46 | + for _, test := range tests { |
| 47 | + t.Run(fmt.Sprintf("%d", len(test.nodeIDs)), func(t *testing.T) { |
| 48 | + mgr := gorums.NewManager(gorums.WithNoConnect()) |
| 49 | + cfgs, err := gorums.SubConfigurations(mgr, |
| 50 | + gorums.WithTreeConfigurations(branchFactor, test.id, gorums.WithNodeMap(test.nodeIDs))) |
| 51 | + if err != nil { |
| 52 | + t.Fatal(err) |
| 53 | + } |
| 54 | + if len(cfgs) != log2(len(test.nodeIDs)) { |
| 55 | + t.Errorf("len(cfgs) = %d, expected %d", len(cfgs), 2) |
| 56 | + } |
| 57 | + for i, cfg := range cfgs { |
| 58 | + if len(cfg) != len(test.wantConfig[i]) { |
| 59 | + t.Errorf("len(cfg) = %d, expected %d", len(cfg), len(test.wantConfig[i])) |
| 60 | + } |
| 61 | + for _, id := range test.wantConfig[i] { |
| 62 | + if !cfg.Contains(id) { |
| 63 | + t.Errorf("{%v}.Contains(%d) = false, expected true", cfg.NodeIDs(), id) |
| 64 | + } |
| 65 | + } |
| 66 | + // fmt.Printf("c%d (%d): %v\n", i, cfg.Size(), cfg.NodeIDs()) |
| 67 | + } |
| 68 | + }) |
| 69 | + } |
| 70 | +} |
| 71 | + |
| 72 | +// nodeMapIDs returns a map of localhost node IDs for the given node count. |
| 73 | +func nodeMapIDs(s, n int) map[string]uint32 { |
| 74 | + basePort := 9080 |
| 75 | + nodeMapIDs := make(map[string]uint32) |
| 76 | + for i := s; i < s+n; i++ { |
| 77 | + nodeMapIDs[fmt.Sprintf("127.0.0.1:%d", basePort+i)] = uint32(i) |
| 78 | + } |
| 79 | + return nodeMapIDs |
| 80 | +} |
| 81 | + |
| 82 | +// log2 returns the base 2 logarithm of x. |
| 83 | +func log2(x int) int { |
| 84 | + y := 0 |
| 85 | + for x > 1 { |
| 86 | + x >>= 1 |
| 87 | + y++ |
| 88 | + } |
| 89 | + return y |
| 90 | +} |
0 commit comments