/*
* Copyright 2015 herd contributors
*
* 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 org.finra.herd.service.helper;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import org.finra.herd.dao.impl.MockEc2OperationsImpl;
import org.finra.herd.model.api.xml.EmrClusterDefinition;
import org.finra.herd.model.api.xml.InstanceDefinition;
import org.finra.herd.model.api.xml.InstanceDefinitions;
import org.finra.herd.model.api.xml.MasterInstanceDefinition;
import org.finra.herd.model.api.xml.NodeTag;
import org.finra.herd.service.AbstractServiceTest;
/**
* This class tests functionality within the EmrClusterDefinitionHelper class.
*/
public class EmrClusterDefinitionHelperTest extends AbstractServiceTest
{
@Test
public void testValidateEmrClusterDefinitionConfigurationNullSubnet()
{
EmrClusterDefinition emrClusterDefinition = createValidEmrClusterDefinition();
emrClusterDefinition.setSubnetId(null);
try
{
emrClusterDefinitionHelper.validateEmrClusterDefinitionConfiguration(emrClusterDefinition);
fail("expected IllegalArgumentException, but no exception was thrown");
}
catch (Exception e)
{
assertEquals("thrown exception", IllegalArgumentException.class, e.getClass());
}
}
/**
* Tests case where validation is run against the definition generated by createValidEmrClusterDefinition() without modifications. The definition should be
* valid.
*/
@Test
public void testValidateEmrClusterDefinitionConfigurationValid()
{
EmrClusterDefinition emrClusterDefinition = createValidEmrClusterDefinition();
try
{
emrClusterDefinitionHelper.validateEmrClusterDefinitionConfiguration(emrClusterDefinition);
}
catch (Exception e)
{
fail("expected no exception, but " + e.getClass() + " was thrown. " + e);
}
}
/**
* Tests case where validation is run against the definition generated by createValidEmrClusterDefinition() The master instance spot price is specified The
* definition should be valid because spot price is allowed when max search price is not specified.
*/
@Test
public void testValidateEmrClusterDefinitionConfigurationMasterSpotPriceSpecified()
{
EmrClusterDefinition emrClusterDefinition = createValidEmrClusterDefinition();
emrClusterDefinition.getInstanceDefinitions().getMasterInstances().setInstanceSpotPrice(BigDecimal.ONE);
try
{
emrClusterDefinitionHelper.validateEmrClusterDefinitionConfiguration(emrClusterDefinition);
}
catch (Exception e)
{
fail("expected no exception, but " + e.getClass() + " was thrown. " + e);
}
}
/**
* Tests case where validation is run against the definition generated by createValidEmrClusterDefinition() The master instance max search price is
* specified The definition should be valid because max search price is allowed when no instance spot price is specified.
*/
@Test
public void testValidateEmrClusterDefinitionConfigurationMasterMaxSearchPriceSpecified()
{
EmrClusterDefinition emrClusterDefinition = createValidEmrClusterDefinition();
emrClusterDefinition.getInstanceDefinitions().getMasterInstances().setInstanceMaxSearchPrice(BigDecimal.ONE);
try
{
emrClusterDefinitionHelper.validateEmrClusterDefinitionConfiguration(emrClusterDefinition);
}
catch (Exception e)
{
fail("expected no exception, but " + e.getClass() + " was thrown. " + e);
}
}
/**
* Tests case where validation is run against the definition generated by createValidEmrClusterDefinition() The master instance max search price and
* on-demand threshold is specified The definition should be valid because on-demand threshold can be used with max search price.
*/
@Test
public void testValidateEmrClusterDefinitionConfigurationMasterMaxSearchPriceAndOnDemandThresholdSpecified()
{
EmrClusterDefinition emrClusterDefinition = createValidEmrClusterDefinition();
emrClusterDefinition.getInstanceDefinitions().getMasterInstances().setInstanceMaxSearchPrice(BigDecimal.ONE);
emrClusterDefinition.getInstanceDefinitions().getMasterInstances().setInstanceOnDemandThreshold(BigDecimal.ONE);
try
{
emrClusterDefinitionHelper.validateEmrClusterDefinitionConfiguration(emrClusterDefinition);
}
catch (Exception e)
{
fail("expected no exception, but " + e.getClass() + " was thrown. " + e);
}
}
/**
* Tests case where validation is run against the definition generated by createValidEmrClusterDefinition() The task instance is not specified. The
* definition should be valid because task instance is optional.
*/
@Test
public void testValidateEmrClusterDefinitionConfigurationTaskInstanceDefinitionNotSpecified()
{
EmrClusterDefinition emrClusterDefinition = createValidEmrClusterDefinition();
emrClusterDefinition.getInstanceDefinitions().setTaskInstances(null);
try
{
emrClusterDefinitionHelper.validateEmrClusterDefinitionConfiguration(emrClusterDefinition);
}
catch (Exception e)
{
fail("expected no exception, but " + e.getClass() + " was thrown. " + e);
}
}
/**
* Tests case where validation is run against the definition generated by createValidEmrClusterDefinition() The subnet is whitespace only. The definition is
* not valid. Subnet is required.
*/
@Test
public void testValidateEmrClusterDefinitionConfigurationBlankSubnet()
{
EmrClusterDefinition emrClusterDefinition = createValidEmrClusterDefinition();
emrClusterDefinition.setSubnetId(" \r\t\n");
try
{
emrClusterDefinitionHelper.validateEmrClusterDefinitionConfiguration(emrClusterDefinition);
fail("expected IllegalArgumentException, but no exception was thrown");
}
catch (Exception e)
{
assertEquals("thrown exception", IllegalArgumentException.class, e.getClass());
}
}
/**
* Tests case where validation is run against the definition generated by createValidEmrClusterDefinition() The subnet is a list, and contains at least 1
* whitespace-only element The definition is not valid. All elements in subnet list must not be blank.
*/
@Test
public void testValidateEmrClusterDefinitionConfigurationSubnetListBlankElement()
{
EmrClusterDefinition emrClusterDefinition = createValidEmrClusterDefinition();
emrClusterDefinition.setSubnetId(MockEc2OperationsImpl.SUBNET_1 + ", \r\t\n");
try
{
emrClusterDefinitionHelper.validateEmrClusterDefinitionConfiguration(emrClusterDefinition);
fail("expected IllegalArgumentException, but no exception was thrown");
}
catch (Exception e)
{
assertEquals("thrown exception", IllegalArgumentException.class, e.getClass());
}
}
/**
* Tests case where validation is run against the definition generated by createValidEmrClusterDefinition() The master spot price is negative. The
* definition is not valid. All prices must be positive.
*/
@Test
public void testValidateEmrClusterDefinitionConfigurationMasterSpotPriceNegative()
{
EmrClusterDefinition emrClusterDefinition = createValidEmrClusterDefinition();
emrClusterDefinition.getInstanceDefinitions().getMasterInstances().setInstanceSpotPrice(BigDecimal.ONE.negate());
try
{
emrClusterDefinitionHelper.validateEmrClusterDefinitionConfiguration(emrClusterDefinition);
fail("expected IllegalArgumentException, but no exception was thrown");
}
catch (Exception e)
{
assertEquals("thrown exception", IllegalArgumentException.class, e.getClass());
}
}
/**
* Tests case where validation is run against the definition generated by createValidEmrClusterDefinition() The master instance spot price and max search
* price is specified. The definition is not valid. The two parameters are exclusive.
*/
@Test
public void testValidateEmrClusterDefinitionConfigurationMasterSpotPriceAndMaxSearchPriceSpecified()
{
EmrClusterDefinition emrClusterDefinition = createValidEmrClusterDefinition();
emrClusterDefinition.getInstanceDefinitions().getMasterInstances().setInstanceSpotPrice(BigDecimal.ONE);
emrClusterDefinition.getInstanceDefinitions().getMasterInstances().setInstanceMaxSearchPrice(BigDecimal.ONE);
try
{
emrClusterDefinitionHelper.validateEmrClusterDefinitionConfiguration(emrClusterDefinition);
fail("expected IllegalArgumentException, but no exception was thrown");
}
catch (Exception e)
{
assertEquals("thrown exception", IllegalArgumentException.class, e.getClass());
}
}
/**
* Tests case where validation is run against the definition generated by createValidEmrClusterDefinition() The master instance max search price is
* negative. The definition is not valid. All prices must be positive.
*/
@Test
public void testValidateEmrClusterDefinitionConfigurationMasterMaxSearchPriceNegative()
{
EmrClusterDefinition emrClusterDefinition = createValidEmrClusterDefinition();
emrClusterDefinition.getInstanceDefinitions().getMasterInstances().setInstanceMaxSearchPrice(BigDecimal.ONE.negate());
try
{
emrClusterDefinitionHelper.validateEmrClusterDefinitionConfiguration(emrClusterDefinition);
fail("expected IllegalArgumentException, but no exception was thrown");
}
catch (Exception e)
{
assertEquals("thrown exception", IllegalArgumentException.class, e.getClass());
}
}
/**
* Tests case where validation is run against the definition generated by createValidEmrClusterDefinition() The master instance on-demand threshold is
* specified. The definition is not valid. On-demand threshold is only allowed when max search price is specified.
*/
@Test
public void testValidateEmrClusterDefinitionConfigurationMasterOnDemandThresholdSpecified()
{
EmrClusterDefinition emrClusterDefinition = createValidEmrClusterDefinition();
emrClusterDefinition.getInstanceDefinitions().getMasterInstances().setInstanceOnDemandThreshold(BigDecimal.ONE);
try
{
emrClusterDefinitionHelper.validateEmrClusterDefinitionConfiguration(emrClusterDefinition);
fail("expected IllegalArgumentException, but no exception was thrown");
}
catch (Exception e)
{
assertEquals("thrown exception", IllegalArgumentException.class, e.getClass());
}
}
/**
* Tests case where validation is run against the definition generated by createValidEmrClusterDefinition() The master instance on-demand threshold is
* negative. The definition is not valid. All prices must be positive.
*/
@Test
public void testValidateEmrClusterDefinitionConfigurationMasterMaxSearchPriceSpecifiedAndOnDemandThresholdNegative()
{
EmrClusterDefinition emrClusterDefinition = createValidEmrClusterDefinition();
emrClusterDefinition.getInstanceDefinitions().getMasterInstances().setInstanceMaxSearchPrice(BigDecimal.ONE);
emrClusterDefinition.getInstanceDefinitions().getMasterInstances().setInstanceOnDemandThreshold(BigDecimal.ONE.negate());
try
{
emrClusterDefinitionHelper.validateEmrClusterDefinitionConfiguration(emrClusterDefinition);
fail("expected IllegalArgumentException, but no exception was thrown");
}
catch (IllegalArgumentException e)
{
assertEquals("Master instance on-demand threshold must be greater than 0", e.getMessage());
}
}
@Test
public void testValidateEmrClusterDefinitionConfigurationCoreInstancesNotSpecified()
{
EmrClusterDefinition emrClusterDefinition = createValidEmrClusterDefinition();
emrClusterDefinition.getInstanceDefinitions().setCoreInstances(null);
try
{
emrClusterDefinitionHelper.validateEmrClusterDefinitionConfiguration(emrClusterDefinition);
}
catch (Exception e)
{
fail("expected no exception, but " + e.getClass() + " was thrown. " + e);
}
}
@Test
public void testValidateEmrClusterDefinitionConfigurationCoreInstanceSpecifiedInstanceCountNegative()
{
EmrClusterDefinition emrClusterDefinition = createValidEmrClusterDefinition();
emrClusterDefinition.getInstanceDefinitions().getCoreInstances().setInstanceCount(-1);
try
{
emrClusterDefinitionHelper.validateEmrClusterDefinitionConfiguration(emrClusterDefinition);
fail();
}
catch (IllegalArgumentException e)
{
assertEquals("At least 0 core instance must be specified.", e.getMessage());
}
}
/**
* Creates a EMR cluster definition which does not cause validateEmrClusterDefinitionConfiguration() to throw an exception.
* <p/>
* - One subnet is specified - Master, core, and task instances are specified - Instance count, and instance type are specified for each instance
* definition. - One node tag is specified
*
* @return A new instance of {@link EmrClusterDefinition}
*/
private EmrClusterDefinition createValidEmrClusterDefinition()
{
EmrClusterDefinition emrClusterDefinition = new EmrClusterDefinition();
emrClusterDefinition.setSubnetId(MockEc2OperationsImpl.SUBNET_1);
InstanceDefinitions instanceDefinitions = new InstanceDefinitions();
MasterInstanceDefinition masterInstanceDefinition = new MasterInstanceDefinition();
masterInstanceDefinition.setInstanceCount(1);
masterInstanceDefinition.setInstanceType(MockEc2OperationsImpl.INSTANCE_TYPE_1);
instanceDefinitions.setMasterInstances(masterInstanceDefinition);
InstanceDefinition coreInstanceDefinition = new InstanceDefinition();
coreInstanceDefinition.setInstanceCount(1);
coreInstanceDefinition.setInstanceType(MockEc2OperationsImpl.INSTANCE_TYPE_1);
instanceDefinitions.setCoreInstances(coreInstanceDefinition);
InstanceDefinition taskInstanceDefinition = new InstanceDefinition();
taskInstanceDefinition.setInstanceCount(1);
taskInstanceDefinition.setInstanceType(MockEc2OperationsImpl.INSTANCE_TYPE_1);
instanceDefinitions.setTaskInstances(taskInstanceDefinition);
emrClusterDefinition.setInstanceDefinitions(instanceDefinitions);
List<NodeTag> nodeTags = new ArrayList<>();
{
nodeTags.add(new NodeTag("test_nodeTagName", "test_nodeTagValue"));
}
emrClusterDefinition.setNodeTags(nodeTags);
return emrClusterDefinition;
}
}