// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vdslib.distribution; import org.junit.Test; import java.text.ParseException; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.StringTokenizer; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; public class GroupTestCase { private void assertDistribution(String spec, int redundancy, String expectedResult) throws ParseException { Group.Distribution distribution = new Group.Distribution(spec, redundancy); assertEquals(spec, distribution.toString()); int[] resultArray = distribution.getRedundancyArray(redundancy); StringBuilder sb = new StringBuilder(); for (int i=0; i nodeList = new ArrayList<>(); while (st.hasMoreTokens()) { nodeList.add(new ConfiguredNode(Integer.parseInt(st.nextToken()), false)); } g.setNodes(nodeList); } private void verifyUniqueHashes(Group g, Set hashes) { assertFalse(g.getName(), hashes.contains(g.getDistributionHash())); hashes.add(g.getDistributionHash()); } private Group buildGroupTree() throws ParseException { Group root = new Group(5, "myroot", new Group.Distribution("2|*", 7)); List level_one = new ArrayList<>(); level_one.add(new Group(0, "br0", new Group.Distribution("1|1|*", 7))); level_one.add(new Group(1, "br1", new Group.Distribution("*", 7))); level_one.add(new Group(3, "br3", new Group.Distribution("8|*", 7))); level_one.add(new Group(4, "br4", new Group.Distribution("1|*", 7))); level_one.add(new Group(5, "br5", new Group.Distribution("*|*|*", 7))); level_one.add(new Group(6, "br6", new Group.Distribution("*|*|*|*|*|*", 7))); level_one.add(new Group(7, "br7", new Group.Distribution("*", 7))); level_one.add(new Group(9, "br9", new Group.Distribution("1|*", 7))); for(Group g : level_one) { root.addSubGroup(g); for (int i=0; i<5; ++i) { Group child = new Group(i, g.getName() + "." + i); g.addSubGroup(child); List nodeList = new ArrayList<>(); for (int j=0; j<5; ++j) nodeList.add(new ConfiguredNode(g.getIndex() * 10 + j, false)); child.setNodes(nodeList); } } // Create some irregularities setNodes(level_one.get(3).getSubgroups().get(2), "19,7,8,17"); try{ Group br8 = new Group(5, "br8", new Group.Distribution("*", 5)); root.addSubGroup(br8); fail(); // Should fail index 5 is in use at that level } catch (Exception e) { assertEquals("A subgroup with index 5 already exist.", e.getMessage()); } try{ Group br8 = new Group(5, "br8"); Group br9 = new Group(2, "br9"); br8.addSubGroup(br9); fail(); // Should fail as we want distribution to be set on non-leaf node } catch (Exception e) { assertEquals("Cannot add sub groups to a node without distribution set.", e.getMessage()); } try{ Group br8 = new Group(5, "br8", new Group.Distribution("*", 5)); setNodes(br8, "1,2,3"); fail(); // Should fail as we can't have distribution on leaf node. } catch (Exception e) { assertEquals("Cannot add nodes to non-leaf group with distribution set", e.getMessage()); } root.calculateDistributionHashValues(); Set distributionHashes = new HashSet<>(); verifyUniqueHashes(root, distributionHashes); return root; } @Test public void testNormalusage() throws ParseException { Group root = new Group(2, "myroot", new Group.Distribution("*", 2)); assertFalse(root.isLeafGroup()); Group branch = new Group(5, "myleaf"); assertTrue(branch.isLeafGroup()); root = buildGroupTree(); String expected = "Group(name: myroot, index: 5, distribution: 2|*, subgroups: 8) {\n" + " Group(name: br0, index: 0, distribution: 1|1|*, subgroups: 5) {\n" + " Group(name: br0.0, index: 0, nodes( 0 1 2 3 4 )) {\n" + " }\n" + " Group(name: br0.1, index: 1, nodes( 0 1 2 3 4 )) {\n" + " }\n" + " Group(name: br0.2, index: 2, nodes( 0 1 2 3 4 )) {\n" + " }\n" + " Group(name: br0.3, index: 3, nodes( 0 1 2 3 4 )) {\n" + " }\n" + " Group(name: br0.4, index: 4, nodes( 0 1 2 3 4 )) {\n" + " }\n" + " }\n"; assertEquals(expected, root.toString().substring(0, expected.length())); assertEquals("br5.br5.0", root.getGroupForNode(52).getPath()); } private Group.Distribution dummyDistribution() throws Exception { return new Group.Distribution("*", 1); } @Test public void testRootGroupDoesNotIncludeGroupNameWhenNoChildren() { Group g = new Group(0, "donkeykong"); assertEquals("/", g.getUnixStylePath()); } @Test public void testChildNamesDoNotIncludeRootGroupName() throws Exception { Group g = new Group(0, "donkeykong", dummyDistribution()); Group child = new Group(1, "mario"); g.addSubGroup(child); assertEquals("/mario", child.getUnixStylePath()); } @Test public void testNestedGroupsAreSlashSeparated() throws Exception { Group g = new Group(0, "donkeykong", dummyDistribution()); Group mario = new Group(1, "mario", dummyDistribution()); Group toad = new Group(2, "toad"); mario.addSubGroup(toad); g.addSubGroup(mario); assertEquals("/mario/toad", toad.getUnixStylePath()); } @Test public void testMultipleLeafGroupsAreEnumerated() throws Exception { Group g = new Group(0, "donkeykong", dummyDistribution()); Group mario = new Group(1, "mario", dummyDistribution()); Group toad = new Group(2, "toad"); mario.addSubGroup(toad); Group yoshi = new Group(3, "yoshi"); mario.addSubGroup(yoshi); g.addSubGroup(mario); Group luigi = new Group(4, "luigi"); g.addSubGroup(luigi); assertEquals("/mario/toad", toad.getUnixStylePath()); assertEquals("/mario/yoshi", yoshi.getUnixStylePath()); assertEquals("/luigi", luigi.getUnixStylePath()); } }