// 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.resource; import java.lang.reflect.Field; import java.nio.file.Paths; import java.util.Map; import org.junit.Ignore; import com.twitter.heron.api.Config; import com.twitter.heron.api.generated.TopologyAPI; import com.twitter.heron.api.topology.TopologyBuilder; import com.twitter.heron.common.basics.SingletonRegistry; import com.twitter.heron.common.config.SystemConfig; import com.twitter.heron.common.config.SystemConfigKey; import com.twitter.heron.proto.stmgr.StreamManager; import com.twitter.heron.proto.system.Common; import com.twitter.heron.proto.system.PhysicalPlans; /** * A helper used for unit test, it provides following util methods: * 1. Get a mock physical plan * 2. Clear the singleton registry by using reflection * 3. Get a RegisterInstanceResponse, used by a mock stream manager to send back to instance when it * receives a RegisterInstanceRequest */ @Ignore public final class UnitTestHelper { private UnitTestHelper() { } /** * Construct a physical plan with basic setting. * * @param ackEnabled whether the acking system is enabled * @param messageTimeout the seconds for a tuple to be time-out. -1 means the timeout is not enabled. * @param topologyState the Topology State inside this PhysicalPlan, for instance, RUNNING. * @return the corresponding Physical Plan */ public static PhysicalPlans.PhysicalPlan getPhysicalPlan( boolean ackEnabled, int messageTimeout, TopologyAPI.TopologyState topologyState) { PhysicalPlans.PhysicalPlan.Builder pPlan = PhysicalPlans.PhysicalPlan.newBuilder(); setTopology(pPlan, ackEnabled, messageTimeout, topologyState); setInstances(pPlan); setStMgr(pPlan); return pPlan.build(); } public static PhysicalPlans.PhysicalPlan getPhysicalPlan(boolean ackEnabled, int messageTimeout) { return getPhysicalPlan(ackEnabled, messageTimeout, TopologyAPI.TopologyState.RUNNING); } private static void setTopology(PhysicalPlans.PhysicalPlan.Builder pPlan, boolean ackEnabled, int messageTimeout, TopologyAPI.TopologyState topologyState) { TopologyBuilder topologyBuilder = new TopologyBuilder(); topologyBuilder.setSpout("test-spout", new TestSpout(), 1); // Here we need case switch to corresponding grouping topologyBuilder.setBolt("test-bolt", new TestBolt(), 1).shuffleGrouping("test-spout"); Config conf = new Config(); conf.setTeamEmail("streaming-compute@twitter.com"); conf.setTeamName("stream-computing"); conf.setTopologyProjectName("heron-integration-test"); conf.setNumStmgrs(1); conf.setMaxSpoutPending(100); if (ackEnabled) { conf.setEnableAcking(true); } else { conf.setEnableAcking(false); } if (messageTimeout != -1) { conf.setMessageTimeoutSecs(messageTimeout); conf.put("topology.enable.message.timeouts", "true"); } TopologyAPI.Topology fTopology = topologyBuilder.createTopology(). setName("topology-name"). setConfig(conf). setState(topologyState). getTopology(); pPlan.setTopology(fTopology); } private static void setInstances(PhysicalPlans.PhysicalPlan.Builder pPlan) { // Construct the spoutInstance PhysicalPlans.InstanceInfo.Builder spoutInstanceInfo = PhysicalPlans.InstanceInfo.newBuilder(); spoutInstanceInfo.setComponentName("test-spout"); spoutInstanceInfo.setTaskId(0); spoutInstanceInfo.setComponentIndex(0); PhysicalPlans.Instance.Builder spoutInstance = PhysicalPlans.Instance.newBuilder(); spoutInstance.setInstanceId("spout-id"); spoutInstance.setStmgrId("stream-manager-id"); spoutInstance.setInfo(spoutInstanceInfo); // Construct the boltInstanceInfo PhysicalPlans.InstanceInfo.Builder boltInstanceInfo = PhysicalPlans.InstanceInfo.newBuilder(); boltInstanceInfo.setComponentName("test-bolt"); boltInstanceInfo.setTaskId(1); boltInstanceInfo.setComponentIndex(0); PhysicalPlans.Instance.Builder boltInstance = PhysicalPlans.Instance.newBuilder(); boltInstance.setInstanceId("bolt-id"); boltInstance.setStmgrId("stream-manager-id"); boltInstance.setInfo(boltInstanceInfo); pPlan.addInstances(spoutInstance); pPlan.addInstances(boltInstance); } private static void setStMgr(PhysicalPlans.PhysicalPlan.Builder pPlan) { PhysicalPlans.StMgr.Builder stmgr = PhysicalPlans.StMgr.newBuilder(); stmgr.setId("stream-manager-id"); stmgr.setHostName("127.0.0.1"); stmgr.setDataPort(8888); stmgr.setLocalEndpoint("endpoint"); pPlan.addStmgrs(stmgr); } @SuppressWarnings("unchecked") public static void clearSingletonRegistry() throws Exception { // Remove the Singleton by Reflection Field field = SingletonRegistry.INSTANCE.getClass().getDeclaredField("singletonObjects"); field.setAccessible(true); Map<String, Object> singletonObjects = (Map<String, Object>) field.get(SingletonRegistry.INSTANCE); singletonObjects.clear(); } public static PhysicalPlans.Instance getInstance(String instanceId) { int taskId = 0; int componentIndex = 0; String componentName = "component_name"; String streamId = "stream_id"; // Create the protobuf Instance PhysicalPlans.InstanceInfo instanceInfo = PhysicalPlans.InstanceInfo.newBuilder(). setTaskId(taskId).setComponentIndex(componentIndex).setComponentName(componentName).build(); PhysicalPlans.Instance instance = PhysicalPlans.Instance.newBuilder(). setInstanceId(instanceId).setStmgrId(streamId).setInfo(instanceInfo).build(); return instance; } public static void addSystemConfigToSingleton() { String runFiles = System.getenv(Constants.BUILD_TEST_SRCDIR); if (runFiles == null) { throw new RuntimeException("Failed to fetch run files resources from built jar"); } String filePath = Paths.get(runFiles, Constants.BUILD_TEST_HERON_INTERNALS_CONFIG_PATH).toString(); SystemConfig.Builder sb = SystemConfig.newBuilder(true) .putAll(filePath, true) .put(SystemConfigKey.HERON_METRICS_EXPORT_INTERVAL, 1); SingletonRegistry.INSTANCE.registerSingleton(Constants.HERON_SYSTEM_CONFIG, sb.build()); } public static StreamManager.RegisterInstanceResponse getRegisterInstanceResponse() { StreamManager.RegisterInstanceResponse.Builder registerInstanceResponse = StreamManager.RegisterInstanceResponse.newBuilder(); registerInstanceResponse.setPplan(getPhysicalPlan(false, -1)); Common.Status.Builder status = Common.Status.newBuilder(); status.setStatus(Common.StatusCode.OK); registerInstanceResponse.setStatus(status); return registerInstanceResponse.build(); } }