package com.sequenceiq.cloudbreak.controller.validation.blueprint; import java.io.IOException; import java.util.ArrayList; import java.util.Set; import java.util.stream.Collectors; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.BDDMockito; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.JsonNodeFactory; import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.collect.Sets; import com.sequenceiq.cloudbreak.controller.BadRequestException; import com.sequenceiq.cloudbreak.domain.Blueprint; import com.sequenceiq.cloudbreak.domain.Constraint; import com.sequenceiq.cloudbreak.domain.HostGroup; import com.sequenceiq.cloudbreak.domain.InstanceGroup; @RunWith(MockitoJUnitRunner.class) public class BlueprintValidatorTest { private static final String BLUEPRINT_STRING = "blueprint"; private static final String GROUP1 = "group1"; private static final String GROUP2 = "group2"; private static final String GROUP3 = "group3"; private static final String GROUP4 = "group4"; private static final String MA_MIN1_MAX5 = "mastercomp1"; private static final String MA_MIN1_MAX1 = "mastercomp2"; private static final String MA_MIN1_MAX3 = "mastercomp3"; private static final String SL_MIN0_MAX3 = "slavecomp1"; private static final String SL_MIN5_MAX6 = "slavecomp2"; private static final String UNKNOWN = "unknown"; @Mock private StackServiceComponentDescriptors stackServiceComponentDescriptors; @Mock private ObjectMapper objectMapper; @InjectMocks private BlueprintValidator underTest; @Before public void setUp() { setupStackServiceComponentDescriptors(); } @Test(expected = BadRequestException.class) public void testValidateBlueprintForStackShouldThrowBadRequestExceptionWhenJsonTreeCreationIsFailed() throws Exception { // GIVEN Blueprint blueprint = createBlueprint(); Set<InstanceGroup> instanceGroups = createInstanceGroups(); Set<HostGroup> hostGroups = createHostGroups(instanceGroups); BDDMockito.given(objectMapper.readTree(BDDMockito.anyString())).willThrow(new IOException()); // WHEN underTest.validateBlueprintForStack(blueprint, hostGroups, instanceGroups); // THEN throw exception } @Test(expected = BadRequestException.class) public void testValidateBlueprintForStackShouldThrowBadRequestExceptionWhenNoInstanceGroupForAHostGroup() throws IOException { // GIVEN Blueprint blueprint = createBlueprint(); Set<InstanceGroup> instanceGroups = createInstanceGroups(); Set<HostGroup> hostGroups = createHostGroups(instanceGroups.stream().limit(instanceGroups.size() - 1).collect(Collectors.toSet())); JsonNode blueprintJsonTree = createJsonTree(); BDDMockito.given(objectMapper.readTree(BLUEPRINT_STRING)).willReturn(blueprintJsonTree); // WHEN underTest.validateBlueprintForStack(blueprint, hostGroups, instanceGroups); // THEN throw exception } @Test(expected = BadRequestException.class) public void testValidateBlueprintForStackShouldThrowBadRequestExceptionWhenNodeCountForAHostGroupIsMoreThanMax() throws IOException { // GIVEN Blueprint blueprint = createBlueprint(); Set<InstanceGroup> instanceGroups = createInstanceGroups(); Set<HostGroup> hostGroups = createHostGroups(instanceGroups); instanceGroups.add(createInstanceGroup("gateway", 1)); JsonNode blueprintJsonTree = createJsonTreeWithIllegalGroup(); BDDMockito.given(objectMapper.readTree(BLUEPRINT_STRING)).willReturn(blueprintJsonTree); // WHEN underTest.validateBlueprintForStack(blueprint, hostGroups, instanceGroups); // THEN throw exception } @Test(expected = BadRequestException.class) public void testValidateBlueprintForStackShouldThrowBadRequestExceptionWhenGroupCountsAreDifferent() throws IOException { // GIVEN Blueprint blueprint = createBlueprint(); Set<InstanceGroup> instanceGroups = createInstanceGroups(); Set<HostGroup> hostGroups = createHostGroups(instanceGroups); instanceGroups.add(createInstanceGroup("gateway", 1)); JsonNode blueprintJsonTree = createJsonTreeWithTooMuchGroup(); BDDMockito.given(objectMapper.readTree(BLUEPRINT_STRING)).willReturn(blueprintJsonTree); // WHEN underTest.validateBlueprintForStack(blueprint, hostGroups, instanceGroups); // THEN throw exception } @Test(expected = BadRequestException.class) public void testValidateBlueprintForStackShouldThrowBadRequestExceptionWhenNotEnoughGroupDefinedInBlueprint() throws IOException { // GIVEN Blueprint blueprint = createBlueprint(); Set<InstanceGroup> instanceGroups = createInstanceGroups(); Set<HostGroup> hostGroups = createHostGroups(instanceGroups); JsonNode blueprintJsonTree = createJsonTreeWithNotEnoughGroup(); BDDMockito.given(objectMapper.readTree(BLUEPRINT_STRING)).willReturn(blueprintJsonTree); // WHEN underTest.validateBlueprintForStack(blueprint, hostGroups, instanceGroups); // THEN throw exception } @Test(expected = BadRequestException.class) public void testValidateBlueprintForStackShouldThrowBadRequestExceptionWhenComponentIsInMoreGroupsAndNodeCountIsMoreThanMax() throws IOException { // GIVEN Blueprint blueprint = createBlueprint(); Set<InstanceGroup> instanceGroups = createInstanceGroups(); Set<HostGroup> hostGroups = createHostGroups(instanceGroups); instanceGroups.add(createInstanceGroup("gateway", 1)); JsonNode blueprintJsonTree = createJsonTreeWithComponentInMoreGroups(); BDDMockito.given(objectMapper.readTree(BLUEPRINT_STRING)).willReturn(blueprintJsonTree); // WHEN underTest.validateBlueprintForStack(blueprint, hostGroups, instanceGroups); // THEN throw exception } @Test(expected = BadRequestException.class) public void testValidateBlueprintForStackShouldThrowBadRequestExceptionWhenComponentIsLessThanMin() throws IOException { // GIVEN Blueprint blueprint = createBlueprint(); Set<InstanceGroup> instanceGroups = createInstanceGroups(); Set<HostGroup> hostGroups = createHostGroups(instanceGroups); instanceGroups.add(createInstanceGroup("gateway", 1)); JsonNode blueprintJsonTree = createJsonTreeWithComponentIsLess(); BDDMockito.given(objectMapper.readTree(BLUEPRINT_STRING)).willReturn(blueprintJsonTree); // WHEN underTest.validateBlueprintForStack(blueprint, hostGroups, instanceGroups); // THEN throw exception } @Test public void testValidateBlueprintForStackShouldNotThrowAnyExceptionWhenBlueprintIsValid() throws IOException { // GIVEN Blueprint blueprint = createBlueprint(); Set<InstanceGroup> instanceGroups = createInstanceGroups(); Set<HostGroup> hostGroups = createHostGroups(instanceGroups); instanceGroups.add(createInstanceGroup("gateway", 1)); JsonNode blueprintJsonTree = createJsonTree(); BDDMockito.given(objectMapper.readTree(BLUEPRINT_STRING)).willReturn(blueprintJsonTree); // WHEN underTest.validateBlueprintForStack(blueprint, hostGroups, instanceGroups); // THEN doesn't throw exception } @Test public void testValidateBlueprintForStackShouldNotThrowAnyExceptionWhenBlueprintContainsUnknownComponent() throws IOException { // GIVEN Blueprint blueprint = createBlueprint(); Set<InstanceGroup> instanceGroups = createInstanceGroups(); Set<HostGroup> hostGroups = createHostGroups(instanceGroups); instanceGroups.add(createInstanceGroup("gateway", 1)); JsonNode blueprintJsonTree = createJsonTreeWithUnknownComponent(); BDDMockito.given(objectMapper.readTree(BLUEPRINT_STRING)).willReturn(blueprintJsonTree); // WHEN underTest.validateBlueprintForStack(blueprint, hostGroups, instanceGroups); // THEN doesn't throw exception } @Test(expected = BadRequestException.class) public void testHostGroupScalingThrowsBadRequestExceptionWhenNodeCountIsMoreThanMax() throws IOException { // GIVEN Blueprint blueprint = createBlueprint(); JsonNode blueprintJsonTree = createJsonTree(); InstanceGroup instanceGroup = createInstanceGroup(GROUP3, 3); HostGroup hostGroup = createHostGroup(instanceGroup.getGroupName(), instanceGroup); BDDMockito.given(objectMapper.readTree(BLUEPRINT_STRING)).willReturn(blueprintJsonTree); // WHEN underTest.validateHostGroupScalingRequest(blueprint, hostGroup, 1); // THEN throw exception } @Test(expected = BadRequestException.class) public void testHostGroupScalingThrowsBadRequestExceptionWhenNodeCountIsLessThanMin() throws IOException { // GIVEN Blueprint blueprint = createBlueprint(); JsonNode blueprintJsonTree = createJsonTree(); InstanceGroup instanceGroup = createInstanceGroup(GROUP3, 1); HostGroup hostGroup = createHostGroup(instanceGroup.getGroupName(), instanceGroup); BDDMockito.given(objectMapper.readTree(BLUEPRINT_STRING)).willReturn(blueprintJsonTree); // WHEN underTest.validateHostGroupScalingRequest(blueprint, hostGroup, -1); // THEN throw exception } @Test public void testHostGroupScalingNoThrowsAnyExceptionWhenNumbersAreOk() throws IOException { // GIVEN Blueprint blueprint = createBlueprint(); JsonNode blueprintJsonTree = createJsonTree(); InstanceGroup instanceGroup = createInstanceGroup(GROUP3, 2); HostGroup hostGroup = createHostGroup(instanceGroup.getGroupName(), instanceGroup); BDDMockito.given(objectMapper.readTree(BLUEPRINT_STRING)).willReturn(blueprintJsonTree); // WHEN underTest.validateHostGroupScalingRequest(blueprint, hostGroup, 1); // THEN throw exception } private void setupStackServiceComponentDescriptors() { BDDMockito.given(stackServiceComponentDescriptors.get(MA_MIN1_MAX5)).willReturn(new StackServiceComponentDescriptor(MA_MIN1_MAX5, "MASTER", 1, 5)); BDDMockito.given(stackServiceComponentDescriptors.get(MA_MIN1_MAX1)).willReturn(new StackServiceComponentDescriptor(MA_MIN1_MAX1, "MASTER", 1, 1)); BDDMockito.given(stackServiceComponentDescriptors.get(MA_MIN1_MAX3)).willReturn(new StackServiceComponentDescriptor(MA_MIN1_MAX3, "MASTER", 1, 3)); BDDMockito.given(stackServiceComponentDescriptors.get(SL_MIN0_MAX3)).willReturn(new StackServiceComponentDescriptor(SL_MIN0_MAX3, "SLAVE", 0, 3)); BDDMockito.given(stackServiceComponentDescriptors.get(SL_MIN5_MAX6)).willReturn(new StackServiceComponentDescriptor(SL_MIN5_MAX6, "SLAVE", 5, 6)); } private Blueprint createBlueprint() { Blueprint blueprint = new Blueprint(); blueprint.setBlueprintText(BLUEPRINT_STRING); return blueprint; } private Set<InstanceGroup> createInstanceGroups() { Set<InstanceGroup> groups = Sets.newHashSet(); groups.add(createInstanceGroup(GROUP1, 1)); groups.add(createInstanceGroup(GROUP2, 2)); groups.add(createInstanceGroup(GROUP3, 3)); return groups; } private InstanceGroup createInstanceGroup(String groupName, int nodeCount) { InstanceGroup group = new InstanceGroup(); group.setGroupName(groupName); group.setNodeCount(nodeCount); return group; } private Set<HostGroup> createHostGroups(Set<InstanceGroup> instanceGroups) { Set<HostGroup> groups = Sets.newHashSet(); for (InstanceGroup instanceGroup : new ArrayList<>(instanceGroups)) { groups.add(createHostGroup(instanceGroup.getGroupName(), instanceGroup)); } return groups; } private HostGroup createHostGroup(String groupName, InstanceGroup instanceGroup) { HostGroup group = new HostGroup(); group.setName(groupName); Constraint constraint = new Constraint(); constraint.setHostCount(instanceGroup.getNodeCount()); constraint.setInstanceGroup(instanceGroup); group.setConstraint(constraint); return group; } private JsonNode createJsonTreeWithIllegalGroup() { JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance; ObjectNode rootNode = jsonNodeFactory.objectNode(); ArrayNode hostGroupsNode = rootNode.putArray("host_groups"); addHostGroup(hostGroupsNode, GROUP1, SL_MIN0_MAX3); addHostGroup(hostGroupsNode, GROUP2, MA_MIN1_MAX5, MA_MIN1_MAX1); addHostGroup(hostGroupsNode, GROUP3, MA_MIN1_MAX3); return rootNode; } private JsonNode createJsonTreeWithTooMuchGroup() { JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance; ObjectNode rootNode = jsonNodeFactory.objectNode(); ArrayNode hostGroupsNode = rootNode.putArray("host_groups"); addHostGroup(hostGroupsNode, GROUP1, MA_MIN1_MAX1); addHostGroup(hostGroupsNode, GROUP2, MA_MIN1_MAX5); addHostGroup(hostGroupsNode, GROUP3, MA_MIN1_MAX3); addHostGroup(hostGroupsNode, GROUP4, SL_MIN0_MAX3); return rootNode; } private JsonNode createJsonTreeWithNotEnoughGroup() { JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance; ObjectNode rootNode = jsonNodeFactory.objectNode(); ArrayNode hostGroupsNode = rootNode.putArray("host_groups"); addHostGroup(hostGroupsNode, GROUP1, MA_MIN1_MAX1); addHostGroup(hostGroupsNode, GROUP2, MA_MIN1_MAX5); return rootNode; } private JsonNode createJsonTreeWithUnknownComponent() { JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance; ObjectNode rootNode = jsonNodeFactory.objectNode(); ArrayNode hostGroupsNode = rootNode.putArray("host_groups"); addHostGroup(hostGroupsNode, GROUP1, MA_MIN1_MAX1); addHostGroup(hostGroupsNode, GROUP2, MA_MIN1_MAX5); addHostGroup(hostGroupsNode, GROUP3, UNKNOWN); return rootNode; } private JsonNode createJsonTreeWithComponentInMoreGroups() { JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance; ObjectNode rootNode = jsonNodeFactory.objectNode(); ArrayNode hostGroupsNode = rootNode.putArray("host_groups"); addHostGroup(hostGroupsNode, GROUP1, MA_MIN1_MAX1, MA_MIN1_MAX3); addHostGroup(hostGroupsNode, GROUP2, MA_MIN1_MAX5); addHostGroup(hostGroupsNode, GROUP3, MA_MIN1_MAX3); return rootNode; } private JsonNode createJsonTreeWithComponentIsLess() { JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance; ObjectNode rootNode = jsonNodeFactory.objectNode(); ArrayNode hostGroupsNode = rootNode.putArray("host_groups"); addHostGroup(hostGroupsNode, GROUP1, MA_MIN1_MAX1); addHostGroup(hostGroupsNode, GROUP2, MA_MIN1_MAX3); addHostGroup(hostGroupsNode, GROUP3, SL_MIN5_MAX6); return rootNode; } private JsonNode createJsonTree() { JsonNodeFactory jsonNodeFactory = JsonNodeFactory.instance; ObjectNode rootNode = jsonNodeFactory.objectNode(); ArrayNode hostGroupsNode = rootNode.putArray("host_groups"); addHostGroup(hostGroupsNode, GROUP1, SL_MIN0_MAX3, MA_MIN1_MAX1); addHostGroup(hostGroupsNode, GROUP2, MA_MIN1_MAX5); addHostGroup(hostGroupsNode, GROUP3, MA_MIN1_MAX3); return rootNode; } private void addHostGroup(ArrayNode hostGroupsNode, String name, String... components) { ObjectNode hostGroupNode = hostGroupsNode.addObject(); hostGroupNode.put("name", name); ArrayNode componentsNode = hostGroupNode.putArray("components"); for (String comp : components) { ObjectNode compNode = componentsNode.addObject(); compNode.put("name", comp); } } }