// Copyright 2016 Twitter. 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 com.twitter.heron.packing; import com.twitter.heron.common.basics.ByteAmount; import com.twitter.heron.common.basics.Pair; import com.twitter.heron.packing.builder.PackingPlanBuilder; import com.twitter.heron.spi.packing.InstanceId; import com.twitter.heron.spi.packing.PackingPlan; import com.twitter.heron.spi.packing.Resource; /** * Utility methods for common test methods related to packing */ public final class PackingTestHelper { private PackingTestHelper() { } public static PackingPlan createTestPackingPlan(String topologyName, Pair<Integer, String>[] instances, int containerPadding) throws ResourceExceededException { return generateTestPackingPlan(topologyName, null, instances, null, containerPadding); } public static PackingPlan addToTestPackingPlan(String topologyName, PackingPlan previousPackingPlan, Pair<Integer, String>[] instances, int containerPadding) throws ResourceExceededException { return generateTestPackingPlan( topologyName, previousPackingPlan, instances, null, containerPadding); } public static PackingPlan removeFromTestPackingPlan(String topologyName, PackingPlan previousPackingPlan, Pair<Integer, String>[] instances, int containerPadding) throws ResourceExceededException { return generateTestPackingPlan( topologyName, previousPackingPlan, null, instances, containerPadding); } /** * Returns a PackingPlan to use for testing scale up/down that has instances of specific * components on specific containers. */ private static PackingPlan generateTestPackingPlan(String topologyName, PackingPlan previousPackingPlan, Pair<Integer, String>[] addInstances, Pair<Integer, String>[] removeInstances, int containerPadding) throws ResourceExceededException { PackingPlanBuilder builder = new PackingPlanBuilder(topologyName, previousPackingPlan); int instanceCount = 0; if (previousPackingPlan != null) { instanceCount = previousPackingPlan.getInstanceCount(); } else if (addInstances != null) { instanceCount = addInstances.length; } // use basic default resource to allow all instances to fit on a single container, if that's // what the tester desired. We can extend this to permit passing custom resource requirements // as needed. builder.setDefaultInstanceResource( new Resource(1, ByteAmount.fromMegabytes(192), ByteAmount.fromMegabytes(1))); builder.setMaxContainerResource(new Resource( instanceCount, ByteAmount.fromMegabytes(192).multiply(instanceCount), ByteAmount.fromMegabytes(instanceCount))); // This setting is important, see https://github.com/twitter/heron/issues/1577 builder.setRequestedContainerPadding(containerPadding); if (addInstances != null) { for (Pair<Integer, String> componentInstance : addInstances) { builder.addInstance(componentInstance.first, componentInstance.second); } } if (removeInstances != null) { for (Pair<Integer, String> componentInstance : removeInstances) { builder.removeInstance(componentInstance.first, componentInstance.second); } } return builder.build(); } public static Pair<Integer, String>[] toContainerIdComponentNames( Pair<Integer, InstanceId>[] containerIdInstanceIds) { @SuppressWarnings({"unchecked", "rawtypes"}) Pair<Integer, String>[] containerIdComponentNames = new Pair[containerIdInstanceIds.length]; int i = 0; for (Pair<Integer, InstanceId> containerIdInstanceId : containerIdInstanceIds) { containerIdComponentNames[i++] = new Pair<>( containerIdInstanceId.first, containerIdInstanceId.second.getComponentName()); } return containerIdComponentNames; } }